1dd3f9b4cd98fd30b84df152c0d7681ed97ffd90
[platform/core/ml/nnfw.git] / tests / nnfw_api / src / CircleGen.cc
1 /*
2  * Copyright (c) 2020 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 "CircleGen.h"
18
19 CircleGen::CircleGen() : _subgraph_contexts(1) // Create primary subgraph
20 {
21   // 0th buffer is always the empty buffer for non-const tensors
22   addBuffer(nullptr, 0);
23 }
24
25 template <typename T> uint32_t addBuffer(const std::vector<T> &buf_vec)
26 {
27   auto buf = reinterpret_cast<const uint8_t *>(buf_vec.data());
28   auto size = buf_vec.size() * sizeof(T);
29   return addBuffer(buf, size);
30 }
31
32 uint32_t CircleGen::addBuffer(const uint8_t *buf, size_t size)
33 {
34   uint32_t ind = _buffers.size();
35   _buffers.emplace_back(buildBuffer(buf, size));
36   return ind;
37 }
38
39 uint32_t CircleGen::addTensor(const TensorParams &params)
40 {
41   uint32_t ind = curSubgCtx().tensors.size();
42   curSubgCtx().tensors.emplace_back(buildTensor(params));
43   return ind;
44 }
45
46 uint32_t CircleGen::addTensor(const TensorParams &params, float scale, int64_t zero_point)
47 {
48   // TensorType_INT8: scale >= 0, zero_point: [-128, 127]
49   // TensorType_UINT8: scale >= 0, zero_point: [0, 255]
50   uint32_t ind = curSubgCtx().tensors.size();
51   curSubgCtx().tensors.emplace_back(buildTensor(params, scale, zero_point));
52   return ind;
53 }
54
55 uint32_t CircleGen::addTensor(const TensorParams &params, const SparsityParams &sp)
56 {
57   uint32_t ind = curSubgCtx().tensors.size();
58   curSubgCtx().tensors.emplace_back(buildTensor(params, sp));
59   return ind;
60 }
61
62 void CircleGen::setInputsAndOutputs(const std::vector<int> &inputs, const std::vector<int> &outputs)
63 {
64   curSubgCtx().inputs = inputs;
65   curSubgCtx().outputs = outputs;
66 }
67
68 uint32_t CircleGen::nextSubgraph()
69 {
70   uint32_t ind = _subgraph_contexts.size();
71   _subgraph_contexts.push_back({});
72   return ind;
73 }
74
75 CircleBuffer CircleGen::finish()
76 {
77   std::vector<flatbuffers::Offset<circle::SubGraph>> subgraphs;
78   for (auto &ctx : _subgraph_contexts)
79     subgraphs.push_back(buildSubGraph(ctx));
80   auto model =
81       circle::CreateModelDirect(_fbb, 3, &_opcodes, &subgraphs, "CircleGen generated", &_buffers);
82   _fbb.Finish(model);
83   return CircleBuffer{std::move(_fbb)};
84 }
85
86 // ===== Add Operator methods begin =====
87
88 uint32_t CircleGen::addOperatorAdd(const OperatorParams &params,
89                                    circle::ActivationFunctionType actfn)
90 {
91   auto options = circle::CreateAddOptions(_fbb, actfn).Union();
92   return addOperatorWithOptions(params, circle::BuiltinOperator_ADD,
93                                 circle::BuiltinOptions_AddOptions, options);
94 }
95
96 uint32_t CircleGen::addOperatorAddN(const OperatorParams &params)
97 {
98   auto options = circle::CreateAddNOptions(_fbb).Union();
99   return addOperatorWithOptions(params, circle::BuiltinOperator_ADD_N,
100                                 circle::BuiltinOptions_AddNOptions, options);
101 }
102
103 uint32_t CircleGen::addOperatorArgMax(const OperatorParams &params, circle::TensorType output_type)
104 {
105   auto options = circle::CreateArgMaxOptions(_fbb, output_type).Union();
106   return addOperatorWithOptions(params, circle::BuiltinOperator_ARG_MAX,
107                                 circle::BuiltinOptions_ArgMaxOptions, options);
108 }
109
110 uint32_t CircleGen::addOperatorAveragePool2D(const OperatorParams &params, circle::Padding padding,
111                                              int stride_w, int stride_h, int filter_w, int filter_h,
112                                              circle::ActivationFunctionType actfn)
113 {
114   auto options =
115       circle::CreatePool2DOptions(_fbb, padding, stride_w, stride_h, filter_w, filter_h, actfn)
116           .Union();
117   return addOperatorWithOptions(params, circle::BuiltinOperator_AVERAGE_POOL_2D,
118                                 circle::BuiltinOptions_Pool2DOptions, options);
119 }
120
121 uint32_t CircleGen::addOperatorCast(const OperatorParams &params, circle::TensorType input_type,
122                                     circle::TensorType output_type)
123 {
124   auto options = circle::CreateCastOptions(_fbb, input_type, output_type).Union();
125   return addOperatorWithOptions(params, circle::BuiltinOperator_CAST,
126                                 circle::BuiltinOptions_AddOptions, options);
127 }
128
129 uint32_t CircleGen::addOperatorConcatenation(const OperatorParams &params, int axis,
130                                              circle::ActivationFunctionType actfn)
131 {
132   auto options = circle::CreateConcatenationOptions(_fbb, axis, actfn).Union();
133   return addOperatorWithOptions(params, circle::BuiltinOperator_CONCATENATION,
134                                 circle::BuiltinOptions_ConcatenationOptions, options);
135 }
136
137 uint32_t CircleGen::addOperatorCos(const OperatorParams &params)
138 {
139   auto options = circle::CreateCosOptions(_fbb).Union();
140   return addOperatorWithOptions(params, circle::BuiltinOperator_COS,
141                                 circle::BuiltinOptions_CosOptions, options);
142 }
143
144 uint32_t CircleGen::addOperatorDepthwiseConv2D(const OperatorParams &params,
145                                                circle::Padding padding, int stride_w, int stride_h,
146                                                int depth_multiplier,
147                                                circle::ActivationFunctionType actfn, int dilation_w,
148                                                int dilation_h)
149 {
150   auto options =
151       circle::CreateDepthwiseConv2DOptions(_fbb, padding, stride_w, stride_h, depth_multiplier,
152                                            actfn, dilation_w, dilation_h)
153           .Union();
154   return addOperatorWithOptions(params, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
155                                 circle::BuiltinOptions_DepthwiseConv2DOptions, options);
156 }
157
158 uint32_t CircleGen::addOperatorEqual(const OperatorParams &params)
159 {
160   auto options = circle::CreateEqualOptions(_fbb).Union();
161   return addOperatorWithOptions(params, circle::BuiltinOperator_EQUAL,
162                                 circle::BuiltinOptions_EqualOptions, options);
163 }
164
165 uint32_t
166 CircleGen::addOperatorFullyConnected(const OperatorParams &params,
167                                      circle::FullyConnectedOptionsWeightsFormat weights_format)
168 {
169   auto options =
170       circle::CreateFullyConnectedOptions(_fbb, circle::ActivationFunctionType_NONE, weights_format)
171           .Union();
172   return addOperatorWithOptions(params, circle::BuiltinOperator_FULLY_CONNECTED,
173                                 circle::BuiltinOptions_FullyConnectedOptions, options);
174 }
175
176 uint32_t CircleGen::addOperatorFill(const OperatorParams &params)
177 {
178   auto options = circle::CreateFillOptions(_fbb).Union();
179   return addOperatorWithOptions(params, circle::BuiltinOperator_FILL,
180                                 circle::BuiltinOptions_FillOptions, options);
181 }
182
183 uint32_t CircleGen::addOperatorFloor(const OperatorParams &params)
184 {
185   return addOperatorWithOptions(params, circle::BuiltinOperator_FLOOR, circle::BuiltinOptions_NONE,
186                                 0);
187 }
188
189 uint32_t CircleGen::addOperatorL2Normalization(const OperatorParams &params)
190 {
191   auto options = circle::CreateL2NormOptions(_fbb).Union();
192   return addOperatorWithOptions(params, circle::BuiltinOperator_L2_NORMALIZATION,
193                                 circle::BuiltinOptions_L2NormOptions, options);
194 }
195
196 uint32_t CircleGen::addOperatorLess(const OperatorParams &params)
197 {
198   auto options = circle::CreateLessOptions(_fbb).Union();
199   return addOperatorWithOptions(params, circle::BuiltinOperator_LESS,
200                                 circle::BuiltinOptions_LessOptions, options);
201 }
202
203 uint32_t CircleGen::addOperatorLeakyRelu(const OperatorParams &params, float alpha)
204 {
205   auto options = circle::CreateLeakyReluOptions(_fbb, alpha).Union();
206   return addOperatorWithOptions(params, circle::BuiltinOperator_LEAKY_RELU,
207                                 circle::BuiltinOptions_LeakyReluOptions, options);
208 }
209
210 uint32_t CircleGen::addOperatorLogSoftmax(const OperatorParams &params)
211 {
212   auto options = circle::CreateLogSoftmaxOptions(_fbb).Union();
213   return addOperatorWithOptions(params, circle::BuiltinOperator_LOG_SOFTMAX,
214                                 circle::BuiltinOptions_LogSoftmaxOptions, options);
215 }
216
217 uint32_t CircleGen::addOperatorNeg(const OperatorParams &params)
218 {
219   auto options = circle::CreatePadOptions(_fbb).Union();
220   return addOperatorWithOptions(params, circle::BuiltinOperator_NEG,
221                                 circle::BuiltinOptions_NegOptions, options);
222 }
223
224 uint32_t CircleGen::addOperatorOneHot(const OperatorParams &params, int32_t axis)
225 {
226   auto options = circle::CreateOneHotOptions(_fbb, axis).Union();
227   return addOperatorWithOptions(params, circle::BuiltinOperator_ONE_HOT,
228                                 circle::BuiltinOptions_OneHotOptions, options);
229 }
230
231 uint32_t CircleGen::addOperatorPad(const OperatorParams &params)
232 {
233   auto options = circle::CreatePadOptions(_fbb).Union();
234   return addOperatorWithOptions(params, circle::BuiltinOperator_PAD,
235                                 circle::BuiltinOptions_PadOptions, options);
236 }
237
238 uint32_t CircleGen::addOperatorPadV2(const OperatorParams &params)
239 {
240   auto options = circle::CreatePadOptions(_fbb).Union();
241   return addOperatorWithOptions(params, circle::BuiltinOperator_PADV2,
242                                 circle::BuiltinOptions_PadV2Options, options);
243 }
244
245 uint32_t CircleGen::addOperatorRank(const OperatorParams &params)
246 {
247   auto options = circle::CreateRankOptions(_fbb).Union();
248   return addOperatorWithOptions(params, circle::BuiltinOperator_RANK,
249                                 circle::BuiltinOptions_RankOptions, options);
250 }
251
252 uint32_t CircleGen::addOperatorReduce(const OperatorParams &params,
253                                       circle::BuiltinOperator reduce_op, bool keep_dims)
254 {
255   switch (reduce_op)
256   {
257     case circle::BuiltinOperator_REDUCE_ANY:
258     case circle::BuiltinOperator_REDUCE_MIN:
259     case circle::BuiltinOperator_REDUCE_MAX:
260     case circle::BuiltinOperator_REDUCE_PROD:
261       break;
262     default:
263       throw std::runtime_error{"Wrong reduce op"};
264   }
265   auto options = circle::CreateReducerOptions(_fbb, keep_dims).Union();
266   return addOperatorWithOptions(params, reduce_op, circle::BuiltinOptions_ReducerOptions, options);
267 }
268
269 uint32_t CircleGen::addOperatorReshape(const OperatorParams &params, const Shape *new_shape)
270 {
271   auto options = circle::CreateReshapeOptionsDirect(_fbb, new_shape).Union();
272   return addOperatorWithOptions(params, circle::BuiltinOperator_RESHAPE,
273                                 circle::BuiltinOptions_ReshapeOptions, options);
274 }
275
276 uint32_t CircleGen::addOperatorResizeBilinear(const OperatorParams &params, bool align_corners,
277                                               bool half_pixel_centers)
278 {
279   auto options =
280       circle::CreateResizeBilinearOptions(_fbb, align_corners, half_pixel_centers).Union();
281   return addOperatorWithOptions(params, circle::BuiltinOperator_RESIZE_BILINEAR,
282                                 circle::BuiltinOptions_ResizeBilinearOptions, options);
283 }
284
285 uint32_t CircleGen::addOperatorResizeNearestNeighbor(const OperatorParams &params)
286 {
287   auto options = circle::CreateResizeNearestNeighborOptions(_fbb).Union();
288   return addOperatorWithOptions(params, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
289                                 circle::BuiltinOptions_ResizeNearestNeighborOptions, options);
290 }
291
292 uint32_t CircleGen::addOperatorReverseV2(const OperatorParams &params)
293 {
294   auto options = circle::CreateReverseV2Options(_fbb).Union();
295   return addOperatorWithOptions(params, circle::BuiltinOperator_REVERSE_V2,
296                                 circle::BuiltinOptions_ReverseV2Options, options);
297 }
298
299 uint32_t CircleGen::addOperatorShape(const OperatorParams &params, circle::TensorType type)
300 {
301   auto options = circle::CreateShapeOptions(_fbb, type).Union();
302   return addOperatorWithOptions(params, circle::BuiltinOperator_SHAPE,
303                                 circle::BuiltinOptions_RankOptions, options);
304 }
305
306 uint32_t CircleGen::addOperatorSelect(const OperatorParams &params)
307 {
308   auto options = circle::CreateSelectOptions(_fbb).Union();
309   return addOperatorWithOptions(params, circle::BuiltinOperator_SELECT,
310                                 circle::BuiltinOptions_SelectOptions, options);
311 }
312
313 uint32_t CircleGen::addOperatorSelectV2(const OperatorParams &params)
314 {
315   auto options = circle::CreateSelectV2Options(_fbb).Union();
316   return addOperatorWithOptions(params, circle::BuiltinOperator_SELECT_V2,
317                                 circle::BuiltinOptions_SelectV2Options, options);
318 }
319
320 uint32_t CircleGen::addOperatorSplit(const OperatorParams &params, int32_t num_split)
321 {
322   auto options = circle::CreateSplitOptions(_fbb, num_split).Union();
323   return addOperatorWithOptions(params, circle::BuiltinOperator_SPLIT,
324                                 circle::BuiltinOptions_SplitOptions, options);
325 }
326 uint32_t CircleGen::addOperatorStridedSlice(const OperatorParams &params, int32_t begin_mask,
327                                             int32_t end_mask, int32_t ellipsis_mask,
328                                             int32_t new_axis_mask, int32_t shrink_axis_mask)
329 {
330   auto options = circle::CreateStridedSliceOptions(_fbb, begin_mask, end_mask, ellipsis_mask,
331                                                    new_axis_mask, shrink_axis_mask)
332                      .Union();
333   return addOperatorWithOptions(params, circle::BuiltinOperator_STRIDED_SLICE,
334                                 circle::BuiltinOptions_StridedSliceOptions, options);
335 }
336 uint32_t CircleGen::addOperatorTile(const OperatorParams &params)
337 {
338   auto options = circle::CreateTileOptions(_fbb).Union();
339   return addOperatorWithOptions(params, circle::BuiltinOperator_TILE,
340                                 circle::BuiltinOptions_TileOptions, options);
341 }
342
343 uint32_t CircleGen::addOperatorWhile(const OperatorParams &params, uint32_t cond_subg,
344                                      uint32_t body_subg)
345 {
346   auto options = circle::CreateWhileOptions(_fbb, cond_subg, body_subg).Union();
347   return addOperatorWithOptions(params, circle::BuiltinOperator_WHILE,
348                                 circle::BuiltinOptions_WhileOptions, options);
349 }
350
351 uint32_t CircleGen::addOperatorIf(const OperatorParams &params, uint32_t then_subg,
352                                   uint32_t else_subg)
353 {
354   auto options = circle::CreateIfOptions(_fbb, then_subg, else_subg).Union();
355   return addOperatorWithOptions(params, circle::BuiltinOperator_IF,
356                                 circle::BuiltinOptions_IfOptions, options);
357 }
358
359 uint32_t CircleGen::addOperatorInstanceNorm(const OperatorParams &params, float epsilon,
360                                             circle::ActivationFunctionType actfn)
361 {
362   auto options = circle::CreateInstanceNormOptions(_fbb, epsilon, actfn).Union();
363   return addOperatorWithOptions(params, circle::BuiltinOperator_INSTANCE_NORM,
364                                 circle::BuiltinOptions_InstanceNormOptions, options);
365 }
366
367 uint32_t CircleGen::addOperatorTranspose(const OperatorParams &params)
368 {
369   auto options = circle::CreateTransposeOptions(_fbb).Union();
370   return addOperatorWithOptions(params, circle::BuiltinOperator_TRANSPOSE,
371                                 circle::BuiltinOptions_TransposeOptions, options);
372 }
373
374 // NOTE Please add addOperator functions ABOVE this lie
375 //
376 // %  How to add a new addOperatorXXX fuction
377 // 0. Copy code from one of the existing addOperatorXXX function
378 // 1. Change the function signature (need BuiltinOperator params)
379 // 2. Change enum BuiltinOperator
380 // 3. Change enum BuiltinOptions
381 // 4. Change CreateXXXOptions accordingly
382
383 // ===== Add Operator methods end =====
384
385 uint32_t CircleGen::addOperatorWithOptions(const OperatorParams &params,
386                                            circle::BuiltinOperator opcode,
387                                            circle::BuiltinOptions options_type,
388                                            flatbuffers::Offset<void> options)
389 {
390   uint32_t opcode_ind = addOperatorCode(opcode);
391   auto op = circle::CreateOperatorDirect(_fbb, opcode_ind, &params.inputs, &params.outputs,
392                                          options_type, options);
393
394   uint32_t ind = curSubgCtx().operators.size();
395   curSubgCtx().operators.emplace_back(op);
396   return ind;
397 }
398
399 uint32_t CircleGen::addOperatorCode(circle::BuiltinOperator opcode)
400 {
401   // TODO If the same OperatorCode is registered already, just return it
402   uint32_t ind = _opcodes.size();
403   _opcodes.emplace_back(circle::CreateOperatorCode(_fbb, opcode));
404   return ind;
405 }
406
407 flatbuffers::Offset<circle::Buffer> CircleGen::buildBuffer(const uint8_t *buf, size_t size)
408 {
409   if (buf == nullptr && size == 0)
410     return circle::CreateBuffer(_fbb);
411   auto buffer = _fbb.CreateVector(buf, size);
412   return circle::CreateBuffer(_fbb, buffer);
413 }
414
415 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams &params)
416 {
417   auto shape = _fbb.CreateVector(params.shape);
418   auto name = _fbb.CreateString(params.name);
419   return circle::CreateTensor(_fbb, shape, params.tensor_type, params.buffer, name,
420                               0 /* QuantParam */, false /* is_variable */, 0 /* sparsity */,
421                               0 /* shape_signature */);
422 }
423
424 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams &params, float scale,
425                                                            int64_t zero_point)
426 {
427   auto shape = _fbb.CreateVector(params.shape);
428   auto name = _fbb.CreateString(params.name);
429   std::vector<float> scale_vector = {scale};
430   std::vector<int64_t> zero_point_vector = {zero_point};
431   auto quantization = circle::CreateQuantizationParametersDirect(_fbb, nullptr, nullptr,
432                                                                  &scale_vector, &zero_point_vector);
433   return circle::CreateTensor(_fbb, shape, params.tensor_type, params.buffer, name, quantization,
434                               false /* is_variable */, 0 /* sparsity */, 0 /* shape_signature */);
435 }
436
437 flatbuffers::Offset<circle::SparsityParameters>
438 CircleGen::buildSparsityParameters(const SparsityParams &sp)
439 {
440   flatbuffers::Offset<flatbuffers::Vector<int32_t>> traversal_order;
441   flatbuffers::Offset<flatbuffers::Vector<int32_t>> block_map;
442   flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<circle::DimensionMetadata>>>
443       dim_metadata;
444
445   traversal_order = _fbb.CreateVector(sp.traversal_order);
446   block_map = _fbb.CreateVector(sp.block_map);
447
448   std::vector<flatbuffers::Offset<circle::DimensionMetadata>> dim_metadata_vec;
449   for (auto &it : sp.dim_metadata)
450   {
451     auto fb_array_segments = circle::CreateUint16VectorDirect(_fbb, &it._array_segments.u16);
452     auto fb_array_indices = circle::CreateUint16VectorDirect(_fbb, &it._array_indices.u16);
453     auto dim_metadata = circle::CreateDimensionMetadata(
454         _fbb, it._format, it._dense_size, it._array_segments_type, fb_array_segments.Union(),
455         it._array_indices_type, fb_array_indices.Union());
456     dim_metadata_vec.emplace_back(dim_metadata);
457   }
458   dim_metadata = _fbb.CreateVector(dim_metadata_vec);
459
460   return circle::CreateSparsityParameters(_fbb, traversal_order, block_map, dim_metadata);
461 }
462
463 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams &params,
464                                                            const SparsityParams &sp)
465 {
466   auto shape = _fbb.CreateVector(params.shape);
467   auto name = _fbb.CreateString(params.name);
468   auto sparsity = buildSparsityParameters(sp);
469   return circle::CreateTensor(_fbb, shape, params.tensor_type, params.buffer, name,
470                               0 /* QuantParam */, false /* is_variable */, sparsity,
471                               0 /* shape_signature */);
472 }
473
474 flatbuffers::Offset<circle::SubGraph> CircleGen::buildSubGraph(const SubgraphContext &ctx)
475 {
476   return circle::CreateSubGraphDirect(_fbb, &ctx.tensors, &ctx.inputs, &ctx.outputs, &ctx.operators,
477                                       nullptr);
478 }