[mir_caffe] Switch to AvgPool2D and MaxPool2D ops (#7029)
authorСергей Баранников/AI Tools Lab /SRR/Engineer/삼성전자 <s.barannikov@samsung.com>
Fri, 30 Aug 2019 08:11:21 +0000 (17:11 +0900)
committerAlexander Efimov/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Fri, 30 Aug 2019 08:11:21 +0000 (11:11 +0300)
Switch from `PoolOp` to `AvgPool2DOp` and `MaxPool2DOp`. The former ones are deprecated.

Signed-off-by: Sergei Barannikov <s.barannikov@samsung.com>
compiler/mir-caffe-importer/caffe_op_creator.cpp
compiler/mir-caffe-importer/caffe_op_creator.h

index af0530c..c0c3c34 100644 (file)
@@ -17,6 +17,7 @@
 #include "caffe_op_creator.h"
 
 #include "mir/ops/AddOp.h"
+#include "mir/ops/AvgPool2DOp.h"
 #include "mir/ops/CappedReluOp.h"
 #include "mir/ops/ConcatOp.h"
 #include "mir/ops/ConstantOp.h"
@@ -28,8 +29,8 @@
 #include "mir/ops/GatherOp.h"
 #include "mir/ops/LeakyReluOp.h"
 #include "mir/ops/MaxOp.h"
+#include "mir/ops/MaxPool2DOp.h"
 #include "mir/ops/MulOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/ops/ReluOp.h"
 #include "mir/ops/ReshapeOp.h"
 #include "mir/ops/SigmoidOp.h"
@@ -413,80 +414,71 @@ CaffeOpCreator::convertConcat(const caffe::LayerParameter &layer,
   return {concat->getOutput(0)};
 }
 
-static ops::PoolOp::PoolingType getPoolingType(const PoolingParameter &pool_param)
+static void
+convertPoolingParam(const caffe::PoolingParameter &params, const mir::Shape &input_shape,
+                    std::vector<std::int32_t> &window_size, std::vector<std::int32_t> &strides,
+                    std::vector<int32_t> &padding_before, std::vector<int32_t> &padding_after)
 {
-  using PoolingType = ops::PoolOp::PoolingType;
-
-  if (pool_param.pool() == PoolingParameter::MAX)
-    return PoolingType::MAX;
-  else if (pool_param.pool() == PoolingParameter::AVE)
-    return PoolingType::AVG;
-  else
-    throw std::runtime_error("Unsupported pooling type: " +
-                             PoolingParameter::PoolMethod_Name(pool_param.pool()));
-}
-
-static void convertPoolingParam(const caffe::PoolingParameter &pool_param,
-                                const mir::Shape &input_shape, Shape &window_shape, Shape &strides,
-                                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())
+  std::int32_t kernel_h, kernel_w;
+  assert(!params.global_pooling());
+  if (params.has_kernel_size())
   {
-    kernel_h = kernel_w = pool_param.kernel_size();
+    kernel_h = kernel_w = params.kernel_size();
   }
   else
   {
-    kernel_h = pool_param.kernel_h();
-    kernel_w = pool_param.kernel_w();
+    kernel_h = params.kernel_h();
+    kernel_w = params.kernel_w();
   }
-  window_shape = {kernel_h, kernel_w};
+  window_size = {kernel_h, kernel_w};
 
-  int32_t stride_h, stride_w;
-  if (pool_param.has_stride_h() || pool_param.has_stride_w())
+  std::int32_t stride_h, stride_w;
+  if (params.has_stride_h() || params.has_stride_w())
   {
-    stride_h = pool_param.stride_h();
-    stride_w = pool_param.stride_w();
+    stride_h = params.stride_h();
+    stride_w = params.stride_w();
   }
   else
   {
-    stride_h = stride_w = pool_param.stride();
+    stride_h = stride_w = params.stride();
   }
   strides = {stride_h, stride_w};
 
-  int32_t pad_h, pad_w;
-  if (pool_param.has_pad_h() || pool_param.has_pad_w())
+  std::int32_t pad_h, pad_w;
+  if (params.has_pad_h() || params.has_pad_w())
   {
-    pad_h = pool_param.pad_h();
-    pad_w = pool_param.pad_w();
+    pad_h = params.pad_h();
+    pad_w = params.pad_w();
   }
   else
   {
-    pad_h = pad_w = pool_param.pad();
+    pad_h = pad_w = params.pad();
   }
 
   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];
+
+  // Caffe uses different formula for computing output shape than MIR. Adjust padding so that
+  // the output shape stays the same.
+  constexpr int num_spatial_dims = 2;
+  for (int i = 0; i < num_spatial_dims; ++i)
+  {
+    // Assuming NCHW format.
+    const std::int32_t padded_input = input_shape.dim(2 + i) + padding_before[i] + padding_after[i];
+    if ((padded_input - window_size[i]) % strides[i] != 0)
+      ++padding_after[i];
+  }
 }
 
-void CaffeOpCreator::checkPooling(const PoolingParameter &opts,
+void CaffeOpCreator::checkPooling(const PoolingParameter &params,
                                   std::set<std::string> &problems_ops_set)
 {
-  if (opts.has_global_pooling() && opts.global_pooling())
+  if (params.has_global_pooling() && params.global_pooling())
     problems_ops_set.insert("Pooling: pooling layer global_pooling param is not supported yet");
 
-  ops::PoolOp::PoolingType pool_type = getPoolingType(opts);
-  if (pool_type != ops::PoolOp::PoolingType::AVG && pool_type != ops::PoolOp::PoolingType::MAX)
+  if (params.pool() != PoolingParameter::AVE && params.pool() != PoolingParameter::MAX)
     problems_ops_set.insert("Pooling: unsupported pooling type");
 
-  if (opts.has_pad() && (opts.has_pad_h() || opts.has_pad_w()))
+  if (params.has_pad() && (params.has_pad_h() || params.has_pad_w()))
     problems_ops_set.insert("Pooling: conflicting padding properties in pooling");
 }
 
@@ -494,31 +486,39 @@ std::vector<mir::Operation::Output *>
 CaffeOpCreator::convertPooling(const caffe::LayerParameter &layer,
                                const std::vector<mir::Operation::Output *> &inputs)
 {
-  auto &opts = layer.pooling_param();
-  Shape window_shape;
-  Shape strides;
-  std::vector<int32_t> padding_before, padding_after;
+  const auto &params = layer.pooling_param();
 
-  const auto &input_shape = inputs[0]->getShape();
-  convertPoolingParam(opts, input_shape, window_shape, strides, padding_before, padding_after);
+  assert(inputs.size() == 1);
+  auto input = inputs[0];
 
-  ops::PoolOp::PoolingType pool_type = getPoolingType(opts);
-  ops::PoolOp::BorderType border_type;
-  switch (pool_type)
+  std::vector<std::int32_t> window_size;
+  std::vector<std::int32_t> strides;
+  std::vector<std::int32_t> padding_before, padding_after;
+  convertPoolingParam(params, input->getShape(), window_size, strides, padding_before,
+                      padding_after);
+
+  input = convertCaffeToMIR(input);
+  mir::Operation::Output *result;
+
+  switch (params.pool())
   {
-    case ops::PoolOp::PoolingType::AVG:
-      border_type = ops::PoolOp::BorderType::ZEROFILLED;
+    case PoolingParameter::AVE:
+      result = createOp<ops::AvgPool2DOp>(input, window_size, strides, padding_before,
+                                          padding_after, true, mir::DataFormat::NHWC)
+                   ->getOutput(0);
       break;
-    case ops::PoolOp::PoolingType::MAX:
-      border_type = ops::PoolOp::BorderType::EMPTY;
+    case PoolingParameter::MAX:
+      result = createOp<ops::MaxPool2DOp>(input, window_size, strides, padding_before,
+                                          padding_after, mir::DataFormat::NHWC)
+                   ->getOutput(0);
       break;
     default:
       assert(false);
   }
 
-  auto pooling = createOp<ops::PoolOp>(convertCaffeToMIR(inputs[0]), pool_type, window_shape,
-                                       strides, padding_before, padding_after, border_type);
-  return {convertMIRToCaffe(pooling->getOutput(0))};
+  result = convertMIRToCaffe(result);
+
+  return {result};
 }
 
 std::vector<mir::Operation::Output *>
index 4936263..98f2161 100644 (file)
@@ -116,7 +116,7 @@ public:
   void checkConvolution(const caffe::ConvolutionParameter &opts,
                         std::set<std::string> &problems_ops_set);
 
-  void checkPooling(const caffe::PoolingParameter &opts, std::set<std::string> &problems_ops_set);
+  void checkPooling(const caffe::PoolingParameter &params, std::set<std::string> &problems_ops_set);
 
   void checkReshape(const caffe::ReshapeParameter &opts, std::set<std::string> &problems_ops_set);