Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compiler / luci / export / src / CircleExporterImpl.cpp
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 "CircleExporterImpl.h"
18 #include "Optimize.h"
19 #include "CircleTensorExporter.h"
20 #include "CircleOperationExporter.h"
21 #include "CircleExporterUtils.h"
22
23 #include <oops/InternalExn.h>
24 #include <mio/circle/schema_generated.h>
25 #include <flatbuffers/flatbuffers.h>
26
27 #include <cassert>
28 #include <unordered_map>
29 #include <string>
30 #include <stdexcept>
31
32 namespace
33 {
34
35 luci::CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index)
36 {
37   for (uint32_t n = 0; n < g->nodes()->size(); ++n)
38   {
39     if (auto input = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n)))
40     {
41       if (input->indexed() && input->index() == index)
42       {
43         return input;
44       }
45     }
46   }
47   return nullptr;
48 }
49
50 luci::CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index)
51 {
52   for (uint32_t n = 0; n < g->nodes()->size(); ++n)
53   {
54     if (auto output = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n)))
55     {
56       if (output->indexed() && output->index() == index)
57       {
58         return output;
59       }
60     }
61   }
62   return nullptr;
63 }
64
65 void registerGraphInputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
66 {
67   for (uint32_t n = 0; n < graph->inputs()->size(); ++n)
68   {
69     auto node = input_node(graph, n);
70     assert(node != nullptr);
71     ctx._inputs.push_back(luci::get_tensor_index(node));
72   }
73 }
74
75 void registerGraphOutputTensors(loco::Graph *graph, luci::SubGraphContext &ctx)
76 {
77   for (uint32_t n = 0; n < graph->outputs()->size(); ++n)
78   {
79     auto push = output_node(graph, n);
80     assert(push != nullptr);
81     auto node = push->from();
82     assert(node != nullptr);
83
84     // Do not export CircleOutput when it's input is CircleOutputExclude
85     if (dynamic_cast<luci::CircleOutputExclude *>(push->from()) != nullptr)
86     {
87       continue;
88     }
89
90     ctx._outputs.push_back(luci::get_tensor_index(node));
91   }
92 }
93
94 } // namespace
95
96 namespace
97 {
98
99 using namespace circle;
100 using namespace flatbuffers;
101
102 Offset<Vector<Offset<OperatorCode>>>
103 encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes)
104 {
105   std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size());
106   for (auto it : opcodes)
107   {
108     uint32_t idx = it.second;
109     if (it.first.opcode != BuiltinOperator_CUSTOM)
110     {
111       operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode, 0, it.first.version);
112     }
113     else
114     {
115       operator_codes_vec[idx] =
116           CreateOperatorCode(builder, it.first.opcode, builder.CreateString(it.first.custom_code));
117     }
118   }
119
120   return builder.CreateVector(operator_codes_vec);
121 }
122
123 } // namespace
124
125 namespace luci
126 {
127
128 using namespace circle;
129 using namespace flatbuffers;
130
131 CircleExporterImpl::CircleExporterImpl(loco::Graph *graph) { exportGraph(graph); }
132 CircleExporterImpl::CircleExporterImpl(Module *module) { exportModule(module); }
133
134 ::flatbuffers::Offset<::circle::SubGraph>
135 CircleExporterImpl::exportSubgraph(SerializedGraphData &gd)
136 {
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);
144   return subgraph;
145 }
146
147 void CircleExporterImpl::exportGraph(loco::Graph *graph)
148 {
149   // do graph optimization
150   optimize(graph);
151
152   _builder.Clear();
153
154   SerializedModelData md;
155   SerializedGraphData gd;
156
157   // This version is taken from comment in fbs
158   constexpr uint32_t version = 0;
159
160   // set Subgraph name
161   gd._name = graph->name();
162
163   // TODO set this value properly
164   gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
165
166   // prepare model data
167   prepareModelData(_builder, md);
168
169   // parse graph into SerializedModelData structure
170   exportOpDefinedTensors(graph, _builder, md, gd);
171
172   // NOTE Invoke these register functions only after each node is annotated with its tensor_index
173   registerGraphInputTensors(graph, gd);
174   registerGraphOutputTensors(graph, gd);
175
176   exportNodes(graph, _builder, md, gd);
177
178   // encode operator codes
179   auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
180
181   // Subgraphs
182   Offset<SubGraph> subgraph = exportSubgraph(gd);
183   auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph});
184
185   // Description
186   std::string description_str = "nnpackage";
187   auto description = _builder.CreateString(description_str);
188
189   // create array of buffers
190   auto buffers = _builder.CreateVector(md._buffers);
191
192   // empty metadata
193   std::vector<int> metadata_buffer_vec;
194   auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
195
196   // Model
197   auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
198                                   buffers, metadata_buffer);
199   FinishModelBuffer(_builder, model_offset);
200 }
201
202 void CircleExporterImpl::exportModule(Module *module)
203 {
204   assert(module->size() > 0);
205   // do graph optimization
206
207   SerializedModelData md;
208
209   _builder.Clear();
210
211   // prepare model data
212   prepareModelData(_builder, md);
213
214   std::vector<flatbuffers::Offset<circle::SubGraph>> subgraph_vec;
215
216   for (size_t g = 0; g < module->size(); ++g)
217   {
218     auto graph = module->graph(g);
219
220     optimize(graph);
221
222     SerializedGraphData gd;
223
224     // set Subgraph name
225     gd._name = graph->name();
226
227     // TODO set this value properly
228     gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST;
229
230     // parse graph into SerializedModelData structure
231     exportOpDefinedTensors(graph, _builder, md, gd);
232
233     // NOTE Invoke these register functions only after each node is annotated with its tensor_index
234     registerGraphInputTensors(graph, gd);
235     registerGraphOutputTensors(graph, gd);
236
237     exportNodes(graph, _builder, md, gd);
238
239     // Subgraphs
240     Offset<SubGraph> subgraph = exportSubgraph(gd);
241     subgraph_vec.push_back(subgraph);
242   }
243
244   auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph_vec});
245
246   // encode operator codes
247   auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes);
248
249   // Description
250   std::string description_str = "nnpackage";
251   auto description = _builder.CreateString(description_str);
252
253   // create array of buffers
254   auto buffers = _builder.CreateVector(md._buffers);
255
256   // empty metadata
257   std::vector<int> metadata_buffer_vec;
258   auto metadata_buffer = _builder.CreateVector(metadata_buffer_vec);
259
260   // This version is taken from comment in fbs
261   constexpr uint32_t version = 0;
262
263   // Model
264   auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description,
265                                   buffers, metadata_buffer);
266   FinishModelBuffer(_builder, model_offset);
267 }
268
269 const char *CircleExporterImpl::getBufferPointer() const
270 {
271   return reinterpret_cast<const char *>(_builder.GetBufferPointer());
272 }
273
274 size_t CircleExporterImpl::getBufferSize() const { return _builder.GetSize(); }
275
276 } // namespace luci