Introduce TfLiteFeatureView (#412)
author박종현/동작제어Lab(SR)/Senior Engineer/삼성전자 <jh1302.park@samsung.com>
Wed, 4 Apr 2018 06:42:02 +0000 (15:42 +0900)
committer김정현/동작제어Lab(SR)/Senior Engineer/삼성전자 <jh0822.kim@samsung.com>
Wed, 4 Apr 2018 06:42:02 +0000 (15:42 +0900)
This commit implements TfLiteFeatureView in NN API Unittest (conv_1).

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
tools/nnapi_unittests/tests/conv_1.cpp

index 25b140e..7841c2a 100644 (file)
@@ -6,12 +6,72 @@
 #include "env.h"
 
 #include "util/feature/RandomObject.h"
+#include "util/feature/Reader.h"
 
 #include <iostream>
+#include <cassert>
 
 using namespace tflite;
 using namespace tflite::ops::builtin;
 
+class TfLiteOutputIndex
+{
+public:
+  TfLiteOutputIndex(int index) : _index(index)
+  {
+
+  }
+
+public:
+  int asInt(void) const { return _index; }
+
+private:
+  int _index;
+};
+
+template<typename T> class TfLiteFeatureView;
+
+template<> class TfLiteFeatureView<float> : public nnfw::util::feature::Reader<float>
+{
+public:
+  TfLiteFeatureView(tflite::Interpreter &interp, const TfLiteOutputIndex &index);
+
+public:
+  float at(uint32_t ch, uint32_t row, uint32_t col) const;
+
+private:
+  nnfw::util::feature::Shape _shape;
+  float *_base;
+};
+
+TfLiteFeatureView<float>::TfLiteFeatureView(tflite::Interpreter &interp, const TfLiteOutputIndex &index)
+{
+  const auto tensor_index = interp.outputs().at(index.asInt());
+  auto tensor_ptr = interp.tensor(tensor_index);
+
+  assert(tensor_ptr->type == kTfLiteFloat32);
+  assert(tensor_ptr->dims->size == 4);
+  assert(tensor_ptr->dims->data[0] == 1);
+
+  _shape.C = tensor_ptr->dims->data[3];
+  _shape.H = tensor_ptr->dims->data[1];
+  _shape.W = tensor_ptr->dims->data[2];
+
+  _base = interp.typed_tensor<float>(tensor_index);
+}
+
+float TfLiteFeatureView<float>::at(uint32_t ch, uint32_t row, uint32_t col) const
+{
+  uint32_t element_offset = 0;
+
+  // TensorFlow Lite assumes that NHWC ordering for tessor
+  element_offset += row * _shape.W * _shape.C;
+  element_offset += col * _shape.C;
+  element_offset += ch;
+
+  return *(_base + element_offset);
+}
+
 int main(int argc, char **argv)
 {
 #define INT_VALUE(NAME, VALUE) IntVar NAME##_Value(#NAME, VALUE);
@@ -192,7 +252,8 @@ int main(int argc, char **argv)
 
   // Compare OFM
   {
-    uint32_t off = 0;
+    const TfLiteFeatureView<float> interp_output{pure, TfLiteOutputIndex{0}};
+    const TfLiteFeatureView<float> nnapi_output{delegated, TfLiteOutputIndex{0}};
 
     for (uint32_t row = 0; row < OFM_H; ++row)
     {
@@ -200,8 +261,8 @@ int main(int argc, char **argv)
       {
         for (uint32_t ch = 0; ch < kernel.shape().N; ++ch)
         {
-          const auto value_from_interp = pure.typed_output_tensor<float>(0)[off];
-          const auto value_from_NNAPI = delegated.typed_output_tensor<float>(0)[off];
+          const auto value_from_interp = interp_output.at(ch, row, col);
+          const auto value_from_NNAPI = nnapi_output.at(ch, row, col);
 
           if (value_from_interp != value_from_NNAPI)
           {
@@ -209,8 +270,6 @@ int main(int argc, char **argv)
             std::cerr << "  Value from interpreter: " << value_from_interp << std::endl;
             std::cerr << "  Value from NNAPI: " << value_from_NNAPI << std::endl;
           }
-
-          off += 1;
         }
       }
     }