Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / runtime / onert / frontend / nnapi / wrapper / ANeuralNetworksModel.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "ANeuralNetworksModel.h"
18 #include "OperationFactory.h"
19 #include "NNAPIConvert.h"
20
21 #include "ir/Operations.Include.h"
22 #include "util/logging.h"
23
24 #include <memory>
25
26 //
27 // ANeuralNetworksModel
28 //
29 ANeuralNetworksModel::ANeuralNetworksModel() noexcept
30   : _optional_operands{}, _operand_usages{}, _allowFloat32toFloat16{false}
31 {
32   _graph = std::make_shared<onert::ir::Graph>();
33 }
34
35 bool ANeuralNetworksModel::addOperand(const ANeuralNetworksOperandType *type) noexcept
36 {
37   try
38   {
39     const auto shape = NNAPIConvert::getShape(type);
40     const auto typeInfo = NNAPIConvert::getTypeInfo(type);
41     _graph->addOperand(shape, typeInfo);
42     _operand_usages.emplace_back(OperandUsage::NOT_DEFINED);
43   }
44   catch (const std::exception &e)
45   {
46     VERBOSE(EXCEPTION) << e.what() << std::endl;
47
48     return false;
49   }
50
51   return true;
52 }
53
54 bool ANeuralNetworksModel::setOperandValue(uint32_t index, const void *buffer, size_t length,
55                                            bool optional, bool copy) noexcept
56 {
57   const onert::ir::OperandIndex ind{index};
58
59   try
60   {
61     _operand_usages[index] = OperandUsage::CONSTANT;
62
63     // Remain operands.at(ind).data()->base() as nullptr for optional operand
64     // This will be filled when model finished
65     if (optional)
66     {
67       setOptionalOperand(ind);
68     }
69
70     using onert::ir::CachedData;
71     using onert::ir::ExternalData;
72     if (copy)
73     {
74       _graph->operands().at(ind).data(
75         std::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length));
76     }
77     else
78     {
79       _graph->operands().at(ind).data(
80         std::make_unique<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length));
81     }
82   }
83   catch (const std::exception &e)
84   {
85     VERBOSE(EXCEPTION) << e.what() << std::endl;
86
87     return false;
88   }
89
90   return true;
91 }
92
93 bool ANeuralNetworksModel::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount,
94                                         const uint32_t *inputs, uint32_t outputCount,
95                                         const uint32_t *outputs) noexcept
96 {
97   try
98   {
99     for (uint32_t i = 0; i < outputCount; i++)
100     {
101       _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT;
102     }
103
104     auto &factory = OperationFactory::get();
105     OperationFactory::Param param{inputCount, inputs, outputCount, outputs};
106
107     auto node = factory.create(type, param, _graph->operands());
108     _graph->addOperation(std::unique_ptr<onert::ir::Operation>{node});
109
110     // TODO Move these codes to delegate.cpp
111     if (type == ANEURALNETWORKS_FULLY_CONNECTED)
112     {
113       const auto &input_operand =
114         _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::INPUT));
115       auto &weights_operand =
116         _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::WEIGHT));
117       if (input_operand.typeInfo().type() == onert::ir::DataType::FLOAT32 &&
118           weights_operand.typeInfo().type() == onert::ir::DataType::QUANT_UINT8_ASYMM)
119       {
120         weights_operand.type(onert::ir::DataType::QUANT_INT8_SYMM);
121       }
122     }
123   }
124   catch (const std::exception &e)
125   {
126     VERBOSE(EXCEPTION) << e.what() << std::endl;
127
128     return false;
129   }
130
131   return true;
132 }
133
134 bool ANeuralNetworksModel::addOperationEx(ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
135                                           const uint32_t *inputs, uint32_t outputCount,
136                                           const uint32_t *outputs) noexcept
137 {
138   try
139   {
140     for (uint32_t i = 0; i < outputCount; i++)
141     {
142       _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT;
143     }
144
145     auto &factory = OperationFactory::get();
146     OperationFactory::Param param{inputCount, inputs, outputCount, outputs};
147
148     auto node = factory.create(type, param, _graph->operands());
149     _graph->addOperation(std::unique_ptr<onert::ir::Operation>{node});
150   }
151   catch (const std::exception &e)
152   {
153     return false;
154   }
155   return true;
156 }
157
158 bool ANeuralNetworksModel::addModelInput(uint32_t index) noexcept
159 {
160   try
161   {
162     _operand_usages[index] = OperandUsage::MODEL_INPUT;
163
164     const onert::ir::OperandIndex ind{index};
165     _graph->addInput(ind);
166   }
167   catch (const std::exception &e)
168   {
169     VERBOSE(EXCEPTION) << e.what() << std::endl;
170
171     return false;
172   }
173
174   return true;
175 }
176 bool ANeuralNetworksModel::addModelOutput(uint32_t index) noexcept
177 {
178   try
179   {
180     const onert::ir::OperandIndex ind{index};
181
182     // Duplicated output is not allowed
183     if (_graph->getOutputs().contains(ind))
184     {
185       return false;
186     }
187
188     _graph->addOutput(ind);
189   }
190   catch (const std::exception &e)
191   {
192     VERBOSE(EXCEPTION) << e.what() << std::endl;
193
194     return false;
195   }
196
197   return true;
198 }
199
200 void ANeuralNetworksModel::allowFloat32toFloat16(bool allow) noexcept
201 {
202   _allowFloat32toFloat16 = allow;
203 }
204
205 bool ANeuralNetworksModel::finish() noexcept
206 {
207   try
208   {
209     fillOptionalOperand();
210
211     _graph->finishBuilding();
212
213     _operand_usages.clear();
214   }
215   catch (const std::exception &e)
216   {
217     VERBOSE(EXCEPTION) << e.what() << '\n';
218
219     return false;
220   }
221
222   return true;
223 }
224
225 bool ANeuralNetworksModel::isFinished() noexcept { return !_graph->isBuildingPhase(); }
226
227 bool ANeuralNetworksModel::isExistOperand(uint32_t index) noexcept
228 {
229   return _graph->operands().exist(onert::ir::OperandIndex{index});
230 }
231
232 size_t ANeuralNetworksModel::operandSize(uint32_t index) noexcept
233 {
234   try
235   {
236     return _graph->operands().at(onert::ir::OperandIndex{index}).operandSize();
237   }
238   catch (const std::exception &e)
239   {
240     VERBOSE(EXCEPTION) << e.what() << '\n';
241
242     return 0;
243   }
244 }
245
246 bool ANeuralNetworksModel::isUsageSet(uint32_t index) noexcept
247 {
248   return (_operand_usages[index] != OperandUsage::NOT_DEFINED);
249 }
250
251 bool ANeuralNetworksModel::isOperationOutput(uint32_t index) noexcept
252 {
253   return (_operand_usages[index] == OperandUsage::OPERATION_OUTPUT);
254 }
255
256 void ANeuralNetworksModel::setOptionalOperand(const onert::ir::OperandIndex idx)
257 {
258   _optional_operands.insert(idx);
259 }
260
261 void ANeuralNetworksModel::fillOptionalOperand(void)
262 {
263   _graph->operations().iterate([&](const onert::ir::OperationIndex &, onert::ir::Operation &node) {
264     for (auto input : node.getInputs())
265     {
266       // TODO fill default value for optional operands
267       if (_optional_operands.find(input) != _optional_operands.end())
268       {
269         throw std::runtime_error{"Optional operand is not supported yet"};
270       }
271     }
272   });
273 }
274
275 std::shared_ptr<onert::ir::Subgraphs> ANeuralNetworksModel::getSubGraphs() const
276 {
277   auto all_subgs = std::make_shared<onert::ir::Subgraphs>();
278
279   all_subgs->push(onert::ir::SubgraphIndex{0}, _graph);
280   // TODO Find all child subgraphs and copy them to all_subgs
281   // Must find the same subgraph by using to compare pointer of subgraphs and set subgraph's index
282   // to operands of control flow operations
283   // Must clean all child subgraphs's pointer to prevent memory leak in case of that graph has
284   // subgraph itself recursively
285
286   return all_subgs;
287 }