Imported Upstream version 1.19.0
[platform/core/ml/nnfw.git] / compiler / luci / import / src / Importer.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 "luci/Importer.h"
18 #include "CircleImportMetadata.h"
19 #include "PostImport.h"
20
21 #include "luci/Import/GraphBuilder.h"
22 #include "luci/Import/GraphBuilderContext.h"
23 #include "luci/Import/GraphBuilderRegistry.h"
24 #include "luci/Import/CircleReader.h"
25 #include "luci/Import/Nodes/CircleConst.h"
26
27 #include <luci/IR/Module.h>
28 #include <luci/IR/CircleNodes.h>
29 #include <luci/Profile/CircleNodeID.h>
30 #include <luci/Profile/CircleNodeOrigin.h>
31 #include <luci/Plan/CircleNodeExecutionPlan.h>
32 #include <luci/Log.h>
33 #include <luci/LogHelper.h>
34
35 #include <oops/InternalExn.h>
36 #include <oops/UserExn.h>
37
38 #include <memory>
39
40 namespace
41 {
42
43 void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &reader,
44                    loco::Graph *graph)
45 {
46   LOGGER(l);
47
48   auto nodefinder = std::make_unique<luci::IndexNodeFinder>();
49   auto tensoroutputs = std::make_unique<luci::IndexTensorOutputs>();
50
51   luci::GraphBuilderContext gb_context(graph, &reader, nodefinder.get(), tensoroutputs.get());
52
53   const auto &operators = reader.operators();
54   const auto &tensors = reader.tensors();
55   auto tensors_ptr = reader.tensors_ptr();
56   assert(tensors_ptr != nullptr);
57   auto circle_metadata = std::make_unique<luci::CircleImportMetadata>(reader);
58
59   // build a cache to identify if a tensor is output of an operator
60   // if this is set, we should not create a CircleConst for this tensor
61   for (uint32_t i = 0; i < operators.size(); ++i)
62   {
63     const circle::OperatorT &op = *operators[i];
64     const auto &outputs = op.outputs;
65
66     for (uint32_t j = 0; j < outputs.size(); ++j)
67     {
68       auto tidx = outputs[j];
69       tensoroutputs->enroll(tidx);
70     }
71   }
72
73   // graph inputs; there are no input nodes in TFlite but just Tensors
74   // creating virtual input nodes will make possible to connect nodes that uses them
75   // all attributes of tensor should be copied to CircleInput node
76   for (const auto input : reader.inputs())
77   {
78     auto input_node = graph->nodes()->create<luci::CircleInput>();
79     assert(input_node != nullptr);
80     const circle::TensorT &tensor = *tensors[input];
81
82     luci::copy_tensor_attributes(tensor, input_node);
83     if (tensors_ptr->Get(input)->shape() == nullptr)
84       input_node->shape_status(luci::ShapeStatus::NOSHAPE);
85     else
86       input_node->shape_status(luci::ShapeStatus::VALID);
87
88     INFO(l) << "[luci] NodeFinder INPUT(" << input << ") = " << input_node << std::endl;
89     nodefinder->enroll(input, input_node);
90
91     // input_node is also an output to a tensor
92     tensoroutputs->enroll(input);
93
94     // Name
95     auto graph_input = graph->inputs()->create();
96     graph_input->name(input_node->name());
97
98     // Set GraphInputOutputIndex for graph
99     input_node->index(graph_input->index());
100
101     // Data type
102     graph_input->dtype(input_node->dtype());
103
104     assert(tensor.shape_signature.size() == 0 ||
105            tensor.shape_signature.size() == tensor.shape.size());
106
107     // Shape of GraphInput
108     auto input_shape = std::make_unique<loco::TensorShape>();
109     const std::vector<int32_t> &input_dims = tensor.shape; // in NHWC
110     input_shape->rank(input_dims.size());
111     for (uint32_t r = 0; r < input_dims.size(); ++r)
112     {
113       if (tensor.shape_signature.size() > 0 && tensor.shape_signature.at(r) == -1)
114         input_shape->dim(r).unset();
115       else
116         input_shape->dim(r).set(input_dims[r]);
117     }
118     graph_input->shape(std::move(input_shape));
119   }
120
121   // Create CircleConst nodes for constant tensors.
122   // NOTE Origin is intentionally not provided for constants.
123   for (uint32_t i = 0; i < tensors.size(); ++i)
124   {
125     luci::CircleConst *const_node = luci::create_circleconst(&gb_context, i);
126     if (const_node != nullptr)
127       nodefinder->enroll(i, const_node);
128   }
129
130   // Import the operators.
131   // Note that operators in model are stored in execution order. This means that when importing
132   // an operator, its input operators have already been imported. We exploit this fact to set up
133   // node's inputs right after creating the node.
134   auto origin_table = circle_metadata->origin_table();
135   for (uint32_t i = 0; i < operators.size(); ++i)
136   {
137     const circle::OperatorT &op = *operators[i];
138     circle::BuiltinOperator builtincode = reader.builtin_code(op);
139
140     if (const auto *builder = source.lookup(builtincode))
141     {
142       luci::GraphBuilder::ValidateArgs args(op, reader);
143       if (!builder->validate(args))
144       {
145         throw oops::UserExn("Invalid operator", reader.opcode_name(op));
146       }
147
148       auto built_op = builder->build(op, &gb_context);
149       set_node_id(built_op, i);
150       if (origin_table.find(i) != origin_table.end())
151         add_origin(built_op, origin_table.at(i));
152       else
153         add_origin(built_op, luci::single_origin(i, built_op->name()));
154     }
155     else
156     {
157       throw oops::UserExn("Not supported", reader.opcode_name(op));
158     }
159   }
160
161   // graph outputs
162   for (auto output : reader.outputs())
163   {
164     const circle::TensorT &tensor = *tensors[output];
165
166     auto output_node = graph->nodes()->create<luci::CircleOutput>();
167     assert(output_node != nullptr);
168     auto output_from = nodefinder->node(output);
169     if (output_from != nullptr)
170       output_node->from(output_from);
171     else
172     {
173       // NOTE loco::Graph requires all input node(s) to a node should exist.
174       //      Here, CircleOutput needs an input node.
175       //      We add a dummy node to make it happy.
176       auto output_dummy = graph->nodes()->create<luci::CircleOutputDummy>();
177       assert(output_dummy != nullptr);
178       output_node->from(output_dummy);
179
180       luci::copy_tensor_attributes(tensor, output_dummy);
181       if (tensors_ptr->Get(output)->shape() == nullptr)
182         output_dummy->shape_status(luci::ShapeStatus::NOSHAPE);
183       else
184         output_dummy->shape_status(luci::ShapeStatus::VALID);
185     }
186
187     INFO(l) << "[luci] NodeFinder OUTPUT(" << output << ") = " << output_node << std::endl;
188
189     // set the graph output name and node object
190     auto graph_output = graph->outputs()->create();
191     std::string tname = luci::tensor_name(tensor);
192     assert(tname.length() > 0);
193     graph_output->name(tname);
194
195     luci::copy_tensor_attributes(tensor, output_node);
196
197     // Set GraphInputOutputIndex for graph
198     output_node->index(graph_output->index());
199
200     assert(tensor.shape_signature.size() == 0 ||
201            tensor.shape_signature.size() == tensor.shape.size());
202
203     // Shape of Output
204     auto output_shape = std::make_unique<loco::TensorShape>();
205     const std::vector<int32_t> &output_dims = tensor.shape; // in NHWC
206     output_shape->rank(output_dims.size());
207     for (uint32_t r = 0; r < output_dims.size(); ++r)
208     {
209       if (tensor.shape_signature.size() > 0 && tensor.shape_signature.at(r) == -1)
210         output_shape->dim(r).unset();
211       else
212         output_shape->dim(r).set(output_dims[r]);
213     }
214     graph_output->shape(std::move(output_shape));
215
216     // Data type
217     auto dtype = luci::luci_datatype(tensor.type);
218     graph_output->dtype(dtype);
219   }
220 }
221
222 class ValidateCollector final : public loco::ErrorListener
223 {
224 public:
225   void notify(const loco::ErrorDetail<loco::ErrorCategory::MissingArgument> &d) override
226   {
227     LOGGER(l);
228     INFO(l) << "[luci] GraphValidate error " << d.node() << "(" << d.index() << ")" << std::endl;
229   }
230 };
231
232 } // namespace
233
234 namespace luci
235 {
236
237 Importer::Importer()
238 {
239   // DO NOTHING
240 }
241
242 std::unique_ptr<loco::Graph> Importer::import(const circle::Model *model) const
243 {
244   auto graph = loco::make_graph();
245
246   const GraphBuilderSource *source_ptr = &GraphBuilderRegistry::get();
247
248   if (_source != nullptr)
249   {
250     // Use user-defined GraphBuilderSource
251     source_ptr = _source;
252   }
253
254   CircleReader reader;
255   if (!reader.parse(model))
256     return nullptr;
257
258   if (reader.num_subgraph() != 1)
259   {
260     INTERNAL_EXN("Use 'importModule()' for multiple subgraphs");
261   }
262   if (!reader.select_subgraph(0))
263     return nullptr;
264
265   // Convert circle::Model to loco::Graph
266   convert_graph(*source_ptr, reader, graph.get());
267
268   LOGGER(l);
269   VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------";
270   VERBOSE(l, 3) << "Name: " << graph->name();
271   VERBOSE(l, 3) << fmt(graph.get());
272   VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------";
273
274   assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>()));
275
276   return graph;
277 }
278
279 std::unique_ptr<Module> Importer::importModule(const circle::Model *model) const
280 {
281   auto module = make_module();
282
283   const GraphBuilderSource *source_ptr = &GraphBuilderRegistry::get();
284
285   if (_source != nullptr)
286   {
287     // Use user-defined GraphBuilderSource
288     source_ptr = _source;
289   }
290
291   CircleReader reader;
292   if (!reader.parse(model))
293     return nullptr;
294
295   for (uint32_t g = 0; g < reader.num_subgraph(); ++g)
296   {
297     auto graph = loco::make_graph();
298
299     if (!reader.select_subgraph(g))
300       return nullptr;
301
302     graph->name(reader.name());
303
304     // Convert circle::Model to loco::Graph
305     convert_graph(*source_ptr, reader, graph.get());
306
307     LOGGER(l);
308     VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------";
309     VERBOSE(l, 3) << "Name: " << graph->name();
310     VERBOSE(l, 3) << fmt(graph.get());
311     VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------";
312
313     assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>()));
314
315     module->add(std::move(graph));
316   }
317
318   post_import_graph(module.get(), reader);
319
320   // Initialize 'source_table'
321   auto circle_metadata = std::make_unique<luci::CircleImportMetadata>(reader);
322   if (circle_metadata->source_table().size() > 0)
323   {
324     // If there is 'source_table' metadata in circle model, copy the table.
325     module->source_table(circle_metadata->source_table());
326   }
327   else
328   {
329     // If there is no 'source_table' metadata in circle model,
330     // create new table with circle nodes.
331     std::map<uint32_t, std::string> table;
332
333     // NOTE Only first subgraph is considered
334     for (auto node : loco::all_nodes(module->graph(0)))
335     {
336       auto circle_node = loco::must_cast<luci::CircleNode *>(node);
337
338       // Virtual nodes may not have id
339       if (!has_node_id(circle_node))
340         continue;
341
342       assert(table.find(get_node_id(circle_node)) == table.end());
343       table.insert({get_node_id(circle_node), circle_node->name()});
344     }
345
346     module->source_table(table);
347   }
348
349   // Add execution_plan annotations
350   if (circle_metadata->execution_plan_table().size() > 0)
351   {
352     auto execution_plan_table = circle_metadata->execution_plan_table();
353     auto node_position = 0;
354     for (auto node : loco::postorder_traversal(loco::output_nodes(module->graph())))
355     {
356       if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
357       {
358         auto node_plan = execution_plan_table[node_position];
359         luci::add_execution_plan(
360           circle_node,
361           luci::CircleNodeExecutionPlan(
362             node_plan[0], std::vector<uint32_t>(node_plan.begin() + 1, node_plan.end())));
363       }
364       node_position++;
365     }
366   }
367
368   return module;
369 }
370
371 } // namespace luci