From 796de9a753b672f5a04f5a24293a6ee3a1938edb Mon Sep 17 00:00:00 2001 From: "Efimov Alexander/AI Tools Lab/./Samsung Electronics" Date: Fri, 30 Nov 2018 15:38:50 +0300 Subject: [PATCH] [nnc] Support asimmetrical paddings in tflite models in ACL backend (#2447) Inference asimmetrical paddings for "Same" padding type on acl backend Signed-off-by: Efimov Alexander --- contrib/nnc/include/core/modelIR/TensorUtil.h | 4 +- .../passes/acl_soft_backend/AclCppOpGenerator.h | 2 +- .../passes/acl_soft_backend/AclCppOpGenerator.cpp | 112 +++++++++++++++++---- 3 files changed, 93 insertions(+), 25 deletions(-) diff --git a/contrib/nnc/include/core/modelIR/TensorUtil.h b/contrib/nnc/include/core/modelIR/TensorUtil.h index 683652d..d289b16 100644 --- a/contrib/nnc/include/core/modelIR/TensorUtil.h +++ b/contrib/nnc/include/core/modelIR/TensorUtil.h @@ -31,9 +31,9 @@ namespace mir { // TODO: This is potentialy unsafe. Consider how to improve the transposition concept. -template +template Shape transposeShape(const Shape& shape) { - std::vector permutes{Ints...}; + std::vector permutes{Ints...}; Shape result(shape); int32_t nof_permutes = std::min(shape.rank(), permutes.size()); diff --git a/contrib/nnc/include/passes/acl_soft_backend/AclCppOpGenerator.h b/contrib/nnc/include/passes/acl_soft_backend/AclCppOpGenerator.h index 53ea6f6..86b2220 100644 --- a/contrib/nnc/include/passes/acl_soft_backend/AclCppOpGenerator.h +++ b/contrib/nnc/include/passes/acl_soft_backend/AclCppOpGenerator.h @@ -133,7 +133,7 @@ private: * elements to the left of and including the in2 term, or the operation out if * in2 was the last term in the sequence. */ - std::shared_ptr genMultiplication(const std::string& prefix, int index, + std::shared_ptr genMultiplication(const std::string& prefix, size_t index, const mir::Shape& ir_shape, std::shared_ptr in1, std::shared_ptr in2, diff --git a/contrib/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp b/contrib/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp index e79db22..051f317 100644 --- a/contrib/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp +++ b/contrib/nnc/passes/acl_soft_backend/AclCppOpGenerator.cpp @@ -59,7 +59,7 @@ const ArtifactModule& AclCppOpGenerator::generate(mir::Graph* g) { _parIn = _parInVar->use(); string par_file_name = cli::artifactName + ".par"; _constrBlock->call("open", {AF::lit("\"" + par_file_name + "\""), - AF::lit("std::ios_base::in | std::ios_base::binary")}, _parIn); + AF::lit("std::ios_base::in | std::ios_base::binary")}, _parIn); auto file_fail = _constrBlock->ifCond(AF::call("fail", {}, _parIn)); auto file_fail_block = file_fail->getBlock(); file_fail_block->addStatement(AF::lit("throw std::string(\"Failed to open file: " + @@ -181,8 +181,89 @@ void AclCppOpGenerator::visit(ops::SoftmaxOp& op) { } } +template +static Shape getWindowShape(const Oper& op) { + const Shape& kshape = op.getKernel().getShape(); + return Shape{1, kshape.dim(0), kshape.dim(1), kshape.dim(2)}; +} + +template<> +Shape getWindowShape(const ops::PoolOp& op) { + const Shape& wshape = op.getWindowShape(); + return Shape{1, wshape.dim(-3), wshape.dim(-2), wshape.dim(-1)}; +} + +/** + * @brief Generate DOM for PadStrideInfo object + * @tparam Oper Class of operation with pad and stride properties + * @param op Operation entity to generate variable for + * @param prefix First part of generated variable name + * @param block Code block where insert variable declaration + * @return generated variable + */ +template +static shared_ptr + genPadStrideInfo(const Oper& op, const string& prefix, ArtifactBlock* block) { + using AF = ArtifactFactory; + + const Shape& strides = transposeShape<1, 0>(op.getStrides()); + assert(strides.rank() == 3 && strides.dim(2) == 1); + + // array of paddings + // order is following: [(top, bottom), (left, right)] + std::array, 2> pads; + + // TODO this is workaround to overcome limitations of Model IR + // replace when left and right paddings introduced + if (op.getPaddingType() == mir::ops::PaddingType::Same) { + // If padding type is Same we need to recompute paddigns, + // to cover case with unequal "left" and "right" paddings + const int32_t h_axis = -3; + const int32_t w_axis = -2; + // This is offset to work correctly with bare padding and strides arrays + const int32_t axis_offset = 3; + + const Shape window_shape = getWindowShape(op); + + for (int32_t axis : {h_axis, w_axis}) { + int32_t full_pad; + const int32_t n = op.getInputShape(0).dim(axis); + const int32_t k = window_shape.dim(axis); + const int32_t s = op.getStrides().dim(axis); + if (n % s == 0) + full_pad = max(k - s, 0); + else + full_pad = max(k - n % s, 0); + pads[axis + axis_offset].first = full_pad / 2; + pads[axis + axis_offset].second = full_pad - pads[axis + axis_offset].first; + } + } else { + pads[0].first = pads[0].second = op.getPadding(0); + pads[1].first = pads[1].second = op.getPadding(1); + } + + assert(op.getPadding(2) == 0); + + string type_name = "arm_compute::PadStrideInfo"; + + string var_name = prefix + "_pad_stride_info"; + + list> var_init_params = + {AF::lit(to_string(op.getStrides().dim(1))), + AF::lit(to_string(op.getStrides().dim(0))), + AF::lit(to_string(pads[1].first)), + AF::lit(to_string(pads[1].second)), + AF::lit(to_string(pads[0].first)), + AF::lit(to_string(pads[0].second)), + AF::lit("arm_compute::DimensionRoundingType::FLOOR")}; + + auto pad_stride_info_var = block->var(type_name, var_name, {}, var_init_params); + + return pad_stride_info_var; +} + void AclCppOpGenerator::visit(ops::PoolOp& op) { - const char* pooling_type; + const char* pooling_type = nullptr; switch (op.getPoolingType()) { case ops::PoolOp::PoolingType::MAX: @@ -203,12 +284,8 @@ void AclCppOpGenerator::visit(ops::PoolOp& op) { auto out = genTensor(op, transposeShape<1, 0, 2>(op.getOutputShape(0))); auto prefix = out->name() + "_pooling_layer"; - auto pad_stride_info_var = _constrBlock->var("arm_compute::PadStrideInfo", - prefix + "_pad_stride_info", - {}, {AF::lit(to_string(op.getStrides().dim(1))), - AF::lit(to_string(op.getStrides().dim(0))), - AF::lit(to_string(op.getPadding(1))), - AF::lit(to_string(op.getPadding(0)))}); + auto pad_stride_info_var = genPadStrideInfo(op, prefix, _constrBlock); + auto pad_stride_info = pad_stride_info_var->use(); auto kernel_window_var = _constrBlock->var("arm_compute::Size2D", prefix + "_kernel_window", {}, {AF::lit(to_string(op.getWindowShape().dim(1))), @@ -439,7 +516,7 @@ void AclCppOpGenerator::visit(ops::ElementwiseOp& op) { // Get the identifier of the first input tensor in the DOM. auto in1 = AF::id(tensorName(in_op1)); - for (int i = 1; i < prev_nodes.size(); ++i) { + for (size_t i = 1; i < prev_nodes.size(); ++i) { auto in_op2 = prev_nodes[i].op; // Get the identifier of the second input tensor in the DOM. @@ -481,11 +558,6 @@ void AclCppOpGenerator::genConvolution(Op& op, const string& acl_func_name, cons const Shape& ir_weights_shape = ir_weights->getShape(); assert(ir_weights_shape.rank() == 4); Shape ir_biases_shape({ir_weights_shape.dim(-1)}); - const Shape& strides = transposeShape<1, 0>(op.getStrides()); - assert(strides.rank() == 3 && strides.dim(2) == 1); - uint32_t pad_x = op.getPadding(1); - uint32_t pad_y = op.getPadding(0); - assert(op.getPadding(2) == 0); auto& prev_nodes = op.getPrevNodes(); assert(prev_nodes.size() == 1); @@ -503,12 +575,8 @@ void AclCppOpGenerator::genConvolution(Op& op, const string& acl_func_name, cons // Create a local variable of type PadStrideInfo in the artifact constructor: // PadStrideInfo pad_stride_info(stride_x, stride_y, pad_x, pad_y); - auto pad_stride_info_var = _constrBlock->var("arm_compute::PadStrideInfo", - operation_name + "_pad_stride_info", - {}, {AF::lit(to_string(strides.dim(0))), - AF::lit(to_string(strides.dim(1))), - AF::lit(to_string(pad_x)), - AF::lit(to_string(pad_y))}); + auto pad_stride_info_var = genPadStrideInfo(op, operation_name, _constrBlock); + auto pad_stride_info = pad_stride_info_var->use(); // The parameter for the conv_layer.config(&in, &weights, nullptr, &out, pad_stride_info) @@ -517,7 +585,7 @@ void AclCppOpGenerator::genConvolution(Op& op, const string& acl_func_name, cons AF::ref(out), pad_stride_info}; // Add to additional parameters for deconvolution. - if (dynamic_cast(&op)) { + if (op.getType() == Operation::Type::deConv2D) { config_params.push_back(AF::lit("0")); config_params.push_back(AF::lit("0")); } @@ -584,7 +652,7 @@ shared_ptr AclCppOpGenerator::genAddition(const string& prefix, int return out; } -shared_ptr AclCppOpGenerator::genMultiplication(const string& prefix, int index, +shared_ptr AclCppOpGenerator::genMultiplication(const string& prefix, size_t index, const Shape& ir_shape, shared_ptr in1, shared_ptr in2, -- 2.7.4