[enco.caffe] Infer the output shape of Pooling with stride (#1322)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 4 Sep 2018 07:41:11 +0000 (16:41 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 4 Sep 2018 07:41:11 +0000 (16:41 +0900)
With this commit, PoolingSpec is now able to infer the output shape of
Pooling layer with stride values.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/enco/frontend/caffe/src/PoolingSpec.cpp
contrib/enco/frontend/caffe/src/PoolingSpec.h
contrib/enco/frontend/caffe/src/PoolingSpec.test.cpp

index e9b316d..7c5915e 100644 (file)
@@ -37,6 +37,36 @@ uint32_t PoolingSpec::window_width(void) const
   return _param.kernel_size();
 }
 
+uint32_t PoolingSpec::vertical_stride(void) const
+{
+  if (_param.has_stride_h())
+  {
+    return _param.stride_h();
+  }
+
+  if (_param.has_stride())
+  {
+    return _param.stride();
+  }
+
+  return 1;
+}
+
+uint32_t PoolingSpec::horizontal_stride(void) const
+{
+  if (_param.has_stride_w())
+  {
+    return _param.stride_w();
+  }
+
+  if (_param.has_stride())
+  {
+    return _param.stride();
+  }
+
+  return 1;
+}
+
 nncc::core::ADT::tensor::Shape PoolingSpec::ofm_shape(void) const
 {
   nncc::core::ADT::tensor::Shape res;
@@ -51,7 +81,10 @@ nncc::core::ADT::tensor::Shape PoolingSpec::ofm_shape(void) const
   res.dim(1) = _ifm_shape.dim(1);
 
   // H and W are derived from IFM, Window, and Padding
-  res.dim(2) = _ifm_shape.dim(2) - window_height() + 1;
-  res.dim(3) = _ifm_shape.dim(3) - window_width() + 1;
+  // TODO Remove the following asserts
+  assert((_ifm_shape.dim(2) - window_height()) % vertical_stride() == 0);
+  assert((_ifm_shape.dim(3) - window_width()) % horizontal_stride() == 0);
+  res.dim(2) = (_ifm_shape.dim(2) - window_height()) / vertical_stride() + 1;
+  res.dim(3) = (_ifm_shape.dim(3) - window_width()) / horizontal_stride() + 1;
   return res;
 }
index 8993501..d2ffa3a 100644 (file)
@@ -19,6 +19,10 @@ public:
   uint32_t window_width(void) const;
 
 public:
+  uint32_t vertical_stride(void) const;
+  uint32_t horizontal_stride(void) const;
+
+public:
   nncc::core::ADT::tensor::Shape ofm_shape(void) const;
 
 private:
index c36e9aa..0372896 100644 (file)
@@ -147,3 +147,48 @@ TEST_F(PoolingSpecTest, kernel_size_same_for_all)
     ASSERT_EQ(expected, obtained);
   }
 }
+
+TEST_F(PoolingSpecTest, stride_for_all)
+{
+  const tensor::Shape ifm_shape{1, 3, 15, 15};
+
+  ::caffe::NetParameter param;
+  {
+    SequentialBuilder builder{&param};
+
+    builder.addInputLayer(ifm_shape);
+
+    // clang-format off
+    const char *prototxt = STRING(
+      name : "pool"
+      type : "Pooling"
+      bottom : "data"
+      top : "pool"
+      pooling_param {
+        pool: MAX
+        kernel_size : 3
+        stride: 2
+      }
+    );
+    // clang-format on
+
+    builder.addLayer(prototxt);
+  }
+
+  ::caffe::Net<float> net{param};
+
+  PoolingSpec spec{param.layer(1).pooling_param()};
+
+  spec.ifm_shape(ifm_shape);
+
+  ASSERT_EQ(spec.vertical_stride(), 2);
+  ASSERT_EQ(spec.horizontal_stride(), 2);
+
+  // Check 'ofm_shape'
+  {
+    auto expected = as_tensor_shape(net.blob_by_name("pool")->shape());
+    auto obtained = spec.ofm_shape();
+
+    ASSERT_EQ(expected, obtained);
+  }
+}