Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / compiler / luci-interpreter / src / loader / KernelBuilder.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 "loader/KernelBuilder.h"
18
19 #include "kernels/Add.h"
20 #include "kernels/ArgMax.h"
21 #include "kernels/AveragePool2D.h"
22 #include "kernels/Concatenation.h"
23 #include "kernels/Conv2D.h"
24 #include "kernels/DepthwiseConv2D.h"
25 #include "kernels/Elu.h"
26 #include "kernels/FullyConnected.h"
27 #include "kernels/If.h"
28 #include "kernels/L2Normalize.h"
29 #include "kernels/L2Pool2D.h"
30 #include "kernels/LeakyRelu.h"
31 #include "kernels/LocalResponseNormalization.h"
32 #include "kernels/Logistic.h"
33 #include "kernels/MaxPool2D.h"
34 #include "kernels/Mean.h"
35 #include "kernels/Mul.h"
36 #include "kernels/Pad.h"
37 #include "kernels/Reshape.h"
38 #include "kernels/Softmax.h"
39 #include "kernels/SpaceToDepth.h"
40 #include "kernels/Split.h"
41 #include "kernels/StridedSlice.h"
42 #include "kernels/Squeeze.h"
43 #include "kernels/Unpack.h"
44 #include "kernels/Transpose.h"
45 #include "kernels/TransposeConv.h"
46 #include "loader/GraphLoader.h"
47 #include "loader/ModuleLoader.h"
48
49 #include <stdexcept>
50
51 namespace luci_interpreter
52 {
53
54 template <typename CircleNodeOut>
55 static std::vector<const loco::Node *> collectOutputNodes(const luci::CircleNode *node)
56 {
57   std::vector<const CircleNodeOut *> output_nodes;
58   for (const loco::Node *loco_node : loco::succs(node))
59   {
60     output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node));
61   }
62   std::sort(output_nodes.begin(), output_nodes.end(),
63             [](const CircleNodeOut *node1, const CircleNodeOut *node2) {
64               return node1->index() < node2->index();
65             });
66   return {output_nodes.cbegin(), output_nodes.cend()};
67 }
68
69 const Tensor *KernelBuilder::getInputTensor(const loco::Node *node) const
70 {
71   const Tensor *tensor = _graph_loader.getTensorForNode(node);
72   assert(tensor != nullptr);
73   return tensor;
74 }
75
76 const Tensor *KernelBuilder::getOptionalInputTensor(const loco::Node *node) const
77 {
78   // TODO Revise this when optional inputs are implemented in the IR.
79   return getInputTensor(node);
80 }
81
82 Tensor *KernelBuilder::getOutputTensor(const loco::Node *node) const
83 {
84   Tensor *tensor = _graph_loader.getTensorForNode(node);
85   assert(tensor != nullptr);
86   return tensor;
87 }
88
89 std::vector<Tensor *>
90 KernelBuilder::getOutputTensors(const std::vector<const loco::Node *> &nodes) const
91 {
92   std::vector<Tensor *> tensors;
93   tensors.reserve(nodes.size());
94   for (const loco::Node *node : nodes)
95     tensors.push_back(getOutputTensor(node));
96   return tensors;
97 }
98
99 RuntimeGraph *KernelBuilder::getRuntimeGraph(const loco::Graph *graph) const
100 {
101   RuntimeGraph *runtime_graph = _module_loader.getRuntimeGraph(graph);
102   assert(runtime_graph != nullptr);
103   return runtime_graph;
104 }
105
106 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAdd *node)
107 {
108   assert(node->arity() == 2);
109
110   const Tensor *input1 = getInputTensor(node->x());
111   const Tensor *input2 = getInputTensor(node->y());
112   Tensor *output = getOutputTensor(node);
113
114   AddParams params{};
115   params.activation = node->fusedActivationFunction();
116
117   return std::make_unique<kernels::Add>(input1, input2, output, params);
118 }
119
120 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleArgMax *node)
121 {
122   assert(node->arity() == 2);
123   const Tensor *input1 = getInputTensor(node->input());
124   const Tensor *input2 = getInputTensor(node->dimension());
125   Tensor *output = getOutputTensor(node);
126
127   ArgMaxParams params{};
128   params.output_type = node->output_type();
129
130   return std::make_unique<kernels::ArgMax>(input1, input2, output, params);
131 }
132
133 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAveragePool2D *node)
134 {
135   assert(node->arity() == 1);
136
137   const Tensor *input = getInputTensor(node->value());
138   Tensor *output = getOutputTensor(node);
139
140   Pool2DParams params{};
141   params.padding = node->padding();
142   params.filter_height = node->filter()->h();
143   params.filter_width = node->filter()->w();
144   params.stride_height = node->stride()->h();
145   params.stride_width = node->stride()->w();
146   params.activation = node->fusedActivationFunction();
147
148   return std::make_unique<kernels::AveragePool2D>(input, output, params);
149 }
150
151 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConcatenation *node)
152 {
153   std::vector<const Tensor *> inputs(node->numValues());
154   for (uint32_t i = 0; i < node->numValues(); ++i)
155   {
156     inputs[i] = getInputTensor(node->values(i));
157   }
158   Tensor *output = getOutputTensor(node);
159
160   ConcatenationParams params{};
161   params.axis = node->axis();
162
163   return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params);
164 }
165
166 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConst *)
167 {
168   throw std::runtime_error("Const node cannot be executed.");
169 }
170
171 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConv2D *node)
172 {
173   assert(node->arity() == 3);
174
175   const Tensor *input = getInputTensor(node->input());
176   const Tensor *filter = getInputTensor(node->filter());
177   const Tensor *bias = getInputTensor(node->bias());
178   Tensor *output = getOutputTensor(node);
179
180   Conv2DParams params{};
181   params.padding = node->padding();
182   params.stride_height = node->stride()->h();
183   params.stride_width = node->stride()->w();
184   params.dilation_height_factor = node->dilation()->h();
185   params.dilation_width_factor = node->dilation()->w();
186   params.activation = node->fusedActivationFunction();
187
188   return std::make_unique<kernels::Conv2D>(input, filter, bias, output, params);
189 }
190
191 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthwiseConv2D *node)
192 {
193   assert(node->arity() == 3);
194
195   const Tensor *input = getInputTensor(node->input());
196   const Tensor *filter = getInputTensor(node->filter());
197   const Tensor *bias = getInputTensor(node->bias());
198   Tensor *output = getOutputTensor(node);
199
200   DepthwiseConv2DParams params{};
201   params.padding = node->padding();
202   params.depth_multiplier = node->depthMultiplier();
203   params.stride_height = node->stride()->h();
204   params.stride_width = node->stride()->w();
205   params.dilation_height_factor = node->dilation()->h();
206   params.dilation_width_factor = node->dilation()->w();
207   params.activation = node->fusedActivationFunction();
208
209   return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, params);
210 }
211
212 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleElu *node)
213 {
214   assert(node->arity() == 1);
215
216   const Tensor *input = getInputTensor(node->features());
217   Tensor *output = getOutputTensor(node);
218
219   return std::make_unique<kernels::Elu>(input, output);
220 }
221
222 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFullyConnected *node)
223 {
224   assert(node->arity() == 3);
225
226   const Tensor *input = getInputTensor(node->input());
227   const Tensor *filter = getInputTensor(node->weights());
228   const Tensor *bias = getOptionalInputTensor(node->bias());
229   Tensor *output = getOutputTensor(node);
230
231   FullyConnectedParams params{};
232   params.activation = node->fusedActivationFunction();
233
234   return std::make_unique<kernels::FullyConnected>(input, filter, bias, output, params);
235 }
236
237 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node)
238 {
239   auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node);
240   assert(node->arity() == 1 + node->input_count());
241   assert(output_nodes.size() == static_cast<size_t>(node->output_count()));
242
243   const Tensor *cond = getInputTensor(node->cond());
244   std::vector<const Tensor *> inputs(node->input_count());
245   for (uint32_t i = 0; i < node->input_count(); ++i)
246   {
247     inputs[i] = getInputTensor(node->input(i));
248   }
249   std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
250
251   RuntimeGraph *then_graph = getRuntimeGraph(node->then_graph());
252   RuntimeGraph *else_graph = getRuntimeGraph(node->else_graph());
253
254   return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph,
255                                        else_graph);
256 }
257
258 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Normalize *node)
259 {
260   assert(node->arity() == 1);
261
262   const Tensor *input = getInputTensor(node->x());
263   Tensor *output = getOutputTensor(node);
264
265   L2NormParams params{};
266   params.activation = node->fusedActivationFunction();
267
268   return std::make_unique<kernels::L2Normalize>(input, output, params);
269 }
270
271 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Pool2D *node)
272 {
273   assert(node->arity() == 1);
274
275   const Tensor *input = getInputTensor(node->value());
276   Tensor *output = getOutputTensor(node);
277
278   Pool2DParams params{};
279   params.padding = node->padding();
280   params.filter_height = node->filter()->h();
281   params.filter_width = node->filter()->w();
282   params.stride_height = node->stride()->h();
283   params.stride_width = node->stride()->w();
284   params.activation = node->fusedActivationFunction();
285
286   return std::make_unique<kernels::L2Pool2D>(input, output, params);
287 }
288
289 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLeakyRelu *node)
290 {
291   assert(node->arity() == 1);
292   const Tensor *input = getInputTensor(node->features());
293   Tensor *output = getOutputTensor(node);
294
295   LeakyReluParams params{};
296   params.alpha = node->alpha();
297
298   return std::make_unique<kernels::LeakyRelu>(input, output, params);
299 }
300
301 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLocalResponseNormalization *node)
302 {
303   assert(node->arity() == 1);
304   const Tensor *input = getInputTensor(node->input());
305   Tensor *output = getOutputTensor(node);
306
307   LocalResponseNormalizationParams params{};
308   params.radius = node->radius();
309   params.bias = node->bias();
310   params.alpha = node->alpha();
311   params.beta = node->beta();
312
313   return std::make_unique<kernels::LocalResponseNormalization>(input, output, params);
314 }
315
316 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogistic *node)
317 {
318   assert(node->arity() == 1);
319
320   const Tensor *input = getInputTensor(node->x());
321   Tensor *output = getOutputTensor(node);
322
323   return std::make_unique<kernels::Logistic>(input, output);
324 }
325
326 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *)
327 {
328   throw std::runtime_error("Input node cannot be executed.");
329 }
330
331 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaxPool2D *node)
332 {
333   assert(node->arity() == 1);
334
335   const Tensor *input = getInputTensor(node->value());
336   Tensor *output = getOutputTensor(node);
337
338   Pool2DParams params{};
339   params.padding = node->padding();
340   params.filter_height = node->filter()->h();
341   params.filter_width = node->filter()->w();
342   params.stride_height = node->stride()->h();
343   params.stride_width = node->stride()->w();
344   params.activation = node->fusedActivationFunction();
345
346   return std::make_unique<kernels::MaxPool2D>(input, output, params);
347 }
348
349 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMean *node)
350 {
351   assert(node->arity() == 2);
352
353   const Tensor *input = getInputTensor(node->input());
354   const Tensor *axes = getInputTensor(node->reduction_indices());
355   Tensor *output = getOutputTensor(node);
356
357   ReducerParams params{};
358   params.keep_dims = node->keep_dims();
359
360   return std::make_unique<kernels::Mean>(input, axes, output, params);
361 }
362
363 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMul *node)
364 {
365   assert(node->arity() == 2);
366
367   const Tensor *input1 = getInputTensor(node->x());
368   const Tensor *input2 = getInputTensor(node->y());
369   Tensor *output = getOutputTensor(node);
370
371   MulParams params{};
372   params.activation = node->fusedActivationFunction();
373
374   return std::make_unique<kernels::Mul>(input1, input2, output, params);
375 }
376
377 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleOutput *)
378 {
379   throw std::runtime_error("Output node cannot be executed.");
380 }
381
382 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePad *node)
383 {
384   assert(node->arity() == 2);
385
386   const Tensor *input = getInputTensor(node->input());
387   const Tensor *paddings = getInputTensor(node->paddings());
388   Tensor *output = getOutputTensor(node);
389
390   return std::make_unique<kernels::Pad>(input, paddings, output);
391 }
392
393 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReshape *node)
394 {
395   assert(node->arity() == 2);
396
397   const Tensor *input = getInputTensor(node->tensor());
398   const Tensor *shape = getInputTensor(node->shape());
399   Tensor *output = getOutputTensor(node);
400
401   // NOTE 'newShape' attribute is ignored.
402   return std::make_unique<kernels::Reshape>(input, shape, output);
403 }
404
405 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSoftmax *node)
406 {
407   assert(node->arity() == 1);
408
409   const Tensor *input = getInputTensor(node->logits());
410   Tensor *output = getOutputTensor(node);
411
412   SoftmaxParams params{};
413   params.beta = node->beta();
414
415   return std::make_unique<kernels::Softmax>(input, output, params);
416 }
417
418 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSpaceToDepth *node)
419 {
420   assert(node->arity() == 1);
421   const Tensor *input = getInputTensor(node->input());
422
423   Tensor *output = getOutputTensor(node);
424
425   SpaceToDepthParams params{};
426   params.block_size = node->block_size();
427
428   return std::make_unique<kernels::SpaceToDepth>(input, output, params);
429 }
430
431 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSplit *node)
432 {
433   auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node);
434   assert(node->arity() == 2);
435   assert(output_nodes.size() == static_cast<size_t>(node->num_split()));
436
437   const Tensor *axis = getInputTensor(node->split_dim());
438   const Tensor *input = getInputTensor(node->input());
439   std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
440
441   // NOTE 'num_splits' attribute is ignored.
442   return std::make_unique<kernels::Split>(axis, input, std::move(outputs));
443 }
444
445 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *node)
446 {
447   assert(node->arity() == 4);
448
449   const Tensor *input = getInputTensor(node->input());
450   const Tensor *begin = getInputTensor(node->begin());
451   const Tensor *end = getInputTensor(node->end());
452   const Tensor *strides = getInputTensor(node->strides());
453
454   Tensor *output = getOutputTensor(node);
455
456   StridedSliceParams params{};
457   params.begin_mask = node->begin_mask();
458   params.ellipsis_mask = node->ellipsis_mask();
459   params.end_mask = node->end_mask();
460   params.new_axis_mask = node->new_axis_mask();
461   params.shrink_axis_mask = node->shrink_axis_mask();
462
463   return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params);
464 }
465
466 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node)
467 {
468   assert(node->arity() == 1);
469
470   const Tensor *input = getInputTensor(node->input());
471   Tensor *output = getOutputTensor(node);
472
473   SqueezeParams params{};
474   assert(node->squeeze_dims().size() <= 4);
475   for (size_t i = 0; i < node->squeeze_dims().size(); i++)
476   {
477     params.squeeze_dims.push_back(node->squeeze_dims().at(i));
478   }
479
480   return std::make_unique<kernels::Squeeze>(input, output, params);
481 }
482
483 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTransposeConv *node)
484 {
485   assert(node->arity() == 3);
486
487   const Tensor *input_sizes = getInputTensor(node->inputSizes());
488   const Tensor *filter = getInputTensor(node->filter());
489   const Tensor *out_backprop = getInputTensor(node->outBackprop());
490
491   Tensor *output = getOutputTensor(node);
492
493   TransposeConvParams params{};
494   params.padding = node->padding();
495   params.stride_height = node->stride()->h();
496   params.stride_width = node->stride()->w();
497
498   return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, output,
499                                                   params);
500 }
501
502 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleUnpack *node)
503 {
504   auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node);
505   assert(node->arity() == 1);
506   assert(output_nodes.size() == static_cast<size_t>(node->num()));
507
508   const Tensor *input = getInputTensor(node->value());
509   std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
510
511   UnpackParams params{};
512   params.axis = node->axis();
513
514   // NOTE 'num' attribute is ignored.
515   return std::make_unique<kernels::Unpack>(input, std::move(outputs), params);
516 }
517
518 std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node)
519 {
520   assert(node->arity() == 2);
521
522   const Tensor *input = getInputTensor(node->a());
523   const Tensor *perm = getInputTensor(node->perm());
524   Tensor *output = getOutputTensor(node);
525
526   return std::make_unique<kernels::Transpose>(input, perm, output);
527 }
528
529 } // namespace luci_interpreter