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