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/Conv2D.h"
18 #include "kernels/TestUtils.h"
20 namespace luci_interpreter
27 using namespace testing;
29 TEST(Conv2DTest, Float)
31 Shape input_shape{1, 4, 3, 2};
32 Shape filter_shape{2, 2, 2, 2};
34 std::vector<float> input_data{
35 1, 2, 3, 4, 5, 6, // row = 0
36 7, 8, 9, 10, 11, 12, // row = 1
37 13, 14, 15, 16, 17, 18, // row = 2
38 19, 20, 21, 22, 23, 24, // row = 3
40 std::vector<float> filter_data{
41 1, 2, -3, -4, // out = 0, row = 0
42 -5, 6, -7, 8, // out = 1, row = 0
43 4, -2, 3, -1, // out = 0, row = 1
44 -8, -6, 7, 5, // out = 1, row = 1
46 std::vector<float> bias_data{1, 2};
47 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
48 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
49 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
50 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
52 Conv2DParams params{};
53 params.padding = Padding::VALID;
54 params.stride_height = 2;
55 params.stride_width = 1;
56 params.dilation_height_factor = 1;
57 params.dilation_width_factor = 1;
58 params.activation = Activation::RELU;
60 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
64 std::vector<float> ref_output_data{
65 11, 16, 7, 20, // row = 0
66 0, 40, 0, 44, // row = 1
68 std::vector<int32_t> ref_output_shape{1, 2, 2, 2};
69 EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data));
70 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
73 TEST(Conv2DTest, FloatCheck)
75 Shape input_shape{2, 2, 4, 1};
76 Shape filter_shape{3, 2, 2, 1};
78 std::vector<float> input_data{
80 1, 1, 1, 1, // row = 1
81 2, 2, 2, 2, // row = 2
83 1, 2, 3, 4, // row = 1
84 1, 2, 3, 4, // row = 2
86 std::vector<float> filter_data{
87 1, 2, 3, 4, // first 2x2 filter
88 -1, 1, -1, 1, // second 2x2 filter
89 -1, -1, 1, 1, // third 2x2 filter
91 std::vector<float> bias_data{1, 2, 3};
92 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
93 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
94 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
95 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
97 Conv2DParams params{};
98 params.padding = Padding::VALID;
99 params.stride_height = 2;
100 params.stride_width = 2;
101 params.dilation_height_factor = 1;
102 params.dilation_width_factor = 1;
103 params.activation = Activation::NONE;
105 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
109 std::vector<float> ref_output_data{
110 18, 2, 5, // first batch, left
111 18, 2, 5, // first batch, right
112 17, 4, 3, // second batch, left
113 37, 4, 3, // second batch, right
115 std::vector<int32_t> ref_output_shape{2, 1, 2, 3};
116 EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data));
117 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
120 TEST(Conv2DTest, Uint8)
122 std::vector<float> input_data{
124 1, 1, 1, 1, // row = 1
125 2, 2, 2, 2, // row = 2
127 1, 2, 3, 4, // row = 1
128 1, 2, 3, 4, // row = 2
130 std::vector<float> filter_data{
131 1, 2, 3, 4, // first 2x2 filter
132 -1, 1, -1, 1, // second 2x2 filter
133 -1, -1, 1, 1, // third 2x2 filter
135 std::vector<float> bias_data{1, 2, 3};
137 std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64);
138 std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128);
140 Tensor input_tensor = makeInputTensor<DataType::U8>({2, 2, 4, 1}, input_quant_param.first,
141 input_quant_param.second, input_data);
142 Tensor filter_tensor = makeInputTensor<DataType::U8>({3, 2, 2, 1}, input_quant_param.first,
143 input_quant_param.second, filter_data);
144 Tensor bias_tensor = makeInputTensor<DataType::S32>(
145 {3}, input_quant_param.first * input_quant_param.first, 0, bias_data);
146 Tensor output_tensor =
147 makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second);
149 Conv2DParams params{};
150 params.padding = Padding::VALID;
151 params.stride_height = 2;
152 params.stride_width = 2;
153 params.dilation_height_factor = 1;
154 params.dilation_width_factor = 1;
155 params.activation = Activation::NONE;
157 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
161 std::vector<float> ref_output_data{
162 18, 2, 5, // first batch, left
163 18, 2, 5, // first batch, right
164 17, 4, 3, // second batch, left
165 37, 4, 3, // second batch, right
167 std::vector<int32_t> ref_output_shape{2, 1, 2, 3};
168 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
169 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
172 TEST(Conv2DTest, SInt16)
174 Shape input_shape{1, 4, 3, 2};
175 Shape filter_shape{2, 2, 2, 2};
177 std::vector<int32_t> ref_output_shape{1, 2, 2, 2};
179 std::vector<float> input_data{
180 1, 2, 3, 4, 5, 6, // row = 0
181 7, 8, 9, 10, 11, 12, // row = 1
182 13, 14, 15, 16, 17, 18, // row = 2
183 19, 20, 21, 22, 23, 24, // row = 3
185 std::vector<float> filter_data{
186 1, 2, -3, -4, // out = 0, row = 0
187 -5, 6, -7, 8, // out = 1, row = 0
188 4, -2, 3, -1, // out = 0, row = 1
189 -8, -6, 7, 5, // out = 1, row = 1
191 std::vector<float> bias_data{1, 2};
192 std::vector<float> ref_output_data{
193 11, 16, 7, 20, // row = 0
194 0, 40, 0, 44, // row = 1
197 Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.25, 0, input_data);
198 Tensor filter_tensor = makeInputTensor<DataType::S16>(filter_shape, 0.2, 0, filter_data);
199 Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, 0.25 * 0.2, 0, bias_data);
200 Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
202 Conv2DParams params{};
203 params.padding = Padding::VALID;
204 params.stride_height = 2;
205 params.stride_width = 1;
206 params.dilation_height_factor = 1;
207 params.dilation_width_factor = 1;
208 params.activation = Activation::RELU;
210 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
214 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
215 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
218 TEST(Conv2DTest, SInt16_CWQ_weights)
220 Shape input_shape{1, 2, 2, 2}; // Batch x H x W x C
221 Shape filter_shape{3, 1, 1, 2}; // Out channels x H x W x In Channels
223 std::vector<int32_t> ref_output_shape{1, 2, 2, 3};
225 std::vector<float> input_data{
226 1, 2, // row = 0, col 0
227 3, 4, // row = 0, col 1
228 5, 6, // row = 1, col 0
229 7, 8, // row = 1, col 1
231 std::vector<float> filter_data{
236 std::vector<float> bias_data{1, 10, 5};
237 std::vector<float> ref_output_data{
238 0, 5, 4, // row 0, col 0
239 1, 1, 8, // row 0, col 1
240 3, 0, 12, // row 1, col 0
241 5, 0, 16, // row 1, col 1
244 float input_scale = 0.25f;
245 float output_scale = 0.05f;
246 std::vector<float> filter_scales = {0.25f, 0.2f, 0.1f};
247 std::vector<float> bias_scales;
248 for (int i = 0; i < filter_scales.size(); ++i)
249 bias_scales.push_back(filter_scales[i] * input_scale);
250 std::vector<int32_t> zerop = {0, 0, 0};
252 Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
253 Tensor filter_tensor =
254 makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 0, filter_data);
255 Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
256 Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0);
258 Conv2DParams params{};
259 params.padding = Padding::VALID;
260 params.stride_height = 1;
261 params.stride_width = 1;
262 params.dilation_height_factor = 1;
263 params.dilation_width_factor = 1;
264 params.activation = Activation::RELU;
266 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
270 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
271 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
274 TEST(Conv2DTest, Unsupported_Type_Configure_NEG)
276 Shape input_shape{1, 4, 3, 2};
277 Shape filter_shape{2, 2, 2, 2};
279 std::vector<int32_t> input_data{
280 1, 2, 3, 4, 5, 6, // row = 0
281 7, 8, 9, 10, 11, 12, // row = 1
282 13, 14, 15, 16, 17, 18, // row = 2
283 19, 20, 21, 22, 23, 24, // row = 3
285 std::vector<float> filter_data{
286 1, 2, -3, -4, // out = 0, row = 0
287 -5, 6, -7, 8, // out = 1, row = 0
288 4, -2, 3, -1, // out = 0, row = 1
289 -8, -6, 7, 5, // out = 1, row = 1
291 std::vector<float> bias_data{1, 2};
292 Tensor input_tensor = makeInputTensor<DataType::S32>(input_shape, input_data);
293 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
294 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
295 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
297 Conv2DParams params{};
298 params.padding = Padding::VALID;
299 params.stride_height = 2;
300 params.stride_width = 1;
301 params.dilation_height_factor = 1;
302 params.dilation_width_factor = 1;
303 params.activation = Activation::RELU;
305 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
306 EXPECT_ANY_THROW(kernel.configure());
309 TEST(Conv2DTest, Invalid_Bias_Type_NEG)
311 Shape input_shape{1, 4, 3, 2};
312 Shape filter_shape{2, 2, 2, 2};
314 std::vector<float> input_data{
315 1, 2, 3, 4, 5, 6, // row = 0
316 7, 8, 9, 10, 11, 12, // row = 1
317 13, 14, 15, 16, 17, 18, // row = 2
318 19, 20, 21, 22, 23, 24, // row = 3
320 std::vector<float> filter_data{
321 1, 2, -3, -4, // out = 0, row = 0
322 -5, 6, -7, 8, // out = 1, row = 0
323 4, -2, 3, -1, // out = 0, row = 1
324 -8, -6, 7, 5, // out = 1, row = 1
326 std::vector<uint8_t> bias_data{1, 2};
327 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
328 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
329 Tensor bias_tensor = makeInputTensor<DataType::U8>(bias_shape, bias_data);
330 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
332 Conv2DParams params{};
333 params.padding = Padding::VALID;
334 params.stride_height = 2;
335 params.stride_width = 1;
336 params.dilation_height_factor = 1;
337 params.dilation_width_factor = 1;
338 params.activation = Activation::RELU;
340 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
341 EXPECT_ANY_THROW(kernel.configure());
344 TEST(Conv2DTest, Invalid_Bias_Data_NEG)
346 Shape input_shape{1, 4, 3, 2};
347 Shape filter_shape{2, 2, 2, 2};
349 std::vector<float> input_data{
350 1, 2, 3, 4, 5, 6, // row = 0
351 7, 8, 9, 10, 11, 12, // row = 1
352 13, 14, 15, 16, 17, 18, // row = 2
353 19, 20, 21, 22, 23, 24, // row = 3
355 std::vector<float> filter_data{
356 1, 2, -3, -4, // out = 0, row = 0
357 -5, 6, -7, 8, // out = 1, row = 0
358 4, -2, 3, -1, // out = 0, row = 1
359 -8, -6, 7, 5, // out = 1, row = 1
361 std::vector<float> bias_data{1, 2, 3};
362 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
363 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
364 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
365 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
367 Conv2DParams params{};
368 params.padding = Padding::VALID;
369 params.stride_height = 2;
370 params.stride_width = 1;
371 params.dilation_height_factor = 1;
372 params.dilation_width_factor = 1;
373 params.activation = Activation::RELU;
375 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
376 EXPECT_ANY_THROW(kernel.configure());
379 TEST(Conv2DTest, Invalid_Input_Shape_NEG)
381 Shape input_shape{1, 4, 6, 1};
382 Shape filter_shape{2, 2, 2, 2};
384 std::vector<float> input_data{
385 1, 2, 3, 4, 5, 6, // row = 0
386 7, 8, 9, 10, 11, 12, // row = 1
387 13, 14, 15, 16, 17, 18, // row = 2
388 19, 20, 21, 22, 23, 24, // row = 3
390 std::vector<float> filter_data{
391 1, 2, -3, -4, // out = 0, row = 0
392 -5, 6, -7, 8, // out = 1, row = 0
393 4, -2, 3, -1, // out = 0, row = 1
394 -8, -6, 7, 5, // out = 1, row = 1
396 std::vector<float> bias_data{1, 2};
397 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
398 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
399 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
400 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
402 Conv2DParams params{};
403 params.padding = Padding::VALID;
404 params.stride_height = 2;
405 params.stride_width = 1;
406 params.dilation_height_factor = 1;
407 params.dilation_width_factor = 1;
408 params.activation = Activation::RELU;
410 Conv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
411 EXPECT_ANY_THROW(kernel.configure());
415 } // namespace kernels
416 } // namespace luci_interpreter