diff options
Diffstat (limited to 'runtime/onert/frontend/nnapi/wrapper')
11 files changed, 326 insertions, 377 deletions
diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc index 81cd38f4f..3b5edc180 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc @@ -18,21 +18,23 @@ #include "util/logging.h" +using namespace onert; + // TODO Support multiple subgraphs ANeuralNetworksCompilation::ANeuralNetworksCompilation(const ANeuralNetworksModel *model) noexcept - : _subgraphs{model->getSubGraphs()}, _compiler{new onert::compiler::Compiler{_subgraphs}} + : _model{model->getModel()}, _coptions{compiler::CompilerOptions::fromGlobalConfig()}, + _compiler{std::make_shared<compiler::Compiler>(_model, *_coptions)} { if (model->allowedToFp16()) - { - _compiler->enableToFp16(); - } + _coptions->enableToFp16(); } bool ANeuralNetworksCompilation::finish() noexcept { try { - _executors = _compiler->compile(); + _artifact = _compiler->compile(); + _compiler = nullptr; } catch (const std::exception &e) { diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h index 5f0650b9a..3898f1d5e 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h @@ -21,8 +21,9 @@ #include "compiler/Compiler.h" #include "ir/Graph.h" -#include "ir/Subgraphs.h" -#include "exec/IExecutor.h" +#include "ir/Model.h" +#include "exec/IExecutors.h" +#include "util/TracingCtx.h" struct ANeuralNetworksCompilation { @@ -31,17 +32,18 @@ public: public: bool finish() noexcept; + bool isFinished() noexcept { return _compiler == nullptr; } - onert::compiler::State state(void) noexcept { return _compiler->state(); } - void publish(std::shared_ptr<onert::exec::ExecutorMap> &executors) noexcept + void publish(std::shared_ptr<onert::exec::IExecutors> &executors) noexcept { - executors = _executors; + executors = _artifact ? _artifact->_executors : nullptr; } private: - std::shared_ptr<onert::ir::Subgraphs> _subgraphs; + std::shared_ptr<onert::ir::Model> _model; + std::unique_ptr<onert::compiler::CompilerOptions> _coptions; std::shared_ptr<onert::compiler::Compiler> _compiler; - std::shared_ptr<onert::exec::ExecutorMap> _executors; + std::shared_ptr<onert::compiler::CompilerArtifact> _artifact; }; #endif diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc index 2bea729be..b0ea51917 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc @@ -20,7 +20,7 @@ #include "util/logging.h" ANeuralNetworksEvent::ANeuralNetworksEvent(const std::shared_ptr<onert::exec::Execution> &execution) - : _execution{execution} + : _execution{execution} { // DO NOTHING } diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc index eb12d7e76..2265e990f 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc @@ -64,7 +64,7 @@ bool ANeuralNetworksExecution::compareDataType(const ANeuralNetworksOperandType { try { - const auto operand_type = _execution->primary_subgraph().operands().at(index).typeInfo(); + const auto &operand_type = _execution->primary_subgraph().operands().at(index).typeInfo(); const auto typeInfo = NNAPIConvert::getTypeInfo(type); if (operand_type != typeInfo) @@ -98,9 +98,20 @@ bool ANeuralNetworksExecution::compareShape(const ANeuralNetworksOperandType *ty return operand_shape == shape_from_type; } +bool ANeuralNetworksExecution::IsOptionalInput(const onert::ir::OperandIndex index) noexcept +{ + const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape(); + for (int32_t i = 0; i < operand_shape.rank(); ++i) + { + if (operand_shape.dim(i) != 0) + return false; + } + return true; +} + bool ANeuralNetworksExecution::hasUnspecifiedDims(const onert::ir::OperandIndex index) noexcept { - const auto operand_shape = _execution->primary_subgraph().operands().at(index).shape(); + const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape(); return operand_shape.hasUnspecifiedDims(); } @@ -127,10 +138,10 @@ bool ANeuralNetworksExecution::setInput(uint32_t index, const ANeuralNetworksOpe onert::ir::IOIndex input_index{index}; const auto operand_index = getInputOperandIndex(index); - const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo(); + const auto &type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo(); const auto shape = (type != nullptr) - ? NNAPIConvert::getShape(type) - : _execution->primary_subgraph().operands().at(operand_index).shape(); + ? NNAPIConvert::getShape(type) + : _execution->primary_subgraph().operands().at(operand_index).shape(); // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other // words, we can assume that io_layout from nnapi always is the same as layout of the used @@ -148,6 +159,44 @@ bool ANeuralNetworksExecution::setInput(uint32_t index, const ANeuralNetworksOpe return true; } +bool ANeuralNetworksExecution::setOptionalInput(uint32_t index, + const ANeuralNetworksOperandType *type, + const void *buffer, size_t length) noexcept +{ + assert(type == nullptr); + assert(buffer == nullptr); + assert(length == 0); + try + { + onert::ir::IOIndex input_index{index}; + const auto operand_index = getInputOperandIndex(index); + + const auto shape = (type != nullptr) + ? NNAPIConvert::getShape(type) + : _execution->primary_subgraph().operands().at(operand_index).shape(); + + // ANeuralNetworksExecution::setInput() uses only shape information + ANeuralNetworksOperandType optional_input_type; + optional_input_type.dimensionCount = shape.rank(); + std::vector<uint32_t> dims(optional_input_type.dimensionCount); + for (uint32_t i = 0; i < optional_input_type.dimensionCount; ++i) + { + dims.at(i) = shape.dim(i); + } + optional_input_type.dimensions = dims.data(); + + return setInput(index, &optional_input_type, buffer, length); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + bool ANeuralNetworksExecution::setOutput(uint32_t index, const ANeuralNetworksOperandType *type, void *buffer, size_t length) noexcept { @@ -156,10 +205,10 @@ bool ANeuralNetworksExecution::setOutput(uint32_t index, const ANeuralNetworksOp onert::ir::IOIndex output_index{index}; const auto operand_index = getOutputOperandIndex(index); - const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo(); + const auto &type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo(); const auto shape = (type != nullptr) - ? NNAPIConvert::getShape(type) - : _execution->primary_subgraph().operands().at(operand_index).shape(); + ? NNAPIConvert::getShape(type) + : _execution->primary_subgraph().operands().at(operand_index).shape(); // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other // words, we can assume that io_layout from nnapi always is the same as layout of the used diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h index 848ae743f..6fbc4c2e0 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h @@ -26,8 +26,8 @@ struct ANeuralNetworksExecution { public: - ANeuralNetworksExecution(const std::shared_ptr<onert::exec::ExecutorMap> &executors) - : _execution{std::make_shared<onert::exec::Execution>(executors)} + ANeuralNetworksExecution(const std::shared_ptr<onert::exec::IExecutors> &executors) + : _execution{std::make_shared<onert::exec::Execution>(executors)} { // DO NOTHING } @@ -35,6 +35,8 @@ public: public: bool setInput(uint32_t index, const ANeuralNetworksOperandType *type, const void *buffer, size_t length) noexcept; + bool setOptionalInput(uint32_t index, const ANeuralNetworksOperandType *type, const void *buffer, + size_t length) noexcept; bool setOutput(uint32_t index, const ANeuralNetworksOperandType *type, void *buffer, size_t length) noexcept; bool startExecute(void) noexcept; @@ -46,6 +48,7 @@ public: const onert::ir::OperandIndex index) noexcept; bool compareShape(const ANeuralNetworksOperandType *type, const onert::ir::OperandIndex index) noexcept; + bool IsOptionalInput(const onert::ir::OperandIndex index) noexcept; bool hasUnspecifiedDims(const onert::ir::OperandIndex index) noexcept; size_t getOperandSize(const onert::ir::OperandIndex index) noexcept; const std::shared_ptr<onert::exec::Execution> instance(void) noexcept; diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc index 97b820aea..837dac954 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc @@ -27,7 +27,8 @@ // ANeuralNetworksModel // ANeuralNetworksModel::ANeuralNetworksModel() noexcept - : _optional_operands{}, _operand_usages{}, _allowFloat32toFloat16{false} + : _finished_building{false}, _optional_operands{}, _operand_usages{}, _allowFloat32toFloat16{ + false} { _graph = std::make_shared<onert::ir::Graph>(); } @@ -72,12 +73,12 @@ bool ANeuralNetworksModel::setOperandValue(uint32_t index, const void *buffer, s if (copy) { _graph->operands().at(ind).data( - std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length)); + std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length)); } else { _graph->operands().at(ind).data( - std::make_unique<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length)); + std::make_unique<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length)); } } catch (const std::exception &e) @@ -111,9 +112,9 @@ bool ANeuralNetworksModel::addOperation(ANeuralNetworksOperationType type, uint3 if (type == ANEURALNETWORKS_FULLY_CONNECTED) { const auto &input_operand = - _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::INPUT)); + _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::INPUT)); auto &weights_operand = - _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::WEIGHT)); + _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::WEIGHT)); if (input_operand.typeInfo().type() == onert::ir::DataType::FLOAT32 && weights_operand.typeInfo().type() == onert::ir::DataType::QUANT_UINT8_ASYMM) { @@ -208,9 +209,9 @@ bool ANeuralNetworksModel::finish() noexcept { fillOptionalOperand(); - _graph->finishBuilding(); - + _graph->verify(); _operand_usages.clear(); + _finished_building = true; } catch (const std::exception &e) { @@ -222,7 +223,7 @@ bool ANeuralNetworksModel::finish() noexcept return true; } -bool ANeuralNetworksModel::isFinished() noexcept { return !_graph->isBuildingPhase(); } +bool ANeuralNetworksModel::isFinished() noexcept { return _finished_building; } bool ANeuralNetworksModel::isExistOperand(uint32_t index) noexcept { @@ -260,8 +261,8 @@ void ANeuralNetworksModel::setOptionalOperand(const onert::ir::OperandIndex idx) void ANeuralNetworksModel::fillOptionalOperand(void) { - _graph->operations().iterate([&](const onert::ir::OperationIndex &, onert::ir::Operation &node) { - for (auto input : node.getInputs()) + _graph->operations().iterate([&](const onert::ir::OperationIndex &, onert::ir::IOperation &node) { + for (auto &&input : node.getInputs()) { // TODO fill default value for optional operands if (_optional_operands.find(input) != _optional_operands.end()) @@ -272,16 +273,16 @@ void ANeuralNetworksModel::fillOptionalOperand(void) }); } -std::shared_ptr<onert::ir::Subgraphs> ANeuralNetworksModel::getSubGraphs() const +std::shared_ptr<onert::ir::Model> ANeuralNetworksModel::getModel() const { - auto all_subgs = std::make_shared<onert::ir::Subgraphs>(); + auto model = std::make_shared<onert::ir::Model>(); - all_subgs->push(onert::ir::SubgraphIndex{0}, _graph); + model->push(onert::ir::SubgraphIndex{0}, _graph); // TODO Find all child subgraphs and copy them to all_subgs // Must find the same subgraph by using to compare pointer of subgraphs and set subgraph's index // to operands of control flow operations // Must clean all child subgraphs's pointer to prevent memory leak in case of that graph has // subgraph itself recursively - return all_subgs; + return model; } diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h index df6c97c44..04f4cf0f2 100644 --- a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h @@ -22,7 +22,7 @@ #include <NeuralNetworksEx.h> #include "ir/Graph.h" -#include "ir/Subgraphs.h" +#include "ir/Model.h" struct ANeuralNetworksModel { @@ -59,7 +59,7 @@ public: size_t operandSize(uint32_t index) noexcept; bool isUsageSet(uint32_t index) noexcept; bool isOperationOutput(uint32_t index) noexcept; - std::shared_ptr<onert::ir::Subgraphs> getSubGraphs() const; + std::shared_ptr<onert::ir::Model> getModel() const; private: void setOptionalOperand(const onert::ir::OperandIndex idx); @@ -67,6 +67,7 @@ private: private: std::shared_ptr<onert::ir::Graph> _graph; + bool _finished_building; std::unordered_set<onert::ir::OperandIndex> _optional_operands; std::vector<OperandUsage> _operand_usages; bool _allowFloat32toFloat16; diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc new file mode 100644 index 000000000..bb42f2b08 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.test.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 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 <gtest/gtest.h> + +#include "ANeuralNetworksModel.h" + +TEST(MODEL, neg_model_build) +{ + ANeuralNetworksModel model; + ASSERT_FALSE(model.isFinished()); +} diff --git a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc index 63d4e3c09..94b8f02f5 100644 --- a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc +++ b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc @@ -39,6 +39,13 @@ DataType NNAPIConvert::getDataType(OperandCode type) case ANEURALNETWORKS_BOOL: case ANEURALNETWORKS_TENSOR_BOOL8: return DataType::BOOL8; + case ANEURALNETWORKS_TENSOR_FLOAT16: + case ANEURALNETWORKS_FLOAT16: + return DataType::FLOAT16; + case ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL: + return DataType::QUANT_INT8_SYMM_PER_CHANNEL; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED: + return DataType::QUANT_INT8_ASYMM; default: throw std::runtime_error("Unsupported type"); } diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc index 8e3d83db4..ba739f618 100644 --- a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc +++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc @@ -82,6 +82,27 @@ uint32_t getUint32Scalar(Operands &operands, const OperandIndex index) return static_cast<uint32_t>(int32_value); } +Activation getActivation(Operands &operands, const OperandIndex index) +{ + switch (operands.at(index).asScalar<int32_t>()) + { + case 0: + return Activation::NONE; + case 1: + return Activation::RELU; + case 2: + return Activation::RELU1; + case 3: + return Activation::RELU6; + case 4: + return Activation::TANH; + case 6: + return Activation::SIGMOID; + default: + throw std::runtime_error("Unsupported activation type"); + } +} + OperationFactory::Generator getElementwiseActivationGenerator(const onert::ir::operation::ElementwiseActivation::Type op_type, float alpha = 0.f, float beta = 0.f) @@ -107,7 +128,7 @@ getElementwiseActivationGenerator(const onert::ir::operation::ElementwiseActivat } OperationFactory::Generator getElementwiseBinaryGenerator( - const onert::ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type) + const onert::ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type) { return [op_type](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 2); @@ -182,7 +203,7 @@ getBinaryArithmeticGenerator(const onert::ir::operation::BinaryArithmetic::Arith param.arithmetic_type = op_type; const auto activation_index = OperandIndex{init_param.inputs[2]}; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); return new operation::BinaryArithmetic{inputs, outputs, param}; }; @@ -221,12 +242,12 @@ getPool2DGenerator(const onert::ir::operation::Pool2D::PoolType pool_type) const auto activation_index = OperandIndex{init_param.inputs[6]}; param.padding.type = - NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); param.stride = makeStride(operands, hstride_index, vstride_index); param.kw = getUint32Scalar(operands, kw_index); param.kh = operands.at(kh_index).asScalar<uint32_t>(); param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } else // support explicit padding { @@ -259,7 +280,7 @@ getPool2DGenerator(const onert::ir::operation::Pool2D::PoolType pool_type) param.kw = getUint32Scalar(operands, kw_index); param.kh = getUint32Scalar(operands, kh_index); param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } return new operation::Pool2D{inputs, outputs, param}; }; @@ -382,11 +403,11 @@ OperationFactory::OperationFactory() const auto activation_index = OperandIndex{init_param.inputs[7]}; param.padding.type = - NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); param.stride = makeStride(operands, hstride_index, vstride_index); param.multiplier = getUint32Scalar(operands, multiplier_index); param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } else { @@ -417,9 +438,13 @@ OperationFactory::OperationFactory() param.stride = makeStride(operands, hstride_index, vstride_index); param.multiplier = getUint32Scalar(operands, multiplier_index); param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } + // TODO set dilation + param.dilation.width_factor = 1; + param.dilation.height_factor = 1; + return new operation::DepthwiseConv2D{inputs, outputs, param}; }; @@ -486,7 +511,8 @@ OperationFactory::OperationFactory() operation::FullyConnected::Param param; const auto activation_index = OperandIndex{init_param.inputs[3]}; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + param.weights_format = FullyConnectedWeightsFormat::Default; return new operation::FullyConnected{inputs, outputs, param}; }; @@ -512,11 +538,7 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_CAST] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::CAST); - - // ANEURALNETWORKS_CAST_EX is deprecated - // TODO Remove ANEURALNETWORKS_CAST_EX - _map[ANEURALNETWORKS_CAST_EX] = _map[ANEURALNETWORKS_CAST]; + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::CAST); _map[ANEURALNETWORKS_CONV_2D] = [](const OperationFactory::Param &init_param, Operands &operands) { @@ -552,14 +574,14 @@ OperationFactory::OperationFactory() const auto activation_index = OperandIndex{init_param.inputs[6]}; param.padding.type = - NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); param.stride = makeStride(operands, hstride_index, vstride_index); param.dilation.width_factor = 1; param.dilation.height_factor = 1; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } else if (init_param.input_count == 10) // support explicit padding { @@ -590,7 +612,7 @@ OperationFactory::OperationFactory() param.dilation.height_factor = 1; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } else if (init_param.input_count == 13) // support dilation { @@ -628,7 +650,7 @@ OperationFactory::OperationFactory() param.dilation.height_factor = height_factor; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); } else { @@ -639,19 +661,15 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_ADD] = - getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::ADD); + getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::ADD); _map[ANEURALNETWORKS_ADDV2_EX] = _map[ANEURALNETWORKS_ADD]; _map[ANEURALNETWORKS_REDUCE_SUM] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::SUM); - - // ANEURALNETWORKS_REDUCE_SUM_EX is deprecated - // TODO Remove ANEURALNETWORKS_REDUCE_SUM_EX - _map[ANEURALNETWORKS_REDUCE_SUM_EX] = _map[ANEURALNETWORKS_REDUCE_SUM]; + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::SUM); _map[ANEURALNETWORKS_SUB] = - getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::SUB); + getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::SUB); _map[ANEURALNETWORKS_SLICE] = [](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 3 && init_param.output_count == 1); @@ -703,39 +721,15 @@ OperationFactory::OperationFactory() param.begin_mask = operands.at(OperandIndex{init_param.inputs[4]}).asScalar<std::int32_t>(); param.end_mask = operands.at(OperandIndex{init_param.inputs[5]}).asScalar<std::int32_t>(); param.shrink_axis_mask = - operands.at(OperandIndex{init_param.inputs[6]}).asScalar<std::int32_t>(); + operands.at(OperandIndex{init_param.inputs[6]}).asScalar<std::int32_t>(); return new operation::StridedSlice{inputs, outputs, param}; }; - _map[ANEURALNETWORKS_TRANSPOSE] = [](const OperationFactory::Param &init_param, - Operands &operands) { - // TODO make this work with init_param.input_count == 1 (when permutation vector is optional) - - // Inputs - // 0: An n-D tensor, specifying the tensor to be transposed. - // 1: An optional 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, - // the permutation of the dimensions of the input tensor. - // The returned tensor's dimension i corresponds to the input dimension - // perm[i]. If perm is not given, it is set to (n-1...0), where n is the - // rank of the input tensor. Hence by default, this operation performs a - // regular matrix transpose on 2-D input Tensors. - assert(init_param.input_count == 2); - assert(init_param.output_count == 1); - - OperandIndexSequence inputs{init_param.inputs[0]}; - OperandIndexSequence outputs{init_param.outputs[0]}; - std::vector<std::int32_t> perm = - operands.at(OperandIndex{init_param.inputs[1]}).asVector<std::int32_t>(); - - operation::Transpose::Param param; - param.perm.assign(perm.cbegin(), perm.cend()); - - return new operation::Transpose{inputs, outputs, param}; - }; + _map[ANEURALNETWORKS_TRANSPOSE] = createSimpleBinaryOp<operation::Transpose>; _map[ANEURALNETWORKS_MUL] = - getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::MUL); + getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::MUL); _map[ANEURALNETWORKS_SQUEEZE] = [](const OperationFactory::Param &init_param, Operands &operands) { @@ -777,151 +771,49 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_TANH] = getElementwiseActivationGenerator( - onert::ir::operation::ElementwiseActivation::Type::TANH, 1.f, 1.f); + onert::ir::operation::ElementwiseActivation::Type::TANH, 1.f, 1.f); _map[ANEURALNETWORKS_LOG] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::LOG); - _map[ANEURALNETWORKS_LOGISTIC] = getElementwiseActivationGenerator( - onert::ir::operation::ElementwiseActivation::Type::LOGISTIC); + _map[ANEURALNETWORKS_LOGISTIC] = + getElementwiseActivationGenerator(onert::ir::operation::ElementwiseActivation::Type::LOGISTIC); _map[ANEURALNETWORKS_DIV] = - getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::DIV); + getBinaryArithmeticGenerator(onert::ir::operation::BinaryArithmetic::ArithmeticType::DIV); _map[ANEURALNETWORKS_EXP] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::EXP); - // ANEURALNETWORKS_EXP_EX is deprecated - // TODO Remove ANEURALNETWORKS_EXP_EX - _map[ANEURALNETWORKS_EXP_EX] = _map[ANEURALNETWORKS_EXP]; - // Each input should be interpreted as follows: // 0 -> Input Tensor Index // 1 -> Axis Tensor Index _map[ANEURALNETWORKS_EXPAND_DIMS] = createSimpleBinaryOp<operation::ExpandDims>; _map[ANEURALNETWORKS_GREATER] = - getComparisonGenerator(operation::Comparison::ComparisonType::Greater); + getComparisonGenerator(operation::Comparison::ComparisonType::Greater); _map[ANEURALNETWORKS_GREATER_EQUAL] = - getComparisonGenerator(operation::Comparison::ComparisonType::GreaterEqual); + getComparisonGenerator(operation::Comparison::ComparisonType::GreaterEqual); _map[ANEURALNETWORKS_LESS] = getComparisonGenerator(operation::Comparison::ComparisonType::Less); _map[ANEURALNETWORKS_LESS_EQUAL] = - getComparisonGenerator(operation::Comparison::ComparisonType::LessEqual); + getComparisonGenerator(operation::Comparison::ComparisonType::LessEqual); _map[ANEURALNETWORKS_NOT_EQUAL] = - getComparisonGenerator(operation::Comparison::ComparisonType::NotEqual); + getComparisonGenerator(operation::Comparison::ComparisonType::NotEqual); _map[ANEURALNETWORKS_EQUAL] = - getComparisonGenerator(operation::Comparison::ComparisonType::Equal); - - // ANEURALNETWORKS_GREATER_EQUAL_EX is deprecated - // TODO Remove ANEURALNETWORKS_GREATER_EQUAL_EX - _map[ANEURALNETWORKS_GREATER_EQUAL_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input0 Tensor Index - // 1 -> input1 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - - operation::Comparison::Param param; - param.comparison_type = operation::Comparison::ComparisonType::GreaterEqual; - - // Output operand type must be boolean - replaceDataType(operands, outputs.at(0), DataType::BOOL8); - - return new operation::Comparison{inputs, outputs, param}; - }; - - // ANEURALNETWORKS_LESS_EX is deprecated - // TODO Remove ANEURALNETWORKS_LESS_EX - _map[ANEURALNETWORKS_LESS_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input0 Tensor Index - // 1 -> input1 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - - operation::Comparison::Param param; - param.comparison_type = operation::Comparison::ComparisonType::Less; - - // Output operand type must be boolean - replaceDataType(operands, outputs.at(0), DataType::BOOL8); - - return new operation::Comparison{inputs, outputs, param}; - }; + getComparisonGenerator(operation::Comparison::ComparisonType::Equal); _map[ANEURALNETWORKS_REDUCE_ALL] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ALL); + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ALL); _map[ANEURALNETWORKS_REDUCE_ANY] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ANY); + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::ANY); _map[ANEURALNETWORKS_REDUCE_MAX] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MAX); - - // ANEURALNETWORKS_REDUCE_MAX_EX is deprecated - // TODO Remove ANEURALNETWORKS_REDUCE_MAX_EX - _map[ANEURALNETWORKS_REDUCE_MAX_EX] = _map[ANEURALNETWORKS_REDUCE_MAX]; - - // ANEURALNETWORKS_NOT_EQUAL_EX is deprecated - // TODO Remove ANEURALNETWORKS_NOT_EQUAL_EX - _map[ANEURALNETWORKS_NOT_EQUAL_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input1 Tensor Index - // 1 -> input2 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - - operation::Comparison::Param param; - param.comparison_type = operation::Comparison::ComparisonType::NotEqual; - - // Output operand type must be boolean - replaceDataType(operands, outputs.at(0), DataType::BOOL8); - - return new operation::Comparison{inputs, outputs, param}; - }; - - _map[ANEURALNETWORKS_LOGICAL_AND] = getElementwiseBinaryGenerator( - operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND); - - // ANEURALNETWORKS_LOGICAL_AND_EX is deprecated - // TODO Remove ANEURALNETWORKS_LOGICAL_AND_EX - _map[ANEURALNETWORKS_LOGICAL_AND_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input0 Tensor Index - // 1 -> input1 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - - // This operation's operands must be boolean type. - replaceDataType(operands, inputs.at(0), DataType::BOOL8); - replaceDataType(operands, inputs.at(1), DataType::BOOL8); - replaceDataType(operands, outputs.at(0), DataType::BOOL8); + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MAX); - operation::ElementwiseBinary::Param param; - param.op_type = operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND; - - return new operation::ElementwiseBinary{inputs, outputs, param}; - }; + _map[ANEURALNETWORKS_LOGICAL_AND] = + getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND); _map[ANEURALNETWORKS_RSQRT] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::RSQRT); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::RSQRT); _map[ANEURALNETWORKS_SELECT] = [](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 3 && init_param.output_count == 1); @@ -938,28 +830,11 @@ OperationFactory::OperationFactory() return new operation::Select{inputs, outputs}; }; - _map[ANEURALNETWORKS_SELECT_V2_EX] = [](const OperationFactory::Param &init_param, Operands &) { - assert(init_param.input_count == 3 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> Condition Tensor Index - // 1 -> Input X(true) Tensor Index - // 2 -> Input Y(false) Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; - - return new operation::Select{inputs, outputs}; - }; - - // ANEURALNETWORKS_RSQRT_EX is deprecated - // TODO Remove ANEURALNETWORKS_RSQRT_EX - _map[ANEURALNETWORKS_RSQRT_EX] = _map[ANEURALNETWORKS_RSQRT]; + _map[ANEURALNETWORKS_SELECT_V2_EX] = _map[ANEURALNETWORKS_SELECT]; _map[ANEURALNETWORKS_RELU] = - getElementwiseActivationGenerator(onert::ir::operation::ElementwiseActivation::Type::RELU, - onert::ir::operation::ElementwiseActivation::infinity, 0); + getElementwiseActivationGenerator(onert::ir::operation::ElementwiseActivation::Type::RELU, + onert::ir::operation::ElementwiseActivation::infinity, 0); _map[ANEURALNETWORKS_RESIZE_BILINEAR] = [](const OperationFactory::Param &init_param, Operands &operands) { @@ -982,11 +857,33 @@ OperationFactory::OperationFactory() return new operation::ResizeBilinear{inputs, outputs, param}; }; + _map[ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert((init_param.input_count == 3 || init_param.input_count == 4) && + init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Index + // 1 -> Height Index + // 2 -> Width Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::ResizeNearestNeighbor::Param param; + param.height_out = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<int32_t>(); + param.width_out = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<int32_t>(); + param.align_corners = false; + // The layout input is not supported yet + return new operation::ResizeNearestNeighbor{inputs, outputs, param}; + }; + _map[ANEURALNETWORKS_RELU1] = getElementwiseActivationGenerator( - onert::ir::operation::ElementwiseActivation::Type::RELU, 1.f, -1.f); + onert::ir::operation::ElementwiseActivation::Type::RELU, 1.f, -1.f); _map[ANEURALNETWORKS_RELU6] = getElementwiseActivationGenerator( - onert::ir::operation::ElementwiseActivation::Type::RELU, 6.f, 0.f); + onert::ir::operation::ElementwiseActivation::Type::RELU, 6.f, 0.f); _map[ANEURALNETWORKS_REVERSE_EX] = [](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 2 && init_param.output_count == 1); @@ -1028,13 +925,13 @@ OperationFactory::OperationFactory() operation::RNN::Param param; const auto activation_index = OperandIndex{init_param.inputs[5]}; param.activation = - NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar<FuseCode>()); return new operation::RNN{inputs, outputs, param}; }; _map[ANEURALNETWORKS_FLOOR] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::FLOOR); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::FLOOR); _map[ANEURALNETWORKS_SPACE_TO_BATCH_ND] = [](const OperationFactory::Param &init_param, Operands &) { @@ -1138,10 +1035,6 @@ OperationFactory::OperationFactory() return new operation::PReLU{inputs, outputs}; }; - // ANEURALNETWORKS_PRELU_EX is deprecated - // TODO Remove ANEURALNETWORKS_PRELU_EX - _map[ANEURALNETWORKS_PRELU_EX] = _map[ANEURALNETWORKS_PRELU]; - _map[ANEURALNETWORKS_TRANSPOSE_CONV_EX] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 6 && init_param.output_count == 1); @@ -1166,72 +1059,20 @@ OperationFactory::OperationFactory() const auto vstride_index = OperandIndex{init_param.inputs[5]}; param.padding.type = - NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar<PaddingCode>()); param.stride = makeStride(operands, hstride_index, vstride_index); return new operation::TransposeConv{inputs, outputs, param}; }; _map[ANEURALNETWORKS_SQRT] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::SQRT); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::SQRT); - // ANEURALNETWORKS_SQRT_EX is deprecated - // TODO Remove ANEURALNETWORKS_SQRT_EX - _map[ANEURALNETWORKS_SQRT_EX] = _map[ANEURALNETWORKS_SQRT]; - - _map[ANEURALNETWORKS_LOGICAL_OR] = getElementwiseBinaryGenerator( - operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR); - - // ANEURALNETWORKS_LOGICAL_OR_EX is deprecated - // TODO Remove ANEURALNETWORKS_LOGICAL_OR_EX - _map[ANEURALNETWORKS_LOGICAL_OR_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input0 Tensor Index - // 1 -> input1 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - - // This operation's operands must be boolean type. - replaceDataType(operands, inputs.at(0), DataType::BOOL8); - replaceDataType(operands, inputs.at(1), DataType::BOOL8); - replaceDataType(operands, outputs.at(0), DataType::BOOL8); - - operation::ElementwiseBinary::Param param; - param.op_type = operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR; - - return new operation::ElementwiseBinary{inputs, outputs, param}; - }; + _map[ANEURALNETWORKS_LOGICAL_OR] = + getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR); _map[ANEURALNETWORKS_LOGICAL_NOT] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::LOGICAL_NOT); - - // ANEURALNETWORKS_LOGICAL_NOT_EX is deprecated - // TODO Remove ANEURALNETWORKS_LOGICAL_NOT_EX - _map[ANEURALNETWORKS_LOGICAL_NOT_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 1 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; - - // Each input should be interpreted as follows: - // - // 0 -> input Tensor Index - OperandIndexSequence inputs{init_param.inputs[0]}; - - // This operation's operands must be boolean type. - replaceDataType(operands, inputs.at(0), DataType::BOOL8); - replaceDataType(operands, outputs.at(0), DataType::BOOL8); - - operation::ElementwiseUnary::Param param; - param.op_type = operation::ElementwiseUnary::Type::LOGICAL_NOT; - - return new operation::ElementwiseUnary{inputs, outputs, param}; - }; + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::LOGICAL_NOT); _map[ANEURALNETWORKS_LSTM] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 23 && init_param.output_count == 4); @@ -1277,58 +1118,86 @@ OperationFactory::OperationFactory() } operation::LSTM::Param param; - const auto activation_index = OperandIndex{init_param.inputs[20]}; - switch (operands.at(activation_index).asScalar<int32_t>()) - { - case 0: - param.activation = Activation::NONE; - break; - case 1: - param.activation = Activation::RELU; - break; - case 2: - param.activation = Activation::RELU1; - break; - case 3: - param.activation = Activation::RELU6; - break; - case 4: - param.activation = Activation::TANH; - break; - case 6: - param.activation = Activation::SIGMOID; - break; - default: - throw std::runtime_error("Unsupported activation type"); - break; - } + param.activation = getActivation(operands, OperandIndex{init_param.inputs[20]}); param.cell_threshold = operands.at(OperandIndex{init_param.inputs[21]}).asScalar<float>(); param.projection_threshold = operands.at(OperandIndex{init_param.inputs[22]}).asScalar<float>(); + // This is initialization to prevent warning or error by static code analyzer. LSTM operation + // does not need time_major + param.time_major = false; return new operation::LSTM{inputs, outputs, param}; }; - // ANEURALNETWORKS_EQUAL_EX is deprecated - // TODO Remove ANEURALNETWORKS_EQUAL_EX - _map[ANEURALNETWORKS_EQUAL_EX] = [](const OperationFactory::Param &init_param, - Operands &operands) { - assert(init_param.input_count == 2 && init_param.output_count == 1); - - OperandIndexSequence outputs{init_param.outputs[0]}; + _map[ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert((init_param.input_count >= 24 || init_param.input_count <= 28) && + (init_param.output_count >= 1 && init_param.output_count <= 3)); // Each input should be interpreted as follows: // - // 0 -> input0 Tensor Index - // 1 -> input1 Tensor Index - OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + // 0 -> Input Tensor Index + // 1 -> Input to Input Tensor Index + // 2 -> Input to Forget Tensor Index + // 3 -> Input to Cell Tensor Index + // 4 -> Input to Output Tensor Index + // 5 -> Recurrent to Input Weights Tensor Index + // 6 -> Recurrent to Forget Weights Tensor Index + // 7 -> Recurrent to Cell Weights Tensor Index + // 8 -> Recurrent to Output Weights Tensor Index + // 9 -> Cell to Input Weights Tensor Index + // 10 -> Cell to Forget Weights Tensor Index + // 11 -> Cell to Output Weights Tensor Index + // 12 -> Input Gate Bias Tensor Index + // 13 -> Forget Gate Bias Tensor Index + // 14 -> Cell Bias Tensor Index + // 15 -> Output Gate Bias Tensor Index + // 16 -> Projection Weights Tensor Index + // 17 -> Projection Bias Tensor Index + // 18 -> Output State In Tensor Index + // 19 -> Cell State In Tensor Index + assert(init_param.input_count - 3 > 20); + OperandIndexSequence inputs; + for (uint32_t n = 0; n < 20; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } - operation::Comparison::Param param; - param.comparison_type = operation::Comparison::ComparisonType::Equal; + // 24 -> Input Layer Normalization Weights Tensor Index + // 25 -> Forget Layer Normalization Weights Tensor Index + // 26 -> Cell Layer Normalization Weights Tensor Index + // 27 -> Output Layer Normalization Weights Tensor Index + if (init_param.input_count > 24) + { + for (uint32_t n = 24; n < 28; ++n) + { + if (init_param.input_count > n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + } + } + + // Each output should be interpreted as follows: + // + // 0 -> Output Tensor Index -> 3 + // 1 -> Output State Out Tensor Index + // 2 -> Cell State Out Tensor Index + const OperandIndex scratch_buffer_index; + OperandIndex output_state_index = + init_param.output_count >= 2 ? OperandIndex{init_param.outputs[1]} : OperandIndex(); + OperandIndex cell_state_index = + init_param.output_count >= 3 ? OperandIndex{init_param.outputs[2]} : OperandIndex(); + const OperandIndex output_index = OperandIndex{init_param.outputs[0]}; + OperandIndexSequence outputs{scratch_buffer_index, output_state_index, cell_state_index, + output_index}; - // Output operand type must be boolean - replaceDataType(operands, outputs.at(0), DataType::BOOL8); + operation::LSTM::Param param; + param.activation = getActivation(operands, OperandIndex{init_param.inputs[20]}); + param.cell_threshold = operands.at(OperandIndex{init_param.inputs[21]}).asScalar<float>(); + param.projection_threshold = operands.at(OperandIndex{init_param.inputs[22]}).asScalar<float>(); + param.time_major = operands.at(OperandIndex{init_param.inputs[23]}).asScalar<bool>(); - return new operation::Comparison{inputs, outputs, param}; + return new operation::LSTM{inputs, outputs, param}; }; _map[ANEURALNETWORKS_SQUARED_DIFFERENCE_EX] = [](const OperationFactory::Param &init_param, @@ -1368,10 +1237,6 @@ OperationFactory::OperationFactory() return new operation::TopKV2{inputs, outputs, param}; }; - // ANEURALNETWORKS_CAST_EX is deprecated - // TODO Remove ANEURALNETWORKS_CAST_EX - _map[ANEURALNETWORKS_TOPK_V2_EX] = _map[ANEURALNETWORKS_TOPK_V2]; - _map[ANEURALNETWORKS_GATHER] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 3 && init_param.output_count == 1); @@ -1390,23 +1255,11 @@ OperationFactory::OperationFactory() return new operation::Gather{inputs, outputs, param}; }; - // ANEURALNETWORKS_GATHER_EX is deprecated - // TODO Remove ANEURALNETWORKS_GATHER_EX - _map[ANEURALNETWORKS_GATHER_EX] = _map[ANEURALNETWORKS_GATHER]; - _map[ANEURALNETWORKS_NEG] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::NEG); - // ANEURALNETWORKS_NEG_EX is deprecated - // TODO Remove ANEURALNETWORKS_NEG_EX - _map[ANEURALNETWORKS_NEG_EX] = _map[ANEURALNETWORKS_NEG]; - _map[ANEURALNETWORKS_ABS] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ABS); - // ANEURALNETWORKS_ABS_EX is deprecated - // TODO Remove ANEURALNETWORKS_ABS_EX - _map[ANEURALNETWORKS_ABS_EX] = _map[ANEURALNETWORKS_ABS]; - - _map[ANEURALNETWORKS_ARGMAX] = [](const OperationFactory::Param &init_param, Operands &operands) { + _map[ANEURALNETWORKS_ARGMAX] = [](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 2 && init_param.output_count == 1); OperandIndexSequence outputs{init_param.outputs[0]}; @@ -1415,22 +1268,37 @@ OperationFactory::OperationFactory() // // 0 -> Input Tensor Index // 1 -> Axis Tensor Index - OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; - operation::ArgMax::Param param; - param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>(); + operation::ArgMinMax::Param param; // NNAPI ARGMAX output type is always int32 param.output_type = DataType::INT32; + param.is_arg_max = true; - return new operation::ArgMax{inputs, outputs, param}; + return new operation::ArgMinMax{inputs, outputs, param}; }; - // ANEURALNETWORKS_ARGMAX_EX is deprecated - // TODO Remove ANEURALNETWORKS_ARGMAX_EX - _map[ANEURALNETWORKS_ARGMAX_EX] = _map[ANEURALNETWORKS_ARGMAX]; + _map[ANEURALNETWORKS_ARGMIN] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::ArgMinMax::Param param; + // NNAPI ARGMIN output type is always int32 + param.output_type = DataType::INT32; + param.is_arg_max = false; + + return new operation::ArgMinMax{inputs, outputs, param}; + }; _map[ANEURALNETWORKS_DEQUANTIZE] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::DEQUANTIZE); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::DEQUANTIZE); _map[ANEURALNETWORKS_MEAN] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 3 && init_param.output_count == 1); @@ -1507,17 +1375,13 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_REDUCE_MIN] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MIN); - - // ANEURALNETWORKS_REDUCE_MIN_EX is deprecated - // TODO Remove ANEURALNETWORKS_REDUCE_MIN_EX - _map[ANEURALNETWORKS_REDUCE_MIN_EX] = _map[ANEURALNETWORKS_REDUCE_MIN]; + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::MIN); _map[ANEURALNETWORKS_SPLIT] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 3); assert(init_param.output_count >= 1); // At least one output tensor and axis - OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence inputs{init_param.inputs[1], init_param.inputs[0]}; OperandIndexSequence outputs; for (uint32_t n = 0; n < init_param.output_count; ++n) { @@ -1525,7 +1389,6 @@ OperationFactory::OperationFactory() } operation::Split::Param param; - param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar<std::int32_t>(); param.num_splits = operands.at(OperandIndex{init_param.inputs[2]}).asScalar<std::int32_t>(); return new operation::Split{inputs, outputs, param}; @@ -1548,10 +1411,6 @@ OperationFactory::OperationFactory() return new operation::SplitV{inputs, outputs, param}; }; - // ANEURALNETWORKS_SPLIT_EX is deprecated - // TODO Remove ANEURALNETWORKS_SPLIT_EX - _map[ANEURALNETWORKS_SPLIT_EX] = _map[ANEURALNETWORKS_SPLIT]; - _map[ANEURALNETWORKS_UNPACK_EX] = [](const OperationFactory::Param &init_param, Operands &operands) { assert(init_param.input_count == 3 && init_param.output_count >= 1); @@ -1589,10 +1448,10 @@ OperationFactory::OperationFactory() _map[ANEURALNETWORKS_PAD_V2] = _map[ANEURALNETWORKS_PAD]; _map[ANEURALNETWORKS_MINIMUM] = - getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MIN); + getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MIN); _map[ANEURALNETWORKS_MAXIMUM] = - getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MAX); + getElementwiseBinaryGenerator(operation::ElementwiseBinary::ElementwiseBinaryType::MAX); _map[ANEURALNETWORKS_ONE_HOT_EX] = [](const OperationFactory::Param &init_param, Operands &operands) { @@ -1619,7 +1478,7 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_COS_EX] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::COS); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::COS); _map[ANEURALNETWORKS_SIN] = getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::SIN); @@ -1633,10 +1492,10 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_REDUCE_PROD] = - getReduceGenerator(onert::ir::operation::Reduce::ReduceType::PROD); + getReduceGenerator(onert::ir::operation::Reduce::ReduceType::PROD); _map[ANEURALNETWORKS_ROUND_EX] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ROUND); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ROUND); _map[ANEURALNETWORKS_RANGE_EX] = [](const OperationFactory::Param &init_param, Operands &) { assert(init_param.input_count == 3 && init_param.output_count == 1); @@ -1664,7 +1523,7 @@ OperationFactory::OperationFactory() _map[ANEURALNETWORKS_FILL_EX] = createSimpleBinaryOp<operation::Fill>; _map[ANEURALNETWORKS_ZEROS_LIKE_EX] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ZEROS_LIKE); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::ZEROS_LIKE); // Each input should be interpreted as follows: // 0 -> Input Tensor Index // 1 -> Multiple Tensor Index @@ -1804,7 +1663,7 @@ OperationFactory::OperationFactory() }; _map[ANEURALNETWORKS_QUANTIZE] = - getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::QUANTIZE); + getElementwiseUnaryGenerator(operation::ElementwiseUnary::Type::QUANTIZE); } Operation *OperationFactory::create(ANeuralNetworksOperationType type, diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h index 367cf74db..74e187421 100644 --- a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h +++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h @@ -40,7 +40,7 @@ public: public: using Generator = - std::function<onert::ir::Operation *(const OperationFactory::Param &, onert::ir::Operands &)>; + std::function<onert::ir::Operation *(const OperationFactory::Param &, onert::ir::Operands &)>; public: static OperationFactory &get(); |