[nnc] Remove support for Reduce and Pool (#7057)
authorСергей Баранников/AI Tools Lab /SRR/Engineer/삼성전자 <s.barannikov@samsung.com>
Mon, 2 Sep 2019 10:25:29 +0000 (13:25 +0300)
committerAlexander Efimov/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Mon, 2 Sep 2019 10:25:29 +0000 (13:25 +0300)
- These operation were replaced by `ReduceMean`, `AvgPool2D` and `MaxPool2D`.
- Pool operations are supported in DataFormatSwitcher optimization.

Signed-off-by: Sergei Barannikov <s.barannikov@samsung.com>
22 files changed:
compiler/nnc/include/passes/interpreter/Interpreter.h
compiler/nnc/include/passes/transformations/DataFormatSwitcher.h
compiler/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp
compiler/nnc/passes/acl_soft_backend/AclCppOpGenerator.h
compiler/nnc/passes/interpreter/Interpreter.cpp
compiler/nnc/passes/interpreter/ops/Pool.cpp [deleted file]
compiler/nnc/passes/interpreter/ops/Pool.h [deleted file]
compiler/nnc/passes/interpreter/ops/Reduce.h [deleted file]
compiler/nnc/passes/interpreter/ops/common.cpp
compiler/nnc/passes/interpreter/ops/common.h
compiler/nnc/passes/optimizations/SinkRelu.cpp
compiler/nnc/passes/soft_backend/ModelAnalyzer.cpp
compiler/nnc/passes/soft_backend/ModelAnalyzer.h
compiler/nnc/passes/soft_backend/SBSerializer.cpp
compiler/nnc/passes/soft_backend/SBSerializer.h
compiler/nnc/passes/soft_backend/code_snippets/cpp_operations.def
compiler/nnc/passes/soft_backend/code_snippets/cpp_pool.def
compiler/nnc/passes/transformations/DataFormatSwitcher.cpp
compiler/nnc/unittests/acl_backend/MIRToDOM.cpp
compiler/nnc/unittests/optimizations/SinkTest.cpp
compiler/nnc/unittests/optimizations/Util.h
compiler/nnc/unittests/soft_backend/CPPOperations.cpp

index 2461412..e80cc5f 100644 (file)
@@ -57,8 +57,6 @@ public:
   void visit(mir::ops::MulOp &op) override;
   void visit(mir::ops::OutputOp &op) override;
   void visit(mir::ops::PadOp &op) override;
-  void visit(mir::ops::PoolOp &op) override;
-  void visit(mir::ops::ReduceOp &op) override;
   void visit(mir::ops::ReduceMeanOp &op) override;
   void visit(mir::ops::ReluOp &op) override;
   void visit(mir::ops::ReshapeOp &op) override;
index c385d97..7d76d93 100644 (file)
@@ -24,6 +24,7 @@
 
 namespace nnc
 {
+
 class DataFormatSwitcher : public Pass
 {
 public:
@@ -35,14 +36,15 @@ public:
 
   ~DataFormatSwitcher() override;
 
-  std::string getName() { return "DataFormatSwitcher"; }
+  std::string getName() override { return "DataFormatSwitcher"; }
 
 private:
   // operations with DataFormat dependency
+  void switchAvgPool2D(mir::ops::AvgPool2DOp *op);
   void switchConv2D(mir::ops::Conv2DOp *op);
   void switchDeConv2D(mir::ops::DeConv2DOp *op);
   void switchDepthwiseConv2D(mir::ops::DepthwiseConv2DOp *op);
-  void switchPool(mir::ops::PoolOp *op);
+  void switchMaxPool2D(mir::ops::MaxPool2DOp *op);
 
   // helper functions
   mir::Operation::Output *insertTransposeBefore(mir::Operation::Output *out);
index 5fd4b08..3f9e6a7 100644 (file)
@@ -248,75 +248,6 @@ shared_ptr<ArtifactId> AclCppOpGenerator::genTransposeACLtoMIR(const string &nam
   return transposed_id;
 }
 
-void AclCppOpGenerator::visit(ops::PoolOp &op)
-{
-  assert(op.getNumInputs() == 1);
-  const auto *ir_input = op.getInput(0)->getProducer();
-  const auto *ir_output = op.getOutput(0);
-
-  const char *pooling_type = nullptr;
-
-  switch (op.getPoolingType())
-  {
-    case ops::PoolOp::PoolingType::MAX:
-      pooling_type = "arm_compute::PoolingType::MAX";
-      break;
-    case ops::PoolOp::PoolingType::AVG:
-      pooling_type = "arm_compute::PoolingType::AVG";
-      break;
-    default:
-      throw AclCppException("Unsupported pooling type");
-  }
-
-  string in_name = tensorName(ir_input);
-  auto in_id = AF::id(in_name);
-
-  const string output_tensor_name = tensorName(ir_output);
-
-  // Transpose data from MIR format to format compatible with ACL
-  const string transposed_input_name = output_tensor_name + "transposed_input";
-  shared_ptr<ArtifactId> transposed_input =
-      genTransposeMIRtoACL(transposed_input_name, ir_input->getShape(), in_id);
-
-  const string layer_name = output_tensor_name + "_pooling_layer";
-
-  shared_ptr<ArtifactVariable> pad_stride_info_var = genPadStrideInfo(op, layer_name, _constrBlock);
-
-  shared_ptr<ArtifactId> pad_stride_info = pad_stride_info_var->use();
-
-  // Create kernel window info
-  shared_ptr<ArtifactVariable> kernel_window_var =
-      _constrBlock->var("arm_compute::Size2D", layer_name + "_kernel_window", {},
-                        {AF::lit(to_string(op.getWindowShape().dim(1))),
-                         AF::lit(to_string(op.getWindowShape().dim(0)))});
-  shared_ptr<ArtifactId> kernel_window = kernel_window_var->use();
-
-  // Create pooling info: pooling type, kernel info, strides, etc
-  shared_ptr<ArtifactVariable> pooling_info_var = _constrBlock->var(
-      "arm_compute::PoolingLayerInfo", layer_name + "_pooling_info", {},
-      {AF::lit(pooling_type), kernel_window, pad_stride_info,
-       AF::lit(op.getBorderType() == ops::PoolOp::BorderType::EMPTY ? "true" : "false")});
-  shared_ptr<ArtifactId> pooling_info = pooling_info_var->use();
-
-  // Generate auxiliary tensor to hold transposed output of pool in NCHW format
-  Shape transposed_output_shape = transposeShape<0, 3, 1, 2>(ir_output->getShape());
-  shared_ptr<ArtifactId> transposed_output =
-      genTensor(layer_name + "_out_transpose", transposed_output_shape);
-
-  // Actual layer creation
-  shared_ptr<ArtifactId> layer =
-      genLayer("arm_compute::CLPoolingLayer", layer_name,
-               {AF::ref(transposed_input), AF::ref(transposed_output), pooling_info});
-  genTensorAllocation(_infBlock, transposed_output);
-  genLayerExecution(layer);
-
-  shared_ptr<ArtifactId> output =
-      genTransposeACLtoMIR(output_tensor_name, transposed_output_shape, transposed_output);
-
-  genTensorDeallocation(_infBlock, transposed_input);
-  genTensorDeallocation(_infBlock, transposed_output);
-}
-
 void AclCppOpGenerator::visit(ops::AvgPool2DOp &op)
 {
   genPooling(op, "arm_compute::PoolingType::AVG", !op.getIncludePad());
@@ -946,11 +877,6 @@ void AclCppOpGenerator::visit(mir::ops::ResizeOp & /*op*/)
   throw AclCppException("Unimplemented operation: Resize");
 }
 
-void AclCppOpGenerator::visit(mir::ops::ReduceOp & /*op*/)
-{
-  throw AclCppException("Unimplemented operation: ReduceOp");
-}
-
 void AclCppOpGenerator::genTranspose(const std::shared_ptr<nnc::ArtifactId> &input,
                                      const std::shared_ptr<nnc::ArtifactId> &output,
                                      const std::vector<size_t> &mir_perm,
index b67135b..79a7a6f 100644 (file)
@@ -68,8 +68,6 @@ public:
   void visit(mir::ops::MulOp &op) override;
   void visit(mir::ops::OutputOp &op) override;
   void visit(mir::ops::PadOp &op) override;
-  void visit(mir::ops::PoolOp &op) override;
-  void visit(mir::ops::ReduceOp &op) override;
   void visit(mir::ops::ReluOp &op) override;
   void visit(mir::ops::ReshapeOp &op) override;
   void visit(mir::ops::ResizeOp &op) override;
index 992b14a..f2df472 100644 (file)
@@ -29,8 +29,6 @@
 #include "ops/MaxPool2D.h"
 #include "ops/Mul.h"
 #include "ops/Pad.h"
-#include "ops/Pool.h"
-#include "ops/Reduce.h"
 #include "ops/ReduceMean.h"
 #include "ops/Reshape.h"
 #include "ops/Softmax.h"
@@ -150,13 +148,6 @@ void NNInterpreter::visit(ops::SoftmaxOp &op)
   setOutputTensors(op, std::move(outputs));
 }
 
-void NNInterpreter::visit(ops::PoolOp &op)
-{
-  auto inputs = getInputTensors(op);
-  auto outputs = Pool(inputs[0], op)();
-  setOutputTensors(op, std::move(outputs));
-}
-
 void NNInterpreter::visit(ops::FullyConnectedOp &op)
 {
   auto inputs = getInputTensors(op);
@@ -263,13 +254,6 @@ void NNInterpreter::visit(ops::ResizeOp &op)
   setOutputTensors(op, std::move(outputs));
 }
 
-void NNInterpreter::visit(ops::ReduceOp &op)
-{
-  auto inputs = getInputTensors(op);
-  auto outputs = Reduce<float>(inputs[0], op)();
-  setOutputTensors(op, std::move(outputs));
-}
-
 void NNInterpreter::visit(ops::ReduceMeanOp &op)
 {
   auto inputs = getInputTensors(op);
diff --git a/compiler/nnc/passes/interpreter/ops/Pool.cpp b/compiler/nnc/passes/interpreter/ops/Pool.cpp
deleted file mode 100644 (file)
index a940cfb..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iostream>
-#include <limits>
-
-#include "mir/ShapeRange.h"
-
-#include "Pool.h"
-#include "common.h"
-
-namespace nnc
-{
-
-using namespace mir;
-using namespace mir::ops;
-
-Pool::Pool(const TensorVariant &_input, const PoolOp &op) : _op(op), _input(_input)
-{
-  assert(_input.getShape().rank() == 4);
-  assert(op.getWindowShape().rank() == 2);
-  assert(op.getStrides().rank() == 2);
-  assert(op.getPaddingBefore().size() == 2);
-  assert(op.getPaddingAfter().size() == 2);
-}
-
-std::vector<TensorVariant> Pool::operator()()
-{
-  auto res = allocate_tensor(_op.getOutputShape(0));
-  Tensor<float> resAccessor(res);
-
-  Shape window_shape{1, _op.getWindowShape().dim(0), _op.getWindowShape().dim(1), 1};
-  Shape strides{1, _op.getStrides().dim(0), _op.getStrides().dim(1), 1};
-  Index pads{0, _op.getPaddingBefore().at(0), _op.getPaddingBefore().at(1), 0};
-
-  const Shape &outShape = resAccessor.getShape();
-  ShapeRange outRange(outShape);
-
-  ShapeRange inRange(_input.getShape());
-
-  float initialValue;
-  switch (_op.getPoolingType())
-  {
-    case PoolOp::PoolingType::MAX:
-      initialValue = std::numeric_limits<float>::lowest();
-      break;
-    case PoolOp::PoolingType::AVG:
-      initialValue = 0.0f;
-      break;
-    case PoolOp::PoolingType::MIN:
-      initialValue = std::numeric_limits<float>::max();
-      break;
-    default:
-      assert(false && "Invalid pooling type");
-  }
-  Index inIdx;
-  inIdx.resize(outShape.rank());
-  for (auto &outIdx : outRange)
-  {
-    float out = initialValue;
-    size_t avgDenominator = 0;
-    for (auto &kIdx : ShapeRange(window_shape))
-    {
-      translate(inIdx, outIdx, kIdx, strides, pads);
-
-      float in = 0.0f;
-      if (inRange.contains(inIdx))
-      {
-        avgDenominator++;
-        in = _input.at(inIdx);
-      }
-      else
-      {
-        switch (_op.getBorderType())
-        {
-          case PoolOp::BorderType::ZEROFILLED:
-          {
-            // Elements outside input range are zero
-            avgDenominator++;
-            in = 0.0f;
-            break;
-          }
-          case PoolOp::BorderType::EMPTY:
-          {
-            // Skip all elements outside input range
-            continue;
-          }
-          default:
-          {
-            assert(false && "Invalid border type for pooling");
-          }
-        }
-      }
-      out = poolingFunc(out, in);
-    }
-    if (_op.getPoolingType() == PoolOp::PoolingType::AVG)
-    {
-      out /= avgDenominator;
-    }
-    resAccessor.at(outIdx) = out;
-  }
-
-  return {res};
-}
-
-float Pool::poolingFunc(float prev, float val)
-{
-  switch (_op.getPoolingType())
-  {
-    case PoolOp::PoolingType::MAX:
-      return (val > prev) ? val : prev;
-    case PoolOp::PoolingType::AVG:
-      return prev + val;
-    case PoolOp::PoolingType::MIN:
-      return (val < prev) ? val : prev;
-    default:
-      assert(false && "Unsupported pooling type");
-  }
-  // This should not happen
-  // Should throw, but it is too expensive
-  return 0.0f;
-}
-
-} // namespace nnc
diff --git a/compiler/nnc/passes/interpreter/ops/Pool.h b/compiler/nnc/passes/interpreter/ops/Pool.h
deleted file mode 100644 (file)
index 3ab79c5..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _NNC_CORE_BACKEND_INTERPRETER_POOL_
-#define _NNC_CORE_BACKEND_INTERPRETER_POOL_
-
-#include "OperationImpl.h"
-#include "mir/ops/PoolOp.h"
-#include "mir/ops/CommonProps.h"
-#include "mir/Tensor.h"
-
-namespace nnc
-{
-
-class Pool : public OperationImpl<float>
-{
-public:
-  std::vector<mir::TensorVariant> operator()() override;
-
-  explicit Pool(const mir::TensorVariant &_input, const mir::ops::PoolOp &op);
-
-  float poolingFunc(float prev, float val);
-
-private:
-  const mir::ops::PoolOp &_op;
-  const mir::Tensor<float> _input;
-};
-
-} // namespace nnc
-
-#endif //_NNC_CORE_BACKEND_INTERPRETER_POOL_
diff --git a/compiler/nnc/passes/interpreter/ops/Reduce.h b/compiler/nnc/passes/interpreter/ops/Reduce.h
deleted file mode 100644 (file)
index 4a72cd2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _NNC_CORE_BACKEND_INTERPRETER_REDUCE_
-#define _NNC_CORE_BACKEND_INTERPRETER_REDUCE_
-
-#include "OperationImpl.h"
-#include "mir/ops/ReduceOp.h"
-#include "mir/Tensor.h"
-#include "mir/ShapeRange.h"
-
-namespace nnc
-{
-
-template <typename T> class Reduce : public OperationImpl<T>
-{
-public:
-  Reduce(const mir::TensorVariant &input, const mir::ops::ReduceOp &op) : _input(input), _op(op) {}
-
-  std::vector<mir::TensorVariant> operator()() override
-  {
-    const auto &input_shape = _op.getInputShape(0);
-    const auto &output_shape = _op.getOutputShape(0);
-    const auto &reduction_dims = _op.getReductionDims();
-    const bool keep_dims = _op.getKeepDims();
-
-    assert(_op.getFuncType() == mir::ops::ReduceOp::FuncType::mean);
-    const auto reductor = [](T result, T x) { return result + x; };
-
-    auto res = OperationImpl<T>::allocate_tensor(output_shape);
-    mir::Tensor<T> res_accessor(res);
-
-    // This mask contains `true` for axis that should be reduced. For example, if we want to reduce
-    // axes 1 and 3 with total number of axes of 4, the mask will be [false, true, false, true].
-    std::vector<bool> reduce_axis_mask(input_shape.rank(), false);
-    for (auto axis : reduction_dims)
-    {
-      reduce_axis_mask[axis] = true;
-    }
-
-    mir::Index out_index;
-    out_index.resize(output_shape.rank());
-    for (const mir::Index &in_index : mir::ShapeRange(input_shape))
-    {
-      int32_t out_index_dim = 0;
-      for (int32_t d = 0; d < input_shape.rank(); ++d)
-      {
-        if (keep_dims)
-        {
-          out_index.at(out_index_dim++) = reduce_axis_mask[d] ? 0 : in_index.at(d);
-        }
-        else
-        {
-          if (!reduce_axis_mask[d])
-          {
-            out_index.at(out_index_dim++) = in_index.at(d);
-          }
-        }
-      }
-      res_accessor.at(out_index) = reductor(res_accessor.at(out_index), _input.at(in_index));
-    }
-
-    const int32_t reduction_factor = input_shape.numElements() / output_shape.numElements();
-
-    for (const auto &index : mir::ShapeRange(output_shape))
-    {
-      res_accessor.at(index) /= reduction_factor;
-    }
-
-    return {res};
-  }
-
-private:
-  const mir::Tensor<T> _input;
-  const mir::ops::ReduceOp &_op;
-};
-
-} // namespace nnc
-
-#endif //_NNC_CORE_BACKEND_INTERPRETER_REDUCE_
index 109ea5f..6434d35 100644 (file)
@@ -23,17 +23,6 @@ namespace nnc
 
 using namespace mir;
 
-void translate(Index &translatedIndex, const Index &sourceIndex, const Index &kernelIndex,
-               const Shape &strides, const Index &paddings)
-{
-  assert(translatedIndex.rank() == sourceIndex.rank());
-
-  for (int32_t d = 0; d < translatedIndex.rank(); ++d)
-  {
-    translatedIndex.at(d) = sourceIndex.at(d) * strides.dim(d) + kernelIndex.at(d) - paddings.at(d);
-  }
-}
-
 Index shift(const Index &in_index, const Shape &shift_from)
 {
   Index index = in_index;
index 9af2264..33093ab 100644 (file)
 namespace nnc
 {
 
-///
-/// Get current input element index using output index, current kernel index, strides and paddings
-///
-/// \param[out] translatedIndex resulting input tensor index
-/// \param[in] sourceIndex current output element
-/// \param[in] kernelIndex current kernel element
-/// \param[in] strides
-/// \param[in] paddings
-void translate(mir::Index &translatedIndex, const mir::Index &sourceIndex,
-               const mir::Index &kernelIndex, const mir::Shape &strides,
-               const mir::Index &paddings);
-
 /**
  * Shift in_index by `shift`
  * @param[in] in_index argument
index 0e2f478..09bdc02 100644 (file)
 #include "mir/ops/TransposeOp.h"
 #include "mir/ops/ConcatOp.h"
 #include "mir/ops/ReluOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/Graph.h"
 #include "mir/GraphPatternMatcher.h"
 
-#include <string>
 #include <algorithm>
 
 namespace nnc
index fc0675f..a7e637f 100644 (file)
@@ -316,27 +316,6 @@ void ModelAnalyzer::visit(ops::DepthwiseConv2DOp &op)
 
 void ModelAnalyzer::visit(ops::SoftmaxOp &op) { appendOperationToInference(&op, "softmax"); }
 
-/**
- * Model Ir does not separate different types of pool operations, but for code generation
- * it is easier to implement different types of pooling by different functions
- */
-void ModelAnalyzer::visit(ops::PoolOp &op)
-{
-  const char *func_name = nullptr;
-  switch (op.getPoolingType())
-  {
-    case ops::PoolOp::PoolingType::MAX:
-      func_name = "maxPool";
-      break;
-    case ops::PoolOp::PoolingType::AVG:
-      func_name = "avgPool";
-      break;
-    default:
-      assert(false && "unsupported pooling type");
-  }
-  appendOperationToInference(&op, func_name);
-}
-
 void ModelAnalyzer::visit(ops::AvgPool2DOp &op) { appendOperationToInference(&op, "avgPool"); }
 
 void ModelAnalyzer::visit(ops::MaxPool2DOp &op) { appendOperationToInference(&op, "maxPool"); }
@@ -408,18 +387,6 @@ void ModelAnalyzer::visit(ops::SqrtOp &op) { appendOperationToInference(&op, "sq
 
 void ModelAnalyzer::visit(mir::ops::PadOp &op) { appendOperationToInference(&op, "pad"); }
 
-void ModelAnalyzer::visit(mir::ops::ReduceOp &op)
-{
-  switch (op.getFuncType())
-  {
-    case mir::ops::ReduceOp::FuncType::mean:
-      appendOperationToInference(&op, "reduceMean");
-      break;
-    default:
-      assert(false && "NOT IMPLEMENTED");
-  }
-}
-
 void ModelAnalyzer::visit(mir::ops::ReduceMeanOp &op)
 {
   appendOperationToInference(&op, "reduceMean");
index c75dcc6..fffd28f 100644 (file)
@@ -66,8 +66,6 @@ public:
   void visit(mir::ops::MulOp &op) override;
   void visit(mir::ops::OutputOp &op) override;
   void visit(mir::ops::PadOp &op) override;
-  void visit(mir::ops::PoolOp &op) override;
-  void visit(mir::ops::ReduceOp &op) override;
   void visit(mir::ops::ReduceMeanOp &op) override;
   void visit(mir::ops::ReluOp &op) override;
   void visit(mir::ops::ReshapeOp &op) override;
index f8784b8..d77d2f4 100644 (file)
 #include "mir/ShapeRange.h"
 #include "mir/TensorUtil.h"
 
-#include "CommonData.def"
-
 #include "mir/OpDefs.h"
 
-#include "pass/PassException.h"
 #include <algorithm>
 
 #define UNUSED(x) ((void)(x))
@@ -161,34 +158,6 @@ void Serializer::visit(ops::SoftmaxOp &op)
   serializeT<int32_t>(op.getAxis());
 }
 
-void Serializer::visit(ops::PoolOp &op)
-{
-  _curOp->paramStartOffset = _buffer.size();
-  // serialize window shape
-  serializeShape(op.getWindowShape());
-  // serialize strindes
-  serializeShape(op.getStrides());
-  // serialize pads
-  int32_t number_of_pads = 2; // windowShape.rank();
-  serializePads(op, number_of_pads);
-  // serialize border type
-  PoolBorderType border_type;
-  switch (op.getBorderType())
-  {
-    case ops::PoolOp::BorderType::EMPTY:
-      border_type = PoolBorderType::EMPTY;
-      break;
-    case ops::PoolOp::BorderType::ZEROFILLED:
-      border_type = PoolBorderType::ZEROFILLED;
-      break;
-    default:
-      throw PassException("Unsupported border type in pooling");
-  }
-  serializeT<int32_t>(etoi(border_type));
-  // serialize output shape
-  serializeShape(op.getOutputShape(0));
-}
-
 void Serializer::visit(ops::AvgPool2DOp &op)
 {
   _curOp->paramStartOffset = _buffer.size();
@@ -199,11 +168,7 @@ void Serializer::visit(ops::AvgPool2DOp &op)
   // serialize pads
   int32_t number_of_pads = 2; // windowShape.rank();
   serializePads(op, number_of_pads);
-  // serialize border type
-  PoolBorderType border_type =
-      op.getIncludePad() ? PoolBorderType::ZEROFILLED : PoolBorderType::EMPTY;
-
-  serializeT<int32_t>(etoi(border_type));
+  serializeT<int32_t>(op.getIncludePad());
   // serialize output shape
   serializeShape(op.getOutputShape(0));
 }
@@ -218,9 +183,6 @@ void Serializer::visit(ops::MaxPool2DOp &op)
   // serialize pads
   int32_t number_of_pads = 2; // windowShape.rank();
   serializePads(op, number_of_pads);
-  // serialize border type
-  // TODO This parameter is not used for max pooling, remove it.
-  serializeT<int32_t>(etoi(PoolBorderType::EMPTY));
   // serialize output shape
   serializeShape(op.getOutputShape(0));
 }
@@ -336,14 +298,6 @@ void Serializer::visit(mir::ops::ResizeOp &op)
   serializeShape(op.getOutputShape(0));
 }
 
-void Serializer::visit(mir::ops::ReduceOp &op)
-{
-  _curOp->paramStartOffset = _buffer.size();
-  serializeShape(Shape(op.getReductionDims())); // reuse shape serialization
-  serializeT<int32_t>(op.getKeepDims());
-  serializeShape(op.getOutputShape(0));
-}
-
 void Serializer::visit(mir::ops::ReduceMeanOp &op)
 {
   _curOp->paramStartOffset = _buffer.size();
index 0566c25..f3e9701 100644 (file)
@@ -60,8 +60,6 @@ public:
   void visit(mir::ops::MulOp &op) override;
   void visit(mir::ops::OutputOp &op) override;
   void visit(mir::ops::PadOp &op) override;
-  void visit(mir::ops::PoolOp &op) override;
-  void visit(mir::ops::ReduceOp &op) override;
   void visit(mir::ops::ReduceMeanOp &op) override;
   void visit(mir::ops::ReluOp &op) override;
   void visit(mir::ops::ReshapeOp &op) override;
index 5e81eb9..e3543b3 100644 (file)
@@ -317,16 +317,14 @@ void softmax(Tensor &out, const char *params, const Tensor &in)
   Softmax(input, input_d, beta, out.getData(), input_d);
 }
 
-template <class Executor>
-static inline void genericPool(Executor executor, Tensor &out,
-                               const char *params, const Tensor &in)
+void avgPool(Tensor &out, const char *params, const Tensor &in)
 {
   const float *input = in.getData();
   Dims<4> input_d = shapeToDims(in.getShape());
   Shape window = deserializeShape(params);
   Shape strides = deserializeShape(params);
   Shape pads = deserializeShape(params);
-  PoolBorderType borderType = static_cast<PoolBorderType>(deserializeT<int32_t>(params));
+  bool include_pad = deserializeT<int32_t>(params);
   Shape out_s = deserializeShape(params);
 
   assert(window.getDims() == 2);
@@ -343,22 +341,42 @@ static inline void genericPool(Executor executor, Tensor &out,
 
   Dims<4> out_d = shapeToDims(out_s);
 
-  executor(input, input_d,
-           stride_w, stride_h,
-           pad_w, pad_h,
-           window_w, window_h,
-           out.getData(), out_d,
-           borderType);
+  AveragePool(input, input_d,
+              stride_w, stride_h,
+              pad_w, pad_h,
+              window_w, window_h,
+              out.getData(), out_d,
+              include_pad);
 }
 
 void maxPool(Tensor &out, const char *params, const Tensor &in)
 {
-  genericPool(MaxPool, out, params, in);
-}
+  const float *input = in.getData();
+  Dims<4> input_d = shapeToDims(in.getShape());
+  Shape window = deserializeShape(params);
+  Shape strides = deserializeShape(params);
+  Shape pads = deserializeShape(params);
+  Shape out_s = deserializeShape(params);
 
-void avgPool(Tensor &out, const char *params, const Tensor &in)
-{
-  genericPool(AveragePool, out, params, in);
+  assert(window.getDims() == 2);
+  const int window_w = static_cast<int>(window[1]);
+  const int window_h = static_cast<int>(window[0]);
+  assert(strides.getDims() == 2);
+  const int stride_w = static_cast<int>(strides[1]);
+  const int stride_h = static_cast<int>(strides[0]);
+  assert(pads.getDims() == 2);
+  const int pad_w = static_cast<int>(pads[1]);
+  const int pad_h = static_cast<int>(pads[0]);
+
+  out.reshape(out_s);
+
+  Dims<4> out_d = shapeToDims(out_s);
+
+  MaxPool(input, input_d,
+          stride_w, stride_h,
+          pad_w, pad_h,
+          window_w, window_h,
+          out.getData(), out_d);
 }
 
 void fullConnect(Tensor& out, const char* params, const Tensor& in, const Tensor& w) {
index b416e1a..bf970c0 100644 (file)
@@ -22,7 +22,7 @@ inline void AveragePool(const float* input_data, const Dims<4>& input_dims,
                         int pad_height, int kwidth, int kheight,
                         float* output_data,
                         const Dims<4>& output_dims,
-                        PoolBorderType borderType) {
+                        bool include_pad) {
 
   const int batches = MatchingArraySize(input_dims, 3, output_dims, 3);
   const int input_height = ArraySize(input_dims, 2);
@@ -65,26 +65,18 @@ inline void AveragePool(const float* input_data, const Dims<4>& input_dims,
   }
   // Divide the output by the actual number of elements being averaged over
   TFLITE_DCHECK_GT(out_count.minCoeff(), 0);
-  switch (borderType)
-  {
-    case PoolBorderType::EMPTY:
-      out_mat.array().rowwise() /= out_count.transpose().array();
-      break;
-    case PoolBorderType::ZEROFILLED:
-      out_mat.array() /= kheight * kwidth;
-      break;
-    default:
-      assert(false && "unsupported border type");
+  if (include_pad) {
+    out_mat.array() /= kheight * kwidth;
+  } else {
+    out_mat.array().rowwise() /= out_count.transpose().array();
   }
 }
 
 inline void MaxPool(const float* input_data, const Dims<4>& input_dims,
                     int stride_width, int stride_height, int pad_width,
                     int pad_height, int kwidth, int kheight,
-                    float* output_data, const Dims<4>& output_dims,
-                    PoolBorderType borderType) {
+                    float* output_data, const Dims<4>& output_dims) {
 
-  assert(borderType == PoolBorderType::EMPTY && "unsupported border type in max pooling");
   const int batches = MatchingArraySize(input_dims, 3, output_dims, 3);
   const int input_height = ArraySize(input_dims, 2);
   const int input_width = ArraySize(input_dims, 1);
index 74950ad..4633b81 100644 (file)
 
 #include "passes/transformations/DataFormatSwitcher.h"
 
+#include "mir/ops/AvgPool2DOp.h"
 #include "mir/ops/Conv2DOp.h"
 #include "mir/ops/Deconv2DOp.h"
 #include "mir/ops/DepthwiseConv2DOp.h"
-#include "mir/ops/PoolOp.h"
+#include "mir/ops/MaxPool2DOp.h"
 #include "mir/ops/TransposeOp.h"
 
 namespace nnc
@@ -41,10 +42,11 @@ PassData DataFormatSwitcher::run(PassData data)
   {
     switch (node->getType())
     { // nodes using DataFormat
+      case mir::Operation::Type::avgPool2D:
       case mir::Operation::Type::conv2D:
       case mir::Operation::Type::deConv2D:
       case mir::Operation::Type::depthwiseConv:
-      case mir::Operation::Type::pool:
+      case mir::Operation::Type::maxPool2D:
         _candidates_for_switch.push_back(node);
         break;
       default:
@@ -56,6 +58,9 @@ PassData DataFormatSwitcher::run(PassData data)
   {
     switch (op->getType())
     {
+      case mir::Operation::Type::avgPool2D:
+        switchAvgPool2D(dynamic_cast<mir::ops::AvgPool2DOp *>(op));
+        break;
       case mir::Operation::Type::conv2D:
         switchConv2D(dynamic_cast<mir::ops::Conv2DOp *>(op));
         break;
@@ -65,8 +70,8 @@ PassData DataFormatSwitcher::run(PassData data)
       case mir::Operation::Type::depthwiseConv:
         switchDepthwiseConv2D(dynamic_cast<mir::ops::DepthwiseConv2DOp *>(op));
         break;
-      case mir::Operation::Type::pool:
-        switchPool(dynamic_cast<mir::ops::PoolOp *>(op));
+      case mir::Operation::Type::maxPool2D:
+        switchMaxPool2D(dynamic_cast<mir::ops::MaxPool2DOp *>(op));
         break;
       default:
         assert(false && "Can't switch DataFormat for this operation!");
@@ -98,6 +103,29 @@ mir::Operation::Output *DataFormatSwitcher::insertTransposeAfter(mir::Operation:
         ->getOutput(0); // NCHW -> NHWC
 }
 
+void DataFormatSwitcher::switchAvgPool2D(mir::ops::AvgPool2DOp *op)
+{
+  if (op->getDataFormat() == _target_format)
+    return;
+
+  auto *input = op->getInput(0)->getProducer();
+
+  const auto &window_size = op->getWindowSize();
+  const auto &strides = op->getStrides();
+  const auto &padding_before = op->getPaddingBefore();
+  const auto &padding_after = op->getPaddingAfter();
+  const auto include_pad = op->getIncludePad();
+
+  auto *trans_in = insertTransposeBefore(input);
+
+  auto new_pool = _graph->create<mir::ops::AvgPool2DOp>(
+      trans_in, window_size, strides, padding_before, padding_after, include_pad, _target_format);
+
+  auto *trans_out = insertTransposeAfter(new_pool->getOutput(0));
+
+  _graph->replaceNode(op, trans_out->getNode());
+}
+
 void DataFormatSwitcher::switchConv2D(mir::ops::Conv2DOp *op)
 {
   if (op->getDataFormat() == _target_format)
@@ -172,25 +200,22 @@ void DataFormatSwitcher::switchDepthwiseConv2D(mir::ops::DepthwiseConv2DOp *op)
   _graph->replaceNode(op, trans_out->getNode());
 }
 
-void DataFormatSwitcher::switchPool(mir::ops::PoolOp *op)
+void DataFormatSwitcher::switchMaxPool2D(mir::ops::MaxPool2DOp *op)
 {
   if (op->getDataFormat() == _target_format)
     return;
 
   auto *input = op->getInput(0)->getProducer();
 
-  const auto &window_shape = op->getWindowShape();
+  const auto &window_size = op->getWindowSize();
   const auto &strides = op->getStrides();
   const auto &padding_before = op->getPaddingBefore();
   const auto &padding_after = op->getPaddingAfter();
-  const auto pooling_type = op->getPoolingType();
-  const auto border_type = op->getBorderType();
 
   auto *trans_in = insertTransposeBefore(input);
 
-  auto new_pool =
-      _graph->create<mir::ops::PoolOp>(trans_in, pooling_type, window_shape, strides,
-                                       padding_before, padding_after, border_type, _target_format);
+  auto new_pool = _graph->create<mir::ops::MaxPool2DOp>(
+      trans_in, window_size, strides, padding_before, padding_after, _target_format);
 
   auto *trans_out = insertTransposeAfter(new_pool->getOutput(0));
 
index 6e8b1e0..0987267 100644 (file)
@@ -40,7 +40,6 @@
 #include "mir/ops/MaxPool2DOp.h"
 #include "mir/ops/OutputOp.h"
 #include "mir/ops/PadOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/ops/ReduceMeanOp.h"
 #include "mir/ops/ReluOp.h"
 #include "mir/ops/ReshapeOp.h"
index 38f895a..e555907 100644 (file)
@@ -22,9 +22,7 @@
 #include "mir/ops/TanhOp.h"
 #include "mir/ops/ConcatOp.h"
 #include "mir/ops/OutputOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/Graph.h"
-#include "pass/PassData.h"
 
 #include <gtest/gtest.h>
 #include <sstream>
index 2b682ac..7467a59 100644 (file)
@@ -25,7 +25,6 @@
 #include "mir/ops/MaxPool2DOp.h"
 #include "mir/ops/MulOp.h"
 #include "mir/ops/OutputOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/ops/ReluOp.h"
 #include "mir/ops/TanhOp.h"
 #include "mir/ops/TransposeOp.h"
@@ -49,8 +48,6 @@ public:
 
   void visit(mir::ops::ReluOp &op) override { _s << "r_" << std::to_string(op.getId()) << "."; }
 
-  void visit(mir::ops::PoolOp &op) override { _s << "p_" << std::to_string(op.getId()) << "."; }
-
   void visit(mir::ops::AvgPool2DOp &op) override
   {
     _s << "p_" << std::to_string(op.getId()) << ".";
index 577c5a4..5576a5b 100644 (file)
@@ -73,7 +73,6 @@
 #include "mir/ops/MulOp.h"
 #include "mir/ops/OutputOp.h"
 #include "mir/ops/PadOp.h"
-#include "mir/ops/PoolOp.h"
 #include "mir/ops/ReduceMeanOp.h"
 #include "mir/ops/ReluOp.h"
 #include "mir/ops/ReshapeOp.h"