fc0e60614135e807db3c830d2e3ee7525377451a
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / kernels / Mul.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/Mul.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 MulTest : 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 TEST_F(MulTest, Float)
40 {
41   Shape base_shape = {2, 3, 1, 2};
42   std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
43   std::vector<std::vector<float>> test_outputs = {
44     {0.00f, 0.69f, 0.12f, 1.15f, 0.00f, 2.07f, 0.18f, 0.15f, 0.00f, 0.25f, 0.90f, 0.45f,
45      0.16f, 0.00f, 0.00f, 0.00f, 0.80f, 0.00f, 0.24f, 0.84f, 0.00f, 1.40f, 1.20f, 2.52f,
46      0.00f, 0.00f, 0.64f, 0.00f, 0.00f, 0.00f, 0.14f, 0.00f, 0.00f, 0.00f, 0.70f, 0.00f},
47     {0.00f, 0.69f, 0.00f, 0.25f, 0.80f, 0.00f, 0.24f, 0.84f, 0.64f, 0.00f, 0.70f, 0.00f},
48     {0.00f, 0.46f, 0.00f, 0.69f, 0.12f, 0.00f, 0.18f, 0.10f, 0.27f, 0.15f, 0.00f, 0.00f,
49      0.16f, 0.00f, 0.24f, 0.00f, 0.00f, 0.44f, 0.60f, 1.40f, 1.20f, 2.80f, 1.08f, 2.52f,
50      0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.35f, 0.00f, 0.70f, 0.00f, 0.63f, 0.00f},
51     {0.00f, 0.46f, 0.27f, 0.15f, 0.00f, 0.44f, 0.60f, 1.40f, 0.00f, 0.00f, 0.63f, 0.00f}};
52   std::vector<float> input1_data{-0.3f, 2.3f, 0.9f,  0.5f, 0.8f, -1.1f,
53                                  1.2f,  2.8f, -1.6f, 0.0f, 0.7f, -2.2f};
54   std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f};
55   for (size_t i = 0; i < test_shapes.size(); ++i)
56   {
57     Tensor input1_tensor =
58       makeInputTensor<DataType::FLOAT32>(base_shape, input1_data, _memory_manager.get());
59     Tensor input2_tensor =
60       makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data, _memory_manager.get());
61     Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
62
63     MulParams params{};
64     params.activation = Activation::RELU;
65
66     Mul 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[i], 0.0001f))
72       << "With shape number " << i;
73   }
74   // Re-run with exchanged inputs.
75   for (size_t i = 0; i < test_shapes.size(); ++i)
76   {
77     Tensor input1_tensor =
78       makeInputTensor<DataType::FLOAT32>(test_shapes[i], input2_data, _memory_manager.get());
79     Tensor input2_tensor =
80       makeInputTensor<DataType::FLOAT32>(base_shape, input1_data, _memory_manager.get());
81     Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
82
83     MulParams params{};
84     params.activation = Activation::RELU;
85
86     Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
87     kernel.configure();
88     _memory_manager->allocate_memory(output_tensor);
89     kernel.execute();
90
91     EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(test_outputs[i], 0.0001f))
92       << "With shape number " << i;
93   }
94 }
95
96 template <loco::DataType DType> void checkInteger(luci_interpreter::IMemoryManager *memory_manager)
97 {
98   using dtype = typename loco::DataTypeImpl<DType>::Type;
99   Shape base_shape = {2, 3, 1, 2};
100   std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
101
102   dtype max_value = std::numeric_limits<dtype>::max();
103   dtype res_max = max_value - max_value % 10;
104
105   std::vector<std::vector<dtype>> test_outputs = {
106     {8,  0, 20,  0, 4,  30,  //
107      16, 0, 40,  3, 8,  0,   //
108      0,  0, 0,   6, 0,  0,   //
109      4,  0, 10,  9, 2,  0,   //
110      40, 0, 100, 0, 20, 150, //
111      28, 0, 70,  0, 14, res_max},
112     {8, 0, 40, 3, 0, 0, 4, 0, 100, 0, 14, res_max},
113     {8,  12,     0, 0, 20, 30, 16, 0, 0, 0,  40, 0,   0,   0, 0, 0,  0,
114      0,  0,      9, 2, 0,  10, 0,  0, 0, 20, 30, 100, 150, 0, 0, 14, max_value / 10 * 2,
115      70, res_max},
116     {8, 12, 0, 0, 0, 0, 0, 9, 20, 30, 70, res_max}};
117   std::vector<dtype> input1_data{2, 3, 4, -1, -3, -2, 1, -3, 10, 15, 7, max_value / 10};
118   std::vector<dtype> input2_data{4, 0, 10, -3, 2, 10};
119   for (size_t i = 0; i < test_shapes.size(); ++i)
120   {
121     Tensor input1_tensor = makeInputTensor<DType>(base_shape, input1_data, memory_manager);
122     Tensor input2_tensor = makeInputTensor<DType>(test_shapes[i], input2_data, memory_manager);
123     Tensor output_tensor = makeOutputTensor(DType);
124
125     MulParams params{};
126     params.activation = Activation::RELU;
127
128     Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
129     kernel.configure();
130     memory_manager->allocate_memory(output_tensor);
131     kernel.execute();
132
133     EXPECT_THAT(extractTensorData<dtype>(output_tensor), test_outputs[i])
134       << "With shape number " << i;
135   }
136   // Re-run with exchanged inputs.
137   for (size_t i = 0; i < test_shapes.size(); ++i)
138   {
139     Tensor input1_tensor = makeInputTensor<DType>(test_shapes[i], input2_data, memory_manager);
140     Tensor input2_tensor = makeInputTensor<DType>(base_shape, input1_data, memory_manager);
141     Tensor output_tensor = makeOutputTensor(DType);
142
143     MulParams params{};
144     params.activation = Activation::RELU;
145
146     Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
147     kernel.configure();
148     memory_manager->allocate_memory(output_tensor);
149     kernel.execute();
150
151     EXPECT_THAT(extractTensorData<dtype>(output_tensor), test_outputs[i])
152       << "With shape number " << i;
153   }
154 }
155
156 TEST_F(MulTest, SInt64)
157 {
158   checkInteger<loco::DataType::S64>(_memory_manager.get());
159   SUCCEED();
160 }
161
162 TEST_F(MulTest, SInt32)
163 {
164   checkInteger<loco::DataType::S32>(_memory_manager.get());
165   SUCCEED();
166 }
167
168 TEST_F(MulTest, SInt16)
169 {
170   Shape base_shape = {2, 3, 1, 2};
171   std::vector<Shape> test_shapes{{1, 1, 3, 2}, {1, 3, 1, 2}, {2, 1, 3, 1}, {2, 3, 1, 1}};
172   std::vector<std::vector<int32_t>> ref_output_shapes{
173     {2, 3, 3, 2}, {2, 3, 1, 2}, {2, 3, 3, 2}, {2, 3, 1, 2}};
174
175   std::vector<float> input1_data{-0.3f, 2.3f, 0.9f,  0.5f, 0.8f, -1.1f,
176                                  1.2f,  2.8f, -1.6f, 0.0f, 0.7f, -2.2f};
177   std::vector<float> input2_data{0.2f, 0.3f, -0.4f, 0.5f, 1.0f, 0.9f};
178   std::vector<std::vector<float>> ref_outputs = {
179     {0.00f, 0.69f, 0.12f, 1.15f, 0.00f, 2.07f, 0.18f, 0.15f, 0.00f, 0.25f, 0.90f, 0.45f,
180      0.16f, 0.00f, 0.00f, 0.00f, 0.80f, 0.00f, 0.24f, 0.84f, 0.00f, 1.40f, 1.20f, 2.52f,
181      0.00f, 0.00f, 0.64f, 0.00f, 0.00f, 0.00f, 0.14f, 0.00f, 0.00f, 0.00f, 0.70f, 0.00f},
182     {0.00f, 0.69f, 0.00f, 0.25f, 0.80f, 0.00f, 0.24f, 0.84f, 0.64f, 0.00f, 0.70f, 0.00f},
183     {0.00f, 0.46f, 0.00f, 0.69f, 0.12f, 0.00f, 0.18f, 0.10f, 0.27f, 0.15f, 0.00f, 0.00f,
184      0.16f, 0.00f, 0.24f, 0.00f, 0.00f, 0.44f, 0.60f, 1.40f, 1.20f, 2.80f, 1.08f, 2.52f,
185      0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.35f, 0.00f, 0.70f, 0.00f, 0.63f, 0.00f},
186     {0.00f, 0.46f, 0.27f, 0.15f, 0.00f, 0.44f, 0.60f, 1.40f, 0.00f, 0.00f, 0.63f, 0.00f}};
187   for (size_t i = 0; i < test_shapes.size(); ++i)
188   {
189     Tensor input1_tensor = makeInputTensor<DataType::S16>(base_shape, 3.0 / 32767, 0, input1_data,
190                                                           _memory_manager.get());
191     Tensor input2_tensor = makeInputTensor<DataType::S16>(test_shapes[i], 1.0 / 32767, 0,
192                                                           input2_data, _memory_manager.get());
193     Tensor output_tensor = makeOutputTensor(DataType::S16, 4.0 / 32767, 0);
194     const float tolerance = output_tensor.scale() * 2;
195
196     MulParams params{};
197     params.activation = Activation::RELU;
198
199     Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
200     kernel.configure();
201     _memory_manager->allocate_memory(output_tensor);
202     kernel.execute();
203
204     EXPECT_THAT(extractTensorShape(output_tensor),
205                 ::testing::ElementsAreArray(ref_output_shapes[i]))
206       << "With shape number " << i;
207     EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_outputs[i], tolerance))
208       << "With shape number " << i;
209   }
210   // Re-run with exchanged inputs and different scales.
211   for (size_t i = 0; i < test_shapes.size(); ++i)
212   {
213     Tensor input1_tensor = makeInputTensor<DataType::S16>(test_shapes[i], 2.0 / 32767, 0,
214                                                           input2_data, _memory_manager.get());
215     Tensor input2_tensor = makeInputTensor<DataType::S16>(base_shape, 4.0 / 32767, 0, input1_data,
216                                                           _memory_manager.get());
217     Tensor output_tensor = makeOutputTensor(DataType::S16, 3.0 / 32767, 0);
218     const float tolerance = output_tensor.scale() * 2;
219
220     MulParams params{};
221     params.activation = Activation::RELU;
222
223     Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
224     kernel.configure();
225     _memory_manager->allocate_memory(output_tensor);
226     kernel.execute();
227
228     EXPECT_THAT(extractTensorShape(output_tensor),
229                 ::testing::ElementsAreArray(ref_output_shapes[i]))
230       << "With shape number " << i;
231     EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_outputs[i], tolerance))
232       << "With shape number " << i;
233   }
234 }
235
236 TEST_F(MulTest, Input_Output_Type_NEG)
237 {
238   Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}, _memory_manager.get());
239   Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}, _memory_manager.get());
240   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
241
242   MulParams params{};
243   params.activation = Activation::RELU;
244
245   Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
246   EXPECT_ANY_THROW(kernel.configure());
247 }
248
249 TEST_F(MulTest, Invalid_Output_Type_NEG)
250 {
251   Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}, _memory_manager.get());
252   Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}, _memory_manager.get());
253   Tensor output_tensor = makeOutputTensor(DataType::S32);
254
255   MulParams params{};
256   params.activation = Activation::RELU;
257
258   Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
259   EXPECT_ANY_THROW(kernel.configure());
260 }
261
262 TEST_F(MulTest, Invalid_Input_Type_NEG)
263 {
264   Tensor input1_tensor = makeInputTensor<DataType::U64>({1}, {1}, _memory_manager.get());
265   Tensor input2_tensor = makeInputTensor<DataType::U64>({1}, {2}, _memory_manager.get());
266   Tensor output_tensor = makeOutputTensor(DataType::U64);
267
268   MulParams params{};
269   params.activation = Activation::RELU;
270
271   Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
272   kernel.configure();
273   _memory_manager->allocate_memory(output_tensor);
274   EXPECT_ANY_THROW(kernel.execute());
275 }
276
277 TEST_F(MulTest, Invalid_Quantization_NEG)
278 {
279   Tensor input1_tensor = makeInputTensor<DataType::S16>({1}, {1}, _memory_manager.get());
280   Tensor input2_tensor = makeInputTensor<DataType::S16>({1}, {2}, _memory_manager.get());
281   Tensor output_tensor = makeOutputTensor(DataType::S16);
282
283   MulParams params{};
284   params.activation = Activation::NONE;
285
286   Mul kernel(&input1_tensor, &input2_tensor, &output_tensor, params);
287   EXPECT_ANY_THROW(kernel.configure());
288 }
289
290 } // namespace
291 } // namespace kernels
292 } // namespace luci_interpreter