From b8900ff6bebd07d31a547b8a69db6e4fd8350d5e Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EA=B9=80=EC=88=98=EC=A7=84/Quality=20Tool=20Lab=28SR=29/En?= =?utf8?q?gineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 26 Mar 2019 11:24:17 +0900 Subject: [PATCH] [neurun] Enable ArgMax, Dequantize, Mean ops (#4751) * [neurun] Enable ArgMax, Dequantize, Mean ops This commit enables `ArgMax`, `Dequantize`, `Mean` ops for `acl_cl`. * fix build break Signed-off-by: sjsujinkim --- runtimes/neurun/backend/acl_cl/StageGenerator.cc | 203 +++++++++++++++++++++ runtimes/neurun/backend/acl_cl/StageGenerator.h | 3 + .../core/include/model/operation/ArgMaxNode.h | 60 ++++++ .../core/include/model/operation/DequantizeNode.h | 49 +++++ .../neurun/core/include/model/operation/MeanNode.h | 61 +++++++ .../core/include/model/operation/Node.Include.h | 3 + .../neurun/core/include/model/operation/Op.lst | 3 + .../neurun/core/src/compiler/OperationValidator.cc | 55 ++++++ .../neurun/core/src/compiler/OperationValidator.h | 2 + .../neurun/core/src/model/operation/ArgMaxNode.cc | 40 ++++ .../core/src/model/operation/DequantizeNode.cc | 39 ++++ .../neurun/core/src/model/operation/MeanNode.cc | 40 ++++ .../frontend/nnapi/wrapper/OperationFactory.cc | 49 +++++ tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun | 3 - .../neurun_frameworktest_list.armv7l.acl_cl.txt | 2 + 15 files changed, 609 insertions(+), 3 deletions(-) create mode 100644 runtimes/neurun/core/include/model/operation/ArgMaxNode.h create mode 100644 runtimes/neurun/core/include/model/operation/DequantizeNode.h create mode 100644 runtimes/neurun/core/include/model/operation/MeanNode.h create mode 100644 runtimes/neurun/core/src/model/operation/ArgMaxNode.cc create mode 100644 runtimes/neurun/core/src/model/operation/DequantizeNode.cc create mode 100644 runtimes/neurun/core/src/model/operation/MeanNode.cc diff --git a/runtimes/neurun/backend/acl_cl/StageGenerator.cc b/runtimes/neurun/backend/acl_cl/StageGenerator.cc index a196a86..6567deb 100644 --- a/runtimes/neurun/backend/acl_cl/StageGenerator.cc +++ b/runtimes/neurun/backend/acl_cl/StageGenerator.cc @@ -2701,6 +2701,209 @@ void StageGenerator::visit(const model::operation::AbsNode &node) }); } +void StageGenerator::visit(const model::operation::ArgMaxNode &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::ArgMaxNode::Input::INPUT)}; + const auto axis_index{node.param().axis_index}; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + auto axis_shape = _ctx.at(axis_index).shape(); + + assert(_ctx.at(axis_index).hasData()); + // Axis dimension is always 1. + assert(axis_shape.rank() == 1); + assert(ifm_shape.rank() == ofm_shape.rank()); + + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); + + std::vector l_axis; + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + auto axis_base = _ctx.at(axis_index).data().base(); + // TODO Should support axis size > 1. + assert(axis_size == 1); + // axis is tensor with 1 dimension - always a vector. + assert(axis_base != nullptr); + for (int32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_shape.rank(); + } + l_axis.push_back(ToARMComputeAxis(ifm_shape.rank(), axis_value).value()); + } + + // Construct operation parameters + struct Param + { + model::operand::Index ofm_index; + model::operand::Index ifm_index; + std::vector axis; + }; + + Param param; + + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; + param.axis = l_axis; + + auto tensors = _tensor_builder; + + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); + + std::unique_ptr<::arm_compute::IFunction> fn; + + auto l = make_layer<::arm_compute::CLArgOperation>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), param.axis, + ::arm_compute::ArgOperation::MAX); + + fn = std::move(l); + + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_fn)); + }); +} + +void StageGenerator::visit(const model::operation::DequantizeNode &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::DequantizeNode::Input::INPUT)}; + + // Construct operation parameters + struct Param + { + model::operand::Index output_index; + model::operand::Index input_index; + }; + + Param param; + + param.output_index = output_index; + param.input_index = input_index; + + auto tensors = _tensor_builder; + + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); + + std::unique_ptr<::arm_compute::IFunction> fn; + + auto l = make_layer<::arm_compute::CLCast>(); + + l->configure(input_alloc->handle(), output_alloc->handle()); + + fn = std::move(l); + + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_fn)); + }); +} + +void StageGenerator::visit(const model::operation::MeanNode &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::MeanNode::Input::INPUT)}; + + const auto axis_index{node.param().axis_index}; + const auto keep_dims_index{node.param().keep_dims_index}; + + const int keep_dims = _ctx.at(keep_dims_index).asScalar(); + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + + std::set axis; + { + const auto ifm_rank = ifm_shape.rank(); + const auto axis_shape = _ctx.at(axis_index).shape(); + switch (axis_shape.rank()) + { + case 0: // scalar + { + int32_t axis_value = _ctx.at(axis_index).asScalar(); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + break; + } + case 1: // vector + { + const auto axis_base = _ctx.at(axis_index).data().base(); + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + + // If axis's data does not exist as constant values and can be gotten as input data, we have + // to find a way to infer output shape when sinking output. + assert(axis_base != nullptr); + for (int32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + } + break; + } + default: + throw std::runtime_error("Not supported"); + break; + } + } + + struct Param + { + model::operand::Index ofm_index; + model::operand::Index ifm_index; + + bool keep_dims; + std::set axis; + }; + + Param param; + + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; + param.keep_dims = keep_dims > 0 ? true : false; + param.axis = axis; + + auto tensors = _tensor_builder; + + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); + + ::arm_compute::Coordinates reduction_axis; + size_t i = 0; + for (auto index : param.axis) + { + reduction_axis.set(i++, index); + } + + std::unique_ptr<::arm_compute::IFunction> fn; + + auto l = make_layer<::arm_compute::CLReduceMean>(); + + l->configure(ifm_alloc->handle(), reduction_axis, param.keep_dims, ofm_alloc->handle()); + + fn = std::move(l); + + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_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 6ddc7d8..5dabade 100644 --- a/runtimes/neurun/backend/acl_cl/StageGenerator.h +++ b/runtimes/neurun/backend/acl_cl/StageGenerator.h @@ -81,6 +81,9 @@ public: void visit(const model::operation::GatherNode &) override; void visit(const model::operation::NegNode &) override; void visit(const model::operation::AbsNode &) override; + void visit(const model::operation::ArgMaxNode &) override; + void visit(const model::operation::DequantizeNode &) override; + void visit(const model::operation::MeanNode &) override; private: const neurun::model::operand::Set &_ctx; diff --git a/runtimes/neurun/core/include/model/operation/ArgMaxNode.h b/runtimes/neurun/core/include/model/operation/ArgMaxNode.h new file mode 100644 index 0000000..e89321c --- /dev/null +++ b/runtimes/neurun/core/include/model/operation/ArgMaxNode.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_MODEL_OPERATION_ARG_MAX_NODE_H__ +#define __NEURUN_MODEL_OPERATION_ARG_MAX_NODE_H__ + +#include "model/operation/Node.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class ArgMaxNode : public model::operation::Node +{ +public: + enum Input + { + INPUT + }; + + struct Param + { + operand::Index axis_index; + }; + +public: + ArgMaxNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs, const Param ¶m); + +public: + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "ArgMax"; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_ARG_MAX_NODE_H__ diff --git a/runtimes/neurun/core/include/model/operation/DequantizeNode.h b/runtimes/neurun/core/include/model/operation/DequantizeNode.h new file mode 100644 index 0000000..87f3114 --- /dev/null +++ b/runtimes/neurun/core/include/model/operation/DequantizeNode.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_MODEL_OPERATION_DEQUANTIZE_NODE_H__ +#define __NEURUN_MODEL_OPERATION_DEQUANTIZE_NODE_H__ + +#include "model/operation/Node.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class DequantizeNode : public model::operation::Node +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + DequantizeNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs); + +public: + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Dequantize"; } +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_DEQUANTIZE_NODE_H__ diff --git a/runtimes/neurun/core/include/model/operation/MeanNode.h b/runtimes/neurun/core/include/model/operation/MeanNode.h new file mode 100644 index 0000000..3c9368f --- /dev/null +++ b/runtimes/neurun/core/include/model/operation/MeanNode.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_MODEL_OPERATION_MEAN_NODE_H__ +#define __NEURUN_MODEL_OPERATION_MEAN_NODE_H__ + +#include "model/operation/Node.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class MeanNode : public model::operation::Node +{ +public: + enum Input + { + INPUT + }; + + struct Param + { + operand::Index axis_index; + operand::Index keep_dims_index; + }; + +public: + MeanNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs, const Param ¶m); + +public: + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Mean"; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_MEAN_NODE_H__ diff --git a/runtimes/neurun/core/include/model/operation/Node.Include.h b/runtimes/neurun/core/include/model/operation/Node.Include.h index d3d3637..0944360 100644 --- a/runtimes/neurun/core/include/model/operation/Node.Include.h +++ b/runtimes/neurun/core/include/model/operation/Node.Include.h @@ -61,3 +61,6 @@ #include "GatherNode.h" #include "NegNode.h" #include "AbsNode.h" +#include "ArgMaxNode.h" +#include "DequantizeNode.h" +#include "MeanNode.h" diff --git a/runtimes/neurun/core/include/model/operation/Op.lst b/runtimes/neurun/core/include/model/operation/Op.lst index df627c9..8a072c3 100644 --- a/runtimes/neurun/core/include/model/operation/Op.lst +++ b/runtimes/neurun/core/include/model/operation/Op.lst @@ -65,5 +65,8 @@ OP(TopKV2Node , true) OP(GatherNode , true) OP(NegNode , true) OP(AbsNode , true) +OP(ArgMaxNode , true) +OP(DequantizeNode , true) +OP(MeanNode , true) OP(PermuteNode , false) diff --git a/runtimes/neurun/core/src/compiler/OperationValidator.cc b/runtimes/neurun/core/src/compiler/OperationValidator.cc index ee4f854..ecbebc6 100644 --- a/runtimes/neurun/core/src/compiler/OperationValidator.cc +++ b/runtimes/neurun/core/src/compiler/OperationValidator.cc @@ -383,5 +383,60 @@ void OperationValidator::visit(const model::operation::GatherNode &node) assert(axis_shape.rank() == 0); } +void OperationValidator::visit(const model::operation::DequantizeNode &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::DequantizeNode::Input::INPUT)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(input_index).shape().rank() <= 4); + assert(_ctx.at(input_index).shape() == _ctx.at(output_index).shape()); + assert(_ctx.at(input_index).typeInfo().type() == + neurun::model::operand::DataType::TENSOR_QUANT8_ASYMM); + assert(_ctx.at(output_index).typeInfo().type() == + neurun::model::operand::DataType::TENSOR_FLOAT32); +} + +void OperationValidator::visit(const model::operation::MeanNode &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::MeanNode::Input::INPUT)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert((ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2)) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } +} + } // namespace compiler } // namespace neurun diff --git a/runtimes/neurun/core/src/compiler/OperationValidator.h b/runtimes/neurun/core/src/compiler/OperationValidator.h index 362c940..af8e158 100644 --- a/runtimes/neurun/core/src/compiler/OperationValidator.h +++ b/runtimes/neurun/core/src/compiler/OperationValidator.h @@ -52,6 +52,8 @@ public: virtual void visit(const model::operation::HashtableLookupNode &node) override; virtual void visit(const model::operation::TransposeConvNode &node) override; virtual void visit(const model::operation::GatherNode &node) override; + virtual void visit(const model::operation::DequantizeNode &node) override; + virtual void visit(const model::operation::MeanNode &node) override; private: const neurun::model::operand::Set &_ctx; diff --git a/runtimes/neurun/core/src/model/operation/ArgMaxNode.cc b/runtimes/neurun/core/src/model/operation/ArgMaxNode.cc new file mode 100644 index 0000000..6d9eac9 --- /dev/null +++ b/runtimes/neurun/core/src/model/operation/ArgMaxNode.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "model/operation/ArgMaxNode.h" + +#include + +#include "model/operation/NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +void ArgMaxNode::accept(NodeVisitor &&v) const { v.visit(*this); } + +ArgMaxNode::ArgMaxNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs, + const Param ¶m) + : model::operation::Node{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/core/src/model/operation/DequantizeNode.cc b/runtimes/neurun/core/src/model/operation/DequantizeNode.cc new file mode 100644 index 0000000..ac777c5 --- /dev/null +++ b/runtimes/neurun/core/src/model/operation/DequantizeNode.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "model/operation/DequantizeNode.h" + +#include + +#include "model/operation/NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +void DequantizeNode::accept(NodeVisitor &&v) const { v.visit(*this); } + +DequantizeNode::DequantizeNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs) + : model::operation::Node{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/core/src/model/operation/MeanNode.cc b/runtimes/neurun/core/src/model/operation/MeanNode.cc new file mode 100644 index 0000000..1762143 --- /dev/null +++ b/runtimes/neurun/core/src/model/operation/MeanNode.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "model/operation/MeanNode.h" + +#include + +#include "model/operation/NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +void MeanNode::accept(NodeVisitor &&v) const { v.visit(*this); } + +MeanNode::MeanNode(const operand::IndexSet &inputs, const operand::IndexSet &outputs, + const Param ¶m) + : model::operation::Node{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/frontend/nnapi/wrapper/OperationFactory.cc b/runtimes/neurun/frontend/nnapi/wrapper/OperationFactory.cc index 4543fd4..5585873 100644 --- a/runtimes/neurun/frontend/nnapi/wrapper/OperationFactory.cc +++ b/runtimes/neurun/frontend/nnapi/wrapper/OperationFactory.cc @@ -1008,6 +1008,55 @@ OperationFactory::OperationFactory() return new operation::AbsNode{inputs, outputs}; }; + + _map[ANEURALNETWORKS_ARGMAX_EX] = [](const OperationFactory::Param &init_param) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + operand::IndexSet outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + operand::IndexSet inputs{init_param.inputs[0]}; + + operation::ArgMaxNode::Param param; + param.axis_index = operand::Index{init_param.inputs[1]}; + + return new operation::ArgMaxNode{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_DEQUANTIZE] = [](const OperationFactory::Param &init_param) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + operand::IndexSet outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + operand::IndexSet inputs{init_param.inputs[0]}; + + return new operation::DequantizeNode{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_MEAN] = [](const OperationFactory::Param &init_param) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + operand::IndexSet outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> ifm Tensor Index + // 1 -> axis Tensor Index + // 2 -> keep_dims Index + operand::IndexSet inputs{init_param.inputs[0]}; + + operation::MeanNode::Param param; + param.axis_index = operand::Index{init_param.inputs[1]}; + param.keep_dims_index = operand::Index{init_param.inputs[2]}; + + return new operation::MeanNode{inputs, outputs, param}; + }; } neurun::model::operation::Node *OperationFactory::create(ANeuralNetworksOperationType type, diff --git a/tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun b/tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun index 4323c62..23a073e 100644 --- a/tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun +++ b/tests/nnapi/nnapi_gtest.skip.armv7l-linux.neurun @@ -8,16 +8,13 @@ ValidationTestExecution.SetInputFromMemory ValidationTestExecution.SetOutputFromMemory ValidationTestExecution.StartCompute ValidationTestExecution.EventWait -GeneratedTests.argmax* GeneratedTests.depth_to_space* -GeneratedTests.dequantize GeneratedTests.local_response_norm* GeneratedTests.lsh_projection* GeneratedTests.lstm* GeneratedTests.mobilenet* GeneratedTests.reduce_min* GeneratedTests.rnn* -GeneratedTests.mean* GeneratedTests.pad* GeneratedTests.svdf* GeneratedTests.batch_to_space* diff --git a/tests/scripts/neurun_frameworktest_list.armv7l.acl_cl.txt b/tests/scripts/neurun_frameworktest_list.armv7l.acl_cl.txt index 71d60bc..74c8abf 100644 --- a/tests/scripts/neurun_frameworktest_list.armv7l.acl_cl.txt +++ b/tests/scripts/neurun_frameworktest_list.armv7l.acl_cl.txt @@ -1,5 +1,6 @@ add/1D add/4D +argmax average_pool_2d cast concat @@ -16,6 +17,7 @@ l2_pool_2d hashtable_lookup l2_normalization max_pool_2d +mean MODELS/mobilenet mul/broadcast neg -- 2.7.4