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