Introduce nnfw::util::tensor::Object (#505)
author박종현/동작제어Lab(SR)/Senior Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 10 Apr 2018 08:10:12 +0000 (17:10 +0900)
committer서상민/동작제어Lab(SR)/Senior Engineer/삼성전자 <sangmin7.seo@samsung.com>
Tue, 10 Apr 2018 08:10:12 +0000 (17:10 +0900)
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 <jh1302.park@samsung.com>
include/util/tensor/NonIncreasingStride.h
include/util/tensor/Object.h [new file with mode: 0644]
tools/nnapi_test/src/nnapi_test.cc
tools/nnapi_unittests/tests/conv_1.cpp

index 30a5c1e..55ee700 100644 (file)
@@ -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 (file)
index 0000000..41ba0e1
--- /dev/null
@@ -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 <vector>
+
+namespace nnfw
+{
+namespace util
+{
+namespace tensor
+{
+
+template<typename T> class Object final : public Reader<T>
+{
+public:
+  using Generator = std::function<T (const Shape &shape, const Index &index)>;
+
+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<T> _values;
+};
+
+} // namespace tensor
+} // namespace util
+} // namespace nnfw
+
+#endif // __NNFW_UTIL_FEATURE_OBJECT_H__
index 5ff9511..d6af1f4 100644 (file)
@@ -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<float> 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<float>::make(interpreter, id);
+    const nnfw::util::tensor::Object<float> 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);
     };
   }
 }
index 1629e01..41fe208 100644 (file)
@@ -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 <iostream>
@@ -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<float> 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<float> 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<float> 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<float> dist(0.0f, 2.0f);
+    return dist(random);
+  };
+
+  for (const auto id : pure->inputs())
+  {
+    auto pure_view = nnfw::support::tflite::TensorView<float>::make(*pure, id);
+    auto nnapi_view = nnfw::support::tflite::TensorView<float>::make(*pure, id);
+
+    assert(pure_view.shape() == nnapi_view.shape());
+
+    const nnfw::util::tensor::Object<float> 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();