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