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 "CircleOperationExporter.h"
18 #include "CircleExporterUtils.h"
21 #include <luci/IR/CircleNode.h>
22 #include <luci/IR/CircleNodes.h>
23 #include <luci/IR/CircleNodeVisitor.h>
24 #include <luci/Service/CircleShapeInference.h>
25 #include <luci/UserSettings.h>
28 #include <loco/IR/CanonicalNodeVisitor.h>
29 #include <oops/InternalExn.h>
31 #include <flatbuffers/flexbuffers.h>
33 using namespace flatbuffers;
34 using namespace circle;
41 class OperationExporter final : public luci::CircleNodeMutableVisitor<void>,
42 public loco::CanonicalNodeMutableVisitor<void>
45 OperationExporter(FlatBufferBuilder &fbb, SerializedModelData &m, SerializedGraphData &g)
46 : builder{fbb}, md{m}, gd{g}
52 void visit(luci::CircleAbs *) final;
53 void visit(luci::CircleAdd *) final;
54 void visit(luci::CircleAddN *) final;
55 void visit(luci::CircleArgMax *) final;
56 void visit(luci::CircleArgMin *) final;
57 void visit(luci::CircleAveragePool2D *) final;
58 void visit(luci::CircleBatchMatMul *) final;
59 void visit(luci::CircleBatchToSpaceND *) final;
60 void visit(luci::CircleCast *) final;
61 void visit(luci::CircleCeil *) final;
62 void visit(luci::CircleConcatenation *) final;
63 void visit(luci::CircleConst *) final{/* skip, everything is done in exportOpDefinedTensors */};
64 void visit(luci::CircleConv2D *) final;
65 void visit(luci::CircleCos *) final;
66 void visit(luci::CircleCustom *) final;
67 void visit(luci::CircleDepthToSpace *) final;
68 void visit(luci::CircleDepthwiseConv2D *) final;
69 void visit(luci::CircleDiv *) final;
70 void visit(luci::CircleElu *) final;
71 void visit(luci::CircleEqual *) final;
72 void visit(luci::CircleExp *) final;
73 void visit(luci::CircleExpandDims *) final;
74 void visit(luci::CircleFill *) final;
75 void visit(luci::CircleFloor *) final;
76 void visit(luci::CircleFloorDiv *) final;
77 void visit(luci::CircleFloorMod *) final;
78 void visit(luci::CircleFullyConnected *) final;
79 void visit(luci::CircleGather *) final;
80 void visit(luci::CircleGatherNd *) final;
81 void visit(luci::CircleGreater *) final;
82 void visit(luci::CircleGreaterEqual *) final;
83 void visit(luci::CircleIf *) final;
84 void visit(luci::CircleL2Normalize *) final;
85 void visit(luci::CircleL2Pool2D *) final;
86 void visit(luci::CircleLeakyRelu *) final;
87 void visit(luci::CircleLess *) final;
88 void visit(luci::CircleLessEqual *) final;
89 void visit(luci::CircleLocalResponseNormalization *) final;
90 void visit(luci::CircleLog *) final;
91 void visit(luci::CircleLogicalAnd *) final;
92 void visit(luci::CircleLogicalNot *) final;
93 void visit(luci::CircleLogicalOr *) final;
94 void visit(luci::CircleLogistic *) final;
95 void visit(luci::CircleLogSoftmax *) final;
96 void visit(luci::CircleMatrixDiag *) final;
97 void visit(luci::CircleMatrixSetDiag *) final;
98 void visit(luci::CircleMaximum *) final;
99 void visit(luci::CircleMaxPool2D *) final;
100 void visit(luci::CircleMean *) final;
101 void visit(luci::CircleMinimum *) final;
102 void visit(luci::CircleMirrorPad *) final;
103 void visit(luci::CircleMul *) final;
104 void visit(luci::CircleNeg *) final;
105 void visit(luci::CircleNotEqual *) final;
106 void visit(luci::CircleOneHot *) final;
107 void visit(luci::CirclePack *) final;
108 void visit(luci::CirclePad *) final;
109 void visit(luci::CirclePow *) final;
110 void visit(luci::CirclePRelu *) final;
111 void visit(luci::CircleRange *) final;
112 void visit(luci::CircleRank *) final;
113 void visit(luci::CircleReduceAny *) final;
114 void visit(luci::CircleReduceMax *) final;
115 void visit(luci::CircleReduceMin *) final;
116 void visit(luci::CircleReduceProd *) final;
117 void visit(luci::CircleRelu *) final;
118 void visit(luci::CircleRelu6 *) final;
119 void visit(luci::CircleReluN1To1 *) final;
120 void visit(luci::CircleReshape *) final;
121 void visit(luci::CircleResizeBilinear *) final;
122 void visit(luci::CircleResizeNearestNeighbor *) final;
123 void visit(luci::CircleReverseSequence *) final;
124 void visit(luci::CircleReverseV2 *) final;
125 void visit(luci::CircleRound *) final;
126 void visit(luci::CircleRsqrt *) final;
127 void visit(luci::CircleScatterNd *) final;
128 void visit(luci::CircleSegmentSum *) final;
129 void visit(luci::CircleSelect *) final;
130 void visit(luci::CircleSelectV2 *) final;
131 void visit(luci::CircleShape *) final;
132 void visit(luci::CircleSin *) final;
133 void visit(luci::CircleSlice *) final;
134 void visit(luci::CircleSoftmax *) final;
135 void visit(luci::CircleSpaceToBatchND *) final;
136 void visit(luci::CircleSpaceToDepth *) final;
137 void visit(luci::CircleSparseToDense *) final;
138 void visit(luci::CircleSplit *) final;
139 void visit(luci::CircleSplitV *) final;
140 void visit(luci::CircleSqrt *) final;
141 void visit(luci::CircleSquare *) final;
142 void visit(luci::CircleSquaredDifference *) final;
143 void visit(luci::CircleSqueeze *) final;
144 void visit(luci::CircleStridedSlice *) final;
145 void visit(luci::CircleSub *) final;
146 void visit(luci::CircleSum *) final;
147 void visit(luci::CircleTanh *) final;
148 void visit(luci::CircleTile *) final;
149 void visit(luci::CircleTopKV2 *) final;
150 void visit(luci::CircleTranspose *) final;
151 void visit(luci::CircleTransposeConv *) final;
152 void visit(luci::CircleUnpack *) final;
153 void visit(luci::CircleWhere *) final;
154 void visit(luci::CircleWhile *) final;
155 void visit(luci::CircleZerosLike *) final;
157 void visit(luci::CircleBCQFullyConnected *) final;
158 void visit(luci::CircleBCQGather *) final;
159 void visit(luci::CircleInstanceNorm *) final;
161 void visit(luci::CircleInput *) final {}
162 void visit(luci::CircleOutput *) final {}
163 void visit(luci::CircleOutputDummy *) final {}
164 void visit(luci::CircleOutputExclude *) final {}
165 // Virtual for multiple-outputs
166 void visit(luci::CircleCustomOut *) final {}
167 void visit(luci::CircleIfOut *) final {}
168 void visit(luci::CircleSplitOut *) final {}
169 void visit(luci::CircleSplitVOut *) final {}
170 void visit(luci::CircleTopKV2Out *) final {}
171 void visit(luci::CircleUnpackOut *) final {}
172 void visit(luci::CircleWhileOut *) final {}
176 * @brief Exports CircleMaxPool2D or CircleAveragePool2D
178 * @note CirclePool2D should be one of CircleMaxPool2D or CircleAveragePool2D
180 template <class CirclePool2D>
181 void export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op);
184 * @brief export simple nodes
186 void export_simple(loco::Node *node, circle::BuiltinOperator bop, circle::BuiltinOptions bot,
187 flatbuffers::Offset<void> options_offset);
190 * @brief export simple nodes having void options
192 void export_simple(loco::Node *node, circle::BuiltinOperator bop);
195 FlatBufferBuilder &builder;
196 SerializedModelData &md;
197 SerializedGraphData &gd;
200 template <class CirclePool2D>
201 void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op)
203 LUCI_ASSERT(builtin_op == circle::BuiltinOperator_MAX_POOL_2D ||
204 builtin_op == circle::BuiltinOperator_L2_POOL_2D ||
205 builtin_op == circle::BuiltinOperator_AVERAGE_POOL_2D,
206 "Should be L2Pool, MaxPool or AvgPool");
207 LUCI_ASSERT(node->padding() != luci::Padding::UNDEFINED, "Padding is not set");
209 uint32_t op_idx = md.registerBuiltinOpcode(builtin_op, node->op_version());
210 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
211 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
212 auto inputs = builder.CreateVector(inputs_vec);
213 auto outputs = builder.CreateVector(outputs_vec);
215 circle::Padding padding = getOpPadding(node->padding());
217 auto options = CreatePool2DOptions(builder, padding, node->stride()->w(), node->stride()->h(),
218 node->filter()->w(), node->filter()->h(),
219 to_circle_actfunc(node->fusedActivationFunction()));
220 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
221 circle::BuiltinOptions_Pool2DOptions, options.Union());
222 gd._operators.push_back(op_offset);
225 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop,
226 circle::BuiltinOptions bot,
227 flatbuffers::Offset<void> options_offset)
230 md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
231 std::vector<int32_t> inputs_vec;
232 std::vector<int32_t> outputs_vec{get_tensor_index(node)};
233 for (uint32_t i = 0; i < node->arity(); ++i)
234 inputs_vec.push_back(get_tensor_index(node->arg(i)));
235 auto inputs = builder.CreateVector(inputs_vec);
236 auto outputs = builder.CreateVector(outputs_vec);
237 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, bot, options_offset);
238 gd._operators.push_back(op_offset);
241 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop)
244 md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
245 std::vector<int32_t> inputs_vec;
246 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
247 for (uint32_t i = 0; i < node->arity(); ++i)
248 inputs_vec.push_back(get_tensor_index(node->arg(i)));
249 auto inputs = builder.CreateVector(inputs_vec);
250 auto outputs = builder.CreateVector(outputs_vec);
251 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
252 gd._operators.push_back(op_offset);
255 void OperationExporter::visit(luci::CircleAbs *node)
257 export_simple(node, circle::BuiltinOperator_ABS, circle::BuiltinOptions_AbsOptions,
258 CreateAbsOptions(builder).Union());
261 void OperationExporter::visit(luci::CircleAdd *node)
264 node, circle::BuiltinOperator_ADD, circle::BuiltinOptions_AddOptions,
265 CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
268 void OperationExporter::visit(luci::CircleAddN *node)
270 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD_N, node->op_version());
271 std::vector<int32_t> inputs_vec;
272 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
274 for (uint32_t i = 0; i < node->arity(); ++i)
275 inputs_vec.push_back(get_tensor_index(node->inputs(i)));
277 auto inputs = builder.CreateVector(inputs_vec);
278 auto outputs = builder.CreateVector(outputs_vec);
279 auto options = CreateAddNOptions(builder);
280 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
281 circle::BuiltinOptions_AddNOptions, options.Union());
282 gd._operators.push_back(op_offset);
285 void OperationExporter::visit(luci::CircleArgMax *node)
287 export_simple(node, circle::BuiltinOperator_ARG_MAX, circle::BuiltinOptions_ArgMaxOptions,
288 CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type())).Union());
291 void OperationExporter::visit(luci::CircleArgMin *node)
293 export_simple(node, circle::BuiltinOperator_ARG_MIN, circle::BuiltinOptions_ArgMinOptions,
294 CreateArgMinOptions(builder, to_circle_tensortype(node->output_type())).Union());
297 void OperationExporter::visit(luci::CircleAveragePool2D *node)
299 export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D);
302 void OperationExporter::visit(luci::CircleBatchMatMul *node)
304 export_simple(node, circle::BuiltinOperator_BATCH_MATMUL,
305 circle::BuiltinOptions_BatchMatMulOptions,
306 CreateBatchMatMulOptions(builder, node->adj_x(), node->adj_y()).Union());
309 void OperationExporter::visit(luci::CircleCast *node)
311 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CAST, node->op_version());
312 std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
313 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
314 auto inputs = builder.CreateVector(inputs_vec);
315 auto outputs = builder.CreateVector(outputs_vec);
317 flatbuffers::Offset<Operator> op_offset;
318 if (node->out_data_type() != loco::DataType::Unknown)
320 auto options = CreateCastOptions(builder, to_circle_tensortype(node->in_data_type()),
321 to_circle_tensortype(node->out_data_type()));
322 op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_CastOptions,
327 op_offset = CreateOperator(builder, op_idx, inputs, outputs);
329 gd._operators.push_back(op_offset);
332 void OperationExporter::visit(luci::CircleCeil *node)
334 export_simple(node, circle::BuiltinOperator_CEIL);
337 void OperationExporter::visit(luci::CircleConcatenation *node)
340 md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION, node->op_version());
341 std::vector<int32_t> inputs_vec;
342 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
344 for (uint32_t i = 0; i < node->numValues(); ++i)
345 inputs_vec.push_back(get_tensor_index(node->values(i)));
347 auto inputs = builder.CreateVector(inputs_vec);
348 auto outputs = builder.CreateVector(outputs_vec);
349 auto options = CreateConcatenationOptions(builder, node->axis(),
350 to_circle_actfunc(node->fusedActivationFunction()));
351 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
352 circle::BuiltinOptions_ConcatenationOptions, options.Union());
353 gd._operators.push_back(op_offset);
356 void OperationExporter::visit(luci::CircleBatchToSpaceND *node)
358 export_simple(node, circle::BuiltinOperator_BATCH_TO_SPACE_ND,
359 circle::BuiltinOptions_BatchToSpaceNDOptions,
360 CreateBatchToSpaceNDOptions(builder).Union());
363 void OperationExporter::visit(luci::CircleConv2D *node)
365 export_simple(node, circle::BuiltinOperator_CONV_2D, circle::BuiltinOptions_Conv2DOptions,
366 CreateConv2DOptions(builder, getOpPadding(node->padding()), node->stride()->w(),
368 to_circle_actfunc(node->fusedActivationFunction()),
369 node->dilation()->w(), node->dilation()->h())
373 void OperationExporter::visit(luci::CircleCos *node)
375 export_simple(node, circle::BuiltinOperator_COS, circle::BuiltinOptions_CosOptions,
376 CreateCosOptions(builder).Union());
379 void OperationExporter::visit(luci::CircleCustom *node)
381 auto custom_outputs = loco::succs(node);
383 uint32_t op_idx = md.registerCustomOpcode(node->custom_code());
384 std::vector<int32_t> inputs_vec;
385 std::vector<int32_t> outputs_vec;
387 for (uint32_t index = 0; index < node->numInputs(); index++)
389 inputs_vec.push_back(get_tensor_index(node->inputs(index)));
391 for (uint32_t index = 0; index < custom_outputs.size(); index++)
393 // store in order of index
395 for (auto out : custom_outputs)
397 auto custom_out = loco::must_cast<luci::CircleCustomOut *>(out);
398 if (custom_out->index() == static_cast<int32_t>(index))
400 outputs_vec.push_back(get_tensor_index(custom_out));
407 INTERNAL_EXN("Invalid Custom output");
411 auto inputs = builder.CreateVector(inputs_vec);
412 auto outputs = builder.CreateVector(outputs_vec);
413 flatbuffers::Offset<flatbuffers::Vector<uint8_t>> circle_custom_options;
414 std::vector<uint8_t> custom_options_vec{node->custom_options().begin(),
415 node->custom_options().end()};
416 circle_custom_options = builder.CreateVector(custom_options_vec);
417 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_NONE,
418 flatbuffers::Offset<void>(), circle_custom_options);
419 gd._operators.push_back(op_offset);
422 void OperationExporter::visit(luci::CircleDepthToSpace *node)
424 export_simple(node, circle::BuiltinOperator_DEPTH_TO_SPACE,
425 circle::BuiltinOptions_DepthToSpaceOptions,
426 CreateDepthToSpaceOptions(builder, node->block_size()).Union());
429 void OperationExporter::visit(luci::CircleDepthwiseConv2D *node)
431 export_simple(node, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
432 circle::BuiltinOptions_DepthwiseConv2DOptions,
433 CreateDepthwiseConv2DOptions(builder, getOpPadding(node->padding()),
434 node->stride()->w(), node->stride()->h(),
435 node->depthMultiplier(),
436 to_circle_actfunc(node->fusedActivationFunction()),
437 node->dilation()->w(), node->dilation()->h())
441 void OperationExporter::visit(luci::CircleDiv *node)
444 node, circle::BuiltinOperator_DIV, circle::BuiltinOptions_DivOptions,
445 CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
448 void OperationExporter::visit(luci::CircleElu *node)
450 export_simple(node, circle::BuiltinOperator_ELU);
453 void OperationExporter::visit(luci::CircleEqual *node)
455 export_simple(node, circle::BuiltinOperator_EQUAL, circle::BuiltinOptions_EqualOptions,
456 CreateEqualOptions(builder).Union());
459 void OperationExporter::visit(luci::CircleExp *node)
461 export_simple(node, circle::BuiltinOperator_EXP, circle::BuiltinOptions_ExpOptions,
462 CreateExpOptions(builder).Union());
465 void OperationExporter::visit(luci::CircleExpandDims *node)
467 export_simple(node, circle::BuiltinOperator_EXPAND_DIMS, circle::BuiltinOptions_ExpandDimsOptions,
468 CreateExpandDimsOptions(builder).Union());
471 void OperationExporter::visit(luci::CircleFill *node)
473 export_simple(node, circle::BuiltinOperator_FILL, circle::BuiltinOptions_FillOptions,
474 CreateFillOptions(builder).Union());
477 void OperationExporter::visit(luci::CircleFloor *node)
479 export_simple(node, circle::BuiltinOperator_FLOOR);
482 void OperationExporter::visit(luci::CircleFloorDiv *node)
484 export_simple(node, circle::BuiltinOperator_FLOOR_DIV, circle::BuiltinOptions_FloorDivOptions,
485 CreateFloorDivOptions(builder).Union());
488 void OperationExporter::visit(luci::CircleFloorMod *node)
490 export_simple(node, circle::BuiltinOperator_FLOOR_MOD, circle::BuiltinOptions_FloorModOptions,
491 CreateFloorModOptions(builder).Union());
494 void OperationExporter::visit(luci::CircleFullyConnected *node)
497 node, circle::BuiltinOperator_FULLY_CONNECTED, circle::BuiltinOptions_FullyConnectedOptions,
498 CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction()))
502 void OperationExporter::visit(luci::CircleGather *node)
504 export_simple(node, circle::BuiltinOperator_GATHER, circle::BuiltinOptions_GatherOptions,
505 CreateGatherOptions(builder, node->axis()).Union());
508 void OperationExporter::visit(luci::CircleGatherNd *node)
510 export_simple(node, circle::BuiltinOperator_GATHER_ND, circle::BuiltinOptions_GatherNdOptions,
511 CreateGatherNdOptions(builder).Union());
514 void OperationExporter::visit(luci::CircleGreater *node)
516 export_simple(node, circle::BuiltinOperator_GREATER, circle::BuiltinOptions_GreaterOptions,
517 CreateGreaterOptions(builder).Union());
520 void OperationExporter::visit(luci::CircleGreaterEqual *node)
522 export_simple(node, circle::BuiltinOperator_GREATER_EQUAL,
523 circle::BuiltinOptions_GreaterEqualOptions,
524 CreateGreaterEqualOptions(builder).Union());
527 void OperationExporter::visit(luci::CircleIf *node)
529 auto if_outs = loco::succs(node);
530 assert(if_outs.size() == node->output_count());
532 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_IF, node->op_version());
533 std::vector<int32_t> inputs_vec;
534 std::vector<int32_t> outputs_vec;
536 inputs_vec.push_back(get_tensor_index(node->cond()));
537 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
538 inputs_vec.push_back(get_tensor_index(node->input(idx)));
540 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
542 // store in order of index
544 for (auto out : if_outs)
546 auto if_out = loco::must_cast<luci::CircleIfOut *>(out);
547 if (if_out->index() == static_cast<int32_t>(idx))
549 outputs_vec.push_back(get_tensor_index(if_out));
556 INTERNAL_EXN("Invalid CircleIf output");
560 auto inputs = builder.CreateVector(inputs_vec);
561 auto outputs = builder.CreateVector(outputs_vec);
562 auto options = CreateIfOptions(builder, node->then_branch(), node->else_branch());
563 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
564 circle::BuiltinOptions_IfOptions, options.Union());
565 gd._operators.push_back(op_offset);
568 void OperationExporter::visit(luci::CircleL2Normalize *node)
571 node, circle::BuiltinOperator_L2_NORMALIZATION, circle::BuiltinOptions_L2NormOptions,
572 CreateL2NormOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
575 void OperationExporter::visit(luci::CircleL2Pool2D *node)
577 export_pool_2d<luci::CircleL2Pool2D>(node, circle::BuiltinOperator_L2_POOL_2D);
580 void OperationExporter::visit(luci::CircleLeakyRelu *node)
582 export_simple(node, circle::BuiltinOperator_LEAKY_RELU, circle::BuiltinOptions_LeakyReluOptions,
583 CreateLeakyReluOptions(builder, node->alpha()).Union());
586 void OperationExporter::visit(luci::CircleLess *node)
588 export_simple(node, circle::BuiltinOperator_LESS, circle::BuiltinOptions_LessOptions,
589 CreateLessOptions(builder).Union());
592 void OperationExporter::visit(luci::CircleLessEqual *node)
594 export_simple(node, circle::BuiltinOperator_LESS_EQUAL, circle::BuiltinOptions_LessEqualOptions,
595 CreateLessEqualOptions(builder).Union());
598 void OperationExporter::visit(luci::CircleLocalResponseNormalization *node)
600 export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
601 circle::BuiltinOptions_LocalResponseNormalizationOptions,
602 CreateLocalResponseNormalizationOptions(builder).Union());
605 void OperationExporter::visit(luci::CircleLog *node)
607 export_simple(node, circle::BuiltinOperator_LOG);
610 void OperationExporter::visit(luci::CircleLogicalAnd *node)
612 export_simple(node, circle::BuiltinOperator_LOGICAL_AND, circle::BuiltinOptions_LogicalAndOptions,
613 CreateLogicalAndOptions(builder).Union());
616 void OperationExporter::visit(luci::CircleLogicalNot *node)
618 export_simple(node, circle::BuiltinOperator_LOGICAL_NOT, circle::BuiltinOptions_LogicalNotOptions,
619 CreateLogicalNotOptions(builder).Union());
622 void OperationExporter::visit(luci::CircleLogicalOr *node)
624 export_simple(node, circle::BuiltinOperator_LOGICAL_OR, circle::BuiltinOptions_LogicalOrOptions,
625 CreateLogicalOrOptions(builder).Union());
628 void OperationExporter::visit(luci::CircleLogistic *node)
630 export_simple(node, circle::BuiltinOperator_LOGISTIC);
633 void OperationExporter::visit(luci::CircleLogSoftmax *node)
635 export_simple(node, circle::BuiltinOperator_LOG_SOFTMAX, circle::BuiltinOptions_LogSoftmaxOptions,
636 CreateLogSoftmaxOptions(builder).Union());
639 void OperationExporter::visit(luci::CircleMatrixDiag *node)
641 export_simple(node, circle::BuiltinOperator_MATRIX_DIAG, circle::BuiltinOptions_MatrixDiagOptions,
642 CreateMatrixDiagOptions(builder).Union());
645 void OperationExporter::visit(luci::CircleMatrixSetDiag *node)
647 export_simple(node, circle::BuiltinOperator_MATRIX_SET_DIAG,
648 circle::BuiltinOptions_MatrixSetDiagOptions,
649 CreateMatrixSetDiagOptions(builder).Union());
652 void OperationExporter::visit(luci::CircleMaximum *node)
654 export_simple(node, circle::BuiltinOperator_MAXIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
655 CreateMaximumMinimumOptions(builder).Union());
658 void OperationExporter::visit(luci::CircleMaxPool2D *node)
660 export_pool_2d<luci::CircleMaxPool2D>(node, circle::BuiltinOperator_MAX_POOL_2D);
663 void OperationExporter::visit(luci::CircleMean *node)
665 export_simple(node, circle::BuiltinOperator_MEAN, circle::BuiltinOptions_ReducerOptions,
666 CreateReducerOptions(builder, node->keep_dims()).Union());
669 void OperationExporter::visit(luci::CircleMinimum *node)
671 export_simple(node, circle::BuiltinOperator_MINIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
672 CreateMaximumMinimumOptions(builder).Union());
675 void OperationExporter::visit(luci::CircleMirrorPad *node)
677 export_simple(node, circle::BuiltinOperator_MIRROR_PAD, circle::BuiltinOptions_MirrorPadOptions,
678 CreateMirrorPadOptions(builder, to_circle_mirrorpadmode(node->mode())).Union());
681 void OperationExporter::visit(luci::CircleMul *node)
684 node, circle::BuiltinOperator_MUL, circle::BuiltinOptions_MulOptions,
685 CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
688 void OperationExporter::visit(luci::CircleNeg *node)
690 export_simple(node, circle::BuiltinOperator_NEG, circle::BuiltinOptions_NegOptions,
691 CreateNegOptions(builder).Union());
694 void OperationExporter::visit(luci::CircleNotEqual *node)
696 export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions,
697 CreateNotEqualOptions(builder).Union());
700 void OperationExporter::visit(luci::CircleOneHot *node)
702 export_simple(node, circle::BuiltinOperator_ONE_HOT, circle::BuiltinOptions_OneHotOptions,
703 CreateOneHotOptions(builder, node->axis()).Union());
706 void OperationExporter::visit(luci::CirclePack *node)
708 export_simple(node, circle::BuiltinOperator_PACK, circle::BuiltinOptions_PackOptions,
709 CreatePackOptions(builder, node->values_count(), node->axis()).Union());
712 void OperationExporter::visit(luci::CirclePad *node)
714 export_simple(node, circle::BuiltinOperator_PAD, circle::BuiltinOptions_PadOptions,
715 CreatePadOptions(builder).Union());
718 void OperationExporter::visit(luci::CirclePow *node)
720 export_simple(node, circle::BuiltinOperator_POW, circle::BuiltinOptions_PowOptions,
721 CreatePowOptions(builder).Union());
724 void OperationExporter::visit(luci::CirclePRelu *node)
726 export_simple(node, circle::BuiltinOperator_PRELU);
729 void OperationExporter::visit(luci::CircleRange *node)
731 export_simple(node, circle::BuiltinOperator_RANGE, circle::BuiltinOptions_RangeOptions,
732 CreateRangeOptions(builder).Union());
735 void OperationExporter::visit(luci::CircleRank *node)
737 export_simple(node, circle::BuiltinOperator_RANK, circle::BuiltinOptions_RankOptions,
738 CreateRankOptions(builder).Union());
741 void OperationExporter::visit(luci::CircleReduceAny *node)
743 export_simple(node, circle::BuiltinOperator_REDUCE_ANY, circle::BuiltinOptions_ReducerOptions,
744 CreateReducerOptions(builder, node->keep_dims()).Union());
747 void OperationExporter::visit(luci::CircleReduceMax *node)
749 export_simple(node, circle::BuiltinOperator_REDUCE_MAX, circle::BuiltinOptions_ReducerOptions,
750 CreateReducerOptions(builder, node->keep_dims()).Union());
753 void OperationExporter::visit(luci::CircleReduceMin *node)
755 export_simple(node, circle::BuiltinOperator_REDUCE_MIN, circle::BuiltinOptions_ReducerOptions,
756 CreateReducerOptions(builder, node->keep_dims()).Union());
759 void OperationExporter::visit(luci::CircleReduceProd *node)
761 export_simple(node, circle::BuiltinOperator_REDUCE_PROD, circle::BuiltinOptions_ReducerOptions,
762 CreateReducerOptions(builder, node->keep_dims()).Union());
765 void OperationExporter::visit(luci::CircleRelu *node)
767 export_simple(node, circle::BuiltinOperator_RELU);
770 void OperationExporter::visit(luci::CircleRelu6 *node)
772 export_simple(node, circle::BuiltinOperator_RELU6);
775 void OperationExporter::visit(luci::CircleReluN1To1 *node)
777 export_simple(node, circle::BuiltinOperator_RELU_N1_TO_1);
780 void OperationExporter::visit(luci::CircleReshape *node)
782 auto new_shape = builder.CreateVector<int32_t>(
783 node->newShape()->rank(), [node](size_t i) { return node->newShape()->dim(i); });
785 export_simple(node, circle::BuiltinOperator_RESHAPE, circle::BuiltinOptions_ReshapeOptions,
786 CreateReshapeOptions(builder, new_shape).Union());
789 void OperationExporter::visit(luci::CircleResizeBilinear *node)
792 node, circle::BuiltinOperator_RESIZE_BILINEAR, circle::BuiltinOptions_ResizeBilinearOptions,
793 CreateResizeBilinearOptions(builder, node->align_corners(), node->half_pixel_centers())
797 void OperationExporter::visit(luci::CircleResizeNearestNeighbor *node)
799 export_simple(node, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
800 circle::BuiltinOptions_ResizeNearestNeighborOptions,
801 CreateResizeNearestNeighborOptions(builder, node->align_corners()).Union());
804 void OperationExporter::visit(luci::CircleReverseSequence *node)
807 node, circle::BuiltinOperator_REVERSE_SEQUENCE, circle::BuiltinOptions_ReverseSequenceOptions,
808 CreateReverseSequenceOptions(builder, node->seq_axis(), node->batch_axis()).Union());
811 void OperationExporter::visit(luci::CircleReverseV2 *node)
814 md.registerBuiltinOpcode(circle::BuiltinOperator_REVERSE_V2, node->op_version());
815 std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), get_tensor_index(node->axis())};
816 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
817 auto inputs = builder.CreateVector(inputs_vec);
818 auto outputs = builder.CreateVector(outputs_vec);
819 auto options = CreateReverseV2Options(builder);
820 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
821 circle::BuiltinOptions_ReverseSequenceOptions, options.Union());
822 gd._operators.push_back(op_offset);
825 void OperationExporter::visit(luci::CircleRound *node)
827 export_simple(node, circle::BuiltinOperator_ROUND);
830 void OperationExporter::visit(luci::CircleRsqrt *node)
832 export_simple(node, circle::BuiltinOperator_RSQRT);
835 void OperationExporter::visit(luci::CircleScatterNd *node)
837 export_simple(node, circle::BuiltinOperator_SCATTER_ND, circle::BuiltinOptions_ScatterNdOptions,
838 CreateScatterNdOptions(builder).Union());
841 void OperationExporter::visit(luci::CircleSegmentSum *node)
843 export_simple(node, circle::BuiltinOperator_SEGMENT_SUM, circle::BuiltinOptions_SegmentSumOptions,
844 CreateSegmentSumOptions(builder).Union());
847 void OperationExporter::visit(luci::CircleSelect *node)
849 export_simple(node, circle::BuiltinOperator_SELECT, circle::BuiltinOptions_SelectOptions,
850 CreateSelectOptions(builder).Union());
853 void OperationExporter::visit(luci::CircleSelectV2 *node)
855 export_simple(node, circle::BuiltinOperator_SELECT_V2, circle::BuiltinOptions_SelectV2Options,
856 CreateSelectV2Options(builder).Union());
859 void OperationExporter::visit(luci::CircleShape *node)
861 export_simple(node, circle::BuiltinOperator_SHAPE, circle::BuiltinOptions_ShapeOptions,
862 CreateShapeOptions(builder, to_circle_tensortype(node->out_type())).Union());
865 void OperationExporter::visit(luci::CircleSin *node)
867 export_simple(node, circle::BuiltinOperator_SIN);
870 void OperationExporter::visit(luci::CircleSlice *node)
872 export_simple(node, circle::BuiltinOperator_SLICE, circle::BuiltinOptions_SliceOptions,
873 CreateSliceOptions(builder).Union());
876 void OperationExporter::visit(luci::CircleSoftmax *node)
878 export_simple(node, circle::BuiltinOperator_SOFTMAX, circle::BuiltinOptions_SoftmaxOptions,
879 CreateSoftmaxOptions(builder, node->beta()).Union());
882 void OperationExporter::visit(luci::CircleSpaceToBatchND *node)
884 export_simple(node, circle::BuiltinOperator_SPACE_TO_BATCH_ND,
885 circle::BuiltinOptions_SpaceToBatchNDOptions,
886 CreateSpaceToBatchNDOptions(builder).Union());
889 void OperationExporter::visit(luci::CircleSpaceToDepth *node)
891 export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH,
892 circle::BuiltinOptions_SpaceToDepthOptions,
893 CreateSpaceToDepthOptions(builder).Union());
896 void OperationExporter::visit(luci::CircleSparseToDense *node)
898 export_simple(node, circle::BuiltinOperator_SPARSE_TO_DENSE,
899 circle::BuiltinOptions_SparseToDenseOptions,
900 CreateSparseToDenseOptions(builder, node->validate_indices()).Union());
903 void OperationExporter::visit(luci::CircleSplit *node)
905 auto split_outs = loco::succs(node);
906 assert(int32_t(split_outs.size()) == node->num_split());
908 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT, node->op_version());
909 // NOTE BuiltinOperator_SPLIT input is placed at second position
910 std::vector<int32_t> inputs_vec{get_tensor_index(node->split_dim()),
911 get_tensor_index(node->input())};
912 std::vector<int32_t> outputs_vec;
914 for (int32_t index = 0; index < node->num_split(); index++)
916 // store in order of index
918 for (auto out : split_outs)
920 auto split_out = loco::must_cast<luci::CircleSplitOut *>(out);
921 if (split_out->index() == index)
923 outputs_vec.push_back(get_tensor_index(split_out));
930 INTERNAL_EXN("Invalid Split output");
934 auto inputs = builder.CreateVector(inputs_vec);
935 auto outputs = builder.CreateVector(outputs_vec);
936 auto options = CreateSplitOptions(builder, node->num_split());
937 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
938 circle::BuiltinOptions_SplitOptions, options.Union());
939 gd._operators.push_back(op_offset);
942 void OperationExporter::visit(luci::CircleSplitV *node)
944 auto split_outs = loco::succs(node);
945 assert(int32_t(split_outs.size()) == node->num_split());
947 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT_V, node->op_version());
948 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
949 get_tensor_index(node->size_splits()),
950 get_tensor_index(node->split_dim())};
951 std::vector<int32_t> outputs_vec;
953 for (int32_t index = 0; index < node->num_split(); index++)
955 // store in order of index
957 for (auto out : split_outs)
959 auto split_out = loco::must_cast<luci::CircleSplitVOut *>(out);
960 if (split_out->index() == index)
962 outputs_vec.push_back(get_tensor_index(split_out));
969 INTERNAL_EXN("Invalid SplitV output");
973 auto inputs = builder.CreateVector(inputs_vec);
974 auto outputs = builder.CreateVector(outputs_vec);
975 auto options = CreateSplitVOptions(builder, node->num_split());
976 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
977 circle::BuiltinOptions_SplitVOptions, options.Union());
978 gd._operators.push_back(op_offset);
981 void OperationExporter::visit(luci::CircleSqrt *node)
983 export_simple(node, circle::BuiltinOperator_SQRT);
986 void OperationExporter::visit(luci::CircleSquare *node)
988 export_simple(node, circle::BuiltinOperator_SQUARE, circle::BuiltinOptions_SquareOptions,
989 CreateSquareOptions(builder).Union());
992 void OperationExporter::visit(luci::CircleSquaredDifference *node)
994 export_simple(node, circle::BuiltinOperator_SQUARED_DIFFERENCE,
995 circle::BuiltinOptions_SquaredDifferenceOptions,
996 CreateSquaredDifferenceOptions(builder).Union());
999 void OperationExporter::visit(luci::CircleSqueeze *node)
1001 auto squeeze_dims = builder.CreateVector<int32_t>(node->squeeze_dims());
1002 export_simple(node, circle::BuiltinOperator_SQUEEZE, circle::BuiltinOptions_SqueezeOptions,
1003 CreateSqueezeOptions(builder, squeeze_dims).Union());
1006 void OperationExporter::visit(luci::CircleStridedSlice *node)
1008 export_simple(node, circle::BuiltinOperator_STRIDED_SLICE,
1009 circle::BuiltinOptions_StridedSliceOptions,
1010 CreateStridedSliceOptions(builder, node->begin_mask(), node->end_mask(),
1011 node->ellipsis_mask(), node->new_axis_mask(),
1012 node->shrink_axis_mask())
1016 void OperationExporter::visit(luci::CircleSub *node)
1019 node, circle::BuiltinOperator_SUB, circle::BuiltinOptions_SubOptions,
1020 CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
1023 void OperationExporter::visit(luci::CircleSum *node)
1025 export_simple(node, circle::BuiltinOperator_SUM, circle::BuiltinOptions_ReducerOptions,
1026 CreateReducerOptions(builder, node->keep_dims()).Union());
1029 void OperationExporter::visit(luci::CircleTanh *node)
1031 export_simple(node, circle::BuiltinOperator_TANH);
1034 void OperationExporter::visit(luci::CircleTile *node)
1036 export_simple(node, circle::BuiltinOperator_TILE, circle::BuiltinOptions_TileOptions,
1037 CreateTileOptions(builder).Union());
1040 void OperationExporter::visit(luci::CircleTopKV2 *node)
1042 auto topkv2_outs = loco::succs(node);
1043 int outs_count = int32_t(topkv2_outs.size());
1044 assert(outs_count == 2);
1046 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TOPK_V2, node->op_version());
1047 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->k())};
1048 std::vector<int32_t> outputs_vec;
1050 for (int32_t index = 0; index < outs_count; index++)
1052 // store in order of index
1054 for (auto out : topkv2_outs)
1056 auto topkv2_out = loco::must_cast<luci::CircleTopKV2Out *>(out);
1057 if (topkv2_out->index() == index)
1059 outputs_vec.push_back(get_tensor_index(topkv2_out));
1066 INTERNAL_EXN("Invalid TopKV2 output");
1070 auto inputs = builder.CreateVector(inputs_vec);
1071 auto outputs = builder.CreateVector(outputs_vec);
1072 auto options = CreateTopKV2Options(builder);
1073 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1074 circle::BuiltinOptions_TopKV2Options, options.Union());
1075 gd._operators.push_back(op_offset);
1078 void OperationExporter::visit(luci::CircleTranspose *node)
1080 export_simple(node, circle::BuiltinOperator_TRANSPOSE, circle::BuiltinOptions_TransposeOptions,
1081 CreateTransposeOptions(builder).Union());
1084 void OperationExporter::visit(luci::CircleTransposeConv *node)
1086 export_simple(node, circle::BuiltinOperator_TRANSPOSE_CONV,
1087 circle::BuiltinOptions_TransposeConvOptions,
1088 CreateTransposeConvOptions(builder, getOpPadding(node->padding()),
1089 node->stride()->w(), node->stride()->h())
1093 void OperationExporter::visit(luci::CircleUnpack *node)
1096 auto settings = luci::UserSettings::settings();
1098 auto unpack_outs = loco::succs(node);
1099 // NOTE real models may not use all of the outputs
1100 if (static_cast<int32_t>(unpack_outs.size()) != node->num())
1102 if (settings->get(luci::UserSettings::Key::DisableValidation))
1104 WARN(l) << "Warning: export Unpack(" << node->name() << ") 'num' not same as outputs";
1110 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNPACK, node->op_version());
1111 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
1112 std::vector<int32_t> outputs_vec;
1114 for (int32_t index = 0; index < node->num(); index++)
1116 // store in order of index
1118 for (auto out : unpack_outs)
1120 auto unpack_out = loco::must_cast<luci::CircleUnpackOut *>(out);
1121 if (unpack_out->index() == index)
1123 outputs_vec.push_back(get_tensor_index(unpack_out));
1128 // NOTE real models may not use all of the outputs
1131 if (settings->get(luci::UserSettings::Key::DisableValidation))
1133 WARN(l) << "Warning: export Unpack(" << node->name() << ") output " << index << " not used";
1140 auto inputs = builder.CreateVector(inputs_vec);
1141 auto outputs = builder.CreateVector(outputs_vec);
1142 auto options = CreateUnpackOptions(builder, node->num(), node->axis());
1143 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1144 circle::BuiltinOptions_UnpackOptions, options.Union());
1145 gd._operators.push_back(op_offset);
1148 void OperationExporter::visit(luci::CircleWhere *node)
1150 export_simple(node, circle::BuiltinOperator_WHERE, circle::BuiltinOptions_WhereOptions,
1151 CreateWhereOptions(builder).Union());
1154 void OperationExporter::visit(luci::CircleWhile *node)
1156 auto while_outs = loco::succs(node);
1157 assert(while_outs.size() == node->output_count());
1159 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_WHILE, node->op_version());
1160 std::vector<int32_t> inputs_vec;
1161 std::vector<int32_t> outputs_vec;
1163 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
1164 inputs_vec.push_back(get_tensor_index(node->input(idx)));
1166 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
1168 // store in order of index
1170 for (auto out : while_outs)
1172 auto while_out = loco::must_cast<luci::CircleWhileOut *>(out);
1173 if (while_out->index() == static_cast<int32_t>(idx))
1175 outputs_vec.push_back(get_tensor_index(while_out));
1182 INTERNAL_EXN("Invalid CircleWhile output");
1186 auto inputs = builder.CreateVector(inputs_vec);
1187 auto outputs = builder.CreateVector(outputs_vec);
1188 auto options = CreateWhileOptions(builder, node->cond_branch(), node->body_branch());
1189 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1190 circle::BuiltinOptions_WhileOptions, options.Union());
1191 gd._operators.push_back(op_offset);
1194 void OperationExporter::visit(luci::CircleZerosLike *node)
1196 export_simple(node, circle::BuiltinOperator_ZEROS_LIKE, circle::BuiltinOptions_ZerosLikeOptions,
1197 CreateZerosLikeOptions(builder).Union());
1200 void OperationExporter::visit(luci::CircleBCQFullyConnected *node)
1202 export_simple(node, circle::BuiltinOperator_BCQ_FULLY_CONNECTED,
1203 circle::BuiltinOptions_BCQFullyConnectedOptions,
1204 CreateBCQFullyConnectedOptions(builder, node->weights_hidden_size(),
1205 to_circle_actfunc(node->fusedActivationFunction()))
1209 void OperationExporter::visit(luci::CircleBCQGather *node)
1211 export_simple(node, circle::BuiltinOperator_BCQ_GATHER, circle::BuiltinOptions_BCQGatherOptions,
1212 CreateBCQGatherOptions(builder, node->input_hidden_size(), node->axis()).Union());
1215 void OperationExporter::visit(luci::CircleInstanceNorm *node)
1217 export_simple(node, circle::BuiltinOperator_INSTANCE_NORM,
1218 circle::BuiltinOptions_InstanceNormOptions,
1219 CreateInstanceNormOptions(builder, node->epsilon(),
1220 to_circle_actfunc(node->fusedActivationFunction()))
1224 void exportNode(loco::Node *node, flatbuffers::FlatBufferBuilder &builder, SerializedModelData &md,
1225 SerializedGraphData &gd)
1227 if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
1229 OperationExporter exporter{builder, md, gd};
1230 circle_node->accept(&exporter);
1234 INTERNAL_EXN("Node with unsupported dialect found");
1243 void exportNodes(loco::Graph *g, FlatBufferBuilder &builder, SerializedModelData &md,
1244 SerializedGraphData &gd)
1246 for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
1248 exportNode(node, builder, md, gd);