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