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/DepthwiseConv2D.h"
18 #include "kernels/TestUtils.h"
20 namespace luci_interpreter
27 using namespace testing;
29 TEST(DepthwiseConv2DTest, Float)
31 Shape input_shape{1, 4, 2, 2};
32 Shape filter_shape{1, 2, 2, 4};
34 std::vector<float> input_data{
40 std::vector<float> filter_data{
46 std::vector<float> bias_data{1, 2, 3, 4};
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 DepthwiseConv2DParams params{};
53 params.padding = Padding::VALID;
54 params.depth_multiplier = 2;
55 params.stride_height = 2;
56 params.stride_width = 1;
57 params.dilation_height_factor = 1;
58 params.dilation_width_factor = 1;
59 params.activation = Activation::RELU;
61 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
65 std::vector<float> ref_output_data{
69 EXPECT_THAT(extractTensorData<float>(output_tensor), FloatArrayNear(ref_output_data));
70 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 1, 4}));
73 TEST(DepthwiseConv2DTest, Uint8)
75 std::vector<float> input_data{
76 1, 2, 7, 8, // column 1
77 3, 4, 9, 10, // column 2
78 5, 6, 11, 12, // column 3
80 std::vector<float> filter_data{
86 std::vector<float> bias_data{1, 2, 3, 4};
88 std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(-63.5, 64);
89 std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128);
91 Tensor input_tensor = makeInputTensor<DataType::U8>({1, 3, 2, 2}, input_quant_param.first,
92 input_quant_param.second, input_data);
93 Tensor filter_tensor = makeInputTensor<DataType::U8>({1, 2, 2, 4}, input_quant_param.first,
94 input_quant_param.second, filter_data);
95 Tensor bias_tensor = makeInputTensor<DataType::S32>(
96 {4}, input_quant_param.first * input_quant_param.first, 0, bias_data);
97 Tensor output_tensor =
98 makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second);
100 DepthwiseConv2DParams params{};
101 params.padding = Padding::VALID;
102 params.depth_multiplier = 2;
103 params.stride_height = 1;
104 params.stride_width = 1;
105 params.dilation_height_factor = 1;
106 params.dilation_width_factor = 1;
107 params.activation = Activation::NONE;
109 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
113 std::vector<float> ref_output_data{
117 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
118 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 1, 4}));
121 TEST(DepthwiseConv2DTest, SInt16)
123 Shape input_shape{1, 4, 2, 2};
124 Shape filter_shape{1, 2, 2, 4};
126 std::vector<int32_t> ref_output_shape{1, 2, 1, 4};
128 std::vector<float> input_data{
134 std::vector<float> filter_data{
140 std::vector<float> bias_data{1, 2, 3, 4};
141 std::vector<float> ref_output_data{
146 Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, 0.25, 0, input_data);
147 Tensor filter_tensor = makeInputTensor<DataType::S16>(filter_shape, 0.2, 0, filter_data);
148 Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, 0.25 * 0.2, 0, bias_data);
149 Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
151 DepthwiseConv2DParams params{};
152 params.padding = Padding::VALID;
153 params.depth_multiplier = 2;
154 params.stride_height = 2;
155 params.stride_width = 1;
156 params.dilation_height_factor = 1;
157 params.dilation_width_factor = 1;
158 params.activation = Activation::RELU;
160 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
164 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
165 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
168 TEST(DepthwiseConv2DTest, SInt16_CWQ_weights)
170 const int output_channels = 4;
171 Shape input_shape{1, 4, 2, 2};
172 Shape filter_shape{1, 2, 2, output_channels};
174 std::vector<int32_t> ref_output_shape{1, 2, 1, output_channels};
176 std::vector<float> input_data{
182 std::vector<float> filter_data{
188 std::vector<float> bias_data{1, 2, 3, 4};
189 std::vector<float> ref_output_data{
194 float input_scale = 0.25;
195 std::vector<float> filter_scales{0.2f, 1.f, 0.5f, 0.1f};
196 std::vector<float> bias_scales;
197 for (int i = 0; i < output_channels; ++i)
198 bias_scales.push_back(filter_scales[i] * input_scale);
199 std::vector<int32_t> zerop(4, 0);
200 Tensor input_tensor = makeInputTensor<DataType::S16>(input_shape, input_scale, 0, input_data);
201 Tensor filter_tensor =
202 makeInputTensor<DataType::S16>(filter_shape, filter_scales, zerop, 3, filter_data);
203 Tensor bias_tensor = makeInputTensor<DataType::S64>(bias_shape, bias_scales, zerop, 0, bias_data);
204 Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0);
206 DepthwiseConv2DParams params{};
207 params.padding = Padding::VALID;
208 params.depth_multiplier = 2;
209 params.stride_height = 2;
210 params.stride_width = 1;
211 params.dilation_height_factor = 1;
212 params.dilation_width_factor = 1;
213 params.activation = Activation::RELU;
215 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
219 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
220 EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data));
223 TEST(DepthwiseConv2DTest, Uint8_CWQ_weights)
225 const int output_channels = 4;
226 Shape input_shape{1, 3, 2, 2};
227 Shape filter_shape{1, 2, 2, output_channels};
229 std::vector<int32_t> ref_output_shape{1, 2, 1, output_channels};
231 std::vector<float> input_data{
236 std::vector<float> filter_data{
242 std::vector<float> bias_data{1, 2, 3, 4};
243 std::vector<float> ref_output_data{
248 std::pair<float, int32_t> input_quant_param = quantizationParams<uint8_t>(0, 16);
249 std::pair<float, int32_t> output_quant_param = quantizationParams<uint8_t>(-127, 128);
251 std::vector<std::pair<float, int32_t>> filter_quant_params;
252 filter_quant_params.push_back(quantizationParams<uint8_t>(-9, 13));
253 filter_quant_params.push_back(quantizationParams<uint8_t>(-14, 10));
254 filter_quant_params.push_back(quantizationParams<uint8_t>(-11, 15));
255 filter_quant_params.push_back(quantizationParams<uint8_t>(-16, 12));
257 std::vector<float> filter_scales;
258 std::vector<int32_t> filter_zerops;
259 for (auto iter : filter_quant_params)
261 filter_scales.push_back(iter.first);
262 filter_zerops.push_back(iter.second);
265 std::vector<float> bias_scales;
266 for (int i = 0; i < output_channels; ++i)
267 bias_scales.push_back(filter_quant_params[i].first * input_quant_param.first);
268 std::vector<int32_t> zerop(output_channels, 0);
270 Tensor input_tensor = makeInputTensor<DataType::U8>(input_shape, input_quant_param.first,
271 input_quant_param.second, input_data);
272 Tensor filter_tensor =
273 makeInputTensor<DataType::U8>(filter_shape, filter_scales, filter_zerops, 3, filter_data);
274 Tensor bias_tensor = makeInputTensor<DataType::S32>(bias_shape, bias_scales, zerop, 0, bias_data);
275 Tensor output_tensor =
276 makeOutputTensor(DataType::U8, output_quant_param.first, output_quant_param.second);
278 DepthwiseConv2DParams params{};
279 params.padding = Padding::VALID;
280 params.depth_multiplier = 2;
281 params.stride_height = 1;
282 params.stride_width = 1;
283 params.dilation_height_factor = 1;
284 params.dilation_width_factor = 1;
285 params.activation = Activation::NONE;
287 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
291 EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape));
292 EXPECT_THAT(dequantizeTensorData(output_tensor),
293 FloatArrayNear(ref_output_data, output_quant_param.first));
296 TEST(DepthwiseConv2DTest, InvalidBiasType_NEG)
298 Shape input_shape{1, 4, 2, 2};
299 Shape filter_shape{1, 2, 2, 4};
301 std::vector<float> input_data{
307 std::vector<float> filter_data{
313 std::vector<int32_t> bias_data{1, 2, 3, 4};
314 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
315 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
316 Tensor bias_tensor = makeInputTensor<DataType::S32>(bias_shape, bias_data);
317 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
319 DepthwiseConv2DParams params{};
320 params.padding = Padding::VALID;
321 params.depth_multiplier = 2;
322 params.stride_height = 2;
323 params.stride_width = 1;
324 params.dilation_height_factor = 1;
325 params.dilation_width_factor = 1;
326 params.activation = Activation::RELU;
328 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
329 EXPECT_ANY_THROW(kernel.configure());
332 TEST(DepthwiseConv2DTest, InOutTypeMismatch_NEG)
334 Shape input_shape{1, 4, 2, 2};
335 Shape filter_shape{1, 2, 2, 4};
337 std::vector<float> input_data{
343 std::vector<float> filter_data{
349 std::vector<float> bias_data{1, 2, 3, 4};
350 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
351 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
352 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
353 Tensor output_tensor = makeOutputTensor(DataType::U8);
355 DepthwiseConv2DParams params{};
356 params.padding = Padding::VALID;
357 params.depth_multiplier = 2;
358 params.stride_height = 2;
359 params.stride_width = 1;
360 params.dilation_height_factor = 1;
361 params.dilation_width_factor = 1;
362 params.activation = Activation::RELU;
364 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
365 EXPECT_ANY_THROW(kernel.configure());
368 TEST(DepthwiseConv2DTest, InvalidInputShape_NEG)
370 Shape input_shape{4, 2, 2};
371 Shape filter_shape{2, 2, 4};
373 std::vector<float> input_data{
379 std::vector<float> filter_data{
385 std::vector<float> bias_data{1, 2, 3, 4};
386 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
387 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
388 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
389 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
391 DepthwiseConv2DParams params{};
392 params.padding = Padding::VALID;
393 params.depth_multiplier = 2;
394 params.stride_height = 2;
395 params.stride_width = 1;
396 params.dilation_height_factor = 1;
397 params.dilation_width_factor = 1;
398 params.activation = Activation::RELU;
400 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
401 EXPECT_ANY_THROW(kernel.configure());
404 TEST(DepthwiseConv2DTest, InvalidFilterShape_NEG)
406 Shape input_shape{1, 4, 2, 2};
407 Shape filter_shape{2, 1, 2, 4};
409 std::vector<float> input_data{
415 std::vector<float> filter_data{
421 std::vector<float> bias_data{1, 2, 3, 4};
422 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
423 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
424 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
425 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
427 DepthwiseConv2DParams params{};
428 params.padding = Padding::VALID;
429 params.depth_multiplier = 2;
430 params.stride_height = 2;
431 params.stride_width = 1;
432 params.dilation_height_factor = 1;
433 params.dilation_width_factor = 1;
434 params.activation = Activation::RELU;
436 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
437 EXPECT_ANY_THROW(kernel.configure());
440 TEST(DepthwiseConv2DTest, InvalidBiasDim_NEG)
442 Shape input_shape{1, 4, 2, 2};
443 Shape filter_shape{1, 2, 4, 2};
445 std::vector<float> input_data{
451 std::vector<float> filter_data{
457 std::vector<float> bias_data{1, 2, 3, 4};
458 Tensor input_tensor = makeInputTensor<DataType::FLOAT32>(input_shape, input_data);
459 Tensor filter_tensor = makeInputTensor<DataType::FLOAT32>(filter_shape, filter_data);
460 Tensor bias_tensor = makeInputTensor<DataType::FLOAT32>(bias_shape, bias_data);
461 Tensor output_tensor = makeOutputTensor(DataType::FLOAT32);
463 DepthwiseConv2DParams params{};
464 params.padding = Padding::VALID;
465 params.depth_multiplier = 2;
466 params.stride_height = 2;
467 params.stride_width = 1;
468 params.dilation_height_factor = 1;
469 params.dilation_width_factor = 1;
470 params.activation = Activation::RELU;
472 DepthwiseConv2D kernel(&input_tensor, &filter_tensor, &bias_tensor, &output_tensor, params);
473 EXPECT_ANY_THROW(kernel.configure());
477 } // namespace kernels
478 } // namespace luci_interpreter