[neurun] Enable basic ADD op (#4186)
author김수진/On-Device Lab(SR)/Engineer/삼성전자 <sjsujin.kim@samsung.com>
Fri, 11 Jan 2019 00:50:18 +0000 (09:50 +0900)
committer박세희/On-Device Lab(SR)/Principal Engineer/삼성전자 <saehie.park@samsung.com>
Fri, 11 Jan 2019 00:50:18 +0000 (09:50 +0900)
* [neurun] Enable basic ADD op

Related : #4173

This commit migrate basic `ADD` op that is already exist in `PACL` to `neurun`.

- Neon cannot be supported now.
  - TensorBuilder should has not only `arm_compute::CLTensor` but also `arm_compute::Tensor`.
- Remove skip test `GeneratedTests.add`

Signed-off-by: sjsujinkim <sjsujin.kim@samsung.com>
* Remove neon codes

* Remove unused codes

runtimes/neurun/src/backend/acl_cl/StageGenerator.cc
runtimes/neurun/src/frontend/model.cc
runtimes/neurun/src/model/operation/AddNode.cc
runtimes/neurun/src/model/operation/AddNode.h
tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun

index 89bbd7b..f7e205b 100644 (file)
@@ -24,6 +24,7 @@
 #include <arm_compute/runtime/CL/functions/CLReshapeLayer.h>
 #include <arm_compute/runtime/CL/functions/CLFullyConnectedLayer.h>
 #include <arm_compute/runtime/CL/functions/CLSoftmaxLayer.h>
+#include <arm_compute/runtime/CL/functions/CLArithmeticAddition.h>
 
 #include "kernel/acl_cl/ConcatLayer.h"
 
@@ -581,11 +582,52 @@ void StageGenerator::visit(const model::operation::PermuteNode & /* node */)
   throw "Unsupported";
 }
 
-void StageGenerator::visit(const model::operation::AddNode &)
+void StageGenerator::visit(const model::operation::AddNode &node)
 {
-  VERBOSE(Add) << "generate CPU Add" << std::endl;
+  const auto output_index{node.getOutputs().at(0)};
+  const auto lhs_index{node.getInputs().at(model::operation::AddNode::Input::LHS)};
+  const auto rhs_index{node.getInputs().at(model::operation::AddNode::Input::RHS)};
+  const auto activation_index{node.param().activation_index};
+
+  struct Param
+  {
+    model::operand::Index ofm_index;
+    model::operand::Index lhs_index;
+    model::operand::Index rhs_index;
 
-  throw std::runtime_error("NYI");
+    FuseCode activation;
+  };
+
+  Param param;
+
+  param.ofm_index = output_index;
+  param.lhs_index = lhs_index;
+  param.rhs_index = rhs_index;
+
+  param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+  auto tensors = _tensor_builder;
+
+  returnStage([tensors, param](IExecutionBuilder &builder) {
+    auto ofm_alloc = tensors->at(param.ofm_index).get();
+    auto lhs_alloc = tensors->at(param.lhs_index).get();
+    auto rhs_alloc = tensors->at(param.rhs_index).get();
+
+    std::unique_ptr<::arm_compute::IFunction> fn;
+
+    auto l = make_layer<::arm_compute::CLArithmeticAddition>();
+
+    l->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(),
+                 arm_compute::ConvertPolicy::SATURATE);
+
+    fn = std::move(l);
+
+    auto acl_fn = make_cl_function(std::move(fn));
+
+    builder.append(std::move(acl_fn));
+
+    ActivationBuilder{builder}.append(param.activation, ofm_alloc->handle());
+  });
 }
 
 } // namespace acl_cl
index 3aa2aa2..0950a10 100644 (file)
@@ -258,6 +258,17 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
   {
     switch (type)
     {
+      case ANEURALNETWORKS_ADD:
+      {
+        assert(inputCount == 3);
+        assert(outputCount == 1);
+
+        using GraphNode = neurun::model::operation::AddNode;
+
+        graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
+
+        break;
+      }
       case ANEURALNETWORKS_CONV_2D:
       {
         // inputCount is either 7 or 10 acccording to NN API specification.
index 0c9d4e0..9a7e798 100644 (file)
@@ -32,7 +32,7 @@ void AddNode::accept(NodeVisitor &&v) const { v.visit(*this); }
 AddNode::AddNode(const model::operation::Node::InitParam &init_param)
     : model::operation::Node{OperandConstraint::createExact(2u)}
 {
-  assert(init_param.input_count == 2);
+  assert(init_param.input_count == 3);
   assert(init_param.output_count == 1);
 
   // Each input should be interpreted as follows:
@@ -42,6 +42,8 @@ AddNode::AddNode(const model::operation::Node::InitParam &init_param)
 
   setInputs({init_param.inputs[0], init_param.inputs[1]});
   setOutputs({init_param.outputs[0]});
+
+  _param.activation_index = operand::Index{init_param.inputs[2]};
 }
 
 } // namespace operation
index 533fb0a..e205806 100644 (file)
@@ -45,6 +45,12 @@ public:
 public:
   virtual void accept(NodeVisitor &&) const override;
   virtual std::string getName() const override { return "Add"; }
+
+public:
+  const Param &param() const { return _param; }
+
+private:
+  Param _param;
 };
 
 } // namespace operation
index 59957ba..ef05522 100644 (file)
@@ -20,7 +20,9 @@ ValidationTestExecution.SetInputFromMemory
 ValidationTestExecution.SetOutputFromMemory
 ValidationTestExecution.StartCompute
 ValidationTestExecution.EventWait
-GeneratedTests.add*
+GeneratedTests.add_broadcast_4D_2D_after_nops_float_nnfw
+GeneratedTests.add_broadcast_quant8
+GeneratedTests.add_quant8
 GeneratedTests.argmax*
 GeneratedTests.avg_pool_float_1
 GeneratedTests.avg_pool_float_2