[ACL CL backend] Support `Unpack` operation in ACL CL backend (#5349)
authorСергей Баранников/AI Tools Lab /SRR/Engineer/삼성전자 <s.barannikov@samsung.com>
Mon, 10 Jun 2019 01:19:05 +0000 (04:19 +0300)
committer오형석/On-Device Lab(SR)/Staff Engineer/삼성전자 <hseok82.oh@samsung.com>
Mon, 10 Jun 2019 01:19:05 +0000 (10:19 +0900)
* [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 <s.barannikov@samsung.com>
* * Remove redundant `static_cast`
* Move checking code to `OperationValidator`

* * Implement `Dumper` method for `UnpackNode` class

runtimes/neurun/backend/acl_cl/StageGenerator.cc
runtimes/neurun/backend/acl_cl/StageGenerator.h
runtimes/neurun/core/src/compiler/OperationValidator.cc
runtimes/neurun/core/src/compiler/OperationValidator.h
runtimes/neurun/core/src/graph/dumper/Dumper.cc
runtimes/neurun/core/src/graph/dumper/Dumper.h
tests/nnapi/nnapi_gtest.skip.armv7l-linux

index ed28c77..dc1bbbb 100644 (file)
@@ -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<model::OperandIndex> 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<arm_compute::ICLTensor *> 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
index 7d1cb4a..e7ad702 100644 (file)
@@ -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;
index d4b6956..05a573f 100644 (file)
@@ -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<int32_t>(input_shape.rank());
+
+  UNUSED_RELEASE(num);
+  UNUSED_RELEASE(axis);
+  UNUSED_RELEASE(input_rank);
+
+  assert(num == static_cast<int32_t>(node.getOutputs().size()));
+  assert(axis >= -input_rank && axis < input_rank);
+}
+
 } // namespace compiler
 } // namespace neurun
index 58ac717..c693a32 100644 (file)
@@ -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;
index eba1de2..42b1148 100644 (file)
@@ -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
index a3e95dc..882108a 100644 (file)
@@ -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
index 489e5d2..c81277a 100644 (file)
@@ -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