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, SInt16)
159 std::vector<float> input_data{1, 2, 3, 4};
160 std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
161 std::vector<float> bias_data{3, 4};
162 std::vector<int32_t> output_shape_data{1, 5, 5, 2};
163 std::vector<float> ref_output_data{
164 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, //
165 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, //
166 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, //
167 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, //
168 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
171 Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 2, 1}, 0.25, 0, input_data);
172 Tensor filter_tensor = makeInputTensor<DataType::S16>({2, 3, 3, 1}, 0.2, 0, filter_data);
173 Tensor bias_tensor = makeInputTensor<DataType::S64>({2}, 0.25 * 0.2, 0, bias_data);
174 Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
175 Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
177 TransposeConvParams params{};
178 params.padding = Padding::VALID;
179 params.stride_height = 2;
180 params.stride_width = 2;
182 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
183 &output_tensor, params);
187 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
188 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
191 TEST(TransposeConvTest, SInt16_CWQ_weights)
193 const int output_channels = 2;
194 const Shape input_shape{1, 2, 2, 1};
195 const Shape filter_shape{output_channels, 3, 3, 1};
196 const Shape bias_shape{output_channels};
197 std::vector<int32_t> output_shape_data{1, 5, 5, output_channels};
199 std::vector<float> input_data{1, 2, 3, 4};
200 std::vector<float> filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18};
201 std::vector<float> bias_data{3, 4};
203 std::vector<float> ref_output_data{
204 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, //
205 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, //
206 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, //
207 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, //
208 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, //
211 const float input_scale = 0.25;
212 const float output_scale = 0.5;
213 const std::vector<float> filter_scales{0.2f, 0.5f};
214 std::vector<float> bias_scales{filter_scales[0] * input_scale, filter_scales[1] * input_scale};
215 const std::vector<int32_t> zerop(2, 0);
217 Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
218 Tensor filter_tensor =
219 makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 0, filter_data);
220 Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
221 Tensor output_shape_tensor = makeInputTensor<DataType::S32>({4}, output_shape_data);
222 Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0);
224 TransposeConvParams params{};
225 params.padding = Padding::VALID;
226 params.stride_height = 2;
227 params.stride_width = 2;
229 TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor,
230 &output_tensor, params);
234 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data));
235 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
239 } // namespace kernels
240 } // namespace luci_interpreter