#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"
#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"
return {concat->getOutput(0)};
}
-static ops::PoolOp::PoolingType getPoolingType(const PoolingParameter &pool_param)
+static void
+convertPoolingParam(const caffe::PoolingParameter ¶ms, 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 ¶ms,
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");
}
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 ¶ms = 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 *>