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 "CircleExporterImpl.h"
19 #include "TypeBridge.h"
20 #include "CircleTensorExporter.h"
21 #include "CircleOperationExporter.h"
22 #include "CircleExporterUtils.h"
24 #include <oops/InternalExn.h>
25 #include <mio/circle/schema_generated.h>
26 #include <flatbuffers/flatbuffers.h>
29 #include <unordered_map>
36 luci::CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index)
38 for (uint32_t n = 0; n < g->nodes()->size(); ++n)
40 if (auto input = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n)))
42 if (input->indexed() && input->index() == index)
51 luci::CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index)
53 for (uint32_t n = 0; n < g->nodes()->size(); ++n)
55 if (auto output = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n)))
57 if (output->indexed() && output->index() == index)
66 void registerGraphInputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
68 for (uint32_t n = 0; n < graph->inputs()->size(); ++n)
70 auto node = input_node(graph, n);
71 assert(node != nullptr);
72 ctx._inputs.push_back(luci::get_tensor_index(node));
76 void registerGraphOutputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
78 for (uint32_t n = 0; n < graph->outputs()->size(); ++n)
80 auto push = output_node(graph, n);
81 assert(push != nullptr);
82 auto node = push->from();
83 assert(node != nullptr);
85 // Do not export CircleOutput when it's input is CircleOutputExclude
86 if (dynamic_cast<luci::CircleOutputExclude *>(push->from()) != nullptr)
91 ctx._outputs.push_back(luci::get_tensor_index(node));
100 using namespace circle;
101 using namespace flatbuffers;
103 Offset<Vector<Offset<OperatorCode>>>
104 encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes)
106 std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size());
107 for (auto it : opcodes)
109 uint32_t idx = it.second;
110 if (it.first.opcode != BuiltinOperator_CUSTOM)
112 operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode, 0, it.first.version);
116 operator_codes_vec[idx] =
117 CreateOperatorCode(builder, it.first.opcode, builder.CreateString(it.first.custom_code));
121 return builder.CreateVector(operator_codes_vec);
129 using namespace circle;
130 using namespace flatbuffers;
132 CircleExporterImpl::CircleExporterImpl(loco::Graph *graph) { exportGraph(graph); }
133 CircleExporterImpl::CircleExporterImpl(Module *module) { exportModule(module); }
135 ::flatbuffers::Offset<::circle::SubGraph>
136 CircleExporterImpl::exportSubgraph(SerializedGraphData &gd)
138 auto tensors = _builder.CreateVector(gd._tensors);
139 auto inputs = _builder.CreateVector(gd._inputs);
140 auto outputs = _builder.CreateVector(gd._outputs);
141 auto operators = _builder.CreateVector(gd._operators);
142 auto name = _builder.CreateString(gd._name);
143 auto df = gd._data_format;
144 auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, name, df);
148 void CircleExporterImpl::exportGraph(loco::Graph *graph)
150 // do graph optimization
153 // copy shape/dtype inference data to CircleNode
154 copy_shape_dtype(graph);
158 SerializedModelData md;
159 SerializedGraphData gd;
161 // This version is taken from comment in fbs
162 constexpr uint32_t version = 0;
165 gd._name = graph->name();
167 // TODO set this value properly
168 gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
170 // prepare model data
171 prepareModelData(_builder, md);
173 // parse graph into SerializedModelData structure
174 exportOpDefinedTensors(graph, _builder, md, gd);
176 // NOTE Invoke these register functions only after each node is annotated with its tensor_index
177 registerGraphInputTensors(graph, gd);
178 registerGraphOutputTensors(graph, gd);
180 exportNodes(graph, _builder, md, gd);
182 // encode operator codes
183 auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
186 Offset<SubGraph> subgraph = exportSubgraph(gd);
187 auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph});
190 std::string description_str = "nnpackage";
191 auto description = _builder.CreateString(description_str);
193 // create array of buffers
194 auto buffers = _builder.CreateVector(md._buffers);
197 std::vector<int> metadata_buffer_vec;
198 auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
201 auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
202 buffers, metadata_buffer);
203 FinishModelBuffer(_builder, model_offset);
206 void CircleExporterImpl::exportModule(Module *module)
208 assert(module->size() > 0);
209 // do graph optimization
211 SerializedModelData md;
215 // prepare model data
216 prepareModelData(_builder, md);
218 std::vector<flatbuffers::Offset<circle::SubGraph>> subgraph_vec;
220 for (size_t g = 0; g < module->size(); ++g)
222 auto graph = module->graph(g);
226 // copy shape/dtype inference data to CircleNode
227 copy_shape_dtype(graph);
229 SerializedGraphData gd;
232 gd._name = graph->name();
234 // TODO set this value properly
235 gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
237 // parse graph into SerializedModelData structure
238 exportOpDefinedTensors(graph, _builder, md, gd);
240 // NOTE Invoke these register functions only after each node is annotated with its tensor_index
241 registerGraphInputTensors(graph, gd);
242 registerGraphOutputTensors(graph, gd);
244 exportNodes(graph, _builder, md, gd);
247 Offset<SubGraph> subgraph = exportSubgraph(gd);
248 subgraph_vec.push_back(subgraph);
251 auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph_vec});
253 // encode operator codes
254 auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
257 std::string description_str = "nnpackage";
258 auto description = _builder.CreateString(description_str);
260 // create array of buffers
261 auto buffers = _builder.CreateVector(md._buffers);
264 std::vector<int> metadata_buffer_vec;
265 auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
267 // This version is taken from comment in fbs
268 constexpr uint32_t version = 0;
271 auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
272 buffers, metadata_buffer);
273 FinishModelBuffer(_builder, model_offset);
276 const char *CircleExporterImpl::getBufferPointer() const
278 return reinterpret_cast<const char *>(_builder.GetBufferPointer());
281 size_t CircleExporterImpl::getBufferSize() const { return _builder.GetSize(); }