Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compiler / luci-interpreter / src / kernels / Conv2D.test.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 "kernels/Conv2D.h"
18 #include "kernels/TestUtils.h"
19
20 namespace luci_interpreter
21 {
22 namespace kernels
23 {
24 namespace
25 {
26
27 using namespace testing;
28
29 TEST(Conv2DTest, Float)
30 {
31   Shape input_shape{1, 4, 3, 2};
32   Shape filter_shape{2, 2, 2, 2};
33   Shape bias_shape{2};
34   std::vector<float> input_data{
35       1,  2,  3,  4,  5,  6,  // row = 0
36       7,  8,  9,  10, 11, 12, // row = 1
37       13, 14, 15, 16, 17, 18, // row = 2
38       19, 20, 21, 22, 23, 24, // row = 3
39   };
40   std::vector<float> filter_data{
41       1,  2,  -3, -4, // out = 0, row = 0
42       -5, 6,  -7, 8,  // out = 1, row = 0
43       4,  -2, 3,  -1, // out = 0, row = 1
44       -8, -6, 7,  5,  // out = 1, row = 1
45   };
46   std::vector<float> bias_data{1, 2};
47   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
48   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
49   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
50   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
51
52   Conv2DParams params{};
53   params.padding = Padding::VALID;
54   params.stride_height = 2;
55   params.stride_width = 1;
56   params.dilation_height_factor = 1;
57   params.dilation_width_factor = 1;
58   params.activation = Activation::RELU;
59
60   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
61   kernel.configure();
62   kernel.execute();
63
64   std::vector<float> ref_output_data{
65       11, 16, 7, 20, // row = 0
66       0,  40, 0, 44, // row = 1
67   };
68   std::vector<int32_t> ref_output_shape{1, 2, 2, 2};
69   EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data));
70   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
71 }
72
73 TEST(Conv2DTest, FloatCheck)
74 {
75   Shape input_shape{2, 2, 4, 1};
76   Shape filter_shape{3, 2, 2, 1};
77   Shape bias_shape{3};
78   std::vector<float> input_data{
79       // First batch
80       1, 1, 1, 1, // row = 1
81       2, 2, 2, 2, // row = 2
82       // Second batch
83       1, 2, 3, 4, // row = 1
84       1, 2, 3, 4, // row = 2
85   };
86   std::vector<float> filter_data{
87       1,  2,  3,  4, // first 2x2 filter
88       -1, 1,  -1, 1, // second 2x2 filter
89       -1, -1, 1,  1, // third 2x2 filter
90   };
91   std::vector<float> bias_data{1, 2, 3};
92   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
93   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
94   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
95   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
96
97   Conv2DParams params{};
98   params.padding = Padding::VALID;
99   params.stride_height = 2;
100   params.stride_width = 2;
101   params.dilation_height_factor = 1;
102   params.dilation_width_factor = 1;
103   params.activation = Activation::NONE;
104
105   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
106   kernel.configure();
107   kernel.execute();
108
109   std::vector<float> ref_output_data{
110       18, 2, 5, // first batch, left
111       18, 2, 5, // first batch, right
112       17, 4, 3, // second batch, left
113       37, 4, 3, // second batch, right
114   };
115   std::vector<int32_t> ref_output_shape{2, 1, 2, 3};
116   EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data));
117   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
118 }
119
120 TEST(Conv2DTest, Uint8)
121 {
122   std::vector<float> input_data{
123       // First batch
124       1, 1, 1, 1, // row = 1
125       2, 2, 2, 2, // row = 2
126                   // Second batch
127       1, 2, 3, 4, // row = 1
128       1, 2, 3, 4, // row = 2
129   };
130   std::vector<float> filter_data{
131       1,  2,  3,  4, // first 2x2 filter
132       -1, 1,  -1, 1, // second 2x2 filter
133       -1, -1, 1,  1, // third 2x2 filter
134   };
135   std::vector<float> bias_data{1, 2, 3};
136
137   std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64);
138   std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128);
139
140   Tensor input_tensor = makeInputTensor<DataType::U8>({2, 2, 4, 1}, input_quant_param.first,
141                                                       input_quant_param.second, input_data);
142   Tensor filter_tensor = makeInputTensor<DataType::U8>({3, 2, 2, 1}, input_quant_param.first,
143                                                        input_quant_param.second, filter_data);
144   Tensor bias_tensor = makeInputTensor<DataType::S32>(
145       {3}, input_quant_param.first * input_quant_param.first, 0, bias_data);
146   Tensor output_tensor =
147       makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second);
148
149   Conv2DParams params{};
150   params.padding = Padding::VALID;
151   params.stride_height = 2;
152   params.stride_width = 2;
153   params.dilation_height_factor = 1;
154   params.dilation_width_factor = 1;
155   params.activation = Activation::NONE;
156
157   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
158   kernel.configure();
159   kernel.execute();
160
161   std::vector<float> ref_output_data{
162       18, 2, 5, // first batch, left
163       18, 2, 5, // first batch, right
164       17, 4, 3, // second batch, left
165       37, 4, 3, // second batch, right
166   };
167   std::vector<int32_t> ref_output_shape{2, 1, 2, 3};
168   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
169   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
170 }
171
172 TEST(Conv2DTest, Uint8_CWQ)
173 {
174   const int output_channels = 3;
175   std::vector<float> input_data{
176       // First batch
177       1, 1, 1, 1, // row = 1
178       2, 2, 2, 2, // row = 2
179                   // Second batch
180       1, 2, 3, 4, // row = 1
181       1, 2, 3, 4, // row = 2
182   };
183   std::vector<float> filter_data{
184       1,  2,  3,  4, // first 2x2 filter
185       -1, 1,  -1, 1, // second 2x2 filter
186       -1, -1, 1,  1, // third 2x2 filter
187   };
188   std::vector<float> bias_data{1, 2, 3};
189   Shape filter_shape{output_channels, 2, 2, 1};
190
191   std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(0, 4);
192   std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128);
193
194   std::vector<std::pair<float, int32_t>> filter_quant_params;
195   filter_quant_params.push_back(quantizationParams<uint8_t>(0, 4));
196   filter_quant_params.push_back(quantizationParams<uint8_t>(-1, 1));
197   filter_quant_params.push_back(quantizationParams<uint8_t>(-1, 1));
198
199   std::vector<float> filter_scales;
200   std::vector<int32_t> filter_zerops;
201   for (auto iter : filter_quant_params)
202   {
203     filter_scales.push_back(iter.first);
204     filter_zerops.push_back(iter.second);
205   }
206
207   std::vector<float> bias_scales;
208   for (int i = 0; i < output_channels; ++i)
209     bias_scales.push_back(filter_quant_params[i].first * input_quant_param.first);
210   std::vector<int32_t> zerop(output_channels, 0);
211
212   Tensor input_tensor = makeInputTensor<DataType::U8>({2, 2, 4, 1}, input_quant_param.first,
213                                                       input_quant_param.second, input_data);
214   Tensor filter_tensor =
215       makeInputTensor<DataType::U8>(filter_shape, filter_scales, filter_zerops, 0, filter_data);
216   Tensor bias_tensor =
217       makeInputTensor<DataType::S32>({output_channels}, bias_scales, zerop, 0, bias_data);
218   Tensor output_tensor =
219       makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second);
220
221   Conv2DParams params{};
222   params.padding = Padding::VALID;
223   params.stride_height = 2;
224   params.stride_width = 2;
225   params.dilation_height_factor = 1;
226   params.dilation_width_factor = 1;
227   params.activation = Activation::NONE;
228
229   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
230   kernel.configure();
231   kernel.execute();
232
233   std::vector<float> ref_output_data{
234       18, 2, 5, // first batch, left
235       18, 2, 5, // first batch, right
236       17, 4, 3, // second batch, left
237       37, 4, 3, // second batch, right
238   };
239   std::vector<int32_t> ref_output_shape{2, 1, 2, 3};
240   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
241   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
242 }
243
244 TEST(Conv2DTest, SInt16)
245 {
246   Shape input_shape{1, 4, 3, 2};
247   Shape filter_shape{2, 2, 2, 2};
248   Shape bias_shape{2};
249   std::vector<int32_t> ref_output_shape{1, 2, 2, 2};
250
251   std::vector<float> input_data{
252       1,  2,  3,  4,  5,  6,  // row = 0
253       7,  8,  9,  10, 11, 12, // row = 1
254       13, 14, 15, 16, 17, 18, // row = 2
255       19, 20, 21, 22, 23, 24, // row = 3
256   };
257   std::vector<float> filter_data{
258       1,  2,  -3, -4, // out = 0, row = 0
259       -5, 6,  -7, 8,  // out = 1, row = 0
260       4,  -2, 3,  -1, // out = 0, row = 1
261       -8, -6, 7,  5,  // out = 1, row = 1
262   };
263   std::vector<float> bias_data{1, 2};
264   std::vector<float> ref_output_data{
265       11, 16, 7, 20, // row = 0
266       0,  40, 0, 44, // row = 1
267   };
268
269   Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.25, 0, input_data);
270   Tensor filter_tensor = makeInputTensor<DataType::S16>(filter_shape, 0.2, 0, filter_data);
271   Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, 0.25 * 0.2, 0, bias_data);
272   Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
273
274   Conv2DParams params{};
275   params.padding = Padding::VALID;
276   params.stride_height = 2;
277   params.stride_width = 1;
278   params.dilation_height_factor = 1;
279   params.dilation_width_factor = 1;
280   params.activation = Activation::RELU;
281
282   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
283   kernel.configure();
284   kernel.execute();
285
286   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
287   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
288 }
289
290 TEST(Conv2DTest, SInt16_CWQ_weights)
291 {
292   Shape input_shape{1, 2, 2, 2};  // Batch x H x W x C
293   Shape filter_shape{3, 1, 1, 2}; // Out channels x H x W x In Channels
294   Shape bias_shape{3};
295   std::vector<int32_t> ref_output_shape{1, 2, 2, 3};
296
297   std::vector<float> input_data{
298       1, 2, // row = 0, col 0
299       3, 4, // row = 0, col 1
300       5, 6, // row = 1, col 0
301       7, 8, // row = 1, col 1
302   };
303   std::vector<float> filter_data{
304       4, -3, // out = 0
305       1, -3, // out = 1
306       5, -3, // out = 2
307   };
308   std::vector<float> bias_data{1, 10, 5};
309   std::vector<float> ref_output_data{
310       0, 5, 4,  // row 0, col 0
311       1, 1, 8,  // row 0, col 1
312       3, 0, 12, // row 1, col 0
313       5, 0, 16, // row 1, col 1
314   };
315
316   float input_scale = 0.25f;
317   float output_scale = 0.05f;
318   std::vector<float> filter_scales = {0.25f, 0.2f, 0.1f};
319   std::vector<float> bias_scales;
320   for (int i = 0; i < filter_scales.size(); ++i)
321     bias_scales.push_back(filter_scales[i] * input_scale);
322   std::vector<int32_t> zerop = {0, 0, 0};
323
324   Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
325   Tensor filter_tensor =
326       makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 0, filter_data);
327   Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
328   Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0);
329
330   Conv2DParams params{};
331   params.padding = Padding::VALID;
332   params.stride_height = 1;
333   params.stride_width = 1;
334   params.dilation_height_factor = 1;
335   params.dilation_width_factor = 1;
336   params.activation = Activation::RELU;
337
338   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
339   kernel.configure();
340   kernel.execute();
341
342   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
343   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
344 }
345
346 TEST(Conv2DTest, Unsupported_Type_Configure_NEG)
347 {
348   Shape input_shape{1, 4, 3, 2};
349   Shape filter_shape{2, 2, 2, 2};
350   Shape bias_shape{2};
351   std::vector<int32_t> input_data{
352       1,  2,  3,  4,  5,  6,  // row = 0
353       7,  8,  9,  10, 11, 12, // row = 1
354       13, 14, 15, 16, 17, 18, // row = 2
355       19, 20, 21, 22, 23, 24, // row = 3
356   };
357   std::vector<float> filter_data{
358       1,  2,  -3, -4, // out = 0, row = 0
359       -5, 6,  -7, 8,  // out = 1, row = 0
360       4,  -2, 3,  -1, // out = 0, row = 1
361       -8, -6, 7,  5,  // out = 1, row = 1
362   };
363   std::vector<float> bias_data{1, 2};
364   Tensor input_tensor = makeInputTensor<DataType::S32>(input_shape, input_data);
365   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
366   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
367   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
368
369   Conv2DParams params{};
370   params.padding = Padding::VALID;
371   params.stride_height = 2;
372   params.stride_width = 1;
373   params.dilation_height_factor = 1;
374   params.dilation_width_factor = 1;
375   params.activation = Activation::RELU;
376
377   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
378   EXPECT_ANY_THROW(kernel.configure());
379 }
380
381 TEST(Conv2DTest, Invalid_Bias_Type_NEG)
382 {
383   Shape input_shape{1, 4, 3, 2};
384   Shape filter_shape{2, 2, 2, 2};
385   Shape bias_shape{2};
386   std::vector<float> input_data{
387       1,  2,  3,  4,  5,  6,  // row = 0
388       7,  8,  9,  10, 11, 12, // row = 1
389       13, 14, 15, 16, 17, 18, // row = 2
390       19, 20, 21, 22, 23, 24, // row = 3
391   };
392   std::vector<float> filter_data{
393       1,  2,  -3, -4, // out = 0, row = 0
394       -5, 6,  -7, 8,  // out = 1, row = 0
395       4,  -2, 3,  -1, // out = 0, row = 1
396       -8, -6, 7,  5,  // out = 1, row = 1
397   };
398   std::vector<uint8_t> bias_data{1, 2};
399   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
400   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
401   Tensor bias_tensor = makeInputTensor<DataType::U8>(bias_shape, bias_data);
402   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
403
404   Conv2DParams params{};
405   params.padding = Padding::VALID;
406   params.stride_height = 2;
407   params.stride_width = 1;
408   params.dilation_height_factor = 1;
409   params.dilation_width_factor = 1;
410   params.activation = Activation::RELU;
411
412   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
413   EXPECT_ANY_THROW(kernel.configure());
414 }
415
416 TEST(Conv2DTest, Invalid_Bias_Data_NEG)
417 {
418   Shape input_shape{1, 4, 3, 2};
419   Shape filter_shape{2, 2, 2, 2};
420   Shape bias_shape{3};
421   std::vector<float> input_data{
422       1,  2,  3,  4,  5,  6,  // row = 0
423       7,  8,  9,  10, 11, 12, // row = 1
424       13, 14, 15, 16, 17, 18, // row = 2
425       19, 20, 21, 22, 23, 24, // row = 3
426   };
427   std::vector<float> filter_data{
428       1,  2,  -3, -4, // out = 0, row = 0
429       -5, 6,  -7, 8,  // out = 1, row = 0
430       4,  -2, 3,  -1, // out = 0, row = 1
431       -8, -6, 7,  5,  // out = 1, row = 1
432   };
433   std::vector<float> bias_data{1, 2, 3};
434   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
435   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
436   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
437   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
438
439   Conv2DParams params{};
440   params.padding = Padding::VALID;
441   params.stride_height = 2;
442   params.stride_width = 1;
443   params.dilation_height_factor = 1;
444   params.dilation_width_factor = 1;
445   params.activation = Activation::RELU;
446
447   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
448   EXPECT_ANY_THROW(kernel.configure());
449 }
450
451 TEST(Conv2DTest, Invalid_Input_Shape_NEG)
452 {
453   Shape input_shape{1, 4, 6, 1};
454   Shape filter_shape{2, 2, 2, 2};
455   Shape bias_shape{2};
456   std::vector<float> input_data{
457       1,  2,  3,  4,  5,  6,  // row = 0
458       7,  8,  9,  10, 11, 12, // row = 1
459       13, 14, 15, 16, 17, 18, // row = 2
460       19, 20, 21, 22, 23, 24, // row = 3
461   };
462   std::vector<float> filter_data{
463       1,  2,  -3, -4, // out = 0, row = 0
464       -5, 6,  -7, 8,  // out = 1, row = 0
465       4,  -2, 3,  -1, // out = 0, row = 1
466       -8, -6, 7,  5,  // out = 1, row = 1
467   };
468   std::vector<float> bias_data{1, 2};
469   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
470   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
471   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
472   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
473
474   Conv2DParams params{};
475   params.padding = Padding::VALID;
476   params.stride_height = 2;
477   params.stride_width = 1;
478   params.dilation_height_factor = 1;
479   params.dilation_width_factor = 1;
480   params.activation = Activation::RELU;
481
482   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
483   EXPECT_ANY_THROW(kernel.configure());
484 }
485
486 } // namespace
487 } // namespace kernels
488 } // namespace luci_interpreter