2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "ANeuralNetworksExecution.h"
18 #include "NNAPIConvert.h"
19 #include "util/logging.h"
21 const onert::ir::OperandIndex ANeuralNetworksExecution::getInputOperandIndex(int32_t index) noexcept
25 // Negative index: return invalid index
26 return onert::ir::OperandIndex{};
29 uint32_t cast_index = static_cast<uint32_t>(index);
30 if (cast_index >= _execution->primary_subgraph().getInputs().size())
32 // Return invalid index
33 return onert::ir::OperandIndex{};
36 onert::ir::IOIndex input_index{cast_index};
37 const auto operand_index = _execution->primary_subgraph().getInputs().at(input_index);
41 const onert::ir::OperandIndex
42 ANeuralNetworksExecution::getOutputOperandIndex(int32_t index) noexcept
46 // Negative index: return invalid index
47 return onert::ir::OperandIndex{};
50 uint32_t cast_index = static_cast<uint32_t>(index);
51 if (cast_index >= _execution->primary_subgraph().getOutputs().size())
53 // Return invalid index
54 return onert::ir::OperandIndex{};
57 onert::ir::IOIndex output_index{cast_index};
58 const auto operand_index = _execution->primary_subgraph().getOutputs().at(output_index);
62 bool ANeuralNetworksExecution::compareDataType(const ANeuralNetworksOperandType *type,
63 const onert::ir::OperandIndex index) noexcept
67 const auto operand_type = _execution->primary_subgraph().operands().at(index).typeInfo();
68 const auto typeInfo = NNAPIConvert::getTypeInfo(type);
70 if (operand_type != typeInfo)
76 catch (const std::exception &e)
78 VERBOSE(EXCEPTION) << e.what() << std::endl;
86 bool ANeuralNetworksExecution::compareShape(const ANeuralNetworksOperandType *type,
87 const onert::ir::OperandIndex index) noexcept
89 // Passed shape should be specified
90 if (hasUnspecifiedDims(index))
95 const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape();
96 const auto &shape_from_type = NNAPIConvert::getShape(type);
98 return operand_shape == shape_from_type;
101 bool ANeuralNetworksExecution::IsOptionalInput(const onert::ir::OperandIndex index) noexcept
103 const auto &operand_shape = _execution->primary_subgraph().operands().at(index).shape();
104 for (int32_t i = 0; i < operand_shape.rank(); ++i)
106 if (operand_shape.dim(i) != 0)
112 bool ANeuralNetworksExecution::hasUnspecifiedDims(const onert::ir::OperandIndex index) noexcept
114 const auto operand_shape = _execution->primary_subgraph().operands().at(index).shape();
116 return operand_shape.hasUnspecifiedDims();
119 size_t ANeuralNetworksExecution::getOperandSize(const onert::ir::OperandIndex index) noexcept
123 return _execution->primary_subgraph().operands().at(index).operandSize();
125 catch (const std::exception &e)
127 VERBOSE(EXCEPTION) << e.what() << std::endl;
133 bool ANeuralNetworksExecution::setInput(uint32_t index, const ANeuralNetworksOperandType *type,
134 const void *buffer, size_t length) noexcept
138 onert::ir::IOIndex input_index{index};
139 const auto operand_index = getInputOperandIndex(index);
141 const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
142 const auto shape = (type != nullptr)
143 ? NNAPIConvert::getShape(type)
144 : _execution->primary_subgraph().operands().at(operand_index).shape();
146 // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other
147 // words, we can assume that io_layout from nnapi always is the same as layout of the used
149 // TODO Set layout of model
150 _execution->setInput(input_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC);
152 catch (const std::exception &e)
154 VERBOSE(EXCEPTION) << e.what() << std::endl;
162 bool ANeuralNetworksExecution::setOptionalInput(uint32_t index,
163 const ANeuralNetworksOperandType *type,
164 const void *buffer, size_t length) noexcept
166 assert(type == nullptr);
167 assert(buffer == nullptr);
171 onert::ir::IOIndex input_index{index};
172 const auto operand_index = getInputOperandIndex(index);
174 const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
175 const auto shape = (type != nullptr)
176 ? NNAPIConvert::getShape(type)
177 : _execution->primary_subgraph().operands().at(operand_index).shape();
179 // ANeuralNetworksExecution::setInput() uses only shape information
180 ANeuralNetworksOperandType optional_input_type;
181 optional_input_type.dimensionCount = shape.rank();
182 std::vector<uint32_t> dims(optional_input_type.dimensionCount);
183 for (uint32_t i = 0; i < optional_input_type.dimensionCount; ++i)
185 dims.at(i) = shape.dim(i);
187 optional_input_type.dimensions = dims.data();
189 return setInput(index, &optional_input_type, buffer, length);
191 catch (const std::exception &e)
193 VERBOSE(EXCEPTION) << e.what() << std::endl;
201 bool ANeuralNetworksExecution::setOutput(uint32_t index, const ANeuralNetworksOperandType *type,
202 void *buffer, size_t length) noexcept
206 onert::ir::IOIndex output_index{index};
207 const auto operand_index = getOutputOperandIndex(index);
209 const auto type_info = _execution->primary_subgraph().operands().at(operand_index).typeInfo();
210 const auto shape = (type != nullptr)
211 ? NNAPIConvert::getShape(type)
212 : _execution->primary_subgraph().operands().at(operand_index).shape();
214 // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other
215 // words, we can assume that io_layout from nnapi always is the same as layout of the used
217 // TODO Set layout of model
218 _execution->setOutput(output_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC);
220 catch (const std::exception &e)
222 VERBOSE(EXCEPTION) << e.what() << std::endl;
230 bool ANeuralNetworksExecution::startExecute(void) noexcept
234 _execution->startExecute();
236 catch (const std::exception &e)
238 VERBOSE(EXCEPTION) << e.what() << std::endl;
246 bool ANeuralNetworksExecution::execute(void) noexcept
250 _execution->execute();
252 catch (const std::exception &e)
254 VERBOSE(EXCEPTION) << e.what() << std::endl;
262 const std::shared_ptr<onert::exec::Execution> ANeuralNetworksExecution::instance(void) noexcept
267 bool ANeuralNetworksExecution::getOutputOperandRank(uint32_t index, uint32_t *rank) noexcept
271 onert::ir::IOIndex output_index{index};
273 // Check execution is finished
274 if (!_execution->isFinished())
279 const auto shape = _execution->getOutputShape(output_index);
280 if (shape.hasUnspecifiedDims())
282 throw std::runtime_error{"Internal error: Output tensor has unspecified dims"};
285 *rank = shape.rank();
287 catch (const std::exception &e)
289 VERBOSE(EXCEPTION) << e.what() << std::endl;
297 bool ANeuralNetworksExecution::getOutputOperandDimensions(uint32_t index, uint32_t *dimensions)
301 onert::ir::IOIndex output_index{index};
303 // Check execution is finished
304 if (!_execution->isFinished())
309 const auto shape = _execution->getOutputShape(output_index);
310 if (shape.hasUnspecifiedDims())
312 throw std::runtime_error{"Internal error: Output tensor has unspecified dims"};
315 for (int i = 0; i < shape.rank(); i++)
317 auto dim = shape.dim(i);
321 throw std::runtime_error{"Invalid dimension value"};
324 dimensions[i] = static_cast<uint32_t>(dim);
327 catch (const std::exception &e)
329 VERBOSE(EXCEPTION) << e.what() << std::endl;