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 "CircleTensorExporter.h"
20 #include "CircleOperationExporter.h"
21 #include "CircleExporterUtils.h"
23 #include <oops/InternalExn.h>
24 #include <mio/circle/schema_generated.h>
25 #include <flatbuffers/flatbuffers.h>
28 #include <unordered_map>
35 luci::CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index)
37 for (uint32_t n = 0; n < g->nodes()->size(); ++n)
39 if (auto input = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n)))
41 if (input->indexed() && input->index() == index)
50 luci::CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index)
52 for (uint32_t n = 0; n < g->nodes()->size(); ++n)
54 if (auto output = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n)))
56 if (output->indexed() && output->index() == index)
65 void registerGraphInputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
67 for (uint32_t n = 0; n < graph->inputs()->size(); ++n)
69 auto node = input_node(graph, n);
70 assert(node != nullptr);
71 ctx._inputs.push_back(luci::get_tensor_index(node));
75 void registerGraphOutputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
77 for (uint32_t n = 0; n < graph->outputs()->size(); ++n)
79 auto push = output_node(graph, n);
80 assert(push != nullptr);
81 auto node = push->from();
82 assert(node != nullptr);
84 // Do not export CircleOutput when it's input is CircleOutputExclude
85 if (dynamic_cast<luci::CircleOutputExclude *>(push->from()) != nullptr)
90 ctx._outputs.push_back(luci::get_tensor_index(node));
99 using namespace circle;
100 using namespace flatbuffers;
102 Offset<Vector<Offset<OperatorCode>>>
103 encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes)
105 std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size());
106 for (auto it : opcodes)
108 uint32_t idx = it.second;
109 if (it.first.opcode != BuiltinOperator_CUSTOM)
111 operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode, 0, it.first.version);
115 operator_codes_vec[idx] =
116 CreateOperatorCode(builder, it.first.opcode, builder.CreateString(it.first.custom_code));
120 return builder.CreateVector(operator_codes_vec);
128 using namespace circle;
129 using namespace flatbuffers;
131 CircleExporterImpl::CircleExporterImpl(loco::Graph *graph) { exportGraph(graph); }
132 CircleExporterImpl::CircleExporterImpl(Module *module) { exportModule(module); }
134 ::flatbuffers::Offset<::circle::SubGraph>
135 CircleExporterImpl::exportSubgraph(SerializedGraphData &gd)
137 auto tensors = _builder.CreateVector(gd._tensors);
138 auto inputs = _builder.CreateVector(gd._inputs);
139 auto outputs = _builder.CreateVector(gd._outputs);
140 auto operators = _builder.CreateVector(gd._operators);
141 auto name = _builder.CreateString(gd._name);
142 auto df = gd._data_format;
143 auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, name, df);
147 void CircleExporterImpl::exportGraph(loco::Graph *graph)
149 // do graph optimization
154 SerializedModelData md;
155 SerializedGraphData gd;
157 // This version is taken from comment in fbs
158 constexpr uint32_t version = 0;
161 gd._name = graph->name();
163 // TODO set this value properly
164 gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
166 // prepare model data
167 prepareModelData(_builder, md);
169 // parse graph into SerializedModelData structure
170 exportOpDefinedTensors(graph, _builder, md, gd);
172 // NOTE Invoke these register functions only after each node is annotated with its tensor_index
173 registerGraphInputTensors(graph, gd);
174 registerGraphOutputTensors(graph, gd);
176 exportNodes(graph, _builder, md, gd);
178 // encode operator codes
179 auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
182 Offset<SubGraph> subgraph = exportSubgraph(gd);
183 auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph});
186 std::string description_str = "nnpackage";
187 auto description = _builder.CreateString(description_str);
189 // create array of buffers
190 auto buffers = _builder.CreateVector(md._buffers);
193 std::vector<int> metadata_buffer_vec;
194 auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
197 auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
198 buffers, metadata_buffer);
199 FinishModelBuffer(_builder, model_offset);
202 void CircleExporterImpl::exportModule(Module *module)
204 assert(module->size() > 0);
205 // do graph optimization
207 SerializedModelData md;
211 // prepare model data
212 prepareModelData(_builder, md);
214 std::vector<flatbuffers::Offset<circle::SubGraph>> subgraph_vec;
216 for (size_t g = 0; g < module->size(); ++g)
218 auto graph = module->graph(g);
222 SerializedGraphData gd;
225 gd._name = graph->name();
227 // TODO set this value properly
228 gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
230 // parse graph into SerializedModelData structure
231 exportOpDefinedTensors(graph, _builder, md, gd);
233 // NOTE Invoke these register functions only after each node is annotated with its tensor_index
234 registerGraphInputTensors(graph, gd);
235 registerGraphOutputTensors(graph, gd);
237 exportNodes(graph, _builder, md, gd);
240 Offset<SubGraph> subgraph = exportSubgraph(gd);
241 subgraph_vec.push_back(subgraph);
244 auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph_vec});
246 // encode operator codes
247 auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
250 std::string description_str = "nnpackage";
251 auto description = _builder.CreateString(description_str);
253 // create array of buffers
254 auto buffers = _builder.CreateVector(md._buffers);
257 std::vector<int> metadata_buffer_vec;
258 auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
260 // This version is taken from comment in fbs
261 constexpr uint32_t version = 0;
264 auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
265 buffers, metadata_buffer);
266 FinishModelBuffer(_builder, model_offset);
269 const char *CircleExporterImpl::getBufferPointer() const
271 return reinterpret_cast<const char *>(_builder.GetBufferPointer());
274 size_t CircleExporterImpl::getBufferSize() const { return _builder.GetSize(); }