2 * Copyright (c) 2020 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 "CircleGen.h"
19 CircleGen::CircleGen() : _subgraph_contexts(1) // Create primary subgraph
21 // 0th buffer is always the empty buffer for non-const tensors
22 addBuffer(nullptr, 0);
25 template <typename T> uint32_t addBuffer(const std::vector<T> &buf_vec)
27 auto buf = reinterpret_cast<const uint8_t *>(buf_vec.data());
28 auto size = buf_vec.size() * sizeof(T);
29 return addBuffer(buf, size);
32 uint32_t CircleGen::addBuffer(const uint8_t *buf, size_t size)
34 uint32_t ind = _buffers.size();
35 _buffers.emplace_back(buildBuffer(buf, size));
39 uint32_t CircleGen::addTensor(const TensorParams ¶ms)
41 uint32_t ind = curSubgCtx().tensors.size();
42 curSubgCtx().tensors.emplace_back(buildTensor(params));
46 uint32_t CircleGen::addTensor(const TensorParams ¶ms, float scale, int64_t zero_point)
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));
55 uint32_t CircleGen::addTensor(const TensorParams ¶ms, const SparsityParams &sp)
57 uint32_t ind = curSubgCtx().tensors.size();
58 curSubgCtx().tensors.emplace_back(buildTensor(params, sp));
62 void CircleGen::setInputsAndOutputs(const std::vector<int> &inputs, const std::vector<int> &outputs)
64 curSubgCtx().inputs = inputs;
65 curSubgCtx().outputs = outputs;
68 uint32_t CircleGen::nextSubgraph()
70 uint32_t ind = _subgraph_contexts.size();
71 _subgraph_contexts.push_back({});
75 CircleBuffer CircleGen::finish()
77 std::vector<flatbuffers::Offset<circle::SubGraph>> subgraphs;
78 for (auto &ctx : _subgraph_contexts)
79 subgraphs.push_back(buildSubGraph(ctx));
81 circle::CreateModelDirect(_fbb, 3, &_opcodes, &subgraphs, "CircleGen generated", &_buffers);
83 return CircleBuffer{std::move(_fbb)};
86 // ===== Add Operator methods begin =====
88 uint32_t CircleGen::addOperatorAdd(const OperatorParams ¶ms,
89 circle::ActivationFunctionType actfn)
91 auto options = circle::CreateAddOptions(_fbb, actfn).Union();
92 return addOperatorWithOptions(params, circle::BuiltinOperator_ADD,
93 circle::BuiltinOptions_AddOptions, options);
96 uint32_t CircleGen::addOperatorAddN(const OperatorParams ¶ms)
98 auto options = circle::CreateAddNOptions(_fbb).Union();
99 return addOperatorWithOptions(params, circle::BuiltinOperator_ADD_N,
100 circle::BuiltinOptions_AddNOptions, options);
103 uint32_t CircleGen::addOperatorArgMax(const OperatorParams ¶ms, circle::TensorType output_type)
105 auto options = circle::CreateArgMaxOptions(_fbb, output_type).Union();
106 return addOperatorWithOptions(params, circle::BuiltinOperator_ARG_MAX,
107 circle::BuiltinOptions_ArgMaxOptions, options);
110 uint32_t CircleGen::addOperatorAveragePool2D(const OperatorParams ¶ms, circle::Padding padding,
111 int stride_w, int stride_h, int filter_w, int filter_h,
112 circle::ActivationFunctionType actfn)
115 circle::CreatePool2DOptions(_fbb, padding, stride_w, stride_h, filter_w, filter_h, actfn)
117 return addOperatorWithOptions(params, circle::BuiltinOperator_AVERAGE_POOL_2D,
118 circle::BuiltinOptions_Pool2DOptions, options);
121 uint32_t CircleGen::addOperatorCast(const OperatorParams ¶ms, circle::TensorType input_type,
122 circle::TensorType output_type)
124 auto options = circle::CreateCastOptions(_fbb, input_type, output_type).Union();
125 return addOperatorWithOptions(params, circle::BuiltinOperator_CAST,
126 circle::BuiltinOptions_AddOptions, options);
129 uint32_t CircleGen::addOperatorConcatenation(const OperatorParams ¶ms, int axis,
130 circle::ActivationFunctionType actfn)
132 auto options = circle::CreateConcatenationOptions(_fbb, axis, actfn).Union();
133 return addOperatorWithOptions(params, circle::BuiltinOperator_CONCATENATION,
134 circle::BuiltinOptions_ConcatenationOptions, options);
137 uint32_t CircleGen::addOperatorCos(const OperatorParams ¶ms)
139 auto options = circle::CreateCosOptions(_fbb).Union();
140 return addOperatorWithOptions(params, circle::BuiltinOperator_COS,
141 circle::BuiltinOptions_CosOptions, options);
144 uint32_t CircleGen::addOperatorDepthwiseConv2D(const OperatorParams ¶ms,
145 circle::Padding padding, int stride_w, int stride_h,
146 int depth_multiplier,
147 circle::ActivationFunctionType actfn, int dilation_w,
151 circle::CreateDepthwiseConv2DOptions(_fbb, padding, stride_w, stride_h, depth_multiplier,
152 actfn, dilation_w, dilation_h)
154 return addOperatorWithOptions(params, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
155 circle::BuiltinOptions_DepthwiseConv2DOptions, options);
158 uint32_t CircleGen::addOperatorEqual(const OperatorParams ¶ms)
160 auto options = circle::CreateEqualOptions(_fbb).Union();
161 return addOperatorWithOptions(params, circle::BuiltinOperator_EQUAL,
162 circle::BuiltinOptions_EqualOptions, options);
166 CircleGen::addOperatorFullyConnected(const OperatorParams ¶ms,
167 circle::FullyConnectedOptionsWeightsFormat weights_format)
170 circle::CreateFullyConnectedOptions(_fbb, circle::ActivationFunctionType_NONE, weights_format)
172 return addOperatorWithOptions(params, circle::BuiltinOperator_FULLY_CONNECTED,
173 circle::BuiltinOptions_FullyConnectedOptions, options);
176 uint32_t CircleGen::addOperatorFill(const OperatorParams ¶ms)
178 auto options = circle::CreateFillOptions(_fbb).Union();
179 return addOperatorWithOptions(params, circle::BuiltinOperator_FILL,
180 circle::BuiltinOptions_FillOptions, options);
183 uint32_t CircleGen::addOperatorFloor(const OperatorParams ¶ms)
185 return addOperatorWithOptions(params, circle::BuiltinOperator_FLOOR, circle::BuiltinOptions_NONE,
189 uint32_t CircleGen::addOperatorL2Normalization(const OperatorParams ¶ms)
191 auto options = circle::CreateL2NormOptions(_fbb).Union();
192 return addOperatorWithOptions(params, circle::BuiltinOperator_L2_NORMALIZATION,
193 circle::BuiltinOptions_L2NormOptions, options);
196 uint32_t CircleGen::addOperatorLess(const OperatorParams ¶ms)
198 auto options = circle::CreateLessOptions(_fbb).Union();
199 return addOperatorWithOptions(params, circle::BuiltinOperator_LESS,
200 circle::BuiltinOptions_LessOptions, options);
203 uint32_t CircleGen::addOperatorLeakyRelu(const OperatorParams ¶ms, float alpha)
205 auto options = circle::CreateLeakyReluOptions(_fbb, alpha).Union();
206 return addOperatorWithOptions(params, circle::BuiltinOperator_LEAKY_RELU,
207 circle::BuiltinOptions_LeakyReluOptions, options);
210 uint32_t CircleGen::addOperatorLogSoftmax(const OperatorParams ¶ms)
212 auto options = circle::CreateLogSoftmaxOptions(_fbb).Union();
213 return addOperatorWithOptions(params, circle::BuiltinOperator_LOG_SOFTMAX,
214 circle::BuiltinOptions_LogSoftmaxOptions, options);
217 uint32_t CircleGen::addOperatorNeg(const OperatorParams ¶ms)
219 auto options = circle::CreatePadOptions(_fbb).Union();
220 return addOperatorWithOptions(params, circle::BuiltinOperator_NEG,
221 circle::BuiltinOptions_NegOptions, options);
224 uint32_t CircleGen::addOperatorOneHot(const OperatorParams ¶ms, int32_t axis)
226 auto options = circle::CreateOneHotOptions(_fbb, axis).Union();
227 return addOperatorWithOptions(params, circle::BuiltinOperator_ONE_HOT,
228 circle::BuiltinOptions_OneHotOptions, options);
231 uint32_t CircleGen::addOperatorPad(const OperatorParams ¶ms)
233 auto options = circle::CreatePadOptions(_fbb).Union();
234 return addOperatorWithOptions(params, circle::BuiltinOperator_PAD,
235 circle::BuiltinOptions_PadOptions, options);
238 uint32_t CircleGen::addOperatorPadV2(const OperatorParams ¶ms)
240 auto options = circle::CreatePadOptions(_fbb).Union();
241 return addOperatorWithOptions(params, circle::BuiltinOperator_PADV2,
242 circle::BuiltinOptions_PadV2Options, options);
245 uint32_t CircleGen::addOperatorRank(const OperatorParams ¶ms)
247 auto options = circle::CreateRankOptions(_fbb).Union();
248 return addOperatorWithOptions(params, circle::BuiltinOperator_RANK,
249 circle::BuiltinOptions_RankOptions, options);
252 uint32_t CircleGen::addOperatorReduce(const OperatorParams ¶ms,
253 circle::BuiltinOperator reduce_op, bool keep_dims)
257 case circle::BuiltinOperator_REDUCE_ANY:
258 case circle::BuiltinOperator_REDUCE_MIN:
259 case circle::BuiltinOperator_REDUCE_MAX:
260 case circle::BuiltinOperator_REDUCE_PROD:
263 throw std::runtime_error{"Wrong reduce op"};
265 auto options = circle::CreateReducerOptions(_fbb, keep_dims).Union();
266 return addOperatorWithOptions(params, reduce_op, circle::BuiltinOptions_ReducerOptions, options);
269 uint32_t CircleGen::addOperatorReshape(const OperatorParams ¶ms, const Shape *new_shape)
271 auto options = circle::CreateReshapeOptionsDirect(_fbb, new_shape).Union();
272 return addOperatorWithOptions(params, circle::BuiltinOperator_RESHAPE,
273 circle::BuiltinOptions_ReshapeOptions, options);
276 uint32_t CircleGen::addOperatorResizeBilinear(const OperatorParams ¶ms, bool align_corners,
277 bool half_pixel_centers)
280 circle::CreateResizeBilinearOptions(_fbb, align_corners, half_pixel_centers).Union();
281 return addOperatorWithOptions(params, circle::BuiltinOperator_RESIZE_BILINEAR,
282 circle::BuiltinOptions_ResizeBilinearOptions, options);
285 uint32_t CircleGen::addOperatorResizeNearestNeighbor(const OperatorParams ¶ms)
287 auto options = circle::CreateResizeNearestNeighborOptions(_fbb).Union();
288 return addOperatorWithOptions(params, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
289 circle::BuiltinOptions_ResizeNearestNeighborOptions, options);
292 uint32_t CircleGen::addOperatorReverseV2(const OperatorParams ¶ms)
294 auto options = circle::CreateReverseV2Options(_fbb).Union();
295 return addOperatorWithOptions(params, circle::BuiltinOperator_REVERSE_V2,
296 circle::BuiltinOptions_ReverseV2Options, options);
299 uint32_t CircleGen::addOperatorShape(const OperatorParams ¶ms, circle::TensorType type)
301 auto options = circle::CreateShapeOptions(_fbb, type).Union();
302 return addOperatorWithOptions(params, circle::BuiltinOperator_SHAPE,
303 circle::BuiltinOptions_RankOptions, options);
306 uint32_t CircleGen::addOperatorSelect(const OperatorParams ¶ms)
308 auto options = circle::CreateSelectOptions(_fbb).Union();
309 return addOperatorWithOptions(params, circle::BuiltinOperator_SELECT,
310 circle::BuiltinOptions_SelectOptions, options);
313 uint32_t CircleGen::addOperatorSelectV2(const OperatorParams ¶ms)
315 auto options = circle::CreateSelectV2Options(_fbb).Union();
316 return addOperatorWithOptions(params, circle::BuiltinOperator_SELECT_V2,
317 circle::BuiltinOptions_SelectV2Options, options);
320 uint32_t CircleGen::addOperatorSplit(const OperatorParams ¶ms, int32_t num_split)
322 auto options = circle::CreateSplitOptions(_fbb, num_split).Union();
323 return addOperatorWithOptions(params, circle::BuiltinOperator_SPLIT,
324 circle::BuiltinOptions_SplitOptions, options);
326 uint32_t CircleGen::addOperatorStridedSlice(const OperatorParams ¶ms, int32_t begin_mask,
327 int32_t end_mask, int32_t ellipsis_mask,
328 int32_t new_axis_mask, int32_t shrink_axis_mask)
330 auto options = circle::CreateStridedSliceOptions(_fbb, begin_mask, end_mask, ellipsis_mask,
331 new_axis_mask, shrink_axis_mask)
333 return addOperatorWithOptions(params, circle::BuiltinOperator_STRIDED_SLICE,
334 circle::BuiltinOptions_StridedSliceOptions, options);
336 uint32_t CircleGen::addOperatorTile(const OperatorParams ¶ms)
338 auto options = circle::CreateTileOptions(_fbb).Union();
339 return addOperatorWithOptions(params, circle::BuiltinOperator_TILE,
340 circle::BuiltinOptions_TileOptions, options);
343 uint32_t CircleGen::addOperatorWhile(const OperatorParams ¶ms, uint32_t cond_subg,
346 auto options = circle::CreateWhileOptions(_fbb, cond_subg, body_subg).Union();
347 return addOperatorWithOptions(params, circle::BuiltinOperator_WHILE,
348 circle::BuiltinOptions_WhileOptions, options);
351 uint32_t CircleGen::addOperatorIf(const OperatorParams ¶ms, uint32_t then_subg,
354 auto options = circle::CreateIfOptions(_fbb, then_subg, else_subg).Union();
355 return addOperatorWithOptions(params, circle::BuiltinOperator_IF,
356 circle::BuiltinOptions_IfOptions, options);
359 uint32_t CircleGen::addOperatorInstanceNorm(const OperatorParams ¶ms, float epsilon,
360 circle::ActivationFunctionType actfn)
362 auto options = circle::CreateInstanceNormOptions(_fbb, epsilon, actfn).Union();
363 return addOperatorWithOptions(params, circle::BuiltinOperator_INSTANCE_NORM,
364 circle::BuiltinOptions_InstanceNormOptions, options);
367 uint32_t CircleGen::addOperatorTranspose(const OperatorParams ¶ms)
369 auto options = circle::CreateTransposeOptions(_fbb).Union();
370 return addOperatorWithOptions(params, circle::BuiltinOperator_TRANSPOSE,
371 circle::BuiltinOptions_TransposeOptions, options);
374 // NOTE Please add addOperator functions ABOVE this lie
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
383 // ===== Add Operator methods end =====
385 uint32_t CircleGen::addOperatorWithOptions(const OperatorParams ¶ms,
386 circle::BuiltinOperator opcode,
387 circle::BuiltinOptions options_type,
388 flatbuffers::Offset<void> options)
390 uint32_t opcode_ind = addOperatorCode(opcode);
391 auto op = circle::CreateOperatorDirect(_fbb, opcode_ind, ¶ms.inputs, ¶ms.outputs,
392 options_type, options);
394 uint32_t ind = curSubgCtx().operators.size();
395 curSubgCtx().operators.emplace_back(op);
399 uint32_t CircleGen::addOperatorCode(circle::BuiltinOperator opcode)
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));
407 flatbuffers::Offset<circle::Buffer> CircleGen::buildBuffer(const uint8_t *buf, size_t size)
409 if (buf == nullptr && size == 0)
410 return circle::CreateBuffer(_fbb);
411 auto buffer = _fbb.CreateVector(buf, size);
412 return circle::CreateBuffer(_fbb, buffer);
415 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams ¶ms)
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 */);
424 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams ¶ms, float scale,
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 */);
437 flatbuffers::Offset<circle::SparsityParameters>
438 CircleGen::buildSparsityParameters(const SparsityParams &sp)
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>>>
445 traversal_order = _fbb.CreateVector(sp.traversal_order);
446 block_map = _fbb.CreateVector(sp.block_map);
448 std::vector<flatbuffers::Offset<circle::DimensionMetadata>> dim_metadata_vec;
449 for (auto &it : sp.dim_metadata)
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);
458 dim_metadata = _fbb.CreateVector(dim_metadata_vec);
460 return circle::CreateSparsityParameters(_fbb, traversal_order, block_map, dim_metadata);
463 flatbuffers::Offset<circle::Tensor> CircleGen::buildTensor(const TensorParams ¶ms,
464 const SparsityParams &sp)
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 */);
474 flatbuffers::Offset<circle::SubGraph> CircleGen::buildSubGraph(const SubgraphContext &ctx)
476 return circle::CreateSubGraphDirect(_fbb, &ctx.tensors, &ctx.inputs, &ctx.outputs, &ctx.operators,