From 3d4a30243fe586d0daa81261e08da068903f9895 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Siva=20Sai=20Vaddipati/System=20SW=20/SRI-Bangalore/Enginee?= =?utf8?q?r/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 10 Sep 2018 07:48:01 +0530 Subject: [PATCH] Adding explicit padding support for L2Pool2D (#2633) This commit enables L2Pool2D operation with explicit padding. Related issue: #2562 Signed-off-by: Siva Sai --- runtimes/pure_arm_compute/src/compilation.cc | 102 +++++++++++++++++++++ .../pure_arm_compute/src/internal/op/L2Pool2D.cc | 43 +++++++++ .../pure_arm_compute/src/internal/op/L2Pool2D.h | 49 ++++++++++ .../pure_arm_compute/src/internal/op/NodeVisitor.h | 1 + runtimes/pure_arm_compute/src/model.cc | 13 ++- 5 files changed, 204 insertions(+), 4 deletions(-) diff --git a/runtimes/pure_arm_compute/src/compilation.cc b/runtimes/pure_arm_compute/src/compilation.cc index 9f17014..708defd 100644 --- a/runtimes/pure_arm_compute/src/compilation.cc +++ b/runtimes/pure_arm_compute/src/compilation.cc @@ -481,6 +481,7 @@ public: void visit(const ::internal::tflite::op::Pad::Node &node) override; void visit(const ::internal::tflite::op::SpaceToDepth::Node &node) override; void visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node) override; void visit(const ::internal::tflite::op::EmbeddingLookup::Node &node) override; private: @@ -3506,6 +3507,107 @@ void Planner::visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node _builder.addStage(stage); } +void Planner::visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar(); + const int32_t kw = _ctx.at(kw_index).asScalar(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar(); + const int32_t hstride = _ctx.at(hstride_index).asScalar(); + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar(); + + _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), + _ctx.at(ofm_index).type())); + _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), + _ctx.at(ifm_index).type())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.activation = static_cast(_ctx.at(activation_index).asScalar()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::L2, + ::arm_compute::Size2D{param.kw, param.kh}, + asPadStringInfo(param.padding, param.stride)}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("L2Pool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("L2Pool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + void Planner::visit(const ::internal::tflite::op::EmbeddingLookup::Node &node) { // TODO Implement EMBEDDING_LOOKUP diff --git a/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.cc b/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.cc index e087e40..a6d866e 100644 --- a/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.cc +++ b/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.cc @@ -11,6 +11,13 @@ namespace op { namespace L2Pool2D { +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + namespace Implicit { @@ -30,6 +37,42 @@ namespace op { namespace L2Pool2D { +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 10 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_left_index = inputs[1]; + padding_right_index = inputs[2]; + padding_top_index = inputs[3]; + padding_bottom_index = inputs[4]; + hstride_index = inputs[5]; + vstride_index = inputs[6]; + kw_index = inputs[7]; + kh_index = inputs[8]; + activation_index = inputs[9]; +} + +} // namespace Explicit + namespace Implicit { diff --git a/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.h b/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.h index 6f757d9..cd79bc9 100644 --- a/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.h +++ b/runtimes/pure_arm_compute/src/internal/op/L2Pool2D.h @@ -13,6 +13,55 @@ namespace op { namespace L2Pool2D { +namespace Explicit +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + + int32_t kw_index; + int32_t kh_index; + + int32_t hstride_index; + int32_t vstride_index; + + int32_t padding_left_index; + int32_t padding_right_index; + int32_t padding_top_index; + int32_t padding_bottom_index; + + int32_t activation_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + namespace Implicit { diff --git a/runtimes/pure_arm_compute/src/internal/op/NodeVisitor.h b/runtimes/pure_arm_compute/src/internal/op/NodeVisitor.h index 3c9ce33..659ca08 100644 --- a/runtimes/pure_arm_compute/src/internal/op/NodeVisitor.h +++ b/runtimes/pure_arm_compute/src/internal/op/NodeVisitor.h @@ -88,6 +88,7 @@ struct NodeVisitor virtual void visit(const Pad::Node &) = 0; virtual void visit(const SpaceToDepth::Node &) = 0; virtual void visit(const L2Pool2D::Implicit::Node &) = 0; + virtual void visit(const L2Pool2D::Explicit::Node &) = 0; virtual void visit(const EmbeddingLookup::Node &) = 0; }; diff --git a/runtimes/pure_arm_compute/src/model.cc b/runtimes/pure_arm_compute/src/model.cc index 500b103..3ce28dd 100644 --- a/runtimes/pure_arm_compute/src/model.cc +++ b/runtimes/pure_arm_compute/src/model.cc @@ -589,8 +589,8 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, case ANEURALNETWORKS_L2_POOL_2D: { // Input count is 7 for Implicit Padding - // TODO: Support explicit padding i.e for input count 10. - assert(inputCount == 7); + // Input count is 10 for Explicit Padding + assert(inputCount == 7 || inputCount == 10); assert(outputCount == 1); if (inputCount == 7) @@ -605,8 +605,13 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, } else { - /* TODO: Support Explicit padding as well. */ - throw std::runtime_error{"Not supported operation"}; + using internal::tflite::op::L2Pool2D::Explicit::Param; + using internal::tflite::op::L2Pool2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back(Param{inputCount, inputs, outputCount, outputs}); } break; -- 2.7.4