- 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>
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;
namespace nnc
{
+
class DataFormatSwitcher : public Pass
{
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);
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());
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,
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;
#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"
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);
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);
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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_
+++ /dev/null
-/*
- * 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_
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;
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
#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
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"); }
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");
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;
#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))
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();
// 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));
}
// 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));
}
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();
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;
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);
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) {
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);
}
// 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);
#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
{
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:
{
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;
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!");
->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)
_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));
#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"
#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>
#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"
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()) << ".";
#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"