[nnc] Fix pool operation round mode (#2470)
authorПавел Ильютченко/AI Tools Lab /SRR/Engineer/삼성전자 <p.iliutchenk@samsung.com>
Mon, 3 Dec 2018 16:05:35 +0000 (19:05 +0300)
committerEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Mon, 3 Dec 2018 16:05:35 +0000 (19:05 +0300)
* Add round mode to Pool operations for each framework
* Fix output shape for pooling operation
* Fix strides on Pool op shape inference

Signed-off-by: Pavel Iliutchenko <p.iliutchenk@samsung.com>
contrib/nnc/core/modelIR/operations/PoolOp.cpp
contrib/nnc/include/core/modelIR/operations/PoolOp.h
contrib/nnc/passes/caffe_frontend/caffe_op_creator.cpp
contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp
contrib/nnc/tests/interpreter/graph_creator.cpp
contrib/nnc/unittests/soft_backend/CPPOperations.cpp

index 457ee01..a49e1da 100644 (file)
@@ -50,8 +50,18 @@ void PoolOp::inferOutputShapes() {
       _paddings.at(1) = 0;
       // FALLTHROUGH
     case ops::PaddingType::Custom:
-      output_shape.dim(1) = (input_shape.dim(1) + 2 * getPadding(0) - window_shape.dim(0)) / strides.dim(0) + 1;
-      output_shape.dim(2) = (input_shape.dim(2) + 2 * getPadding(1) - window_shape.dim(1)) / strides.dim(0) + 1;
+      switch (_roundMode) {
+        case PoolOp::RoundMode::ceil:
+          output_shape.dim(1) = static_cast<int>(ceil(static_cast<double>(
+              input_shape.dim(1) + 2 * getPadding(0) - window_shape.dim(0)) / strides.dim(0))) + 1;
+          output_shape.dim(2) = static_cast<int>(ceil(static_cast<double>(
+              input_shape.dim(2) + 2 * getPadding(1) - window_shape.dim(1)) / strides.dim(1))) + 1;
+          break;
+        case PoolOp::RoundMode::floor:
+          output_shape.dim(1) = (input_shape.dim(1) + 2 * getPadding(0) - window_shape.dim(0)) / strides.dim(0) + 1;
+          output_shape.dim(2) = (input_shape.dim(2) + 2 * getPadding(1) - window_shape.dim(1)) / strides.dim(1) + 1;
+          break;
+      }
       break;
     default:
       assert(false && "invalid padding type");
index 2576e8a..df411c3 100644 (file)
@@ -20,6 +20,7 @@
 #include "core/modelIR/Operation.h"
 #include "core/modelIR/operations/common.h"
 #include <vector>
+#include <cmath>
 
 namespace nnc {
 namespace mir {
@@ -38,19 +39,26 @@ public:
     EMPTY // Consider that there are no elements outside of input shape
   };
 
+  enum class RoundMode {
+    ceil, // used in caffe
+    floor // used in tflite
+  };
+
   PoolOp(const IODescriptor& arg,
          const Shape& window_shape,
          const Shape& strides,
          PoolingType pooling_type,
          const std::vector<int32_t>& paddings,
-         BorderType border_type)
+         BorderType border_type,
+         RoundMode round_mode)
       : Operation(Type::pool, {arg}),
         _windowShape(window_shape),
         _strides(strides),
         _poolingType(pooling_type),
         _paddingType(PaddingType::Custom),
         _paddings(paddings),
-        _borderType(border_type) {
+        _borderType(border_type),
+        _roundMode(round_mode) {
     inferOutputShapes();
   }
 
@@ -59,14 +67,16 @@ public:
          const Shape& strides,
          PoolingType pooling_type,
          PaddingType padding_type,
-         BorderType border_type)
+         BorderType border_type,
+         RoundMode round_mode)
       : Operation(Type::pool, {arg}),
         _windowShape(window_shape),
         _strides(strides),
         _poolingType(pooling_type),
         _paddingType(padding_type),
         _paddings(window_shape.rank()),
-        _borderType(border_type) {
+        _borderType(border_type),
+        _roundMode(round_mode) {
     assert(_paddingType != PaddingType::Custom);
     inferOutputShapes();
   }
@@ -88,6 +98,7 @@ private:
   PaddingType _paddingType;
   PoolingType _poolingType;
   BorderType _borderType;
+  RoundMode _roundMode;
   Shape _windowShape;
   Shape _strides;
   std::vector<int32_t> _paddings;
index 4b6a5d6..d66563a 100644 (file)
@@ -402,7 +402,7 @@ CaffeOpCreator::convertPooling(const caffe::LayerParameter& layer,
   }
 
   auto pooling = createOp<ops::PoolOp>(layer.name(), inputs[0], window_shape, strides, pool_type,
-                                       paddings, border_type);
+                                       paddings, border_type, ops::PoolOp::RoundMode::ceil);
 
   return {pooling->getOutput(0)};
 }
index a5b86ca..b8304a6 100644 (file)
@@ -103,7 +103,8 @@ std::vector<mir::Operation*> TFLiteOpCreator::convertMaxPool2D(InputOps inputs,
   Shape strides{opts->stride_h(), opts->stride_w(), 1};
   return createOp<ops::PoolOp>(opts->fused_activation_function(), inputs[0]->getOutput(0),
                                window_shape, strides, ops::PoolOp::PoolingType::MAX,
-                               paddingMap[opts->padding()], ops::PoolOp::BorderType::EMPTY);
+                               paddingMap[opts->padding()], ops::PoolOp::BorderType::EMPTY,
+                               ops::PoolOp::RoundMode::floor);
 }
 
 std::vector<mir::Operation*> TFLiteOpCreator::convertAveragePool2D(InputOps inputs,
@@ -113,7 +114,8 @@ std::vector<mir::Operation*> TFLiteOpCreator::convertAveragePool2D(InputOps inpu
   Shape strides{opts->stride_h(), opts->stride_w(), 1};
   return createOp<ops::PoolOp>(opts->fused_activation_function(), inputs[0]->getOutput(0),
                                window_shape, strides, ops::PoolOp::PoolingType::AVG,
-                               paddingMap[opts->padding()], ops::PoolOp::BorderType::EMPTY);
+                               paddingMap[opts->padding()], ops::PoolOp::BorderType::EMPTY,
+                               ops::PoolOp::RoundMode::floor);
 }
 
 std::vector<mir::Operation*> TFLiteOpCreator::createSoftmax(InputOps inputs, InputParams params,
@@ -297,7 +299,7 @@ std::vector<mir::Operation*> TFLiteOpCreator::createPad(InputOps inputs, InputPa
 
   paddings.reserve(static_cast<size_t>(num_dims));
   // create strucuture with paddings
-  for (int i = 1; i < num_dims; i++)
+  for (int i = 0; i < num_dims; i++)
     paddings.emplace_back(paddings_tensor.at(Index({i, 0})), paddings_tensor.at(Index({i, 1})));
   // create const value, it's float because we can't see input type
   float const_value = 0.0; // not support different constant value
@@ -305,7 +307,7 @@ std::vector<mir::Operation*> TFLiteOpCreator::createPad(InputOps inputs, InputPa
   Scalar constant_value(reinterpret_cast<char*>(&const_value), DTYPE::FLOAT32, sizeof(float));
 
   return createOp<ops::PadOp>(ActivationFunctionType_NONE, inputs[0]->getOutput(0),
-                              num_dims - 1, paddings, constant_value);
+                              num_dims, paddings, constant_value);
 }
 
 std::vector<mir::Operation*>
index f08185f..f870a72 100644 (file)
@@ -63,7 +63,8 @@ static Operation* createPool(std::unique_ptr<Graph>& g,
                              const opinfo::OperatorInfo* opInfo) {
   return g->create<ops::PoolOp>("y", inputs[0], getShapeParam(opInfo, 0), getShapeParam(opInfo, 1),
                                 getPoolingType(opInfo), getPaddingType(opInfo),
-                                ops::PoolOp::BorderType::ZEROFILLED);
+                                ops::PoolOp::BorderType::ZEROFILLED,
+                                ops::PoolOp::RoundMode::floor);
 }
 
 static Operation* createConcatenation(std::unique_ptr<Graph>& g,
index 31e649c..f7109c0 100644 (file)
@@ -581,7 +581,7 @@ static void genericPoolTest(Func testFunc, const vector<irOps::PoolOp::BorderTyp
               auto opGenerator = [windowShape, strides, padT, border](mir::Graph& g,
                                                                       const std::vector<mir::IODescriptor>& inputs) {
                 return g.create<mir::ops::PoolOp>("y", inputs[0], windowShape, strides, poolT, padT,
-                                                  border);
+                                                  border, irOps::PoolOp::RoundMode::floor);
               };
 
               createAndRunTestGraph(opGenerator, testFunc, inputNTensors, aInputTensor);