From: 박종현/동작제어Lab(SR)/Senior Engineer/삼성전자 Date: Tue, 10 Apr 2018 08:10:12 +0000 (+0900) Subject: Introduce nnfw::util::tensor::Object (#505) X-Git-Tag: 0.1~362 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=14b263339f7c9a92dd285aa29d31e906e8d7bc48;p=platform%2Fcore%2Fml%2Fnnfw.git Introduce nnfw::util::tensor::Object (#505) This commit introduces nnfw::util::tensor::Object, which makes it easy to generate a random tensor object for testing. This commit also simplifies nnapi_test and nnapi_unintest_conv_1 implementations using this new helper class. Signed-off-by: Jonghyun Park --- diff --git a/include/util/tensor/NonIncreasingStride.h b/include/util/tensor/NonIncreasingStride.h index 30a5c1e..55ee700 100644 --- a/include/util/tensor/NonIncreasingStride.h +++ b/include/util/tensor/NonIncreasingStride.h @@ -29,6 +29,9 @@ public: } public: + uint32_t at(uint32_t axis) const { return _stride.at(axis); } + +public: uint32_t offset(const Index &index) const; private: diff --git a/include/util/tensor/Object.h b/include/util/tensor/Object.h new file mode 100644 index 0000000..41ba0e1 --- /dev/null +++ b/include/util/tensor/Object.h @@ -0,0 +1,61 @@ +#ifndef __NNFW_UTIL_TENSOR_OBJECT_H__ +#define __NNFW_UTIL_TENSOR_OBJECT_H__ + +#include "util/tensor/Shape.h" +#include "util/tensor/Index.h" +#include "util/tensor/IndexIterator.h" +#include "util/tensor/NonIncreasingStride.h" +#include "util/tensor/Reader.h" + +#include + +namespace nnfw +{ +namespace util +{ +namespace tensor +{ + +template class Object final : public Reader +{ +public: + using Generator = std::function; + +public: + Object(const Shape &shape, const Generator &fn) : _shape{shape} + { + // Set 'stride' + _stride.init(shape); + + // Pre-allocate buffer + _values.resize(_shape.dim(0) * _stride.at(0)); + + // Set 'value' + iterate(_shape) << [this, &fn] (const Index &index) + { + _values.at(_stride.offset(index)) = fn(_shape, index); + }; + } + +public: + const Shape &shape(void) const { return _shape; } + +public: + T at(const Index &index) const override + { + return _values.at(_stride.offset(index)); + } + +private: + Shape _shape; + NonIncreasingStride _stride; + +private: + std::vector _values; +}; + +} // namespace tensor +} // namespace util +} // namespace nnfw + +#endif // __NNFW_UTIL_FEATURE_OBJECT_H__ diff --git a/tools/nnapi_test/src/nnapi_test.cc b/tools/nnapi_test/src/nnapi_test.cc index 5ff9511..d6af1f4 100644 --- a/tools/nnapi_test/src/nnapi_test.cc +++ b/tools/nnapi_test/src/nnapi_test.cc @@ -3,7 +3,9 @@ #include "util/environment.h" #include "util/fp32.h" +#include "util/vector.h" #include "util/tensor/IndexIterator.h" +#include "util/tensor/Object.h" #include "support/tflite/interp/FlatBufferBuilder.h" #include "support/tflite/Diff.h" @@ -29,13 +31,21 @@ void initialize_interpreter(Interpreter &interpreter) std::default_random_engine generator(0); std::uniform_real_distribution distribution(0.0f, 1.0f); + auto number_fn = [&] (const nnfw::util::tensor::Shape &, const nnfw::util::tensor::Index &) + { + return distribution(generator); + }; + for (const auto &id : interpreter.inputs()) { auto view = nnfw::support::tflite::TensorView::make(interpreter, id); + const nnfw::util::tensor::Object data(view.shape(), number_fn); + + assert(view.shape() == data.shape()); nnfw::util::tensor::iterate(view.shape()) << [&] (const nnfw::util::tensor::Index &ind) { - view.at(ind) = distribution(generator); + view.at(ind) = data.at(ind); }; } } diff --git a/tools/nnapi_unittests/tests/conv_1.cpp b/tools/nnapi_unittests/tests/conv_1.cpp index 1629e01..41fe208 100644 --- a/tools/nnapi_unittests/tests/conv_1.cpp +++ b/tools/nnapi_unittests/tests/conv_1.cpp @@ -7,11 +7,14 @@ #include "util/feature/IndexIterator.h" #include "util/feature/Object.h" #include "util/feature/Reader.h" +#include "util/tensor/Object.h" + #include "util/fp32.h" #include "util/environment.h" #include "support/tflite/Diff.h" #include "support/tflite/FeatureView.h" +#include "support/tflite/TensorView.h" #include "support/tflite/interp/FunctionBuilder.h" #include @@ -62,15 +65,6 @@ int main(int argc, char **argv) // Initialize random number generator std::minstd_rand random(SEED); - // Fill IFM with random numbers - auto ifm_gen = [&random] (const nnfw::util::feature::Shape &, const nnfw::util::feature::Index &) - { - std::normal_distribution dist(0.0f,2.0f); - return dist(random); - }; - const nnfw::util::feature::Shape ifm_shape{IFM_C, IFM_H, IFM_W}; - const nnfw::util::feature::Object ifm{ifm_shape, ifm_gen}; - std::cout << "Configurations:" << std::endl; #define PRINT_NEWLINE() { std::cout << std::endl; } #define PRINT_VALUE(value) { std::cout << " " << #value << ": " << (value) << std::endl; } @@ -199,26 +193,6 @@ int main(int argc, char **argv) // Set Tensor #1 as Input #0, and Tensor #0 as Output #0 interp.SetInputs({1}); interp.SetOutputs({0}); - - // Allocate Tensor - interp.AllocateTensors(); - - // Fill IFM data in HWC order - { - nnfw::support::tflite::FeatureView interp_input{interp, InputIndex{0}}; - - for (uint32_t row = 0; row < ifm.shape().H; ++row) - { - for (uint32_t col = 0; col < ifm.shape().W; ++col) - { - for (uint32_t ch = 0; ch < ifm.shape().C; ++ch) - { - const auto value = ifm.at(ch, row, col); - interp_input.at(ch, row, col) = value; - } - } - } - } }; const nnfw::support::tflite::interp::FunctionBuilder builder(setup); @@ -229,6 +203,39 @@ int main(int argc, char **argv) pure->UseNNAPI(false); delegated->UseNNAPI(true); + // Allocate Tensors + pure->AllocateTensors(); + delegated->AllocateTensors(); + + assert(pure->inputs() == delegated->inputs()); + + // Fill IFM with random numbers + auto ifm_gen = [&random] (const nnfw::util::tensor::Shape &, const nnfw::util::tensor::Index &) + { + std::normal_distribution dist(0.0f, 2.0f); + return dist(random); + }; + + for (const auto id : pure->inputs()) + { + auto pure_view = nnfw::support::tflite::TensorView::make(*pure, id); + auto nnapi_view = nnfw::support::tflite::TensorView::make(*pure, id); + + assert(pure_view.shape() == nnapi_view.shape()); + + const nnfw::util::tensor::Object data(pure_view.shape(), ifm_gen); + + assert(pure_view.shape() == data.shape()); + + nnfw::util::tensor::iterate(pure_view.shape()) << [&] (const nnfw::util::tensor::Index &ind) + { + const auto value = data.at(ind); + + pure_view.at(ind) = value; + nnapi_view.at(ind) = value; + }; + } + // Let's Rock-n-Roll! pure->Invoke(); delegated->Invoke();