7aa66a89818a88dc901dd4e4d13ba2b74e1a1264
[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, SInt16)
173 {
174   Shape input_shape{1, 4, 3, 2};
175   Shape filter_shape{2, 2, 2, 2};
176   Shape bias_shape{2};
177   std::vector<int32_t> ref_output_shape{1, 2, 2, 2};
178
179   std::vector<float> input_data{
180       1,  2,  3,  4,  5,  6,  // row = 0
181       7,  8,  9,  10, 11, 12, // row = 1
182       13, 14, 15, 16, 17, 18, // row = 2
183       19, 20, 21, 22, 23, 24, // row = 3
184   };
185   std::vector<float> filter_data{
186       1,  2,  -3, -4, // out = 0, row = 0
187       -5, 6,  -7, 8,  // out = 1, row = 0
188       4,  -2, 3,  -1, // out = 0, row = 1
189       -8, -6, 7,  5,  // out = 1, row = 1
190   };
191   std::vector<float> bias_data{1, 2};
192   std::vector<float> ref_output_data{
193       11, 16, 7, 20, // row = 0
194       0,  40, 0, 44, // row = 1
195   };
196
197   Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.25, 0, input_data);
198   Tensor filter_tensor = makeInputTensor<DataType::S16>(filter_shape, 0.2, 0, filter_data);
199   Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, 0.25 * 0.2, 0, bias_data);
200   Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
201
202   Conv2DParams params{};
203   params.padding = Padding::VALID;
204   params.stride_height = 2;
205   params.stride_width = 1;
206   params.dilation_height_factor = 1;
207   params.dilation_width_factor = 1;
208   params.activation = Activation::RELU;
209
210   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
211   kernel.configure();
212   kernel.execute();
213
214   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
215   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
216 }
217
218 TEST(Conv2DTest, SInt16_CWQ_weights)
219 {
220   Shape input_shape{1, 2, 2, 2};  // Batch x H x W x C
221   Shape filter_shape{3, 1, 1, 2}; // Out channels x H x W x In Channels
222   Shape bias_shape{3};
223   std::vector<int32_t> ref_output_shape{1, 2, 2, 3};
224
225   std::vector<float> input_data{
226       1, 2, // row = 0, col 0
227       3, 4, // row = 0, col 1
228       5, 6, // row = 1, col 0
229       7, 8, // row = 1, col 1
230   };
231   std::vector<float> filter_data{
232       4, -3, // out = 0
233       1, -3, // out = 1
234       5, -3, // out = 2
235   };
236   std::vector<float> bias_data{1, 10, 5};
237   std::vector<float> ref_output_data{
238       0, 5, 4,  // row 0, col 0
239       1, 1, 8,  // row 0, col 1
240       3, 0, 12, // row 1, col 0
241       5, 0, 16, // row 1, col 1
242   };
243
244   float input_scale = 0.25f;
245   float output_scale = 0.05f;
246   std::vector<float> filter_scales = {0.25f, 0.2f, 0.1f};
247   std::vector<float> bias_scales;
248   for (int i = 0; i < filter_scales.size(); ++i)
249     bias_scales.push_back(filter_scales[i] * input_scale);
250   std::vector<int32_t> zerop = {0, 0, 0};
251
252   Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
253   Tensor filter_tensor =
254       makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 0, filter_data);
255   Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
256   Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0);
257
258   Conv2DParams params{};
259   params.padding = Padding::VALID;
260   params.stride_height = 1;
261   params.stride_width = 1;
262   params.dilation_height_factor = 1;
263   params.dilation_width_factor = 1;
264   params.activation = Activation::RELU;
265
266   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
267   kernel.configure();
268   kernel.execute();
269
270   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
271   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
272 }
273
274 TEST(Conv2DTest, Unsupported_Type_Configure_NEG)
275 {
276   Shape input_shape{1, 4, 3, 2};
277   Shape filter_shape{2, 2, 2, 2};
278   Shape bias_shape{2};
279   std::vector<int32_t> input_data{
280       1,  2,  3,  4,  5,  6,  // row = 0
281       7,  8,  9,  10, 11, 12, // row = 1
282       13, 14, 15, 16, 17, 18, // row = 2
283       19, 20, 21, 22, 23, 24, // row = 3
284   };
285   std::vector<float> filter_data{
286       1,  2,  -3, -4, // out = 0, row = 0
287       -5, 6,  -7, 8,  // out = 1, row = 0
288       4,  -2, 3,  -1, // out = 0, row = 1
289       -8, -6, 7,  5,  // out = 1, row = 1
290   };
291   std::vector<float> bias_data{1, 2};
292   Tensor input_tensor = makeInputTensor<DataType::S32>(input_shape, input_data);
293   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
294   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
295   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
296
297   Conv2DParams params{};
298   params.padding = Padding::VALID;
299   params.stride_height = 2;
300   params.stride_width = 1;
301   params.dilation_height_factor = 1;
302   params.dilation_width_factor = 1;
303   params.activation = Activation::RELU;
304
305   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
306   EXPECT_ANY_THROW(kernel.configure());
307 }
308
309 TEST(Conv2DTest, Invalid_Bias_Type_NEG)
310 {
311   Shape input_shape{1, 4, 3, 2};
312   Shape filter_shape{2, 2, 2, 2};
313   Shape bias_shape{2};
314   std::vector<float> input_data{
315       1,  2,  3,  4,  5,  6,  // row = 0
316       7,  8,  9,  10, 11, 12, // row = 1
317       13, 14, 15, 16, 17, 18, // row = 2
318       19, 20, 21, 22, 23, 24, // row = 3
319   };
320   std::vector<float> filter_data{
321       1,  2,  -3, -4, // out = 0, row = 0
322       -5, 6,  -7, 8,  // out = 1, row = 0
323       4,  -2, 3,  -1, // out = 0, row = 1
324       -8, -6, 7,  5,  // out = 1, row = 1
325   };
326   std::vector<uint8_t> bias_data{1, 2};
327   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
328   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
329   Tensor bias_tensor = makeInputTensor<DataType::U8>(bias_shape, bias_data);
330   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
331
332   Conv2DParams params{};
333   params.padding = Padding::VALID;
334   params.stride_height = 2;
335   params.stride_width = 1;
336   params.dilation_height_factor = 1;
337   params.dilation_width_factor = 1;
338   params.activation = Activation::RELU;
339
340   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
341   EXPECT_ANY_THROW(kernel.configure());
342 }
343
344 TEST(Conv2DTest, Invalid_Bias_Data_NEG)
345 {
346   Shape input_shape{1, 4, 3, 2};
347   Shape filter_shape{2, 2, 2, 2};
348   Shape bias_shape{3};
349   std::vector<float> input_data{
350       1,  2,  3,  4,  5,  6,  // row = 0
351       7,  8,  9,  10, 11, 12, // row = 1
352       13, 14, 15, 16, 17, 18, // row = 2
353       19, 20, 21, 22, 23, 24, // row = 3
354   };
355   std::vector<float> filter_data{
356       1,  2,  -3, -4, // out = 0, row = 0
357       -5, 6,  -7, 8,  // out = 1, row = 0
358       4,  -2, 3,  -1, // out = 0, row = 1
359       -8, -6, 7,  5,  // out = 1, row = 1
360   };
361   std::vector<float> bias_data{1, 2, 3};
362   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
363   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
364   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
365   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
366
367   Conv2DParams params{};
368   params.padding = Padding::VALID;
369   params.stride_height = 2;
370   params.stride_width = 1;
371   params.dilation_height_factor = 1;
372   params.dilation_width_factor = 1;
373   params.activation = Activation::RELU;
374
375   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
376   EXPECT_ANY_THROW(kernel.configure());
377 }
378
379 TEST(Conv2DTest, Invalid_Input_Shape_NEG)
380 {
381   Shape input_shape{1, 4, 6, 1};
382   Shape filter_shape{2, 2, 2, 2};
383   Shape bias_shape{2};
384   std::vector<float> input_data{
385       1,  2,  3,  4,  5,  6,  // row = 0
386       7,  8,  9,  10, 11, 12, // row = 1
387       13, 14, 15, 16, 17, 18, // row = 2
388       19, 20, 21, 22, 23, 24, // row = 3
389   };
390   std::vector<float> filter_data{
391       1,  2,  -3, -4, // out = 0, row = 0
392       -5, 6,  -7, 8,  // out = 1, row = 0
393       4,  -2, 3,  -1, // out = 0, row = 1
394       -8, -6, 7,  5,  // out = 1, row = 1
395   };
396   std::vector<float> bias_data{1, 2};
397   Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
398   Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
399   Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
400   Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
401
402   Conv2DParams params{};
403   params.padding = Padding::VALID;
404   params.stride_height = 2;
405   params.stride_width = 1;
406   params.dilation_height_factor = 1;
407   params.dilation_width_factor = 1;
408   params.activation = Activation::RELU;
409
410   Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
411   EXPECT_ANY_THROW(kernel.configure());
412 }
413
414 } // namespace
415 } // namespace kernels
416 } // namespace luci_interpreter