2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "kernels/TransposeConv.h"
18 #include "kernels/TestUtils.h"
19 #include "luci_interpreter/TestMemoryManager.h"
21 namespace luci_interpreter
28 using namespace testing;
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,
39 std::unique_ptr<IMemoryManager> memory_manager = std::make_unique<TestMemoryManager>();
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());
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);
53 TransposeConvParams params{};
54 params.padding = padding;
55 params.stride_height = stride_height;
56 params.stride_width = stride_width;
58 if (bias_data.size() != 0)
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);
65 memory_manager->allocate_memory(output_tensor);
66 memory_manager->allocate_memory(scratch_tensor);
71 TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, nullptr,
72 &output_tensor, &scratch_tensor, params);
74 memory_manager->allocate_memory(output_tensor);
75 memory_manager->allocate_memory(scratch_tensor);
78 EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data));
81 TEST(TransposeConvTest, FloatSimple)
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},
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);
95 TEST(TransposeConvTest, FloatTwoFiltersTest)
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},
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);
111 TEST(TransposeConvTest, SimpleBiasTest)
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);
128 TEST(TransposeConvTest, UInt8)
130 std::unique_ptr<IMemoryManager> memory_manager = std::make_unique<TestMemoryManager>();
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, //
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
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);
159 DataType scratch_data_type =
160 input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32;
161 Tensor scratch_tensor(scratch_data_type, Shape({}), {}, "");
163 TransposeConvParams params{};
164 params.padding = Padding::VALID;
165 params.stride_height = 2;
166 params.stride_width = 2;
168 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
169 &output_tensor, &scratch_tensor, params);
171 memory_manager->allocate_memory(output_tensor);
172 memory_manager->allocate_memory(scratch_tensor);
175 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
176 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
179 TEST(TransposeConvTest, UInt8_CWQ)
181 std::unique_ptr<IMemoryManager> memory_manager = std::make_unique<TestMemoryManager>();
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, //
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
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));
204 std::vector<float> filter_scales;
205 std::vector<int32_t> filter_zerops;
206 for (auto iter : filter_quant_params)
208 filter_scales.push_back(iter.first);
209 filter_zerops.push_back(iter.second);
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);
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);
227 DataType scratch_data_type =
228 input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32;
229 Tensor scratch_tensor(scratch_data_type, Shape({}), {}, "");
231 TransposeConvParams params{};
232 params.padding = Padding::VALID;
233 params.stride_height = 2;
234 params.stride_width = 2;
236 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
237 &output_tensor, &scratch_tensor, params);
239 memory_manager->allocate_memory(output_tensor);
240 memory_manager->allocate_memory(scratch_tensor);
243 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
244 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
247 TEST(TransposeConvTest, SInt16)
249 std::unique_ptr<IMemoryManager> memory_manager = std::make_unique<TestMemoryManager>();
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, //
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());
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);
273 DataType scratch_data_type =
274 input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32;
275 Tensor scratch_tensor(scratch_data_type, Shape({}), {}, "");
277 TransposeConvParams params{};
278 params.padding = Padding::VALID;
279 params.stride_height = 2;
280 params.stride_width = 2;
282 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
283 &output_tensor, &scratch_tensor, params);
285 memory_manager->allocate_memory(output_tensor);
286 memory_manager->allocate_memory(scratch_tensor);
289 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
290 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
293 TEST(TransposeConvTest, SInt16_CWQ_weights)
295 std::unique_ptr<IMemoryManager> memory_manager = std::make_unique<TestMemoryManager>();
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};
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};
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, //
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);
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);
331 DataType scratch_data_type =
332 input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32;
333 Tensor scratch_tensor(scratch_data_type, Shape({}), {}, "");
335 TransposeConvParams params{};
336 params.padding = Padding::VALID;
337 params.stride_height = 2;
338 params.stride_width = 2;
340 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
341 &output_tensor, &scratch_tensor, params);
343 memory_manager->allocate_memory(output_tensor);
344 memory_manager->allocate_memory(scratch_tensor);
347 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
348 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
352 } // namespace kernels
353 } // namespace luci_interpreter