From 140fdc76e99c92b2f71865b679de0659a70b713f Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Fri, 16 Feb 2018 11:42:38 +0000 Subject: COMPMID-913: Fix preprocessing step for TF models. Change-Id: If0fbb6bbe5384038124d3dc189274b8266f796ca Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/120771 Reviewed-by: Anthony Barbier Reviewed-by: Pablo Tello Tested-by: Jenkins --- utils/GraphUtils.cpp | 65 +++++++++++++++++++++++++---------------- utils/GraphUtils.h | 81 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 88 insertions(+), 58 deletions(-) (limited to 'utils') diff --git a/utils/GraphUtils.cpp b/utils/GraphUtils.cpp index a36cf8ea9f..448343a977 100644 --- a/utils/GraphUtils.cpp +++ b/utils/GraphUtils.cpp @@ -36,6 +36,41 @@ using namespace arm_compute::graph_utils; +void TFPreproccessor::preprocess(ITensor &tensor) +{ + Window window; + window.use_tensor_dimensions(tensor.info()->tensor_shape()); + + execute_window_loop(window, [&](const Coordinates & id) + { + const float value = *reinterpret_cast(tensor.ptr_to_element(id)); + float res = value / 255.f; // Normalize to [0, 1] + res = (res - 0.5f) * 2.f; // Map to [-1, 1] + *reinterpret_cast(tensor.ptr_to_element(id)) = res; + }); +} + +CaffePreproccessor::CaffePreproccessor(std::array mean, bool bgr) + : _mean(mean), _bgr(bgr) +{ + if(_bgr) + { + std::swap(_mean[0], _mean[2]); + } +} + +void CaffePreproccessor::preprocess(ITensor &tensor) +{ + Window window; + window.use_tensor_dimensions(tensor.info()->tensor_shape()); + + execute_window_loop(window, [&](const Coordinates & id) + { + const float value = *reinterpret_cast(tensor.ptr_to_element(id)) - _mean[id.z()]; + *reinterpret_cast(tensor.ptr_to_element(id)) = value; + }); +} + PPMWriter::PPMWriter(std::string name, unsigned int maximum) : _name(std::move(name)), _iterator(0), _maximum(maximum) { @@ -76,28 +111,14 @@ bool DummyAccessor::access_tensor(ITensor &tensor) return ret; } -PPMAccessor::PPMAccessor(std::string ppm_path, bool bgr, - float mean_r, float mean_g, float mean_b, - float std_r, float std_g, float std_b) - : _ppm_path(std::move(ppm_path)), _bgr(bgr), _mean_r(mean_r), _mean_g(mean_g), _mean_b(mean_b), _std_r(std_r), _std_g(std_g), _std_b(std_b) +PPMAccessor::PPMAccessor(std::string ppm_path, bool bgr, std::unique_ptr preprocessor) + : _ppm_path(std::move(ppm_path)), _bgr(bgr), _preprocessor(std::move(preprocessor)) { } bool PPMAccessor::access_tensor(ITensor &tensor) { utils::PPMLoader ppm; - const float mean[3] = - { - _bgr ? _mean_b : _mean_r, - _mean_g, - _bgr ? _mean_r : _mean_b - }; - const float std[3] = - { - _bgr ? _std_b : _std_r, - _std_g, - _bgr ? _std_r : _std_b - }; // Open PPM file ppm.open(_ppm_path); @@ -108,15 +129,11 @@ bool PPMAccessor::access_tensor(ITensor &tensor) // Fill the tensor with the PPM content (BGR) ppm.fill_planar_tensor(tensor, _bgr); - // Subtract the mean value from each channel - Window window; - window.use_tensor_dimensions(tensor.info()->tensor_shape()); - - execute_window_loop(window, [&](const Coordinates & id) + // Preprocess tensor + if(_preprocessor) { - const float value = *reinterpret_cast(tensor.ptr_to_element(id)) - mean[id.z()]; - *reinterpret_cast(tensor.ptr_to_element(id)) = value / std[id.z()]; - }); + _preprocessor->preprocess(tensor); + } return true; } diff --git a/utils/GraphUtils.h b/utils/GraphUtils.h index b48e5b563d..cc6f40417e 100644 --- a/utils/GraphUtils.h +++ b/utils/GraphUtils.h @@ -29,6 +29,7 @@ #include "arm_compute/graph/ITensorAccessor.h" #include "arm_compute/graph/Types.h" +#include #include #include #include @@ -37,6 +38,38 @@ namespace arm_compute { namespace graph_utils { +/** Preprocessor interface **/ +class IPreprocessor +{ +public: + virtual ~IPreprocessor() = default; + virtual void preprocess(ITensor &tensor) = 0; +}; + +/** Caffe preproccessor */ +class CaffePreproccessor : public IPreprocessor +{ +public: + /** Default Constructor + * + * @param mean Mean array in RGB ordering + * @param bgr Boolean specifying if the preprocessing should assume BGR format + */ + CaffePreproccessor(std::array mean = std::array { { 0, 0, 0 } }, bool bgr = true); + void preprocess(ITensor &tensor) override; + +private: + std::array _mean; + bool _bgr; +}; + +/** TF preproccessor */ +class TFPreproccessor : public IPreprocessor +{ +public: + void preprocess(ITensor &tensor) override; +}; + /** PPM writer class */ class PPMWriter : public graph::ITensorAccessor { @@ -85,18 +118,11 @@ class PPMAccessor final : public graph::ITensorAccessor public: /** Constructor * - * @param[in] ppm_path Path to PPM file - * @param[in] bgr (Optional) Fill the first plane with blue channel (default = false) - * @param[in] mean_r (Optional) Red mean value to be subtracted from red channel - * @param[in] mean_g (Optional) Green mean value to be subtracted from green channel - * @param[in] mean_b (Optional) Blue mean value to be subtracted from blue channel - * @param[in] std_r (Optional) Red standard deviation value to be divided from red channel - * @param[in] std_g (Optional) Green standard deviation value to be divided from green channel - * @param[in] std_b (Optional) Blue standard deviation value to be divided from blue channel + * @param[in] ppm_path Path to PPM file + * @param[in] bgr (Optional) Fill the first plane with blue channel (default = false) + * @param[in] preprocessor (Optional) PPM pre-processing object */ - PPMAccessor(std::string ppm_path, bool bgr = true, - float mean_r = 0.0f, float mean_g = 0.0f, float mean_b = 0.0f, - float std_r = 1.f, float std_g = 1.f, float std_b = 1.f); + PPMAccessor(std::string ppm_path, bool bgr = true, std::unique_ptr preprocessor = nullptr); /** Allow instances of this class to be move constructed */ PPMAccessor(PPMAccessor &&) = default; @@ -104,14 +130,9 @@ public: bool access_tensor(ITensor &tensor) override; private: - const std::string _ppm_path; - const bool _bgr; - const float _mean_r; - const float _mean_g; - const float _mean_b; - const float _std_r; - const float _std_g; - const float _std_b; + const std::string _ppm_path; + const bool _bgr; + std::unique_ptr _preprocessor; }; /** Result accessor class */ @@ -226,21 +247,15 @@ inline std::unique_ptr get_weights_accessor(const std::s * * @note If ppm_path is empty will generate a DummyAccessor else will generate a PPMAccessor * - * @param[in] ppm_path Path to PPM file - * @param[in] mean_r Red mean value to be subtracted from red channel - * @param[in] mean_g Green mean value to be subtracted from green channel - * @param[in] mean_b Blue mean value to be subtracted from blue channel - * @param[in] std_r (Optional) Red standard deviation value to be divided from red channel - * @param[in] std_g (Optional) Green standard deviation value to be divided from green channel - * @param[in] std_b (Optional) Blue standard deviation value to be divided from blue channel - * @param[in] bgr (Optional) Fill the first plane with blue channel (default = true) + * @param[in] ppm_path Path to PPM file + * @param[in] preprocessor Preproccessor object + * @param[in] bgr (Optional) Fill the first plane with blue channel (default = true) * * @return An appropriate tensor accessor */ -inline std::unique_ptr get_input_accessor(const std::string &ppm_path, - float mean_r = 0.f, float mean_g = 0.f, float mean_b = 0.f, - float std_r = 1.f, float std_g = 1.f, float std_b = 1.f, - bool bgr = true) +inline std::unique_ptr get_input_accessor(const std::string &ppm_path, + std::unique_ptr preprocessor = nullptr, + bool bgr = true) { if(ppm_path.empty()) { @@ -248,9 +263,7 @@ inline std::unique_ptr get_input_accessor(const std::str } else { - return arm_compute::support::cpp14::make_unique(ppm_path, bgr, - mean_r, mean_g, mean_b, - std_r, std_g, std_b); + return arm_compute::support::cpp14::make_unique(ppm_path, bgr, std::move(preprocessor)); } } -- cgit v1.2.1