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"
20 namespace luci_interpreter
27 using namespace testing;
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,
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);
45 TransposeConvParams params{};
46 params.padding = padding;
47 params.stride_height = stride_height;
48 params.stride_width = stride_width;
50 if (bias_data.size() != 0)
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);
60 TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, nullptr,
61 &output_tensor, params);
65 EXPECT_THAT(extractTensorData<T>(output_tensor), ::testing::ElementsAreArray(output_data));
68 TEST(TransposeConvTest, FloatSimple)
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},
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);
82 TEST(TransposeConvTest, FloatTwoFiltersTest)
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},
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);
98 TEST(TransposeConvTest, SimpleBiasTest)
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);
115 TEST(TransposeConvTest, UInt8)
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, //
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
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);
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);
143 TransposeConvParams params{};
144 params.padding = Padding::VALID;
145 params.stride_height = 2;
146 params.stride_width = 2;
148 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
149 &output_tensor, params);
153 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
154 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
157 TEST(TransposeConvTest, UInt8_CWQ)
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, //
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
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));
180 std::vector<float> filter_scales;
181 std::vector<int32_t> filter_zerops;
182 for (auto iter : filter_quant_params)
184 filter_scales.push_back(iter.first);
185 filter_zerops.push_back(iter.second);
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);
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);
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);
202 TransposeConvParams params{};
203 params.padding = Padding::VALID;
204 params.stride_height = 2;
205 params.stride_width = 2;
207 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
208 &output_tensor, params);
212 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
213 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
216 TEST(TransposeConvTest, SInt16)
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, //
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);
236 TransposeConvParams params{};
237 params.padding = Padding::VALID;
238 params.stride_height = 2;
239 params.stride_width = 2;
241 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
242 &output_tensor, params);
246 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
247 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
250 TEST(TransposeConvTest, SInt16_CWQ_weights)
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};
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};
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, //
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);
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);
283 TransposeConvParams params{};
284 params.padding = Padding::VALID;
285 params.stride_height = 2;
286 params.stride_width = 2;
288 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
289 &output_tensor, params);
293 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
294 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
298 } // namespace kernels
299 } // namespace luci_interpreter