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