Imported Upstream version 1.21.0
[platform/core/ml/nnfw.git] / compiler / luci-micro / luci-interpreter / src / kernels / Div.test.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "kernels/Div.h"
19 #include "kernels/TestUtils.h"
20 #include "luci_interpreter/TestMemoryManager.h"
21
22 namespace luci_interpreter
23 {
24 namespace kernels
25 {
26 namespace
27 {
28
29 using namespace testing;
30
31 class DivTest : public ::testing::Test
32 {
33 protected:
34   void SetUp() override { _memory_manager = std::make_unique<TestMemoryManager>(); }
35
36   std::unique_ptr<IMemoryManager> _memory_manager;
37 };
38
39 float GetTolerance(float min, float max)
40 {
41   const float kQuantizedStep = (max - min) / 255.0f;
42   const float kQuantizedTolerance = 2.0f * kQuantizedStep + kQuantizedStep * kQuantizedStep;
43   return kQuantizedTolerance;
44 }
45
46 TEST_F(DivTest, Float)
47 {
48   Shape base_shape = {2, 3, 1, 1};
49
50   std::vector<int32_t> output_shape = {2, 3, 1, 1};
51
52   std::vector<float> input1_data{0.3f, 2.3f, 0.9f, 0.5f, 0.8f, 1.1f};
53   std::vector<float> input2_data{0.2f, 1.6f, 0.5f, 0.4f, 1.6f, 0.4f};
54   std::vector<float> test_outputs{1.5f, 1.4375f, 1.8f, 1.25f, 0.5f, 2.75f};
55
56   Tensor input1_tensor =
57     makeInputTensor<DataType::FLOAT32>(base_shape, input1_data, _memory_manager.get());
58   Tensor input2_tensor =
59     makeInputTensor<DataType::FLOAT32>(base_shape, input2_data, _memory_manager.get());
60
61   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
62
63   DivParams params{};
64   params.activation = Activation::RELU;
65
66   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
67   kernel.configure();
68   _memory_manager->allocate_memory(output_tensor);
69   kernel.execute();
70
71   EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f));
72   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape));
73 }
74
75 TEST_F(DivTest, FloatBroadcast)
76 {
77   Shape input1_shape = {1, 3};
78   Shape input2_shape = {3, 1};
79
80   std::vector<float> input1_data{-0.3f, 2.3f, 0.9f};
81   std::vector<float> input2_data{0.2f, 1.6f, 0.5f};
82   std::vector<float> test_outputs{0.f, 11.5f, 4.5f, 0.f, 1.4375f, 0.5625f, 0.f, 4.6f, 1.8f};
83
84   Tensor input1_tensor =
85     makeInputTensor<DataType::FLOAT32>(input1_shape, input1_data, _memory_manager.get());
86   Tensor input2_tensor =
87     makeInputTensor<DataType::FLOAT32>(input2_shape, input2_data, _memory_manager.get());
88
89   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
90
91   DivParams params{};
92   params.activation = Activation::RELU;
93
94   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
95   kernel.configure();
96   _memory_manager->allocate_memory(output_tensor);
97   kernel.execute();
98
99   EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs, 0.0001f));
100 }
101
102 TEST_F(DivTest, Uint8)
103 {
104   Shape base_shape = {1, 2, 2, 1};
105
106   std::vector<int32_t> output_shape = {1, 2, 2, 1};
107
108   std::vector<float> input1_data = {-0.8f, -0.2f, 0.3f, 0.7f};
109   std::vector<float> input2_data = {-0.8f, 0.4f, 0.8f, 1.0f};
110   std::vector<float> test_outputs{1.0f, 0.f, 0.375f, 0.7f};
111
112   const float kQuantizedTolerance = GetTolerance(-1.0, 1.0);
113
114   std::pair<float, int32_t> quant_param = quantizationParams<uint8_t>(-1.f, 1.f);
115
116   Tensor input1_tensor = makeInputTensor<DataType::U8>(
117     base_shape, quant_param.first, quant_param.second, input1_data, _memory_manager.get());
118   Tensor input2_tensor = makeInputTensor<DataType::U8>(
119     base_shape, quant_param.first, quant_param.second, input2_data, _memory_manager.get());
120
121   Tensor output_tensor =
122     makeOutputTensor(getElementType<uint8_t>(), quant_param.first, quant_param.second);
123
124   DivParams params{};
125   params.activation = Activation::RELU;
126
127   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
128   kernel.configure();
129   _memory_manager->allocate_memory(output_tensor);
130   kernel.execute();
131
132   EXPECT_THAT(dequantizeTensorData(output_tensor),
133               FloatArrayNear(test_outputs, kQuantizedTolerance));
134   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape));
135 }
136
137 template <loco::DataType DType> void checkInteger(luci_interpreter::IMemoryManager *memory_manager)
138 {
139   using dtype = typename loco::DataTypeImpl<DType>::Type;
140   Shape base_shape = {2, 3, 1, 2};
141   std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
142
143   std::vector<std::vector<dtype>> test_outputs = {{5,  6,  2, 0,  10, 3, //
144                                                    10, 0,  4, 5,  20, 0, //
145                                                    0,  0,  0, 2,  0,  0, //
146                                                    2,  0,  1, 10, 5,  0, //
147                                                    2,  3,  1, 0,  5,  1, //
148                                                    18, 20, 7, 0,  37, 10},
149                                                   {5, 6, 4, 5, 0, 0, 2, 0, 1, 0, 37, 10},
150                                                   {5, 7, 4, 6, 2, 3, 10, 0,  8,  0,  4, 0,
151                                                    0, 0, 0, 0, 0, 0, 0,  10, 5,  0,  1, 0,
152                                                    0, 0, 5, 9, 1, 1, 0,  0,  37, 50, 7, 10},
153                                                   {5, 7, 8, 0, 0, 0, 0, 10, 5, 9, 7, 10}};
154   std::vector<dtype> input1_data{20, 30, 40, -17, -4, -7, 11, -31, 10, 19, 75, 100};
155   std::vector<dtype> input2_data{4, 5, 10, -3, 2, 10};
156   for (size_t i = 0; i < test_shapes.size(); ++i)
157   {
158     Tensor input1_tensor = makeInputTensor<DType>(base_shape, input1_data, memory_manager);
159     Tensor input2_tensor = makeInputTensor<DType>(test_shapes[i], input2_data, memory_manager);
160     Tensor output_tensor = makeOutputTensor(DType);
161
162     DivParams params{};
163     params.activation = Activation::RELU;
164
165     Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
166     kernel.configure();
167     memory_manager->allocate_memory(output_tensor);
168     kernel.execute();
169
170     EXPECT_THAT(extractTensorData<dtype>(output_tensor), test_outputs[i])
171       << "With shape number " << i;
172   }
173 }
174
175 TEST_F(DivTest, SInt64)
176 {
177   checkInteger<loco::DataType::S64>(_memory_manager.get());
178   SUCCEED();
179 }
180
181 TEST_F(DivTest, SInt32)
182 {
183   checkInteger<loco::DataType::S32>(_memory_manager.get());
184   SUCCEED();
185 }
186
187 TEST_F(DivTest, Input_Output_Type_NEG)
188 {
189   Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}, _memory_manager.get());
190   Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}, _memory_manager.get());
191   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
192
193   DivParams params{};
194   params.activation = Activation::RELU;
195
196   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
197   EXPECT_ANY_THROW(kernel.configure());
198 }
199
200 TEST_F(DivTest, Invalid_Input_Type_NEG)
201 {
202   Tensor input1_tensor = makeInputTensor<DataType::U64>({1}, {1}, _memory_manager.get());
203   Tensor input2_tensor = makeInputTensor<DataType::U64>({1}, {2}, _memory_manager.get());
204   Tensor output_tensor = makeOutputTensor(DataType::U64);
205
206   DivParams params{};
207   params.activation = Activation::RELU;
208
209   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
210   kernel.configure();
211   _memory_manager->allocate_memory(output_tensor);
212   EXPECT_ANY_THROW(kernel.execute());
213 }
214
215 TEST_F(DivTest, Invalid_Output_Type_NEG)
216 {
217   Tensor input1_tensor = makeInputTensor<DataType::S32>({1}, {1}, _memory_manager.get());
218   Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}, _memory_manager.get());
219   Tensor output_tensor = makeOutputTensor(DataType::S64);
220
221   DivParams params{};
222   params.activation = Activation::RELU;
223
224   Div kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
225   EXPECT_ANY_THROW(kernel.configure());
226 }
227
228 } // namespace
229 } // namespace kernels
230 } // namespace luci_interpreter