From: Сергей Баранников/AI Tools Lab /SRR/Engineer/삼성전자 Date: Fri, 30 Aug 2019 08:11:21 +0000 (+0900) Subject: [mir_caffe] Switch to AvgPool2D and MaxPool2D ops (#7029) X-Git-Tag: accepted/tizen/unified/20190903.052428~28 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7f4f11cac2a567ea25757162e049097edfd96213;p=platform%2Fcore%2Fml%2Fnnfw.git [mir_caffe] Switch to AvgPool2D and MaxPool2D ops (#7029) Switch from `PoolOp` to `AvgPool2DOp` and `MaxPool2DOp`. The former ones are deprecated. Signed-off-by: Sergei Barannikov --- diff --git a/compiler/mir-caffe-importer/caffe_op_creator.cpp b/compiler/mir-caffe-importer/caffe_op_creator.cpp index af0530c..c0c3c34 100644 --- a/compiler/mir-caffe-importer/caffe_op_creator.cpp +++ b/compiler/mir-caffe-importer/caffe_op_creator.cpp @@ -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 ¶ms, const mir::Shape &input_shape, + std::vector &window_size, std::vector &strides, + std::vector &padding_before, std::vector &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 &padding_before, - std::vector &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 &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 CaffeOpCreator::convertPooling(const caffe::LayerParameter &layer, const std::vector &inputs) { - auto &opts = layer.pooling_param(); - Shape window_shape; - Shape strides; - std::vector 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 window_size; + std::vector strides; + std::vector 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(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(input, window_size, strides, padding_before, + padding_after, mir::DataFormat::NHWC) + ->getOutput(0); break; default: assert(false); } - auto pooling = createOp(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 diff --git a/compiler/mir-caffe-importer/caffe_op_creator.h b/compiler/mir-caffe-importer/caffe_op_creator.h index 4936263..98f2161 100644 --- a/compiler/mir-caffe-importer/caffe_op_creator.h +++ b/compiler/mir-caffe-importer/caffe_op_creator.h @@ -116,7 +116,7 @@ public: void checkConvolution(const caffe::ConvolutionParameter &opts, std::set &problems_ops_set); - void checkPooling(const caffe::PoolingParameter &opts, std::set &problems_ops_set); + void checkPooling(const caffe::PoolingParameter ¶ms, std::set &problems_ops_set); void checkReshape(const caffe::ReshapeParameter &opts, std::set &problems_ops_set);