From 9e1f59875078015d192caa49b7cfd97f62e23fb7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=91=D0=B0=D1=80?= =?utf8?q?=D0=B0=D0=BD=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2/AI=20Tools=20Lab=20/S?= =?utf8?q?RR/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 10 Jun 2019 04:19:05 +0300 Subject: [PATCH] [ACL CL backend] Support `Unpack` operation in ACL CL backend (#5349) * [backend] Support `Unpack` operation in ACL CL backend Added support of `Unpack` operation in ACL CL backend through `Unstack` layer. Signed-off-by: Sergei Barannikov * * Remove redundant `static_cast` * Move checking code to `OperationValidator` * * Implement `Dumper` method for `UnpackNode` class --- runtimes/neurun/backend/acl_cl/StageGenerator.cc | 55 ++++++++++++++++++++++ runtimes/neurun/backend/acl_cl/StageGenerator.h | 1 + .../neurun/core/src/compiler/OperationValidator.cc | 17 +++++++ .../neurun/core/src/compiler/OperationValidator.h | 1 + runtimes/neurun/core/src/graph/dumper/Dumper.cc | 16 +++++++ runtimes/neurun/core/src/graph/dumper/Dumper.h | 1 + tests/nnapi/nnapi_gtest.skip.armv7l-linux | 1 - 7 files changed, 91 insertions(+), 1 deletion(-) diff --git a/runtimes/neurun/backend/acl_cl/StageGenerator.cc b/runtimes/neurun/backend/acl_cl/StageGenerator.cc index ed28c77..dc1bbbb 100644 --- a/runtimes/neurun/backend/acl_cl/StageGenerator.cc +++ b/runtimes/neurun/backend/acl_cl/StageGenerator.cc @@ -3343,6 +3343,61 @@ void StageGenerator::visit(const model::operation::SplitNode &node) }); } +void StageGenerator::visit(const model::operation::UnpackNode &node) +{ + const auto input_index{node.getInputs().at(model::operation::UnpackNode::Input::INPUT)}; + const auto axis{node.param().axis}; + + const auto input_rank = _ctx.at(input_index).shape().rank(); + + struct Param + { + model::OperandIndex input_index; + std::vector output_indexes; + int32_t axis; + }; + + Param param; + param.input_index = input_index; + param.axis = axis; + if (param.axis < 0) + param.axis += input_rank; + param.axis = acl_common::ToARMComputeAxis(input_rank, param.axis).value(); + + _tensor_builder->dimCorrection(input_index, false); + for (const auto &output_index : node.getOutputs()) + { + param.output_indexes.emplace_back(output_index); + _tensor_builder->dimCorrection(output_index, false); + } + + auto tensors = _tensor_builder; + + returnStage([tensors, param](IExecutionBuilder &builder) { + auto input = tensors->at(param.input_index).get()->handle(); + std::vector outputs; + for (const auto output_index : param.output_indexes) + { + outputs.emplace_back(tensors->at(output_index)->handle()); + } + + int axis = param.axis; + if (input->info()->num_dimensions() == 4 && + input->info()->data_layout() == ::arm_compute::DataLayout::NCHW) + { + // CWHN -> WHCN + const int permutation[4] = {2, 0, 1, 3}; + axis = permutation[axis]; + } + + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLUnstack>(); + + fn->configure(input, outputs, axis); + + builder.append(asAclFunction(std::move(fn))); + }); +} + } // namespace acl_cl } // namespace backend } // namespace neurun diff --git a/runtimes/neurun/backend/acl_cl/StageGenerator.h b/runtimes/neurun/backend/acl_cl/StageGenerator.h index 7d1cb4a..e7ad702 100644 --- a/runtimes/neurun/backend/acl_cl/StageGenerator.h +++ b/runtimes/neurun/backend/acl_cl/StageGenerator.h @@ -90,6 +90,7 @@ public: void visit(const model::operation::DepthToSpaceNode &) override; void visit(const model::operation::ReduceMinNode &) override; void visit(const model::operation::SplitNode &) override; + void visit(const model::operation::UnpackNode &) override; private: const neurun::model::Operands &_ctx; diff --git a/runtimes/neurun/core/src/compiler/OperationValidator.cc b/runtimes/neurun/core/src/compiler/OperationValidator.cc index d4b6956..05a573f 100644 --- a/runtimes/neurun/core/src/compiler/OperationValidator.cc +++ b/runtimes/neurun/core/src/compiler/OperationValidator.cc @@ -794,5 +794,22 @@ void OperationValidator::visit(const model::operation::LSTMNode &node) } } +void OperationValidator::visit(const model::operation::UnpackNode &node) +{ + const auto input_index{node.getInputs().at(model::operation::UnpackNode::Input::INPUT)}; + const auto num{node.param().num}; + const auto axis{node.param().axis}; + + const auto &input_shape = _ctx.at(input_index).shape(); + const auto input_rank = static_cast(input_shape.rank()); + + UNUSED_RELEASE(num); + UNUSED_RELEASE(axis); + UNUSED_RELEASE(input_rank); + + assert(num == static_cast(node.getOutputs().size())); + assert(axis >= -input_rank && axis < input_rank); +} + } // namespace compiler } // namespace neurun diff --git a/runtimes/neurun/core/src/compiler/OperationValidator.h b/runtimes/neurun/core/src/compiler/OperationValidator.h index 58ac717..c693a32 100644 --- a/runtimes/neurun/core/src/compiler/OperationValidator.h +++ b/runtimes/neurun/core/src/compiler/OperationValidator.h @@ -56,6 +56,7 @@ public: void visit(const model::operation::DepthToSpaceNode &node) override; void visit(const model::operation::ReduceMinNode &node) override; void visit(const model::operation::LSTMNode &node) override; + void visit(const model::operation::UnpackNode &node) override; private: const neurun::model::Operands &_ctx; diff --git a/runtimes/neurun/core/src/graph/dumper/Dumper.cc b/runtimes/neurun/core/src/graph/dumper/Dumper.cc index eba1de2..42b1148 100644 --- a/runtimes/neurun/core/src/graph/dumper/Dumper.cc +++ b/runtimes/neurun/core/src/graph/dumper/Dumper.cc @@ -548,6 +548,22 @@ void Dumper::visit(const TransposeNode &node) VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; } +void Dumper::visit(const model::operation::UnpackNode &node) +{ + VERBOSE(LIR) << "* Unpack" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(UnpackNode::Input::INPUT).value() + << ")" << std::endl; + std::string outputs; + const auto &output_indices = node.getOutputs(); + for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it) + { + outputs += std::to_string(it->value()); + if (std::next(it) != std::end(output_indices)) + outputs += ", "; + } + VERBOSE(LIR) << " - Outputs : Outputs(" << outputs << ")" << std::endl; +} + } // namespace dumper } // namespace graph } // namespace neurun diff --git a/runtimes/neurun/core/src/graph/dumper/Dumper.h b/runtimes/neurun/core/src/graph/dumper/Dumper.h index a3e95dc..882108a 100644 --- a/runtimes/neurun/core/src/graph/dumper/Dumper.h +++ b/runtimes/neurun/core/src/graph/dumper/Dumper.h @@ -86,6 +86,7 @@ public: void visit(const model::operation::TopKV2Node &) override; void visit(const model::operation::TransposeConvNode &) override; void visit(const model::operation::TransposeNode &) override; + void visit(const model::operation::UnpackNode &) override; }; } // namespace dumper diff --git a/tests/nnapi/nnapi_gtest.skip.armv7l-linux b/tests/nnapi/nnapi_gtest.skip.armv7l-linux index 489e5d2..c81277a 100644 --- a/tests/nnapi/nnapi_gtest.skip.armv7l-linux +++ b/tests/nnapi/nnapi_gtest.skip.armv7l-linux @@ -12,7 +12,6 @@ GeneratedTests.prelu_ex_quant8_1 GeneratedTests.prelu_ex_broadcast_quant8_1 # Unexpected result GeneratedTests.pack* -GeneratedTests.unpack* # Not support broadcast GeneratedTests.logical_or_ex_broadcast_4D_2D # Unsupported optional input that has shape -- 2.7.4