From 37ad512d9807d335e3cf63804e8a6a1394626610 Mon Sep 17 00:00:00 2001 From: Edward Shogulin Date: Mon, 20 Dec 2021 11:19:40 +0300 Subject: [PATCH] [CPU] Optimize quantization scheme for SPR/ATS (#7549) * [CPU] Optimize quantization scheme for SPR/ATS * [CPU] [LPT] plugin tests * [GPU] [LPT] plugin tests * [CPU] limitation was removed * [CPU] optimization FP32 old way support * [LPT] comment fix * [LPT] Multiply plugin test improvement * [LPT] Multiply support * [LPT] GPU tests fix * [LPT] test quick fix * [LPT] new ppi fix * look like spent time for tests refactoring --- .../mkldnn_plugin/mkldnn_graph_optimizer.cpp | 34 ++++- .../src/multiply.cpp | 18 +-- ...ntwise_branch_selection_transformation.cpp | 100 +++++++++++++++ .../multiply_transformation.cpp | 79 +++++++----- ...ntwise_branch_selection_transformation.cpp | 88 +++++++++++++ .../multiply_transformation.cpp | 81 ++++++------ ...ntwise_branch_selection_transformation.hpp | 51 ++++++++ .../multiply_transformation.hpp | 8 +- ...ntwise_branch_selection_transformation.cpp | 120 ++++++++++++++++++ .../multiply_transformation.cpp | 45 +++++-- .../base/layer_test_utils.hpp | 8 ++ .../src/base/layer_test_utils.cpp | 58 ++++++++- .../lpt_ngraph_functions/add_function.hpp | 7 +- .../lpt_ngraph_functions/common/builders.hpp | 5 +- .../common/convolution.hpp | 36 ++++++ .../elementwise_function.hpp | 38 ++++++ .../multiply_function.hpp | 11 +- .../lpt_ngraph_functions/src/add_function.cpp | 3 +- .../src/common/builders.cpp | 30 +++++ .../src/common/convolution.cpp | 29 +++++ .../src/elementwise_function.cpp | 119 +++++++++++++++++ .../src/group_convolution_function.cpp | 8 +- .../src/multiply_function.cpp | 34 ++++- 23 files changed, 892 insertions(+), 118 deletions(-) create mode 100644 src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp create mode 100644 src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp create mode 100644 src/tests/functional/plugin/shared/include/low_precision_transformations/elementwise_branch_selection_transformation.hpp create mode 100644 src/tests/functional/plugin/shared/src/low_precision_transformations/elementwise_branch_selection_transformation.cpp create mode 100644 src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/convolution.hpp create mode 100644 src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/elementwise_function.hpp create mode 100644 src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/convolution.cpp create mode 100644 src/tests/ngraph_helpers/lpt_ngraph_functions/src/elementwise_function.cpp diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_graph_optimizer.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_graph_optimizer.cpp index b789d1c01ff..3a6fa6c1df9 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_graph_optimizer.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_graph_optimizer.cpp @@ -1134,8 +1134,38 @@ void MKLDNNGraphOptimizer::FuseConvolutionSumAndConvolutionSumActivation(MKLDNNG if (!isSuitableParent1 && !isSuitableParent2) continue; - auto mergedConv = isSuitableParent1 ? parent1 : parent2; - auto peerNode = isSuitableParent1 ? parent2 : parent1; + std::shared_ptr mergedConv; + std::shared_ptr peerNode; + + if (isSuitableParent1 && isSuitableParent2) { + // not merged operation (peerNode) has to be in low precision + const auto isBranchQuantized = [](const MKLDNNNodePtr& branchParent) { + const auto& fused = branchParent->getFusedWith(); + const auto branchPrecision = fused.empty() ? + branchParent->getOriginalOutputPrecisionAtPort(0) : + fused[fused.size() - 1]->getOriginalOutputPrecisionAtPort(0); + return (branchPrecision == Precision::I8) || (branchPrecision == Precision::U8); + }; + + const auto isBranch1Quantized = isBranchQuantized(graphNode->getParentEdgesAtPort(0)[0]->getParent()); + const auto isBranch2Quantized = isBranchQuantized(graphNode->getParentEdgesAtPort(1)[0]->getParent()); + if (isBranch1Quantized || isBranch2Quantized) { + // INT8 + const auto parent1CanBeMerged = parent1->getChildEdges().size() == 1ul; + + // if both branches are quantized, then parent1 is selected (result is not changed) + mergedConv = isBranch2Quantized && parent1CanBeMerged ? parent1 : parent2; + peerNode = isBranch2Quantized && parent1CanBeMerged ? parent2 : parent1; + } else { + // original FP32 + mergedConv = isSuitableParent1 ? parent1 : parent2; + peerNode = isSuitableParent1 ? parent2 : parent1; + } + } else { + mergedConv = isSuitableParent1 ? parent1 : parent2; + peerNode = isSuitableParent1 ? parent2 : parent1; + } + if (isSuitableParent1 && isSuitableParent2) { if ((peerNode->getType() == Convolution || peerNode->getType() == BinaryConvolution) && mergedConv->getChildEdges().size() != 1) { diff --git a/src/common/low_precision_transformations/src/multiply.cpp b/src/common/low_precision_transformations/src/multiply.cpp index 68792d2d3c7..021cd2cd569 100644 --- a/src/common/low_precision_transformations/src/multiply.cpp +++ b/src/common/low_precision_transformations/src/multiply.cpp @@ -97,18 +97,14 @@ bool MultiplyTransformation::transform(TransformationContext& context, ngraph::p } else { const int emptyPathIndex = fullPathIndex == 0 ? 1 : 0; - FakeQuantizeDequantization dequantizationEmptyPath = NetworkHelper::getDequantization(multiply, emptyPathIndex); - if ((updatePrecisions && !dequantizationEmptyPath.empty() && !dequantizationEmptyPath.isLowPrecision()) || - (dequantizationEmptyPath.multiply == nullptr && dequantizationEmptyPath.subtract == nullptr)) { - return false; + if (updatePrecisions) { + const FakeQuantizeDequantization dequantizationEmptyPath = NetworkHelper::getDequantization(multiply, emptyPathIndex); + if (!dequantizationEmptyPath.empty() && !dequantizationEmptyPath.isLowPrecision()) { + return false; + } } - FakeQuantizeDequantization dequantizationFullPath = NetworkHelper::getDequantization(multiply, fullPathIndex); - if (updatePrecisions && !dequantizationFullPath.empty() && !dequantizationFullPath.isLowPrecision()) { - return false; - } - - dequantizationEmptyPath = NetworkHelper::foldDequantization(multiply, emptyPathIndex); + FakeQuantizeDequantization dequantizationEmptyPath = NetworkHelper::foldDequantization(multiply, emptyPathIndex); std::shared_ptr subtractValuesEmptyPath; std::shared_ptr multiplyValuesEmptyPath; std::tie(subtractValuesEmptyPath, multiplyValuesEmptyPath) = NetworkHelper::createEmptyValues(dequantizationEmptyPath, deqPrecision); @@ -118,7 +114,7 @@ bool MultiplyTransformation::transform(TransformationContext& context, ngraph::p return false; } - dequantizationFullPath = NetworkHelper::foldDequantization(multiply, fullPathIndex); + FakeQuantizeDequantization dequantizationFullPath = NetworkHelper::foldDequantization(multiply, fullPathIndex); std::shared_ptr subtractValuesFullPath; std::shared_ptr multiplyValuesFullPath; std::tie(subtractValuesFullPath, multiplyValuesFullPath) = NetworkHelper::createEmptyValues(dequantizationFullPath, deqPrecision); diff --git a/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp b/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp new file mode 100644 index 00000000000..4a92eb20391 --- /dev/null +++ b/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/elementwise_branch_selection_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32, +}; + +const std::vector elementwiseTypes = { + "add", + "multiply" +}; + +const std::vector params = { + { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + {} + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {"Constant", "convolution1"}, + {"Constant", "convolution2"}, + {"fakeQuantizeBefore1", "convolution1"}, + {"fakeQuantizeBefore2", "convolution2"}, + {"maxPool", "result"} + }, + { + {"convolution1", "U8"}, + {"convolution2", "U8"}, + {"eltwise", "U8"} + } + }, + { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + {} + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {"Constant", "convolution1"}, + {"Constant", "convolution2"}, + {"fakeQuantizeBefore1", "convolution1"}, + {"fakeQuantizeBefore2", "convolution2"}, + {"maxPool", "result"} + }, + { + {"convolution1", "U8"}, + {"convolution2", "U8"}, + {"eltwise", "U8"} + } + } +}; + +INSTANTIATE_TEST_SUITE_P(smoke_LPT, ElementwiseBranchSelectionTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(ngraph::PartialShape({ 1, 3, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(params), + ::testing::ValuesIn(elementwiseTypes)), + ElementwiseBranchSelectionTransformation::getTestCaseName); +} // namespace diff --git a/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp b/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp index de85a663877..240a127894a 100644 --- a/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp +++ b/src/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp @@ -17,54 +17,63 @@ const std::vector netPrecisions = { const std::vector params = { { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } }, false, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::i8} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, false, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::i8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } }, - true, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - true, - {ngraph::element::i8}, {ngraph::element::i8, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } }, false, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, false, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::u8} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::u8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } }, true, - {ngraph::element::u8}, {ngraph::element::u8, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::u8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, true, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::i8 }, - { {}, {}, false }, { {}, {}, true }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + true, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::i8 + }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -128.f }, { 1.27f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::u8 + }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + true, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.27f }, { 1.28f }, { -1.27f }, { 1.28f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::u8 + }, + { false, {}, false, {}, {}, ngraph::element::f32 }, + { true, {}, true, {}, {}, ngraph::element::f32 }, }; INSTANTIATE_TEST_SUITE_P(smoke_LPT, MultiplyTransformation, diff --git a/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp b/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp new file mode 100644 index 00000000000..eb2eeba0a92 --- /dev/null +++ b/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/elementwise_branch_selection_transformation.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/elementwise_branch_selection_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32, +}; + +const std::vector elementwiseTypes = { + "add", + "multiply" +}; + +const std::vector params = { + { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + {} + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + {}, // GPU doesn't returns Reorders in performance counters + { + {"convolution1", "U8"}, + {"convolution2", "U8"}, + {"eltwise", "U8"} + } + }, + { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + {} + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { + {}, + { std::vector(9, 1.f), ngraph::element::i8, {3, 3, 1, 1} }, + { {ngraph::element::f32}, {}, {std::vector(3, 1.f), ngraph::element::f32, {3, 1, 1, 1}} } + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + {}, // GPU doesn't returns Reorders in performance counters + { + {"convolution1", "U8"}, + {"convolution2", "U8"}, + {"eltwise", "U8"} + } + } +}; + +INSTANTIATE_TEST_SUITE_P(smoke_LPT, ElementwiseBranchSelectionTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(ngraph::PartialShape({ 1, 3, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(params), + ::testing::ValuesIn(elementwiseTypes)), + ElementwiseBranchSelectionTransformation::getTestCaseName); +} // namespace diff --git a/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp b/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp index 815f096e85c..614c5148ec6 100644 --- a/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp +++ b/src/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/multiply_transformation.cpp @@ -12,59 +12,68 @@ using namespace LayerTestsDefinitions; namespace { const std::vector netPrecisions = { ngraph::element::f32, - ngraph::element::f16 + //ngraph::element::f16 }; const std::vector params = { { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } }, false, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::i8} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, false, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::undefined // ngraph::element::i8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } }, - true, - {ngraph::element::i8}, {ngraph::element::f32, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - true, - {ngraph::element::i8}, {ngraph::element::i8, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } }, false, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::f32} - }, - { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, false, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::u8} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::undefined // ngraph::element::u8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } }, true, - {ngraph::element::u8}, {ngraph::element::u8, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::undefined //ngraph::element::u8 }, { - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } }, - { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } }, true, - {ngraph::element::u8}, {ngraph::element::f32, ngraph::element::f32} + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::undefined // ngraph::element::i8 }, - { {}, {}, false }, { {}, {}, true }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + true, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -1.28f }, { 1.27f } }, + ngraph::element::undefined // ngraph::element::i8 + }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.28f }, { 1.27f }, { -128.f }, { 1.27f } }, + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::undefined // ngraph::element::u8 + }, + { + false, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + true, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -1.27f }, { 1.28f }, { -1.27f }, { 1.28f } }, + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } }, + ngraph::element::undefined // ngraph::element::u8 + }, + { false, {}, false, {}, {}, ngraph::element::undefined /* ngraph::element::f32 */ }, + { true, {}, true, {}, {}, ngraph::element::undefined /* ngraph::element::f32 */ }, }; INSTANTIATE_TEST_SUITE_P(smoke_LPT, MultiplyTransformation, diff --git a/src/tests/functional/plugin/shared/include/low_precision_transformations/elementwise_branch_selection_transformation.hpp b/src/tests/functional/plugin/shared/include/low_precision_transformations/elementwise_branch_selection_transformation.hpp new file mode 100644 index 00000000000..06dbd4b63a2 --- /dev/null +++ b/src/tests/functional/plugin/shared/include/low_precision_transformations/elementwise_branch_selection_transformation.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include "shared_test_classes/base/low_precision_transformations/layer_transformation.hpp" +#include "lpt_ngraph_functions/common/convolution.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" + +namespace LayerTestsDefinitions { + +class ElementwiseBranchSelectionTestValues{ +public: + class Branch { + public: + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeBefore; + ngraph::builder::subgraph::Convolution convolution; + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeAfter; + }; + + Branch branch1; + Branch branch2; + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeAfter; + std::vector> expectedReorders; + // expected operation name + expected operation precision + std::vector> expectedPrecisions; +}; + +typedef std::tuple< + ngraph::element::Type, + ngraph::PartialShape, + std::string, + ElementwiseBranchSelectionTestValues, + std::string +> ElementwiseBranchSelectionTransformationParams; + +class ElementwiseBranchSelectionTransformation : + public testing::WithParamInterface, + public LayerTestsUtils::LayerTransformation { +public: + static std::string getTestCaseName(const testing::TestParamInfo& obj); + +protected: + void SetUp() override; + void Run() override; +}; + +} // namespace LayerTestsDefinitions diff --git a/src/tests/functional/plugin/shared/include/low_precision_transformations/multiply_transformation.hpp b/src/tests/functional/plugin/shared/include/low_precision_transformations/multiply_transformation.hpp index 81816916e63..67d484bb955 100644 --- a/src/tests/functional/plugin/shared/include/low_precision_transformations/multiply_transformation.hpp +++ b/src/tests/functional/plugin/shared/include/low_precision_transformations/multiply_transformation.hpp @@ -14,11 +14,12 @@ namespace LayerTestsDefinitions { class MultiplyTestValues { public: + bool broadcast1; ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantize1; + bool broadcast2; ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantize2; - bool broadcast; - std::vector precisionOnActivations; - std::vector expectedPrecisions; + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeAfter; + ngraph::element::Type expectedPrecisions; }; typedef std::tuple< @@ -36,6 +37,7 @@ public: protected: void SetUp() override; + void Run() override; }; } // namespace LayerTestsDefinitions diff --git a/src/tests/functional/plugin/shared/src/low_precision_transformations/elementwise_branch_selection_transformation.cpp b/src/tests/functional/plugin/shared/src/low_precision_transformations/elementwise_branch_selection_transformation.cpp new file mode 100644 index 00000000000..b6820698505 --- /dev/null +++ b/src/tests/functional/plugin/shared/src/low_precision_transformations/elementwise_branch_selection_transformation.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision_transformations/elementwise_branch_selection_transformation.hpp" + +#include +#include + +#include +#include "lpt_ngraph_functions/add_function.hpp" + +namespace LayerTestsDefinitions { + +std::string ElementwiseBranchSelectionTransformation::getTestCaseName(const testing::TestParamInfo& obj) { + ngraph::element::Type netPrecision; + ngraph::PartialShape inputShapes; + std::string targetDevice; + auto params = LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8(); + ElementwiseBranchSelectionTestValues param; + std::string elementwiseType; + std::tie(netPrecision, inputShapes, targetDevice, param, elementwiseType) = obj.param; + + std::ostringstream result; + result << getTestCaseNameByParams(netPrecision, inputShapes, targetDevice, params) << + "_elementwiseType_" << elementwiseType; + + auto toString = [](const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData) -> std::string { + if (fqOnData.empty()) { + return ""; + } + + std::stringstream ss; + ss << "_on_branch1_" << + fqOnData.inputLowValues[0] << "_" << + fqOnData.inputHighValues[0] << "_" << + fqOnData.outputLowValues[0] << "_" << + fqOnData.outputHighValues[0]; + return ss.str(); + }; + + result << + "_on_branch1_" << toString(param.branch1.fakeQuantizeBefore) << toString(param.branch1.fakeQuantizeAfter) << + "_on_branch1_" << toString(param.branch1.fakeQuantizeBefore) << toString(param.branch1.fakeQuantizeAfter) << + "_" << toString(param.fakeQuantizeAfter); + + return result.str(); +} + +void ElementwiseBranchSelectionTransformation::SetUp() { + ngraph::element::Type precision; + ngraph::PartialShape inputShape; + ElementwiseBranchSelectionTestValues param; + std::string elementwiseType; + std::tie(precision, inputShape, targetDevice, param, elementwiseType) = this->GetParam(); + + function = ngraph::builder::subgraph::AddFunction::getOriginalSubgraphWithConvolutions( + precision, + inputShape, + false, + elementwiseType, + param.branch1.fakeQuantizeBefore, + param.branch1.convolution, + param.branch1.fakeQuantizeAfter, + param.branch2.fakeQuantizeBefore, + param.branch2.convolution, + param.branch2.fakeQuantizeAfter, + param.fakeQuantizeAfter); + + ngraph::pass::InitNodeInfo().run_on_function(function); +} + +void ElementwiseBranchSelectionTransformation::Run() { + LayerTestsCommon::Run(); + + const auto params = std::get<3>(GetParam()); + const auto elementwiseType = std::get<4>(GetParam()); + + std::vector> expectedReorders = params.expectedReorders; + if (!expectedReorders.empty()) { + auto rtInfo = LayerTestsCommon::getRuntimeInfo(); + for (auto it : rtInfo) { + const auto& typeIt = it.second.find("layerType"); + const auto type = typeIt->second.as(); + if (type == "Reorder") { + const auto name = it.first; + bool wasFound = false; + for (auto it = expectedReorders.begin(); it != expectedReorders.end(); ++it) { + auto pair = *it; + const std::string parent = name.substr(0, name.find("_")); + const std::string child = name.substr(name.rfind("_") + 1, name.size() - name.rfind("_") - 1); + if ((pair.first == parent) && (pair.second == child)) { + expectedReorders.erase(it); + wasFound = true; + break; + } + } + + ASSERT_TRUE(wasFound) << it.first << " was not found in expected list"; + } else if (type == "Convolution") { + const auto& precisionIt = it.second.find("runtimePrecision"); + const auto precision = precisionIt->second.as(); + ASSERT_EQ("U8", precision); + } + } + + ASSERT_TRUE(expectedReorders.empty()) << "Some Reorder operations were not found in execution graph"; + } + + for (auto it : params.expectedPrecisions) { + const auto actualPrecision = getRuntimePrecisionByFusedName(it.first == "eltwise" ? elementwiseType : it.first); + ASSERT_EQ(it.second, actualPrecision) << "actual precision for operation '" << it.first << "' is not correct"; + } +} + +TEST_P(ElementwiseBranchSelectionTransformation, CompareWithRefImpl) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/src/tests/functional/plugin/shared/src/low_precision_transformations/multiply_transformation.cpp b/src/tests/functional/plugin/shared/src/low_precision_transformations/multiply_transformation.cpp index cf0c42c06e9..6bd05c2ca5c 100644 --- a/src/tests/functional/plugin/shared/src/low_precision_transformations/multiply_transformation.cpp +++ b/src/tests/functional/plugin/shared/src/low_precision_transformations/multiply_transformation.cpp @@ -27,14 +27,10 @@ std::string MultiplyTransformation::getTestCaseName(const testing::TestParamInfo std::ostringstream result; result << getTestCaseNameByParams(precision, inputShapes, targetDevice, params) << - (param.broadcast ? "_broadcast" : ""); - for (const auto& elem : param.precisionOnActivations) { - result << "_" << elem << "_"; - } - result << "expected_precisions_"; - for (const auto& elem : param.expectedPrecisions) { - result << "_" << elem << "_"; - } + (param.broadcast1 ? "_broadcast1" : "") << + (param.broadcast2 ? "_broadcast2" : ""); + + result << "_" << param.expectedPrecisions << "_"; if (!param.fakeQuantize1.empty()) { result << "_on_branch1_" << @@ -62,13 +58,42 @@ void MultiplyTransformation::SetUp() { function = ngraph::builder::subgraph::MultiplyFunction::getOriginal( precision, inputShape, - param.broadcast, + param.broadcast1, param.fakeQuantize1, - param.fakeQuantize2); + param.broadcast2, + param.fakeQuantize2, + param.fakeQuantizeAfter); ngraph::pass::InitNodeInfo().run_on_function(function); } +void MultiplyTransformation::Run() { + LayerTestsCommon::Run(); + + const auto params = std::get<3>(GetParam()); + + auto to_string = [](const ngraph::element::Type& precision) -> std::string { + switch (precision) { + case ngraph::element::f32: { + return "FP32"; + } + case ngraph::element::i8: { + return "I8"; + } + case ngraph::element::u8: { + return "U8"; + } + default: { + return ""; + } + } + }; + + const auto expectedFqPrecision = to_string(params.expectedPrecisions); + const auto actualFqPrecision = getRuntimePrecision("multiply"); + EXPECT_EQ(expectedFqPrecision, actualFqPrecision); +} + TEST_P(MultiplyTransformation, CompareWithRefImpl) { Run(); }; diff --git a/src/tests/functional/shared_test_classes/include/shared_test_classes/base/layer_test_utils.hpp b/src/tests/functional/shared_test_classes/include/shared_test_classes/base/layer_test_utils.hpp index 92d12e3a8a6..35bfb91a492 100644 --- a/src/tests/functional/shared_test_classes/include/shared_test_classes/base/layer_test_utils.hpp +++ b/src/tests/functional/shared_test_classes/include/shared_test_classes/base/layer_test_utils.hpp @@ -85,9 +85,17 @@ public: std::map& GetConfiguration(); + // get runtime precision by operation friendly name std::string getRuntimePrecision(const std::string& layerName); + + // get runtime precision by operation type std::string getRuntimePrecisionByType(const std::string& layerType); + // get runtime precision by operation friendly name which can be fused + std::string getRuntimePrecisionByFusedName(const std::string& layerName); + + std::map getRuntimeInfo(); + #ifndef NDEBUG void showRuntimePrecisions(); #endif diff --git a/src/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp b/src/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp index 7292ae0eb78..d4b297c9420 100644 --- a/src/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp +++ b/src/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp @@ -516,6 +516,54 @@ std::string LayerTestsCommon::getRuntimePrecisionByType(const std::string& layer return ""; } +std::string LayerTestsCommon::getRuntimePrecisionByFusedName(const std::string& layerName) { + const auto execGraph = executableNetwork.GetExecGraphInfo(); + const auto execFunction = execGraph.getFunction(); + + const auto parse = [](const std::string& originalLayersNames) -> std::set { + std::set names; + + std::string tmp = originalLayersNames; + size_t beginPosition = 0ul; + size_t endPosition; + while ((endPosition = tmp.find(",", beginPosition)) != std::string::npos) { + names.insert(tmp.substr(beginPosition, endPosition - beginPosition)); + beginPosition = endPosition + 1; + } + + names.insert(tmp.substr(beginPosition, endPosition - beginPosition)); + return names; + }; + + for (const auto& op : execFunction->get_ops()) { + const auto& rtInfo = op->get_rt_info(); + + const auto& nameIt = rtInfo.find("originalLayersNames"); + IE_ASSERT(nameIt != rtInfo.end()) << "originalLayersNames is not found for node: " << layerName; + const auto fusedName = parse(nameIt->second.as()); + if (fusedName.find(layerName) == fusedName.end()) { + continue; + } + + const auto& it = rtInfo.find("runtimePrecision"); + IE_ASSERT(it != rtInfo.end()) << "runtimePrecision is not found for node: " << layerName; + const auto rtPrecisionPtr = it->second.as(); + return rtPrecisionPtr; + } + + return ""; +} + +std::map LayerTestsCommon::getRuntimeInfo() { + const auto execGraph = executableNetwork.GetExecGraphInfo(); + const auto function = execGraph.getFunction(); + std::map runtimeInfo; + for (const auto& op : function->get_ops()) { + runtimeInfo[op->get_friendly_name()] = op->get_rt_info(); + } + return runtimeInfo; +} + #ifndef NDEBUG void LayerTestsCommon::showRuntimePrecisions() { const auto execGraph = executableNetwork.GetExecGraphInfo(); @@ -523,13 +571,17 @@ void LayerTestsCommon::showRuntimePrecisions() { for (const auto& op : execFunction->get_ops()) { const auto& rtInfo = op->get_rt_info(); + + const auto& nameIt = rtInfo.find("originalLayersNames"); + const auto name = nameIt->second.as(); + const auto& typeIt = rtInfo.find("layerType"); - const auto type = typeIt->second.as(); - const auto& it = rtInfo.find("runtimePrecision"); + const auto& it = rtInfo.find("runtimePrecision"); const auto rtPrecisionPtr = it->second.as(); - std::cout << type << ": " << rtPrecisionPtr << std::endl; + + std::cout << type << "(" << name << "): " << rtPrecisionPtr << std::endl; } } #endif diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/add_function.hpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/add_function.hpp index b0b4e9ad693..3b5a8a86a24 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/add_function.hpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/add_function.hpp @@ -8,8 +8,11 @@ #include #include -#include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "elementwise_function.hpp" #include "lpt_ngraph_functions/common/builders.hpp" +#include "lpt_ngraph_functions/common/convolution.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" namespace ngraph { namespace builder { @@ -53,7 +56,7 @@ inline std::ostream& operator<<(std::ostream& out, const AddExpectedValues& valu "_mutliply" << values.mutliplyValuesAfter.size(); } -class AddFunction { +class AddFunction : public ElementwiseFunction { public: static std::shared_ptr getOriginal( const ngraph::element::Type precision, diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/builders.hpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/builders.hpp index efed4204a3d..0ffab7b4a85 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/builders.hpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/builders.hpp @@ -15,8 +15,9 @@ #include "low_precision/network_helper.hpp" #include "lpt_ngraph_functions/common/add.hpp" -#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" +#include "lpt_ngraph_functions/common/convolution.hpp" #include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" #include "lpt_ngraph_functions/common/reshape.hpp" #include "lpt_ngraph_functions/common/transpose.hpp" @@ -78,6 +79,8 @@ std::shared_ptr makeFakeQuantize( const ngraph::element::Type precision, const FakeQuantizeOnData& fqOnData); +std::shared_ptr makeConvolution(const Output& output, const Convolution& convolution); + std::shared_ptr makeFakeQuantizeTypeRelaxed( const Output& output, const ngraph::element::Type precision, diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/convolution.hpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/convolution.hpp new file mode 100644 index 00000000000..907a46a162f --- /dev/null +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/common/convolution.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "constant.hpp" +#include "dequantization_operations.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +class Convolution { +public: + Convolution(); + + Convolution( + const DequantizationOperations::Subtract zeroPointOnActivations, + const Constant& constantOnWeights, + const DequantizationOperations& dequantizationOnWeights); + + bool empty() const; + + DequantizationOperations::Subtract zeroPointOnActivations; + Constant constantOnWeights; + DequantizationOperations dequantizationOnWeights; +}; + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/elementwise_function.hpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/elementwise_function.hpp new file mode 100644 index 00000000000..66e33ec307f --- /dev/null +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/elementwise_function.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "lpt_ngraph_functions/common/builders.hpp" +#include "lpt_ngraph_functions/common/convolution.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +class ElementwiseFunction { +public: + static std::shared_ptr getOriginalSubgraphWithConvolutions( + const ngraph::element::Type precision, + const ngraph::PartialShape& inputShape, + const bool broadcast, + const std::string& elementWiseType, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataBefore1, + const ngraph::builder::subgraph::Convolution& convolution1, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter1, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataBefore2, + const ngraph::builder::subgraph::Convolution& convolution2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter); +}; + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/multiply_function.hpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/multiply_function.hpp index 96c1b387e34..870ba9b6116 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/multiply_function.hpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/multiply_function.hpp @@ -7,6 +7,7 @@ #include #include +#include "elementwise_function.hpp" #include "lpt_ngraph_functions/common/constant.hpp" #include "lpt_ngraph_functions/common/dequantization_operations.hpp" @@ -37,7 +38,7 @@ inline std::ostream& operator<<(std::ostream& out, const MultiplyValues& values) return out << "_" << values.branch1 << "_" << values.branch2 << (values.isDequantization ? "_isDequantization" : ""); } -class MultiplyFunction { +class MultiplyFunction : public ElementwiseFunction { public: static std::shared_ptr get( const element::Type precision, @@ -46,9 +47,11 @@ public: static std::shared_ptr getOriginal( const ngraph::element::Type precision, const ngraph::PartialShape& inputShape, - const bool broadcast, - const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData1, - const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData2); + const bool broadcast1, + const ngraph::builder::subgraph::FakeQuantizeOnData& fq1, + const bool broadcast2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fq2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqAfter); }; } // namespace subgraph diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/add_function.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/add_function.cpp index 634fc3bb962..b819c513b5b 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/add_function.cpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/add_function.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include "lpt_ngraph_functions/add_function.hpp" + #include "low_precision/network_helper.hpp" #include "low_precision/layer_transformation.hpp" @@ -9,7 +11,6 @@ #include "lpt_ngraph_functions/common/dequantization_operations.hpp" #include "ngraph_functions/subgraph_builders.hpp" -#include "lpt_ngraph_functions/add_function.hpp" using namespace ngraph::pass::low_precision; diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/builders.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/builders.cpp index 4500e739bd1..5ad53ea23ca 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/builders.cpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/builders.cpp @@ -205,6 +205,36 @@ std::shared_ptr makeFakeQuantize( fqOnData.outputHighValues)); } +std::shared_ptr makeConvolution(const Output& output, const Convolution& convolution) { + auto parentOnActivations = output; + if (!convolution.zeroPointOnActivations.empty()) { + auto constant = std::make_shared( + convolution.zeroPointOnActivations.outPrecision, + convolution.zeroPointOnActivations.constantShape, + convolution.zeroPointOnActivations.values); + parentOnActivations = std::make_shared(parentOnActivations, constant); + } + + assert(!convolution.constantOnWeights.empty()); + + ngraph::Output weights = std::make_shared( + convolution.constantOnWeights.outPrecision, + convolution.constantOnWeights.shape, + convolution.constantOnWeights.values); + + if (!convolution.dequantizationOnWeights.empty()) { + weights = makeDequantization(weights, convolution.dequantizationOnWeights); + } + + return std::make_shared( + parentOnActivations, + weights, + ngraph::Strides{ 1, 1 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::Strides{ 1, 1 }); +} + std::shared_ptr makeFakeQuantizeTypeRelaxed( const Output& output, const ngraph::element::Type precision, diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/convolution.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/convolution.cpp new file mode 100644 index 00000000000..777a8350200 --- /dev/null +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/common/convolution.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "lpt_ngraph_functions/common/convolution.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +Convolution::Convolution() { +} + +Convolution::Convolution( + const DequantizationOperations::Subtract zeroPointOnActivations, + const Constant& constantOnWeights, + const DequantizationOperations& dequantizationOnWeights) : + zeroPointOnActivations(zeroPointOnActivations), + constantOnWeights(constantOnWeights), + dequantizationOnWeights(dequantizationOnWeights) { +} + +bool Convolution::empty() const { + return zeroPointOnActivations.empty() && constantOnWeights.empty() && dequantizationOnWeights.empty(); +} + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/elementwise_function.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/elementwise_function.cpp new file mode 100644 index 00000000000..de97ac89d46 --- /dev/null +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/elementwise_function.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "lpt_ngraph_functions/elementwise_function.hpp" + +#include "low_precision/layer_transformation.hpp" +#include "ngraph/opsets/opset1.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" + +using namespace ngraph::pass::low_precision; + +namespace ngraph { +namespace builder { +namespace subgraph { + +namespace { + +std::shared_ptr makeFakeQuantizeWithNames( + const Output& parent, + const ngraph::element::Type precision, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData, + const std::string name) { + auto fq = ngraph::builder::subgraph::makeFakeQuantize(parent, precision, fqOnData); + fq->set_friendly_name(name); + fq->get_input_node_ptr(1)->set_friendly_name(name + "/inputLow"); + fq->get_input_node_ptr(2)->set_friendly_name(name + "/inputHigh"); + fq->get_input_node_ptr(3)->set_friendly_name(name + "/outputLow"); + fq->get_input_node_ptr(4)->set_friendly_name(name + "/outputHigh"); + return fq; +} + +} // namespace + +std::shared_ptr ElementwiseFunction::getOriginalSubgraphWithConvolutions( + const ngraph::element::Type precision, + const ngraph::PartialShape& inputShape, + const bool broadcast, + const std::string& elementWiseType, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataBefore1, + const ngraph::builder::subgraph::Convolution& convolution1, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter1, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataBefore2, + const ngraph::builder::subgraph::Convolution& convolution2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter) { + ngraph::PartialShape inputShape2 = inputShape; + + if (broadcast) { + inputShape2[2] = 1; + inputShape2[3] = 1; + } + + auto makeBranch = [&]( + const ngraph::element::Type precision, + const ngraph::PartialShape& inputShape, + const size_t index, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataBefore, + const ngraph::builder::subgraph::Convolution& convolution, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnDataAfter) -> + std::pair, std::shared_ptr> { + const auto input = std::make_shared(precision, inputShape); + input->set_friendly_name("input" + std::to_string(index)); + std::shared_ptr parent = input; + + if (!fqOnDataBefore.empty()) { + parent = makeFakeQuantizeWithNames(parent, precision, fqOnDataBefore, "fakeQuantizeBefore" + std::to_string(index)); + } + + if (!convolution.empty()) { + parent = makeConvolution(parent, convolution); + parent->set_friendly_name("convolution" + std::to_string(index)); + } + + if (!fqOnDataAfter.empty()) { + parent = makeFakeQuantizeWithNames(parent, precision, fqOnDataAfter, "fakeQuantizeAfter" + std::to_string(index)); + } + + return std::make_pair(input, parent); + }; + + const auto branch1 = makeBranch(precision, inputShape, 1, fqOnDataBefore1, convolution1, fqOnDataAfter1); + const auto branch2 = makeBranch(precision, inputShape, 2, fqOnDataBefore2, convolution2, fqOnDataAfter2); + + std::shared_ptr result; + if (elementWiseType == "add") { + result = std::make_shared(branch1.second, branch2.second); + result->set_friendly_name("add"); + } else if (elementWiseType == "multiply") { + result = std::make_shared(branch1.second, branch2.second); + result->set_friendly_name("multiply"); + } else { + THROW_TRANSFORMATION_EXCEPTION << "not supported element-wise operation type " << elementWiseType; + } + + if (!fqOnDataAfter.empty()) { + result = makeFakeQuantizeWithNames(result, precision, fqOnDataAfter, "fakeQuantizeAfter"); + + // we need a some operation to move dequantization operations away from FakeQuantize to avoid cleanup fuse + result = std::make_shared( + result, + Strides{ 1, 1 }, + Shape{ 1, 1 }, + Shape{ 0, 0 }, + Shape{ 2, 2 }, + op::RoundingType::FLOOR); + result->set_friendly_name("maxPool"); + } + + result = std::make_shared(result); + result->set_friendly_name("result"); + + ngraph::ResultVector results{ std::dynamic_pointer_cast(result) }; + return std::make_shared(results, ngraph::ParameterVector{ branch1.first, branch2.first }, "AddTransformation"); +} + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/group_convolution_function.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/group_convolution_function.cpp index 335f6f44df4..6a2d7ff6f30 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/group_convolution_function.cpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/group_convolution_function.cpp @@ -169,25 +169,25 @@ std::shared_ptr GroupConvolutionFunction::getOriginal( if (!fakeQuantizeOnData.empty()) { parent = std::make_shared( input, - std::make_shared( + std::make_shared( precision, rankLength == 3 ? Shape{ 1, fakeQuantizeOnData.inputLowValues.size(), 1 } : Shape{ 1, fakeQuantizeOnData.inputLowValues.size(), 1, 1 }, fakeQuantizeOnData.inputLowValues), - std::make_shared( + std::make_shared( precision, rankLength == 3 ? Shape{ 1, fakeQuantizeOnData.inputHighValues.size(), 1 } : Shape{ 1, fakeQuantizeOnData.inputHighValues.size(), 1, 1 }, fakeQuantizeOnData.inputHighValues), - std::make_shared( + std::make_shared( precision, rankLength == 3 ? Shape{ 1, fakeQuantizeOnData.outputLowValues.size(), 1 } : Shape{ 1, fakeQuantizeOnData.outputLowValues.size(), 1, 1 }, fakeQuantizeOnData.outputLowValues), - std::make_shared( + std::make_shared( precision, rankLength == 3 ? Shape{ 1, fakeQuantizeOnData.outputHighValues.size(), 1 } : diff --git a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/multiply_function.cpp b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/multiply_function.cpp index 714a7ab1cdf..29a4571756a 100644 --- a/src/tests/ngraph_helpers/lpt_ngraph_functions/src/multiply_function.cpp +++ b/src/tests/ngraph_helpers/lpt_ngraph_functions/src/multiply_function.cpp @@ -90,22 +90,32 @@ std::shared_ptr MultiplyFunction::get( std::shared_ptr MultiplyFunction::getOriginal( const ngraph::element::Type precision, const ngraph::PartialShape& inputShape, - const bool broadcast, + const bool broadcast1, const ngraph::builder::subgraph::FakeQuantizeOnData& fq1, - const ngraph::builder::subgraph::FakeQuantizeOnData& fq2) { - auto inputShape2 = inputShape; + const bool broadcast2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fq2, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqAfter) { + auto inputShape1 = inputShape; + if (broadcast1) { + inputShape1[2] = 1; + inputShape1[3] = 1; + } - if (broadcast) { + auto inputShape2 = inputShape; + if (broadcast2) { inputShape2[2] = 1; inputShape2[3] = 1; } - const auto input1 = std::make_shared(precision, inputShape); + const auto input1 = std::make_shared(precision, inputShape1); const auto fakeQuantize1 = fq1.empty() ? nullptr : ngraph::builder::makeFakeQuantize( input1, precision, fq1.quantizationLevel, fq1.constantShape, fq1.inputLowValues, fq1.inputHighValues, fq1.outputLowValues, fq1.outputHighValues); + if (fakeQuantize1 != nullptr) { + fakeQuantize1->set_friendly_name("fakeQuantize1"); + } const auto input2 = std::make_shared(precision, inputShape2); const auto fakeQuantize2 = fq2.empty() ? @@ -113,12 +123,24 @@ std::shared_ptr MultiplyFunction::getOriginal( ngraph::builder::makeFakeQuantize( input2, precision, fq2.quantizationLevel, fq2.constantShape, fq2.inputLowValues, fq2.inputHighValues, fq2.outputLowValues, fq2.outputHighValues); + if (fakeQuantize2 != nullptr) { + fakeQuantize2->set_friendly_name("fakeQuantize2"); + } const auto multiply = std::make_shared( fq1.empty() ? input1 : fakeQuantize1, fq2.empty() ? input2 : fakeQuantize2); + multiply->set_friendly_name("multiply"); - ngraph::ResultVector results{ std::make_shared(multiply) }; + auto const fakeQuantizeAfter = fqAfter.empty() ? + nullptr : + makeFakeQuantize(multiply, precision, fqAfter); + if (fakeQuantizeAfter != nullptr) { + fakeQuantizeAfter->set_friendly_name("fakeQuantizeAfter"); + } + + const std::shared_ptr result = fakeQuantizeAfter == nullptr ? std::dynamic_pointer_cast(multiply) : fakeQuantizeAfter; + ngraph::ResultVector results{ std::make_shared(result) }; std::shared_ptr function = std::make_shared( results, ngraph::ParameterVector{ input1, input2 },