2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "loader/GraphLoader.h"
18 #include "loader/KernelBuilder.h"
20 #include <kernels/Add.h>
21 #include <kernels/ArgMax.h>
22 #include <kernels/AveragePool2D.h>
23 #include <kernels/Concatenation.h>
24 #include <kernels/Conv2D.h>
25 #include <kernels/DepthToSpace.h>
26 #include <kernels/DepthwiseConv2D.h>
27 #include <kernels/Elu.h>
28 #include <kernels/FullyConnected.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/Squeeze.h>
45 #include <kernels/StridedSlice.h>
46 #include <kernels/Transpose.h>
47 #include <kernels/TransposeConv.h>
48 #include <kernels/Unpack.h>
50 #include <gmock/gmock.h>
52 namespace luci_interpreter
57 using namespace testing;
59 class KernelBuilderTest : public Test
62 luci::CircleInput *createInputNode() { return createNode<luci::CircleInput>(); }
64 template <typename NodeT, typename... Args> NodeT *createNode(Args &&... args)
66 auto *node = _graph.nodes()->create<NodeT>(std::forward<Args>(args)...);
67 // The actual type does not matter for the purpose of the tests.
68 // NOTE The type is meaningless for nodes with multiple outputs (corresponding *Out nodes carry
69 // actual output types).
70 node->dtype(loco::DataType::FLOAT32);
74 template <typename NodeOutT> NodeOutT *createNodeOut(loco::Node *node, int index)
76 auto *node_out = createNode<NodeOutT>();
77 node_out->input(node);
78 node_out->index(index);
82 template <typename KernelT> std::unique_ptr<KernelT> buildKernel(const luci::CircleNode *op)
84 std::unordered_map<const loco::Graph *, RuntimeGraph *> graph_to_runtime_graph;
86 RuntimeGraph runtime_graph(nullptr);
87 RuntimeToIR runtime_to_ir;
88 GraphLoader graph_loader(&_graph, &runtime_graph, runtime_to_ir, graph_to_runtime_graph,
90 graph_loader.loadTensors();
92 KernelBuilder kernel_builder(graph_to_runtime_graph, _node_to_tensor);
94 auto kernel = op->accept(&kernel_builder);
95 return std::unique_ptr<KernelT>(dynamic_cast<KernelT *>(kernel.release()));
98 void checkTensor(const Tensor *tensor, const loco::Node *node)
100 EXPECT_THAT(tensor, Eq(_node_to_tensor.at(node)));
105 std::unordered_map<const loco::Node *, Tensor *> _node_to_tensor;
108 TEST_F(KernelBuilderTest, Add)
110 auto *input1 = createInputNode();
111 auto *input2 = createInputNode();
113 auto *op = createNode<luci::CircleAdd>();
117 op->fusedActivationFunction(luci::FusedActFunc::RELU);
119 auto kernel = buildKernel<kernels::Add>(op);
120 ASSERT_THAT(kernel, NotNull());
122 checkTensor(kernel->input1(), input1);
123 checkTensor(kernel->input2(), input2);
124 checkTensor(kernel->output(), op);
125 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
128 TEST_F(KernelBuilderTest, ArgMax)
130 auto *input = createInputNode();
131 auto *axis = createInputNode();
133 auto *op = createNode<luci::CircleArgMax>();
137 op->output_type(loco::DataType::FLOAT32);
139 auto kernel = buildKernel<kernels::ArgMax>(op);
140 ASSERT_THAT(kernel, NotNull());
142 checkTensor(kernel->input(), input);
143 checkTensor(kernel->axis(), axis);
144 checkTensor(kernel->output(), op);
145 EXPECT_THAT(kernel->params().output_type, Eq(op->output_type()));
148 TEST_F(KernelBuilderTest, AveragePool2D)
150 auto *input = createInputNode();
152 auto *op = createNode<luci::CircleAveragePool2D>();
155 op->padding(luci::Padding::SAME);
160 op->fusedActivationFunction(luci::FusedActFunc::RELU);
162 auto kernel = buildKernel<kernels::AveragePool2D>(op);
163 ASSERT_THAT(kernel, NotNull());
165 checkTensor(kernel->input(), input);
166 checkTensor(kernel->output(), op);
167 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
168 EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h()));
169 EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w()));
170 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
171 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
172 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
175 TEST_F(KernelBuilderTest, Concatenation)
177 auto *input1 = createInputNode();
178 auto *input2 = createInputNode();
180 auto *op = createNode<luci::CircleConcatenation>(2);
181 op->values(0, input1);
182 op->values(1, input2);
185 auto kernel = buildKernel<kernels::Concatenation>(op);
186 ASSERT_THAT(kernel, NotNull());
188 checkTensor(kernel->input(0), input1);
189 checkTensor(kernel->input(1), input2);
190 checkTensor(kernel->output(), op);
191 EXPECT_THAT(kernel->params().axis, Eq(op->axis()));
194 TEST_F(KernelBuilderTest, Conv2D)
196 auto *input = createInputNode();
197 auto *filter = createInputNode();
198 auto *bias = createInputNode();
200 auto *op = createNode<luci::CircleConv2D>();
205 op->padding(luci::Padding::SAME);
208 op->dilation()->h(17);
209 op->dilation()->w(19);
210 op->fusedActivationFunction(luci::FusedActFunc::RELU);
212 auto kernel = buildKernel<kernels::Conv2D>(op);
213 ASSERT_THAT(kernel, NotNull());
215 checkTensor(kernel->input(), input);
216 checkTensor(kernel->filter(), filter);
217 checkTensor(kernel->bias(), bias);
218 checkTensor(kernel->output(), op);
219 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
220 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
221 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
222 EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h()));
223 EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w()));
224 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
227 TEST_F(KernelBuilderTest, DepthToSpace)
229 auto *input = createInputNode();
231 auto *op = createNode<luci::CircleDepthToSpace>();
236 auto kernel = buildKernel<kernels::DepthToSpace>(op);
237 ASSERT_THAT(kernel, NotNull());
239 checkTensor(kernel->input(), input);
240 checkTensor(kernel->output(), op);
241 EXPECT_THAT(kernel->params().block_size, Eq(op->block_size()));
244 TEST_F(KernelBuilderTest, DepthwiseConv2D)
246 auto *input = createInputNode();
247 auto *filter = createInputNode();
248 auto *bias = createInputNode();
250 auto *op = createNode<luci::CircleDepthwiseConv2D>();
255 op->padding(luci::Padding::SAME);
256 op->depthMultiplier(11);
259 op->dilation()->h(19);
260 op->dilation()->w(23);
261 op->fusedActivationFunction(luci::FusedActFunc::RELU);
263 auto kernel = buildKernel<kernels::DepthwiseConv2D>(op);
264 ASSERT_THAT(kernel, NotNull());
266 checkTensor(kernel->input(), input);
267 checkTensor(kernel->filter(), filter);
268 checkTensor(kernel->bias(), bias);
269 checkTensor(kernel->output(), op);
270 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
271 EXPECT_THAT(kernel->params().depth_multiplier, Eq(op->depthMultiplier()));
272 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
273 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
274 EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h()));
275 EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w()));
276 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
279 TEST_F(KernelBuilderTest, Elu)
281 auto *input = createInputNode();
283 auto *op = createNode<luci::CircleElu>();
286 auto kernel = buildKernel<kernels::Elu>(op);
287 ASSERT_THAT(kernel, NotNull());
289 checkTensor(kernel->input(), input);
290 checkTensor(kernel->output(), op);
293 TEST_F(KernelBuilderTest, FullyConnected)
295 auto *input = createInputNode();
296 auto *weights = createInputNode();
297 auto *bias = createInputNode();
299 auto *op = createNode<luci::CircleFullyConnected>();
301 op->weights(weights);
304 op->fusedActivationFunction(luci::FusedActFunc::RELU);
306 auto kernel = buildKernel<kernels::FullyConnected>(op);
307 ASSERT_THAT(kernel, NotNull());
309 checkTensor(kernel->input(), input);
310 checkTensor(kernel->weights(), weights);
311 checkTensor(kernel->bias(), bias);
312 checkTensor(kernel->output(), op);
313 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
316 TEST_F(KernelBuilderTest, L2Normalize)
318 auto *input = createInputNode();
320 auto *op = createNode<luci::CircleL2Normalize>();
323 op->fusedActivationFunction(luci::FusedActFunc::RELU);
325 auto kernel = buildKernel<kernels::L2Normalize>(op);
326 ASSERT_THAT(kernel, NotNull());
328 checkTensor(kernel->input(), input);
329 checkTensor(kernel->output(), op);
330 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
333 TEST_F(KernelBuilderTest, L2Pool2D)
335 auto *input = createInputNode();
337 auto *op = createNode<luci::CircleL2Pool2D>();
340 op->padding(luci::Padding::SAME);
345 op->fusedActivationFunction(luci::FusedActFunc::RELU);
347 auto kernel = buildKernel<kernels::L2Pool2D>(op);
348 ASSERT_THAT(kernel, NotNull());
350 checkTensor(kernel->input(), input);
351 checkTensor(kernel->output(), op);
352 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
353 EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h()));
354 EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w()));
355 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
356 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
357 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
360 TEST_F(KernelBuilderTest, LeakyRelu)
362 auto *input = createInputNode();
364 auto *op = createNode<luci::CircleLeakyRelu>();
369 auto kernel = buildKernel<kernels::LeakyRelu>(op);
370 ASSERT_THAT(kernel, NotNull());
372 checkTensor(kernel->input(), input);
373 checkTensor(kernel->output(), op);
374 EXPECT_THAT(kernel->params().alpha, Eq(op->alpha()));
377 TEST_F(KernelBuilderTest, LocalResponseNormalization)
379 auto *input = createInputNode();
381 auto *op = createNode<luci::CircleLocalResponseNormalization>();
389 auto kernel = buildKernel<kernels::LocalResponseNormalization>(op);
390 ASSERT_THAT(kernel, NotNull());
392 checkTensor(kernel->input(), input);
393 checkTensor(kernel->output(), op);
394 EXPECT_THAT(kernel->params().radius, Eq(op->radius()));
395 EXPECT_THAT(kernel->params().bias, Eq(op->bias()));
396 EXPECT_THAT(kernel->params().alpha, Eq(op->alpha()));
397 EXPECT_THAT(kernel->params().beta, Eq(op->beta()));
400 TEST_F(KernelBuilderTest, Logistic)
402 auto *input = createInputNode();
404 auto *op = createNode<luci::CircleLogistic>();
407 auto kernel = buildKernel<kernels::Logistic>(op);
408 ASSERT_THAT(kernel, NotNull());
410 checkTensor(kernel->input(), input);
411 checkTensor(kernel->output(), op);
414 TEST_F(KernelBuilderTest, MaxPool2D)
416 auto *input = createInputNode();
418 auto *op = createNode<luci::CircleMaxPool2D>();
421 op->padding(luci::Padding::SAME);
426 op->fusedActivationFunction(luci::FusedActFunc::RELU);
428 auto kernel = buildKernel<kernels::MaxPool2D>(op);
429 ASSERT_THAT(kernel, NotNull());
431 checkTensor(kernel->input(), input);
432 checkTensor(kernel->output(), op);
433 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
434 EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h()));
435 EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w()));
436 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
437 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
438 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
441 TEST_F(KernelBuilderTest, Mean)
443 auto *input = createInputNode();
444 auto *axes = createInputNode();
446 auto *op = createNode<luci::CircleMean>();
448 op->reduction_indices(axes);
452 auto kernel = buildKernel<kernels::Mean>(op);
453 ASSERT_THAT(kernel, NotNull());
455 checkTensor(kernel->input(), input);
456 checkTensor(kernel->axes(), axes);
457 checkTensor(kernel->output(), op);
458 EXPECT_THAT(kernel->params().keep_dims, Eq(op->keep_dims()));
461 TEST_F(KernelBuilderTest, Mul)
463 auto *input1 = createInputNode();
464 auto *input2 = createInputNode();
466 auto *op = createNode<luci::CircleMul>();
470 op->fusedActivationFunction(luci::FusedActFunc::RELU);
472 auto kernel = buildKernel<kernels::Mul>(op);
473 ASSERT_THAT(kernel, NotNull());
475 checkTensor(kernel->input1(), input1);
476 checkTensor(kernel->input2(), input2);
477 checkTensor(kernel->output(), op);
478 EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
481 TEST_F(KernelBuilderTest, Pad)
483 auto *input = createInputNode();
484 auto *paddings = createInputNode();
486 auto *op = createNode<luci::CirclePad>();
488 op->paddings(paddings);
490 auto kernel = buildKernel<kernels::Pad>(op);
491 ASSERT_THAT(kernel, NotNull());
493 checkTensor(kernel->input(), input);
494 checkTensor(kernel->paddings(), paddings);
495 checkTensor(kernel->output(), op);
498 TEST_F(KernelBuilderTest, Reshape)
500 auto *input = createInputNode();
501 auto *shape = createInputNode();
503 auto *op = createNode<luci::CircleReshape>();
507 auto kernel = buildKernel<kernels::Reshape>(op);
508 ASSERT_THAT(kernel, NotNull());
510 checkTensor(kernel->input(), input);
511 checkTensor(kernel->shape(), shape);
512 checkTensor(kernel->output(), op);
515 TEST_F(KernelBuilderTest, ReverseV2)
517 auto *input = createInputNode();
518 auto *axes = createInputNode();
520 auto *op = createNode<luci::CircleReverseV2>();
524 auto kernel = buildKernel<kernels::Reverse>(op);
525 ASSERT_THAT(kernel, NotNull());
527 checkTensor(kernel->input(), input);
528 checkTensor(kernel->axes(), axes);
529 checkTensor(kernel->output(), op);
532 TEST_F(KernelBuilderTest, Slice)
534 auto *input = createInputNode();
535 auto *begin = createInputNode();
536 auto *size = createInputNode();
538 auto *op = createNode<luci::CircleSlice>();
543 auto kernel = buildKernel<kernels::Slice>(op);
544 ASSERT_THAT(kernel, NotNull());
546 checkTensor(kernel->input(), input);
547 checkTensor(kernel->begin(), begin);
548 checkTensor(kernel->size(), size);
549 checkTensor(kernel->output(), op);
552 TEST_F(KernelBuilderTest, Softmax)
554 auto *input = createInputNode();
556 auto *op = createNode<luci::CircleSoftmax>();
561 auto kernel = buildKernel<kernels::Softmax>(op);
562 ASSERT_THAT(kernel, NotNull());
564 checkTensor(kernel->input(), input);
565 checkTensor(kernel->output(), op);
566 EXPECT_THAT(kernel->params().beta, Eq(op->beta()));
569 TEST_F(KernelBuilderTest, SpaceToDepth)
571 auto *input = createInputNode();
573 auto *op = createNode<luci::CircleSpaceToDepth>();
578 auto kernel = buildKernel<kernels::SpaceToDepth>(op);
579 ASSERT_THAT(kernel, NotNull());
581 checkTensor(kernel->input(), input);
582 checkTensor(kernel->output(), op);
583 EXPECT_THAT(kernel->params().block_size, op->block_size());
586 TEST_F(KernelBuilderTest, Split)
588 auto *axis = createInputNode();
589 auto *input = createInputNode();
590 auto *op = createNode<luci::CircleSplit>();
591 auto *output1 = createNodeOut<luci::CircleSplitOut>(op, 0);
592 auto *output2 = createNodeOut<luci::CircleSplitOut>(op, 1);
599 auto kernel = buildKernel<kernels::Split>(op);
600 ASSERT_THAT(kernel, NotNull());
602 checkTensor(kernel->axis(), axis);
603 checkTensor(kernel->input(), input);
604 checkTensor(kernel->output(0), output1);
605 checkTensor(kernel->output(1), output2);
608 TEST_F(KernelBuilderTest, Squeeze)
610 auto *input = createInputNode();
612 auto *op = createNode<luci::CircleSqueeze>();
615 op->squeeze_dims({11, 13});
617 auto kernel = buildKernel<kernels::Squeeze>(op);
618 ASSERT_THAT(kernel, NotNull());
620 checkTensor(kernel->input(), input);
621 checkTensor(kernel->output(), op);
622 EXPECT_THAT(kernel->params().squeeze_dims, ElementsAreArray(op->squeeze_dims()));
625 TEST_F(KernelBuilderTest, StridedSlice)
627 auto *input = createInputNode();
628 auto *begin = createInputNode();
629 auto *end = createInputNode();
630 auto *strides = createInputNode();
632 auto *op = createNode<luci::CircleStridedSlice>();
636 op->strides(strides);
639 op->ellipsis_mask(13);
641 op->new_axis_mask(19);
642 op->shrink_axis_mask(23);
644 auto kernel = buildKernel<kernels::StridedSlice>(op);
645 ASSERT_THAT(kernel, NotNull());
647 checkTensor(kernel->input(), input);
648 checkTensor(kernel->begin(), begin);
649 checkTensor(kernel->end(), end);
650 checkTensor(kernel->strides(), strides);
651 checkTensor(kernel->output(), op);
652 EXPECT_THAT(kernel->params().begin_mask, Eq(op->begin_mask()));
653 EXPECT_THAT(kernel->params().ellipsis_mask, Eq(op->ellipsis_mask()));
654 EXPECT_THAT(kernel->params().end_mask, Eq(op->end_mask()));
655 EXPECT_THAT(kernel->params().new_axis_mask, Eq(op->new_axis_mask()));
656 EXPECT_THAT(kernel->params().shrink_axis_mask, Eq(op->shrink_axis_mask()));
659 TEST_F(KernelBuilderTest, Transpose)
661 auto *input = createInputNode();
662 auto *perm = createInputNode();
664 auto *op = createNode<luci::CircleTranspose>();
668 auto kernel = buildKernel<kernels::Transpose>(op);
669 ASSERT_THAT(kernel, NotNull());
671 checkTensor(kernel->input(), input);
672 checkTensor(kernel->perm(), perm);
673 checkTensor(kernel->output(), op);
676 TEST_F(KernelBuilderTest, TransposeConv)
678 auto *output_shape = createInputNode();
679 auto *filter = createInputNode();
680 auto *input = createInputNode();
682 auto *op = createNode<luci::CircleTransposeConv>();
683 op->inputSizes(output_shape);
685 op->outBackprop(input);
687 op->padding(luci::Padding::SAME);
691 auto kernel = buildKernel<kernels::TransposeConv>(op);
692 ASSERT_THAT(kernel, NotNull());
694 checkTensor(kernel->output_shape(), output_shape);
695 checkTensor(kernel->filter(), filter);
696 checkTensor(kernel->input(), input);
697 checkTensor(kernel->output(), op);
698 EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
699 EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
700 EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
703 TEST_F(KernelBuilderTest, Unpack)
705 auto *input = createInputNode();
706 auto *op = createNode<luci::CircleUnpack>();
707 auto *output1 = createNodeOut<luci::CircleUnpackOut>(op, 0);
708 auto *output2 = createNodeOut<luci::CircleUnpackOut>(op, 1);
715 auto kernel = buildKernel<kernels::Unpack>(op);
716 ASSERT_THAT(kernel, NotNull());
718 checkTensor(kernel->input(), input);
719 checkTensor(kernel->output(0), output1);
720 checkTensor(kernel->output(1), output2);
721 EXPECT_THAT(kernel->params().axis, Eq(op->axis()));
724 TEST_F(KernelBuilderTest, NonExisting1_NEG)
726 auto *op = createNode<luci::CircleConst>();
727 ASSERT_ANY_THROW(buildKernel<Kernel>(op));
730 TEST_F(KernelBuilderTest, NonExisting2_NEG)
732 auto *op = createNode<luci::CircleInput>();
733 ASSERT_ANY_THROW(buildKernel<Kernel>(op));
736 TEST_F(KernelBuilderTest, NonExisting3_NEG)
738 auto *op = createNode<luci::CircleOutput>();
739 ASSERT_ANY_THROW(buildKernel<Kernel>(op));
743 } // namespace luci_interpreter