Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compiler / luci-interpreter / src / kernels / TransposeConv.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/TransposeConv.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 template <typename T, typename B>
30 void Check(std::initializer_list<int32_t> output_shape_shape,
31            std::initializer_list<int32_t> weight_shape, std::initializer_list<int32_t> input_shape,
32            std::initializer_list<int32_t> bias_shape, std::initializer_list<int32_t> output_shape,
33            std::initializer_list<int32_t> output_shape_data, std::initializer_list<T> weight_data,
34            std::initializer_list<T> input_data, std::initializer_list<B> bias_data,
35            std::initializer_list<T> output_data, luci::Padding padding, int32_t stride_height,
36            int32_t stride_width)
37 {
38   constexpr DataType element_type = getElementType<T>();
39   Tensor output_shape_tensor =
40       makeInputTensor<DataType::S32>(output_shape_shape, output_shape_data);
41   Tensor weight_tensor = makeInputTensor<element_type>(weight_shape, weight_data);
42   Tensor input_data_tensor = makeInputTensor<element_type>(input_shape, input_data);
43   Tensor output_tensor = makeOutputTensor(element_type);
44
45   TransposeConvParams params{};
46   params.padding = padding;
47   params.stride_height = stride_height;
48   params.stride_width = stride_width;
49
50   if (bias_data.size() != 0)
51   {
52     Tensor bias_tensor = makeInputTensor<getElementType<B>()>(bias_shape, bias_data);
53     TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, &bias_tensor,
54                          &output_tensor, params);
55     kernel.configure();
56     kernel.execute();
57   }
58   else
59   {
60     TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, nullptr,
61                          &output_tensor, params);
62     kernel.configure();
63     kernel.execute();
64   }
65   EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data));
66 }
67
68 TEST(TransposeConvTest, FloatSimple)
69 {
70   Check<float, float>(
71       /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 1}, /*input_shape=*/{1, 4, 4, 1},
72       /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1},
73       /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9},
74       /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
75       /*bias_data=*/{},
76       /*output_data=*/{29, 62, 83, 75, 99, 192, 237, 198, 207, 372, 417, 330, 263, 446, 485, 365},
77       /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1);
78
79   SUCCEED();
80 }
81
82 TEST(TransposeConvTest, FloatTwoFiltersTest)
83 {
84   Check<float, float>(
85       /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 2}, /*input_shape=*/{1, 4, 4, 2},
86       /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1},
87       /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18},
88       /*input_data=*/{1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
89                       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
90       /*bias_data=*/{},
91       /*output_data=*/
92       {184, 412, 568, 528, 678, 1347, 1689, 1434, 1494, 2715, 3057, 2442, 1968, 3352, 3652, 2760},
93       /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1);
94
95   SUCCEED();
96 }
97
98 TEST(TransposeConvTest, SimpleBiasTest)
99 {
100   Check<float, float>(
101       /*output_shape_shape=*/{4}, /*weight_shape=*/{2, 3, 3, 1},
102       /*input_shape=*/{1, 2, 2, 1},
103       /*bias_shape=*/{2}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 5, 5, 2},
104       /*weight_data=*/{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18},
105       /*input_data=*/{1, 2, 3, 4},
106       /*bias_data=*/{3, 4},
107       /*output_data=*/{4,  6,  6,  8,  10, 14, 9,  12, 13, 16, 10,  12,  12, 14, 28, 32, 21,
108                        24, 25, 28, 19, 24, 27, 32, 65, 76, 45, 52,  57,  64, 24, 28, 30, 34,
109                        64, 72, 39, 44, 47, 52, 42, 46, 48, 52, 106, 114, 63, 68, 71, 76},
110       /*params.padding=*/luci::Padding::VALID, /*stride_height=*/2, /*stride_width=*/2);
111
112   SUCCEED();
113 }
114
115 TEST(TransposeConvTest, UInt8)
116 {
117   std::vector<float> input_data{1, 2, 3, 4};
118   std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
119   std::vector<float> bias_data{3, 4};
120   std::vector<int32_t> output_shape_data{1, 5, 5, 2};
121   std::vector<float> ref_output_data{
122       4,  6,  6,  8,  10,  14,  9,  12, 13, 16, //
123       10, 12, 12, 14, 28,  32,  21, 24, 25, 28, //
124       19, 24, 27, 32, 65,  76,  45, 52, 57, 64, //
125       24, 28, 30, 34, 64,  72,  39, 44, 47, 52, //
126       42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
127   };
128
129   // Choose quantization parameters carefully.
130   auto input_quant = quantizationParams<uint8_t>(-8.0, 7.9375);  // s = 1 / 16, zp = 128
131   auto filter_quant = quantizationParams<uint8_t>(-24.0, 39.75); // s = 1 / 4, zp = 96
132   auto output_quant = quantizationParams<uint8_t>(-64.0, 191.0); // s = 1, zp = 64
133
134   Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 1}, input_quant.first,
135                                                       input_quant.second, input_data);
136   Tensor filter_tensor = makeInputTensor<DataType::U8>({2, 3, 3, 1}, filter_quant.first,
137                                                        filter_quant.second, filter_data);
138   Tensor bias_tensor =
139       makeInputTensor<DataType::S32>({2}, input_quant.first * filter_quant.first, 0, bias_data);
140   Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
141   Tensor output_tensor = makeOutputTensor(DataType::U8, output_quant.first, output_quant.second);
142
143   TransposeConvParams params{};
144   params.padding = Padding::VALID;
145   params.stride_height = 2;
146   params.stride_width = 2;
147
148   TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
149                        &output_tensor, params);
150   kernel.configure();
151   kernel.execute();
152
153   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
154   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
155 }
156
157 TEST(TransposeConvTest, UInt8_CWQ)
158 {
159   const int32_t output_channels = 2;
160   std::vector<float> input_data{1, 2, 3, 4};
161   std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
162   std::vector<float> bias_data{3, 4};
163   std::vector<int32_t> output_shape_data{1, 5, 5, 2};
164   std::vector<float> ref_output_data{
165       4,  6,  6,  8,  10,  14,  9,  12, 13, 16, //
166       10, 12, 12, 14, 28,  32,  21, 24, 25, 28, //
167       19, 24, 27, 32, 65,  76,  45, 52, 57, 64, //
168       24, 28, 30, 34, 64,  72,  39, 44, 47, 52, //
169       42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
170   };
171
172   // Choose quantization parameters carefully.
173   auto input_quant = quantizationParams<uint8_t>(-8.0, 7.9375);  // s = 1 / 16, zp = 128
174   auto output_quant = quantizationParams<uint8_t>(-64.0, 191.0); // s = 1, zp = 64
175
176   std::vector<std::pair<float, int32_t>> filter_quant_params;
177   filter_quant_params.push_back(quantizationParams<uint8_t>(0, 17));
178   filter_quant_params.push_back(quantizationParams<uint8_t>(0, 18));
179
180   std::vector<float> filter_scales;
181   std::vector<int32_t> filter_zerops;
182   for (auto iter : filter_quant_params)
183   {
184     filter_scales.push_back(iter.first);
185     filter_zerops.push_back(iter.second);
186   }
187
188   std::vector<float> bias_scales;
189   for (int i = 0; i < output_channels; ++i)
190     bias_scales.push_back(filter_quant_params[i].first * input_quant.first);
191   std::vector<int32_t> zerop(output_channels, 0);
192
193   Tensor input_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 1}, input_quant.first,
194                                                       input_quant.second, input_data);
195   Tensor filter_tensor = makeInputTensor<DataType::U8>({output_channels, 3, 3, 1}, filter_scales,
196                                                        filter_zerops, 0, filter_data);
197   Tensor bias_tensor =
198       makeInputTensor<DataType::S32>({output_channels}, bias_scales, zerop, 0, bias_data);
199   Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
200   Tensor output_tensor = makeOutputTensor(DataType::U8, output_quant.first, output_quant.second);
201
202   TransposeConvParams params{};
203   params.padding = Padding::VALID;
204   params.stride_height = 2;
205   params.stride_width = 2;
206
207   TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
208                        &output_tensor, params);
209   kernel.configure();
210   kernel.execute();
211
212   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
213   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
214 }
215
216 TEST(TransposeConvTest, SInt16)
217 {
218   std::vector<float> input_data{1, 2, 3, 4};
219   std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
220   std::vector<float> bias_data{3, 4};
221   std::vector<int32_t> output_shape_data{1, 5, 5, 2};
222   std::vector<float> ref_output_data{
223       4,  6,  6,  8,  10,  14,  9,  12, 13, 16, //
224       10, 12, 12, 14, 28,  32,  21, 24, 25, 28, //
225       19, 24, 27, 32, 65,  76,  45, 52, 57, 64, //
226       24, 28, 30, 34, 64,  72,  39, 44, 47, 52, //
227       42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
228   };
229
230   Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 2, 1}, 0.25, 0, input_data);
231   Tensor filter_tensor = makeInputTensor<DataType::S16>({2, 3, 3, 1}, 0.2, 0, filter_data);
232   Tensor bias_tensor = makeInputTensor<DataType::S64>({2}, 0.25 * 0.2, 0, bias_data);
233   Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
234   Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
235
236   TransposeConvParams params{};
237   params.padding = Padding::VALID;
238   params.stride_height = 2;
239   params.stride_width = 2;
240
241   TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
242                        &output_tensor, params);
243   kernel.configure();
244   kernel.execute();
245
246   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
247   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
248 }
249
250 TEST(TransposeConvTest, SInt16_CWQ_weights)
251 {
252   const int output_channels = 2;
253   const Shape input_shape{1, 2, 2, 1};
254   const Shape filter_shape{output_channels, 3, 3, 1};
255   const Shape bias_shape{output_channels};
256   std::vector<int32_t> output_shape_data{1, 5, 5, output_channels};
257
258   std::vector<float> input_data{1, 2, 3, 4};
259   std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
260   std::vector<float> bias_data{3, 4};
261
262   std::vector<float> ref_output_data{
263       4,  6,  6,  8,  10,  14,  9,  12, 13, 16, //
264       10, 12, 12, 14, 28,  32,  21, 24, 25, 28, //
265       19, 24, 27, 32, 65,  76,  45, 52, 57, 64, //
266       24, 28, 30, 34, 64,  72,  39, 44, 47, 52, //
267       42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
268   };
269
270   const float input_scale = 0.25;
271   const float output_scale = 0.5;
272   const std::vector<float> filter_scales{0.2f, 0.5f};
273   std::vector<float> bias_scales{filter_scales[0] * input_scale, filter_scales[1] * input_scale};
274   const std::vector<int32_t> zerop(2, 0);
275
276   Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
277   Tensor filter_tensor =
278       makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 0, filter_data);
279   Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
280   Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
281   Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0);
282
283   TransposeConvParams params{};
284   params.padding = Padding::VALID;
285   params.stride_height = 2;
286   params.stride_width = 2;
287
288   TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
289                        &output_tensor, params);
290   kernel.configure();
291   kernel.execute();
292
293   EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
294   EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
295 }
296
297 } // namespace
298 } // namespace kernels
299 } // namespace luci_interpreter