1 // Copyright (C) 2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "layer_transformation.hpp"
11 #include <gtest/gtest.h>
13 #include <transformations/utils/utils.hpp>
14 #include <transformations/init_node_info.hpp>
15 #include <low_precision/group_convolution.hpp>
17 #include "common_test_utils/ngraph_test_utils.hpp"
18 #include "simple_low_precision_transformer.hpp"
19 #include "ngraph_functions/low_precision_transformations/group_convolution_function.hpp"
21 #include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_weights.hpp"
22 #include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
24 using namespace testing;
25 using namespace ngraph;
26 using namespace ngraph::pass;
29 class GroupConvolutionTestValues {
33 ngraph::element::Type precisionBeforeDequantization;
34 ngraph::builder::subgraph::DequantizationOperations dequantization;
35 std::shared_ptr<ngraph::opset1::Constant> weights;
36 builder::subgraph::FakeQuantizeOnWeights fakeQuantizeOnWeights;
41 ngraph::element::Type precisionBeforeDequantization;
42 ngraph::builder::subgraph::DequantizationOperations dequantizationBefore;
43 std::shared_ptr<ngraph::opset1::Constant> weights;
44 builder::subgraph::FakeQuantizeOnWeights fakeQuantizeOnWeights;
45 ngraph::element::Type precisionAfterOperation;
46 ngraph::builder::subgraph::DequantizationOperations dequantizationAfter;
47 ngraph::element::Type precisionAfterDequantization;
50 low_precision::LayerTransformation::Params params;
51 ngraph::Shape inputShape;
52 ngraph::Shape outputShape;
58 class GroupConvolutionTransformation : public LayerTransformation, public testing::WithParamInterface<GroupConvolutionTestValues> {
60 void SetUp() override {
61 const GroupConvolutionTestValues testValues = GetParam();
63 actualFunction = ngraph::builder::subgraph::GroupConvolutionFunction::getOriginal(
64 testValues.actual.precisionBeforeDequantization,
65 testValues.inputShape,
66 testValues.outputShape,
68 testValues.actual.dequantization,
69 testValues.actual.weights,
70 testValues.actual.fakeQuantizeOnWeights);
72 SimpleLowPrecisionTransformer transform;
73 transform.add<ngraph::pass::low_precision::GroupConvolutionTransformation, ngraph::opset1::GroupConvolution>(testValues.params);
74 transform.transform(actualFunction);
76 referenceFunction = ngraph::builder::subgraph::GroupConvolutionFunction::getReference(
77 testValues.expected.precisionBeforeDequantization,
78 testValues.inputShape,
79 testValues.outputShape,
81 testValues.expected.dequantizationBefore,
82 testValues.expected.weights,
83 testValues.expected.fakeQuantizeOnWeights,
84 testValues.expected.precisionAfterOperation,
85 testValues.expected.dequantizationAfter,
86 testValues.expected.precisionAfterDequantization);
89 static std::string getTestCaseName(testing::TestParamInfo<GroupConvolutionTestValues> obj) {
90 GroupConvolutionTestValues testValues = obj.param;
92 std::ostringstream result;
93 result << toString(testValues.params) << "_" <<
94 testValues.inputShape << "_" <<
95 testValues.outputShape << "_" <<
96 testValues.group << "_" <<
97 testValues.actual.precisionBeforeDequantization << "_" <<
98 testValues.actual.dequantization << "_" << "_weights_" <<
99 testValues.actual.weights->get_element_type() << "_" << "{ " <<
100 testValues.actual.weights->cast_vector<float>()[0] << " }_" <<
101 testValues.actual.fakeQuantizeOnWeights << "_";
106 TEST_P(GroupConvolutionTransformation, CompareFunctions) {
107 actualFunction->validate_nodes_and_infer_types();
108 auto res = compare_functions(referenceFunction, actualFunction, true, true, true);
109 ASSERT_TRUE(res.first) << res.second;
112 const std::vector<GroupConvolutionTestValues> testValues = {
113 // group convolution, tensor quantization, with zero point
115 LayerTransformation::createParamsU8I8().setSupportAsymmetricQuantization(true),
122 {{ngraph::element::f32}, { 128.f }, { 0.02f }},
123 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
124 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
129 {{}, { { 128.f }, ngraph::element::f32, { 1, 6, 1, 1 }, false }, {}},
130 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
132 ngraph::element::f32,
133 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 24, 1, 1 }}} // 0.0002 = 0.02 (on data) * 0.01 (on weights)
136 // group convolution, tensor quantization, with zero point
138 LayerTransformation::createParamsU8I8().setSupportAsymmetricQuantization(false),
145 {{ngraph::element::f32}, { 128.f }, { 0.02f }},
146 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
147 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
152 {{ ngraph::element::f32 }, { 128.f }, { 0.02f }},
153 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
154 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } },
155 ngraph::element::f32,
159 // group convolution, tensor quantization, with zero point
161 LayerTransformation::createParamsU8I8().setUpdatePrecisions(false),
167 ngraph::element::f32,
168 {{}, { 128.f }, { 0.02f }},
169 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
170 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
174 ngraph::element::f32,
175 {{}, { { 128.f }, ngraph::element::f32, { 1, 6, 1, 1 }, false }, {}},
176 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ -125.f }),
178 ngraph::element::f32,
179 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 24, 1, 1 }}} // 0.0002 = 0.02 (on data) * 0.01 (on weights)
182 // group convolution, per-channel quantization with different values, without zero point
184 LayerTransformation::createParamsU8I8(),
192 {ngraph::element::f32},
194 {{ 0.02f, 0.02f, 0.04f, 0.04f, 0.08f, 0.08f }, ngraph::element::f32, {1, 6, 1, 1}}
196 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
197 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
203 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
205 ngraph::element::f32,
211 // 0.0002 = 0.02 (on data) * 0.01 (on weights)
212 0.0002f, 0.0002f, 0.0002f, 0.0002f, 0.0002f, 0.0002f, 0.0002f, 0.0002f,
213 // 0.0004 = 0.04 (on data) * 0.01 (on weights)
214 0.0004f, 0.0004f, 0.0004f, 0.0004f, 0.0004f, 0.0004f, 0.0004f, 0.0004f,
215 // 0.0008 = 0.08 (on data) * 0.01 (on weights)
216 0.0008f, 0.0008f, 0.0008f, 0.0008f, 0.0008f, 0.0008f, 0.0008f, 0.0008f
218 ngraph::element::f32, {24, 1, 1}
223 // group convolution, per-channel quantization with the same values, without zero point
225 LayerTransformation::createParamsU8I8(),
233 {ngraph::element::f32},
235 {{ 0.02f }, ngraph::element::f32, {1, 6, 1, 1}}
237 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
238 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
244 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
246 ngraph::element::f32,
250 {{ 0.0002f }, ngraph::element::f32, {24, 1, 1}}
254 // group convolution, without zero point, without convert
256 LayerTransformation::createParamsU8I8(),
262 ngraph::element::f32,
264 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
265 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
269 ngraph::element::f32,
271 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
272 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } },
273 ngraph::element::f32,
277 // group convolution, without zero point
279 LayerTransformation::createParamsU8I8(),
286 {{element::f32}, {}, { 0.02f }},
287 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
288 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
294 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
296 ngraph::element::f32,
297 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 24, 1, 1 }}}
300 // depth-wise convolution, tensor quantization, with zero point
302 LayerTransformation::createParamsU8I8(),
309 {{ngraph::element::f32}, { 128.f }, { 0.02f }},
310 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
311 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
316 {{}, { { 128.f }, ngraph::element::f32, { 1, 6, 1, 1 }, false }, {}},
317 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
319 ngraph::element::f32,
320 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 6, 1, 1 }}}
323 // depth-wise convolution, tensor quantization, with zero point
325 LayerTransformation::createParamsU8I8().setUpdatePrecisions(false),
331 ngraph::element::f32,
332 {{}, { 128.f }, { 0.02f }},
333 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
334 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
338 ngraph::element::f32,
339 {{}, { { 128.f }, ngraph::element::f32, { 1, 6, 1, 1 }, false }, {}},
340 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ -125.f }),
342 ngraph::element::f32,
343 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 6, 1, 1 }}}
346 // depth-wise convolution, per-channel quantization with different values, without zero point
348 LayerTransformation::createParamsU8I8(),
356 {ngraph::element::f32},
358 {{ 0.02f, 0.02f, 0.04f, 0.04f, 0.08f, 0.08f }, ngraph::element::f32, {1, 6, 1, 1}}
360 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
361 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
367 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
369 ngraph::element::f32,
375 0.0002f, 0.0002f, // 0.0002 = 0.02 (on data) * 0.01 (on weights)
376 0.0004f, 0.0004f, // 0.0004 = 0.04 (on data) * 0.01 (on weights)
377 0.0008f, 0.0008f // 0.0008 = 0.08 (on data) * 0.01 (on weights)
379 ngraph::element::f32, {6, 1, 1}
384 // depth-wise convolution, per-channel quantization with the same values, without zero point
386 LayerTransformation::createParamsU8I8(),
394 {ngraph::element::f32},
396 {{ 0.02f }, ngraph::element::f32, {1, 6, 1, 1}}
398 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
399 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
405 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
407 ngraph::element::f32,
411 {{ 0.0002f }, ngraph::element::f32, {6, 1, 1}}
415 // depth-wise convolution, without zero point, without convert
417 LayerTransformation::createParamsU8I8(),
423 ngraph::element::f32,
425 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
426 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
430 ngraph::element::f32,
432 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
433 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } },
434 ngraph::element::f32,
438 // depth-wise convolution, without zero point
440 LayerTransformation::createParamsU8I8(),
447 {{element::f32}, {}, { 0.02f }},
448 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
449 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
455 op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector<float>{ -125.f }),
457 ngraph::element::f32,
458 {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 6, 1, 1 }}}
461 // without dequantization operations
463 LayerTransformation::createParamsU8I8(),
469 ngraph::element::f32,
471 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
472 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }
476 ngraph::element::f32,
478 op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector<float>{ 2.f }),
479 { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } },
480 ngraph::element::f32,
486 INSTANTIATE_TEST_CASE_P(
488 GroupConvolutionTransformation,
489 ::testing::ValuesIn(testValues),
490 GroupConvolutionTransformation::getTestCaseName);