[nnc] Fixed several ACL bugs (#2900)
authorIvan Vagin/AI Tools Lab /SRR/Engineer/삼성전자 <ivan.vagin@samsung.com>
Mon, 21 Jan 2019 15:47:55 +0000 (18:47 +0300)
committerEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Mon, 21 Jan 2019 15:47:55 +0000 (18:47 +0300)
* Increased padding if caffe formula for pooling output producing wrong result
* Removed `RoundMode` from `PoolOp`
* Added missing argument for generated `CLArithmeticAddition` call

Signed-off-by: Ivan Vagin <ivan.vagin@samsung.com>
contrib/nnc/core/modelIR/operations/PoolOp.cpp
contrib/nnc/include/core/modelIR/operations/PoolOp.h
contrib/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp
contrib/nnc/passes/caffe2_frontend/caffe2_op_creator.cpp
contrib/nnc/passes/caffe_frontend/caffe_op_creator.cpp
contrib/nnc/passes/onnx_frontend/ONNXOpCreator.cpp
contrib/nnc/passes/tflite_frontend/tflite_op_creator.cpp
contrib/nnc/tests/interpreter/graph_creator.cpp
contrib/nnc/unittests/acl_backend/MIRToDOM.cpp
contrib/nnc/unittests/soft_backend/CPPOperations.cpp

index 318dd47..29f5638 100644 (file)
@@ -35,30 +35,12 @@ void PoolOp::inferOutputShapes() {
   output_shape.dim(0) = input_shape.dim(0);
   output_shape.dim(3) = input_shape.dim(3);
 
-  // Height and width.
-  switch (_roundMode) {
-    case RoundMode::ceil:
-      for (int i = 0; i < 2; i++) {
-        auto padded_input = input_shape.dim(1 + i) + _paddingBefore.at(i) + _paddingAfter.at(i);
-        // Incorrect formula taken from Caffe leading to out-of-bound accesses.
-        // out_size = ceil((in_size - window_size) / stride) + 1 =
-        //   = (in_size - window_size + stride - 1) / stride + 1 =
-        //   = ceil((in_size - window_size + stride) / stride)
-        output_shape.dim(1 + i) =
-            (padded_input - _windowShape.dim(i) + _strides.dim(i) - 1) / _strides.dim(i) + 1;
-      }
-      break;
-    case RoundMode::floor:
-      for (int i = 0; i < 2; i++) {
-        auto padded_input = input_shape.dim(1 + i) + _paddingBefore.at(i) + _paddingAfter.at(i);
-        // out_size = ceil((in_size - window_size + 1) / stride) =
-        //   (in_size - window_size + 1 + stride - 1) / stride =
-        //   (in_size - window_size) / stride + 1
-        output_shape.dim(1 + i) = (padded_input - _windowShape.dim(i)) / _strides.dim(i) + 1;
-      }
-      break;
-    default:
-      assert(false);
+  for (int i = 0; i < 2; i++) {
+    auto padded_input = input_shape.dim(1 + i) + _paddingBefore.at(i) + _paddingAfter.at(i);
+    // out_size = ceil((in_size - window_size + 1) / stride) =
+    //   (in_size - window_size + 1 + stride - 1) / stride =
+    //   (in_size - window_size) / stride + 1
+    output_shape.dim(1 + i) = (padded_input - _windowShape.dim(i)) / _strides.dim(i) + 1;
   }
 
   for (int i = 0; i < output_shape.rank(); i++) {
index 19e9f32..37ff694 100644 (file)
@@ -39,28 +39,20 @@ public:
     EMPTY // Consider that there are no elements outside of input shape
   };
 
-  // Rounding mode to use when calculating the output size.
-  enum class RoundMode {
-    ceil,
-    floor
-  };
-
   PoolOp(const IODescriptor& arg,
          PoolingType pooling_type,
          const Shape& window_shape,
          const Shape& strides,
          const std::vector<int32_t>& padding_before,
          const std::vector<int32_t>& padding_after,
-         BorderType border_type,
-         RoundMode round_mode)
+         BorderType border_type)
       : Operation(Type::pool, {arg}),
         _poolingType(pooling_type),
         _windowShape(window_shape),
         _strides(strides),
         _paddingBefore(padding_before),
         _paddingAfter(padding_after),
-        _borderType(border_type),
-        _roundMode(round_mode) {
+        _borderType(border_type) {
     inferOutputShapes();
   }
 
@@ -85,7 +77,6 @@ private:
   std::vector<int32_t> _paddingBefore;
   std::vector<int32_t> _paddingAfter;
   BorderType _borderType;
-  RoundMode _roundMode;
 };
 
 } // namespace ops
index 2df49b1..8f69740 100644 (file)
@@ -801,7 +801,9 @@ shared_ptr<ArtifactId> AclCppOpGenerator::genAddition(const string& prefix, int
   auto arithmetic_add_layer = arithmetic_add_layer_var->use();
 
   // Generate the call: arithmetic_add_layer.configure(&in1, &in2, &out);
-  _constrBlock->call("configure", {AF::ref(in1), AF::ref(in2), AF::ref(out)}, arithmetic_add_layer);
+  _constrBlock->call("configure", {AF::ref(in1), AF::ref(in2), AF::ref(out),
+                                   AF::lit("arm_compute::ConvertPolicy::WRAP")},
+                     arithmetic_add_layer);
 
   // Generate the call: arithmetic_add_layer.run();
   _infBlock->call("run", {}, arithmetic_add_layer);
index 4f7c46a..d9bd917 100644 (file)
@@ -222,7 +222,7 @@ void Caffe2OpCreator::checkSpatialBN(const ::caffe2::OperatorDef& op,
 void Caffe2OpCreator::commonCheck(const ::caffe2::OperatorDef& op,
                                   std::set<std::string>& problemsOpSet) {
   if (getSingleArgument(op, "order", "NCHW") != "NCHW")
-    problemsOpSet.insert("Only 'NCHW' oreder is supported");
+    problemsOpSet.insert("Only 'NCHW' axis order is supported");
 }
 
 //
@@ -262,9 +262,8 @@ Caffe2OpCreator::convertAveragePool(const std::vector<IODescriptor>& inputs,
   std::vector<int32_t> pad_before, pad_after;
   std::tie(pad_before, pad_after) = getPadding(op);
 
-  auto pooling = createOp<ops::PoolOp>("Average_Pool", convertCaffeToMIR(inputs[0]), pool_type, window_shape,
-                                       strides, pad_before, pad_after, border_type,
-                                       ops::PoolOp::RoundMode::floor);
+  auto pooling = createOp<ops::PoolOp>("Average_Pool", convertCaffeToMIR(inputs[0]), pool_type,
+                                       window_shape, strides, pad_before, pad_after, border_type);
 
   return {convertMIRToCaffe(pooling->getOutput(0))};
 }
@@ -359,8 +358,7 @@ std::vector<IODescriptor> Caffe2OpCreator::convertMaxPool(const std::vector<IODe
   std::tie(pad_before, pad_after) = getPadding(op);
 
   auto pooling = createOp<ops::PoolOp>("Pool", convertCaffeToMIR(inputs[0]), pool_type, window_shape,
-                                       strides, pad_before, pad_after, border_type,
-                                       ops::PoolOp::RoundMode::floor);
+                                       strides, pad_before, pad_after, border_type);
 
   return {convertMIRToCaffe(pooling->getOutput(0))};
 }
index 423c8e4..d8323ea 100644 (file)
@@ -347,8 +347,10 @@ static ops::PoolOp::PoolingType getPoolingType(const PoolingParameter& pool_para
 }
 
 static void convertPoolingParam(const caffe::PoolingParameter& pool_param,
+                                const mir::Shape& input_shape,
                                 Shape& window_shape, Shape& strides,
-                                std::vector<int32_t>& padding) {
+                                std::vector<int32_t>& padding_before,
+                                std::vector<int32_t>& padding_after) {
   int32_t kernel_h, kernel_w;
   assert(!pool_param.global_pooling());
   if (pool_param.has_kernel_size()) {
@@ -375,7 +377,14 @@ static void convertPoolingParam(const caffe::PoolingParameter& pool_param,
   } else {
     pad_h = pad_w = pool_param.pad();
   }
-  padding = {pad_h, pad_w};
+
+  padding_before = padding_after = {pad_h, pad_w};
+  // Since Caffe has incorrect pooling output shape formula,
+  // which leading to out-of-bound accesses - increase padding if needed
+  if ((input_shape.dim(2) + pad_h * 2 - window_shape.dim(0)) % stride_h != 0)
+    ++padding_after[0];
+  if ((input_shape.dim(3) + pad_w * 2 - window_shape.dim(1)) % stride_w != 0)
+    ++padding_after[1];
 }
 
 void CaffeOpCreator::checkPooling(const PoolingParameter& opts,
@@ -397,9 +406,10 @@ CaffeOpCreator::convertPooling(const caffe::LayerParameter& layer,
   auto& opts = layer.pooling_param();
   Shape window_shape;
   Shape strides;
-  std::vector<int32_t> padding;
+  std::vector<int32_t> padding_before, padding_after;
 
-  convertPoolingParam(opts, window_shape, strides, padding);
+  const auto& input_shape = inputs[0].op->getOutputShape(inputs[0].index);
+  convertPoolingParam(opts, input_shape, window_shape, strides, padding_before, padding_after);
 
   ops::PoolOp::PoolingType pool_type = getPoolingType(opts);
   ops::PoolOp::BorderType border_type;
@@ -415,8 +425,8 @@ CaffeOpCreator::convertPooling(const caffe::LayerParameter& layer,
   }
 
   auto pooling = createOp<ops::PoolOp>(layer.name(), convertCaffeToMIR(inputs[0]), pool_type,
-                                       window_shape, strides, padding, padding, border_type,
-                                       ops::PoolOp::RoundMode::ceil);
+                                       window_shape, strides, padding_before, padding_after,
+                                       border_type);
   return {convertMIRToCaffe(pooling->getOutput(0))};
 }
 
index 32b9d25..fbc7e0b 100644 (file)
@@ -279,10 +279,8 @@ ONNXOpCreator::convertPool(const std::vector<mir::IODescriptor>& inputs,
     default:
       assert(false);
   }
-  auto result = createOp<ops::PoolOp>(t_input, pool_type,
-                                      cdata.kernel_shape, cdata.strides_shape,
-                                      cdata.padding_before, cdata.padding_after,
-                                      border_type, ops::PoolOp::RoundMode::floor);
+  auto result = createOp<ops::PoolOp>(t_input, pool_type, cdata.kernel_shape, cdata.strides_shape,
+                                      cdata.padding_before, cdata.padding_after, border_type);
   return {convertMIRToONNX(result->getOutput(0))};
 }
 
index 90b8ed6..3a5e53d 100644 (file)
@@ -191,8 +191,7 @@ TFLiteOpCreator::convertMaxPool2D(const ::tflite::Pool2DOptions* opts,
 
   auto result = createOp<ops::PoolOp>(input, ops::PoolOp::PoolingType::MAX,
                                       window_shape, strides, padding_before, padding_after,
-                                      ops::PoolOp::BorderType::EMPTY,
-                                      ops::PoolOp::RoundMode::floor);
+                                      ops::PoolOp::BorderType::EMPTY);
   return {addFusedActivation(result->getOutput(0), opts->fused_activation_function())};
 }
 
@@ -212,8 +211,7 @@ TFLiteOpCreator::convertAveragePool2D(const ::tflite::Pool2DOptions* opts,
 
   auto result = createOp<ops::PoolOp>(input, ops::PoolOp::PoolingType::AVG,
                                       window_shape, strides, padding_before, padding_after,
-                                      ops::PoolOp::BorderType::EMPTY,
-                                      ops::PoolOp::RoundMode::floor);
+                                      ops::PoolOp::BorderType::EMPTY);
   return {addFusedActivation(result->getOutput(0), opts->fused_activation_function())};
 }
 
index f1fd0e0..d7f78ea 100644 (file)
@@ -66,8 +66,7 @@ static Operation* createPool(std::unique_ptr<Graph>& g,
   return g->create<ops::PoolOp>("y", inputs[0], getPoolingType(opInfo),
                                 getShapeParam(opInfo, 0), getShapeParam(opInfo, 1),
                                 std::vector<int32_t>{0, 0}, std::vector<int32_t>{0, 0},
-                                ops::PoolOp::BorderType::ZEROFILLED,
-                                ops::PoolOp::RoundMode::floor);
+                                ops::PoolOp::BorderType::ZEROFILLED);
 }
 
 static Operation* createConcatenation(std::unique_ptr<Graph>& g,
index a164827..3161cdf 100644 (file)
@@ -402,8 +402,7 @@ TEST(acl_backend_mir_to_dom, maxpool) {
       std::vector<int32_t> padding{0, 0};
       return g.create<mir::ops::PoolOp>("maxPool", inputs[0], ops::PoolOp::PoolingType::MAX,
                                         window_shape, strides, padding, padding,
-                                        mir::ops::PoolOp::BorderType::EMPTY,
-                                        ops::PoolOp::RoundMode::floor);
+                                        mir::ops::PoolOp::BorderType::EMPTY);
   };
 
   vector<Shape> input_shapes{{1, 10, 10, 3}};
index cc07592..92f5f27 100644 (file)
@@ -749,8 +749,7 @@ static mir::Operation* createPool(mir::Graph& g,
                                   irOps::PoolOp::BorderType border) {
   std::vector<int32_t> padding{0, 0};
   return g.create<mir::ops::PoolOp>("pool", inputs[0], poolT, window_shape, strides,
-                                    padding, padding, border,
-                                    irOps::PoolOp::RoundMode::floor);
+                                    padding, padding, border);
 };
 
 template <irOps::PoolOp::PoolingType poolT, class Func>