Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / runtime / onert / frontend / nnapi / model.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 <NeuralNetworks.h>
18 #include <NeuralNetworksEx.h>
19
20 #include <new>
21
22 #include "wrapper/ANeuralNetworksModel.h"
23 #include "wrapper/ANeuralNetworksMemory.h"
24 #include "util/logging.h"
25
26 int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
27 {
28   if (model == nullptr)
29   {
30     VERBOSE(NNAPI::Model) << "create: Incorrect null pointer parameter" << std::endl;
31     return ANEURALNETWORKS_UNEXPECTED_NULL;
32   }
33
34   *model = new (std::nothrow) ANeuralNetworksModel{};
35   if (*model == nullptr)
36   {
37     VERBOSE(NNAPI::Model) << "create: Fail to create model object" << std::endl;
38     return ANEURALNETWORKS_OUT_OF_MEMORY;
39   }
40
41   return ANEURALNETWORKS_NO_ERROR;
42 }
43
44 void ANeuralNetworksModel_free(ANeuralNetworksModel *model) { delete model; }
45
46 int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
47                                     const ANeuralNetworksOperandType *type)
48 {
49   if ((model == nullptr) || (type == nullptr))
50   {
51     VERBOSE(NNAPI::Model) << "addOperand: Incorrect null pointer parameter(s)" << std::endl;
52     return ANEURALNETWORKS_UNEXPECTED_NULL;
53   }
54
55   if (model->isFinished())
56   {
57     VERBOSE(NNAPI::Model) << "addOperand: Already finished" << std::endl;
58     return ANEURALNETWORKS_BAD_STATE;
59   }
60
61   // scale and zeroPoint should be zero for scalars and non-fixed point tensors
62   // Quantized:
63   //  scale: a 32 bit floating point value greater than zero
64   //  zeroPoint: a 32 bit integer, in range [0, 255]
65   if (type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM)
66   {
67     if (!(type->scale > 0.0f))
68     {
69       VERBOSE(NNAPI::Model) << "addOperand: Incorrect scale value for quantization" << std::endl;
70       return ANEURALNETWORKS_BAD_DATA;
71     }
72
73     if ((type->zeroPoint < 0) || (type->zeroPoint > 255))
74     {
75       VERBOSE(NNAPI::Model) << "addOperand: Incorrect zeroPoint value for quantization"
76                             << std::endl;
77       return ANEURALNETWORKS_BAD_DATA;
78     }
79   }
80   // NOTE Validation of scale and zeroPoint would be skipped for a while.
81   //      We do not know whether scalar type can have scale and zeroPoint.
82   //      To pass ValidationTest and GeneratedTest, this validation code
83   //      would not be implemented until we can define this issue clearly.
84   //
85   // scale and zeroPoint should be zero for scalars and non-fixed point tensors
86   // else if ((type->scale != 0.0f) || (type->zeroPoint != 0))
87   // {
88   //   return ANEURALNETWORKS_BAD_DATA;
89   // }
90
91   // dimensionCount should be zero for scalars
92   if ((type->dimensionCount != 0) &&
93       ((type->type == ANEURALNETWORKS_FLOAT32) || (type->type == ANEURALNETWORKS_INT32) ||
94        (type->type == ANEURALNETWORKS_UINT32)))
95   {
96     VERBOSE(NNAPI::Model) << "addOperand: Incorrect data type" << std::endl;
97     return ANEURALNETWORKS_BAD_DATA;
98   }
99
100   if (!model->addOperand(type))
101   {
102     VERBOSE(NNAPI::Model) << "addOperand: Fail to add operand" << std::endl;
103     return ANEURALNETWORKS_BAD_DATA;
104   }
105
106   return ANEURALNETWORKS_NO_ERROR;
107 }
108
109 int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
110                                          const void *buffer, size_t length)
111 {
112   const bool optional_operand = ((buffer == nullptr) && (length == 0));
113
114   if ((model == nullptr) || ((buffer == nullptr) && (length != 0)))
115   {
116     VERBOSE(NNAPI::Model) << "setOperandValue: Incorrect null pointer parameter(s)" << std::endl;
117     return ANEURALNETWORKS_UNEXPECTED_NULL;
118   }
119
120   if (model->isFinished())
121   {
122     VERBOSE(NNAPI::Model) << "setOperandValue: Already finished" << std::endl;
123     return ANEURALNETWORKS_BAD_STATE;
124   }
125
126   // Negative index value is not allowed
127   if (index < 0)
128   {
129     VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (negative)" << std::endl;
130     return ANEURALNETWORKS_BAD_DATA;
131   }
132   // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI
133   //      functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand
134   //      index
135   //      ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index.
136   //
137   //      Below, static_cast<uint32_t>(...) is introduced to eliminate compiler warning.
138   uint32_t ind = static_cast<uint32_t>(index);
139
140   if (!model->isExistOperand(ind))
141   {
142     VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (not exist)" << std::endl;
143     return ANEURALNETWORKS_BAD_DATA;
144   }
145
146   if (!optional_operand && (model->operandSize(ind) != length))
147   {
148     VERBOSE(NNAPI::Model) << "setOperandValue: Invalid data length" << std::endl;
149     return ANEURALNETWORKS_BAD_DATA;
150   }
151
152   if (model->isUsageSet(ind))
153   {
154     VERBOSE(NNAPI::Model) << "setOperandValue: Already set operand" << std::endl;
155     return ANEURALNETWORKS_BAD_DATA;
156   }
157
158   // NNAPI spec in NeuralNetworks.h
159   // For values of length greater than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES,
160   // the application is responsible for not changing the content of this region
161   // until all executions using this model have completed
162   bool copy_value = false;
163   if (length <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES)
164   {
165     copy_value = true;
166   }
167
168   if (!model->setOperandValue(ind, buffer, length, optional_operand, copy_value))
169   {
170     VERBOSE(NNAPI::Model) << "setOperandValue: Fail to set operand value" << std::endl;
171     return ANEURALNETWORKS_BAD_DATA;
172   }
173
174   return ANEURALNETWORKS_NO_ERROR;
175 }
176
177 int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
178                                                    const ANeuralNetworksMemory *memory,
179                                                    size_t offset, size_t length)
180 {
181   if ((model == nullptr) || (memory == nullptr))
182   {
183     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Incorrect null pointer parameter(s)"
184                           << std::endl;
185     return ANEURALNETWORKS_UNEXPECTED_NULL;
186   }
187
188   if (model->isFinished())
189   {
190     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already finished" << std::endl;
191     return ANEURALNETWORKS_BAD_STATE;
192   }
193
194   // Negative index value is not allowed
195   if (index < 0)
196   {
197     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (negative)"
198                           << std::endl;
199     return ANEURALNETWORKS_BAD_DATA;
200   }
201   // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI
202   //      functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand
203   //      index
204   //      ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index.
205   //
206   //      Below, static_cast<uint32_t>(...) is introduced to eliminate compiler warning.
207   uint32_t ind = static_cast<uint32_t>(index);
208
209   if (!model->isExistOperand(ind))
210   {
211     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (not exist)"
212                           << std::endl;
213     return ANEURALNETWORKS_BAD_DATA;
214   }
215
216   if ((model->operandSize(ind) != length) || (memory->size() < (offset + length)))
217   {
218     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid data length" << std::endl;
219     return ANEURALNETWORKS_BAD_DATA;
220   }
221
222   if (model->isUsageSet(ind))
223   {
224     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already set operand" << std::endl;
225     return ANEURALNETWORKS_BAD_DATA;
226   }
227
228   if (!model->setOperandValue(ind, memory->base() + offset, length))
229   {
230     VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Fail to set operand value" << std::endl;
231     return ANEURALNETWORKS_BAD_DATA;
232   }
233
234   return ANEURALNETWORKS_NO_ERROR;
235 }
236
237 int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
238                                       ANeuralNetworksOperationType type, uint32_t inputCount,
239                                       const uint32_t *inputs, uint32_t outputCount,
240                                       const uint32_t *outputs)
241 {
242   if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
243   {
244     VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl;
245     return ANEURALNETWORKS_UNEXPECTED_NULL;
246   }
247
248   if (model->isFinished())
249   {
250     VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl;
251     return ANEURALNETWORKS_BAD_STATE;
252   }
253
254   const ANeuralNetworksOperationType FIRST_OPERATION = ANEURALNETWORKS_ADD;
255   const ANeuralNetworksOperationType LAST_OPERATION = ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR;
256   if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
257   {
258     return ANEURALNETWORKS_BAD_DATA;
259   }
260
261   for (uint32_t i = 0; i < outputCount; i++)
262   {
263     if (model->isUsageSet(outputs[i]))
264     {
265       VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl;
266       return ANEURALNETWORKS_BAD_DATA;
267     }
268   }
269
270   if (!model->addOperation(type, inputCount, inputs, outputCount, outputs))
271   {
272     VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl;
273     return ANEURALNETWORKS_BAD_DATA;
274   }
275
276   return ANEURALNETWORKS_NO_ERROR;
277 }
278
279 int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
280                                         ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
281                                         const uint32_t *inputs, uint32_t outputCount,
282                                         const uint32_t *outputs)
283 {
284   if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
285   {
286     VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl;
287     return ANEURALNETWORKS_UNEXPECTED_NULL;
288   }
289
290   if (model->isFinished())
291   {
292     VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl;
293     return ANEURALNETWORKS_BAD_STATE;
294   }
295
296   const ANeuralNetworksOperationTypeEx FIRST_OPERATION = ANEURALNETWORKS_CAST_EX;
297   const ANeuralNetworksOperationTypeEx LAST_OPERATION = ANEURALNETWORKS_ADDV2_EX;
298   if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
299   {
300     VERBOSE(NNAPI::Model) << "addOperation: Invalid operation type" << std::endl;
301     return ANEURALNETWORKS_BAD_DATA;
302   }
303
304   for (uint32_t i = 0; i < outputCount; i++)
305   {
306     if (model->isUsageSet(outputs[i]))
307     {
308       VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl;
309       return ANEURALNETWORKS_BAD_DATA;
310     }
311   }
312
313   if (!model->addOperationEx(type, inputCount, inputs, outputCount, outputs))
314   {
315     VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl;
316     return ANEURALNETWORKS_BAD_DATA;
317   }
318
319   return ANEURALNETWORKS_NO_ERROR;
320 }
321
322 int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
323                                                   const uint32_t *inputs, uint32_t outputCount,
324                                                   const uint32_t *outputs)
325 {
326   if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
327   {
328     VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Incorrect null pointer parameter(s)"
329                           << std::endl;
330     return ANEURALNETWORKS_UNEXPECTED_NULL;
331   }
332
333   if (model->isFinished())
334   {
335     VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already finished" << std::endl;
336     return ANEURALNETWORKS_BAD_STATE;
337   }
338
339   for (uint32_t n = 0; n < inputCount; ++n)
340   {
341     uint32_t ind = inputs[n];
342     if (model->isUsageSet(ind))
343     {
344       VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already set input operand" << std::endl;
345       return ANEURALNETWORKS_BAD_DATA;
346     }
347
348     if (!model->addModelInput(ind))
349     {
350       VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add input" << std::endl;
351       return ANEURALNETWORKS_BAD_DATA;
352     }
353   }
354
355   for (uint32_t n = 0; n < outputCount; ++n)
356   {
357     uint32_t ind = outputs[n];
358
359     if (!model->isOperationOutput(ind))
360     {
361       VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Need to set output operand" << std::endl;
362       return ANEURALNETWORKS_BAD_DATA;
363     }
364
365     if (!model->addModelOutput(ind))
366     {
367       VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add output" << std::endl;
368       return ANEURALNETWORKS_BAD_DATA;
369     }
370   }
371
372   return ANEURALNETWORKS_NO_ERROR;
373 }
374
375 int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
376 {
377   if (model == nullptr)
378   {
379     VERBOSE(NNAPI::Model) << "finish: Incorrect null pointer parameter" << std::endl;
380     return ANEURALNETWORKS_UNEXPECTED_NULL;
381   }
382
383   if (model->isFinished())
384   {
385     VERBOSE(NNAPI::Model) << "finish: Already finished" << std::endl;
386     return ANEURALNETWORKS_BAD_STATE;
387   }
388
389   if (!model->finish())
390   {
391     VERBOSE(NNAPI::Model) << "finish: Fail to generate internal graph" << std::endl;
392     return ANEURALNETWORKS_BAD_STATE;
393   }
394
395   return ANEURALNETWORKS_NO_ERROR;
396 }
397
398 int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel *model, bool allow)
399 {
400   if (model == nullptr)
401   {
402     VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Incorrect null pointer parameter"
403                           << std::endl;
404     return ANEURALNETWORKS_UNEXPECTED_NULL;
405   }
406
407   if (model->isFinished())
408   {
409     VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Already finished" << std::endl;
410     return ANEURALNETWORKS_BAD_STATE;
411   }
412
413   model->allowFloat32toFloat16(allow);
414
415   return ANEURALNETWORKS_NO_ERROR;
416 }