[LPT] Dequantization constant output precision handling extending (#2987)
authorEdward Shogulin <edward.shogulin@intel.com>
Wed, 11 Nov 2020 15:50:37 +0000 (18:50 +0300)
committerGitHub <noreply@github.com>
Wed, 11 Nov 2020 15:50:37 +0000 (18:50 +0300)
* [LPT] moveDequantizationAfter fix

* [LPT] ConcatTransformation fix: only intermediate operations are handled

14 files changed:
inference-engine/src/low_precision_transformations/include/low_precision/common/subgraph.hpp
inference-engine/src/low_precision_transformations/src/common/concat.cpp
inference-engine/src/low_precision_transformations/src/common/network_helper.cpp
inference-engine/src/low_precision_transformations/src/common/subgraph.cpp
inference-engine/tests/functional/inference_engine/lp_transformations/concat_with_different_precision_on_childs.cpp
inference-engine/tests/functional/inference_engine/lp_transformations/concat_with_reshape_at_the_end_transformation.cpp [new file with mode: 0644]
inference-engine/tests/functional/inference_engine/lp_transformations/move_dequantization_after_with_int_constant_transformation.cpp [new file with mode: 0644]
inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp
inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/concat_function.hpp
inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp [new file with mode: 0644]
inference-engine/tests/ngraph_functions/src/low_precision_transformations/common/builders.cpp
inference-engine/tests/ngraph_functions/src/low_precision_transformations/common/dequantization_operations.cpp
inference-engine/tests/ngraph_functions/src/low_precision_transformations/concat_function.cpp
inference-engine/tests/ngraph_functions/src/low_precision_transformations/move_dequantization_after_with_int_constant_function.cpp [new file with mode: 0644]

index 5256c14..2703d92 100644 (file)
@@ -30,6 +30,7 @@ public:
     std::unordered_map<std::string, std::shared_ptr<ngraph::Node>> layers;
 
 private:
+    bool atLeastOneIsIntermediate(const std::shared_ptr<ngraph::Node>& node) const;
     bool fillSubgraphForQuantization(const std::shared_ptr<ngraph::opset1::FakeQuantize>& fakeQuantize, std::unordered_set<std::string>& handledLayers);
     bool fillSubgraphForIntermediate(const std::shared_ptr<ngraph::Node>& intermediate, std::unordered_set<std::string>& handledLayers);
     bool fill(const std::shared_ptr<ngraph::Node>& concat, std::unordered_set<std::string>& handledLayers);
index 99bf48d..b2c0b33 100644 (file)
@@ -138,7 +138,7 @@ bool ConcatTransformation::transform(TransformationContext& context, ngraph::pat
             dequantizationSub,
             subgraph.quantizationLayers[0]->get_output_element_type(0),
             subgraph.quantizationLayers[0]->get_output_shape(0),
-            dataPrecision.precision,
+            updatePrecisions ? dataPrecision.precision : subgraph.quantizationLayers[0]->get_output_element_type(0),
             dataPrecision.min,
             dataPrecision.max);
 
index 6eb5bc1..86159ed 100644 (file)
@@ -951,14 +951,38 @@ NetworkHelper::InsertDequantizationResult NetworkHelper::moveDequantizationAfter
         parent = std::make_shared<DequantizationConvert>(parent, dequantization.convert->get_output_element_type(0));
         ngraph::copy_runtime_info({ newOperation, parent }, parent);
     }
+
     if (moveSubtract && (dequantization.subtract != nullptr)) {
         auto subtractConstant = dequantization.subtract->get_input_node_shared_ptr(1);
-        parent = std::make_shared<DequantizationSubtract>(parent, subtractConstant);
+        const element::Type parentPrecision = parent->get_output_element_type(0);
+        if (parentPrecision.bitwidth() < subtractConstant->output(0).get_element_type().bitwidth()) {
+            THROW_IE_LPT_EXCEPTION(*parent) <<
+                "unexpected precisions: on data " << parent->get_friendly_name() << ":" << parentPrecision <<
+                ", subtract dequantization constant " << subtractConstant->get_friendly_name() << ":" << subtractConstant->output(0).get_element_type();
+        }
+
+        parent = std::make_shared<DequantizationSubtract>(
+            parent,
+            subtractConstant->output(0).get_element_type() == parentPrecision ?
+                subtractConstant :
+                fold<opset1::Convert>(subtractConstant->output(0), parentPrecision));
         ngraph::copy_runtime_info({ newOperation, parent }, parent);
     }
+
     if (dequantization.multiply != nullptr) {
         auto multiplyConstant = dequantization.multiply->get_input_node_shared_ptr(1);
-        parent = std::make_shared<DequantizationMultiply>(parent, multiplyConstant);
+        const element::Type parentPrecision = parent->get_output_element_type(0);
+        if (parentPrecision.bitwidth() < multiplyConstant->output(0).get_element_type().bitwidth()) {
+            THROW_IE_LPT_EXCEPTION(*parent) <<
+                "unexpected precisions: on data " << parent->get_friendly_name() << ":" << parentPrecision <<
+                ", multiply dequantization constant " << multiplyConstant->get_friendly_name() << ":" << multiplyConstant->output(0).get_element_type();
+        }
+
+        parent = std::make_shared<DequantizationMultiply>(
+            parent,
+            multiplyConstant->output(0).get_element_type() == parentPrecision ?
+                multiplyConstant :
+                fold<opset1::Convert>(multiplyConstant->output(0), parentPrecision));
         ngraph::copy_runtime_info({ newOperation, parent }, parent);
     }
     replace_node(operation, parent);
index f175151..d73d780 100644 (file)
@@ -36,6 +36,10 @@ bool isQuantizationPerChannel(const std::shared_ptr<ngraph::Node>& node) {
         const Shape& in = input.get_shape();
         const Shape& out = node->output(0).get_shape();
         for (size_t i = 0; i < 2; ++i) {
+            if ((i >= in.size()) || (i >= out.size())) {
+                // all previous dimensions are equal
+                return true;
+            }
             if (in[i] != out[i]) {
                 return false;
             }
@@ -86,6 +90,28 @@ bool Subgraph::fillSubgraphForQuantization(
     return true;
 }
 
+bool Subgraph::atLeastOneIsIntermediate(const std::shared_ptr<ngraph::Node>& node) const {
+    for (size_t index = 0; index < node->get_output_size(); ++index) {
+        const auto childInputs = node->get_output_target_inputs(index);
+        for (const auto childInput : childInputs) {
+            auto child = childInput.get_node()->shared_from_this();
+            if (as_type_ptr<opset1::Concat>(child)) {
+                return true;
+            }
+
+            if (!layerTransformationsManager->isPrecisionPreserved(child) || !isQuantizationPerChannel(child)) {
+                // child branch is out of subgraph
+                continue;
+            }
+
+            if (atLeastOneIsIntermediate(child)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool Subgraph::fill(const std::shared_ptr<ngraph::Node>& layer, std::unordered_set<std::string>& handledLayers) {
     // if at least one parent is handled incorrectly then subgraph is not in low precision
     for (size_t index = 0; index < layer->get_input_size(); ++index) {
@@ -138,6 +164,11 @@ bool Subgraph::fill(const std::shared_ptr<ngraph::Node>& layer, std::unordered_s
                     return false;
                 }
             } else {
+                // check if children branches between Concat operations
+                if (!atLeastOneIsIntermediate(child)) {
+                    continue;
+                }
+
                 const std::shared_ptr<ngraph::opset1::FakeQuantize> fakeQuantizeChild = ngraph::as_type_ptr<ngraph::opset1::FakeQuantize>(child);
                 if (fakeQuantizeChild != nullptr) {
                     //
@@ -175,4 +206,4 @@ bool Subgraph::fillSubgraphForConcat(const std::shared_ptr<ngraph::opset1::Conca
 
 }  // namespace low_precision
 }  // namespace pass
-}  // namespace ngraph
\ No newline at end of file
+}  // namespace ngraph
index e150ae5..ee93390 100644 (file)
@@ -104,6 +104,11 @@ public:
         transform.add<ngraph::pass::low_precision::ClampTransformation, ngraph::opset1::Clamp>(testValues.params);
         transform.transform(actualFunction);
 
+        if (!updatePrecisions) {
+            // there is no Convert operation after MaxPool in FP32
+            testValues.result.dequantizationOperations2.convert = {};
+        }
+
         referenceFunction = ngraph::builder::subgraph::ConcatFunction::getReferenceWithDifferentPrecisionOnChilds(
             precision,
             testValues.inputShape,
diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/concat_with_reshape_at_the_end_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/concat_with_reshape_at_the_end_transformation.cpp
new file mode 100644 (file)
index 0000000..cdbef66
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "layer_transformation.hpp"
+
+#include <string>
+#include <sstream>
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include <transformations/utils/utils.hpp>
+#include <transformations/init_node_info.hpp>
+#include <low_precision/transformer.hpp>
+#include <low_precision/concat.hpp>
+#include <low_precision/concat_multi_channels.hpp>
+#include <low_precision/max_pool.hpp>
+#include <low_precision/reshape.hpp>
+
+#include "common_test_utils/ngraph_test_utils.hpp"
+#include "ngraph_functions/low_precision_transformations/concat_function.hpp"
+#include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_data.hpp"
+#include "simple_low_precision_transformer.hpp"
+
+using namespace testing;
+using namespace ngraph;
+using namespace ngraph::pass;
+
+namespace {
+
+class ConcatTransformationActualValues {
+public:
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize1;
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize2;
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize3;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationActualValues& values) {
+    return out << "_" << values.fakeQuantize1 << "_" << values.fakeQuantize2;
+}
+
+class ConcatTransformationResultValues {
+public:
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize1;
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize2;
+    ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize3;
+    ngraph::builder::subgraph::DequantizationOperations dequantizationOperations;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationResultValues& values) {
+    return out << "_" << values.fakeQuantize1 << "_" << values.fakeQuantize2 << "_" << values.fakeQuantize3 << "_" << values.dequantizationOperations;
+}
+
+class ConcatTransformationTestValues {
+public:
+    ngraph::pass::low_precision::LayerTransformation::Params params;
+    ConcatTransformationActualValues actual;
+    ConcatTransformationResultValues result;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationTestValues& values) {
+    return out << "_" << values.actual << "_" << values.result;
+}
+
+typedef std::tuple <
+    ngraph::element::Type,
+    bool,
+    ngraph::Shape,
+    ConcatTransformationTestValues
+> ConcatTransformationParams;
+
+class ConcatWithReshapeAtTheEndTransformation : public LayerTransformation, public testing::WithParamInterface<ConcatTransformationParams> {
+public:
+    void SetUp() override {
+        const ngraph::element::Type precision = std::get<0>(GetParam());
+        const bool updatePrecisions = std::get<1>(GetParam());
+        const ngraph::Shape shape = std::get<2>(GetParam());
+        ConcatTransformationTestValues testValues = std::get<3>(GetParam());
+
+        testValues.params.updatePrecisions = updatePrecisions;
+        if (!updatePrecisions) {
+            testValues.result.fakeQuantize1.outputPrecision = testValues.actual.fakeQuantize1.outputPrecision;
+            testValues.result.fakeQuantize2.outputPrecision = testValues.actual.fakeQuantize2.outputPrecision;
+            testValues.result.fakeQuantize3.outputPrecision = testValues.actual.fakeQuantize3.outputPrecision;
+        }
+
+        actualFunction = ngraph::builder::subgraph::ConcatFunction::getOriginalWithReshapeAtTheEndTransformation(
+            precision,
+            shape,
+            testValues.actual.fakeQuantize1,
+            testValues.actual.fakeQuantize2,
+            testValues.actual.fakeQuantize3);
+
+        SimpleLowPrecisionTransformer transform;
+        transform.add<ngraph::pass::low_precision::ConcatMultiChannelsTransformation, ngraph::opset1::Concat>(testValues.params);
+        transform.add<ngraph::pass::low_precision::MaxPoolTransformation, ngraph::opset1::MaxPool>(testValues.params);
+        transform.add<ngraph::pass::low_precision::ReshapeTransformation, ngraph::opset1::Reshape>(testValues.params);
+        transform.transform(actualFunction);
+
+        if (!testValues.params.updatePrecisions) {
+            // there is no Convert operation after MaxPool in FP32
+            testValues.result.dequantizationOperations.convert = {};
+        }
+
+        referenceFunction = ngraph::builder::subgraph::ConcatFunction::getReferenceWithReshapeAtTheEndTransformation(
+            precision,
+            shape,
+            testValues.result.fakeQuantize1,
+            testValues.result.fakeQuantize2,
+            testValues.result.fakeQuantize3,
+            testValues.result.dequantizationOperations);
+    }
+
+    static std::string getTestCaseName(testing::TestParamInfo<ConcatTransformationParams> obj) {
+        const ngraph::element::Type precision = std::get<0>(obj.param);
+        const bool updatePrecision = std::get<1>(obj.param);
+        const ngraph::Shape shape = std::get<2>(obj.param);
+        const ConcatTransformationTestValues testValues = std::get<3>(obj.param);
+
+        std::ostringstream result;
+        result <<
+            LayerTransformation::getTestCaseNameByParams(precision, shape, testValues.params) << "_" <<
+            (updatePrecision ? "updatePrecision_" : "notUpdatePrecision_") <<
+            testValues.actual << "_" <<
+            testValues.result << "_";
+        return result.str();
+    }
+};
+
+TEST_P(ConcatWithReshapeAtTheEndTransformation, CompareFunctions) {
+    actualFunction->validate_nodes_and_infer_types();
+    auto res = compare_functions(referenceFunction, actualFunction, true, true, true);
+    ASSERT_TRUE(res.first) << res.second;
+}
+
+const std::vector<ngraph::element::Type> precisions = {
+    ngraph::element::f32,
+};
+
+const std::vector<bool> updatePrecisions = { true, false };
+
+const std::vector<ConcatTransformationTestValues> testValues = {
+    {
+        LayerTransformation::createParamsU8I8(),
+        {
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
+        },
+        {
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
+            { 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
+            { ngraph::element::f32, {}, { 0.01f } }
+        }
+    },
+    {
+        LayerTransformation::createParamsU8I8(),
+        {
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
+            },
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
+            },
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
+            },
+        },
+        {
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f}, ngraph::element::u8
+            },
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f},
+                ngraph::element::u8
+            },
+            {
+                256ul,
+                {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
+                {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f},
+                ngraph::element::u8
+            },
+            { ngraph::element::f32, {}, {{ 0.01f, 0.01f / 2.f, 0.01f / 3.f, 0.01f, 0.01f / 2.f, 0.01f / 3.f, 0.01f, 0.01f / 2.f, 0.01f / 3.f }} }
+        }
+    }
+};
+
+const std::vector<ngraph::Shape> shapes = {
+    { 1, 3, 9, 9 },
+    { 4, 3, 9, 9 }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    LPT,
+    ConcatWithReshapeAtTheEndTransformation,
+    ::testing::Combine(
+        ::testing::ValuesIn(precisions),
+        ::testing::ValuesIn(updatePrecisions),
+        ::testing::ValuesIn(shapes),
+        ::testing::ValuesIn(testValues)),
+    ConcatWithReshapeAtTheEndTransformation::getTestCaseName);
+}  // namespace
diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/move_dequantization_after_with_int_constant_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/move_dequantization_after_with_int_constant_transformation.cpp
new file mode 100644 (file)
index 0000000..b88114a
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "layer_transformation.hpp"
+
+#include <string>
+#include <sstream>
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include <utility>
+#include <transformations/utils/utils.hpp>
+#include <transformations/init_node_info.hpp>
+#include <low_precision/network_helper.hpp>
+
+#include "common_test_utils/ngraph_test_utils.hpp"
+#include "ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp"
+#include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
+
+using namespace testing;
+using namespace ngraph::pass;
+using namespace ngraph::builder::subgraph;
+
+class MoveDequantizationAfterTransformationParams {
+public:
+    class Actual {
+    public:
+        ngraph::builder::subgraph::DequantizationOperations dequantization;
+    };
+
+    class Expected {
+    public:
+        ngraph::builder::subgraph::DequantizationOperations dequantizationBefore;
+        ngraph::element::Type precisionAfterOperation;
+        ngraph::builder::subgraph::DequantizationOperations dequantizationAfter;
+    };
+
+    ngraph::element::Type originalPrecision;
+    ngraph::pass::low_precision::LayerTransformation::Params params;
+    bool updatePrecision;
+    bool moveSubtract;
+    Actual actual;
+    Expected expected;
+};
+
+typedef std::tuple<
+    ngraph::Shape,
+    MoveDequantizationAfterTransformationParams> MoveDequantizationAfterTransformationTestValues;
+
+class MoveDequantizationAfterWithIntConstantTransformation :
+    public LayerTransformation,
+    public testing::WithParamInterface<MoveDequantizationAfterTransformationTestValues> {
+public:
+    void SetUp() override {
+        const auto inputShape = std::get<0>(GetParam());
+        const auto testValues = std::get<1>(GetParam());
+        actualFunction = ngraph::builder::subgraph::MoveDequantizationAfterWithIntConstantFunction::getOriginal(
+            testValues.originalPrecision,
+            inputShape,
+            testValues.actual.dequantization);
+
+        const auto targetNode = actualFunction->get_output_op(0)->get_input_node_shared_ptr(0);
+        const auto dequantization = ngraph::pass::low_precision::NetworkHelper::getDequantization(targetNode);
+        ngraph::pass::low_precision::NetworkHelper::moveDequantizationAfter(
+            targetNode,
+            dequantization,
+            testValues.updatePrecision,
+            testValues.moveSubtract);
+
+        referenceFunction = ngraph::builder::subgraph::MoveDequantizationAfterWithIntConstantFunction::getReference(
+            testValues.originalPrecision,
+            inputShape,
+            testValues.expected.dequantizationBefore,
+            testValues.expected.precisionAfterOperation,
+            testValues.expected.dequantizationAfter);
+    }
+
+    static std::string getTestCaseName(testing::TestParamInfo<MoveDequantizationAfterTransformationTestValues> obj) {
+        const auto inputShape = std::get<0>(obj.param);
+        const auto testValues = std::get<1>(obj.param);
+
+        std::ostringstream result;
+        result <<
+            testValues.originalPrecision << "_" <<
+            inputShape << "_" <<
+            testValues.actual.dequantization << "_" <<
+            (testValues.moveSubtract ? "move_subtract_" : "don't_move_subtract_") <<
+            (testValues.updatePrecision ? "updatePrecision" : "don't_update_precision");
+        return result.str();
+    }
+};
+
+TEST_P(MoveDequantizationAfterWithIntConstantTransformation, CompareFunctions) {
+    actualFunction->validate_nodes_and_infer_types();
+    auto res = compare_functions(referenceFunction, actualFunction, true, false, true);
+    ASSERT_TRUE(res.first) << res.second;
+}
+
+const std::vector<ngraph::Shape> inputShapes = {
+    { 1, 3, 16, 16 },
+    { 4, 3, 16, 16 }
+};
+
+const std::vector<MoveDequantizationAfterTransformationParams> testValues = {
+    // I8 & I8: Multiply
+    {
+        ngraph::element::i8,
+        LayerTransformation::createParamsU8I8(),
+        false,
+        true,
+        {
+            { {},  {}, { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 } },
+        },
+        {
+            { {},  {}, {} },
+            ngraph::element::f32,
+            { {},  {}, { 10.f } },
+        },
+    },
+    // I8 & I8: Subtract + Multiply
+    {
+        ngraph::element::i8,
+        LayerTransformation::createParamsU8I8(),
+        false,
+        true,
+        {
+            {
+                {},
+                { {5.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 },
+                { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 }
+            },
+        },
+        {
+            { {},  {}, {} },
+            ngraph::element::f32,
+            { {},  {5.f}, { 10.f } },
+        },
+    },
+    // FP32 & I8: Multiply
+    {
+        ngraph::element::u8,
+        LayerTransformation::createParamsU8I8(),
+        false,
+        true,
+        {
+            { {ngraph::element::f32},  {}, { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 } },
+        },
+        {
+            { {},  {}, {} },
+            ngraph::element::f32,
+            { {},  {}, { 10.f } },
+        },
+    },
+    // FP32 & I8: Subtract + Multiply
+    {
+        ngraph::element::u8,
+        LayerTransformation::createParamsU8I8(),
+        false,
+        true,
+        {
+            {
+                {ngraph::element::f32},
+                { {5.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 },
+                { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 }
+            },
+        },
+        {
+            { {},  {}, {} },
+            ngraph::element::f32,
+            { {},  {5.f}, { 10.f } },
+        },
+    }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    LPT,
+    MoveDequantizationAfterWithIntConstantTransformation,
+    ::testing::Combine(
+        ::testing::ValuesIn(inputShapes),
+        ::testing::ValuesIn(testValues)),
+    MoveDequantizationAfterWithIntConstantTransformation::getTestCaseName);
index 3877cf9..512d3f9 100644 (file)
@@ -34,7 +34,9 @@ public:
             const std::vector<float>& values,
             const ngraph::element::Type outPrecision,
             const ngraph::Shape& constantShape,
-            const bool addDequantizationAttribute = true);
+            const bool addDequantizationAttribute = true,
+            const size_t constantIndex = 1ul,
+            const ngraph::element::Type constantPrecision = ngraph::element::undefined);
         bool empty() const noexcept;
         Subtract& setConstantPrecision(const ngraph::element::Type& precision);
 
@@ -43,7 +45,9 @@ public:
         ngraph::Shape constantShape;
         bool constantShapeIsDefined;
         bool addDequantizationAttribute;
+        size_t constantIndex = 1ul;
         ngraph::element::Type constantPrecision = ngraph::element::undefined;
+
     private:
         bool isEmpty;
     };
@@ -59,7 +63,8 @@ public:
             const ngraph::element::Type outPrecision,
             const ngraph::Shape& constantShape,
             const bool addDequantizationAttribute = true,
-            const size_t constantIndex = 1ul);
+            const size_t constantIndex = 1ul,
+            const ngraph::element::Type constantPrecision = ngraph::element::undefined);
         bool empty() const noexcept;
         Multiply& setConstantPrecision(const ngraph::element::Type& precision);
 
@@ -70,6 +75,7 @@ public:
         bool addDequantizationAttribute;
         size_t constantIndex = 1ul;
         ngraph::element::Type constantPrecision = ngraph::element::undefined;
+
     private:
         bool isEmpty;
     };
index 5e178d6..de18bb6 100644 (file)
@@ -69,6 +69,13 @@ public:
         const FakeQuantizeOnData& fqOnData1,
         const FakeQuantizeOnData& fqOnData2);
 
+    static std::shared_ptr<ngraph::Function> getOriginalWithReshapeAtTheEndTransformation(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const FakeQuantizeOnDataWithConstant& fqOnData1,
+        const FakeQuantizeOnDataWithConstant& fqOnData2,
+        const FakeQuantizeOnDataWithConstant& fqOnData3);
+
     static std::shared_ptr<ngraph::Function> getReference(
         const ngraph::element::Type precision,
         const ngraph::Shape& inputShape,
@@ -138,6 +145,17 @@ public:
         const ngraph::element::Type precisionAfterOperation,
         const DequantizationOperations& dequantizationAfter,
         const ngraph::element::Type precisionAfterDequantization);
+
+    static std::shared_ptr<ngraph::Function> getReferenceWithReshapeAtTheEndTransformation(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const FakeQuantizeOnDataWithConstant& fqOnData1,
+        const FakeQuantizeOnDataWithConstant& fqOnData2,
+        const FakeQuantizeOnDataWithConstant& fqOnData3,
+        const DequantizationOperations& dequantizationOperations);
+
+private:
+    static std::shared_ptr<Node> makeMaxPool(const Output<Node>& parent, const std::vector<size_t>& kernel);
 };
 
 }  // namespace subgraph
diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp
new file mode 100644 (file)
index 0000000..b390888
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <memory>
+#include <ngraph/ngraph.hpp>
+
+#include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
+#include "ngraph_functions/subgraph_builders.hpp"
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+class MoveDequantizationAfterWithIntConstantFunction {
+public:
+    static std::shared_ptr<ngraph::Function> getOriginal(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const ngraph::builder::subgraph::DequantizationOperations dequantization);
+
+    static std::shared_ptr<ngraph::Function> getReference(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const ngraph::builder::subgraph::DequantizationOperations dequantizationBefore,
+        const ngraph::element::Type precisionAfterOperation,
+        const ngraph::builder::subgraph::DequantizationOperations dequantizationAfter);
+};
+
+}  // namespace subgraph
+}  // namespace builder
+}  // namespace ngraph
index 294c4d0..e9beb28 100644 (file)
@@ -51,8 +51,10 @@ std::shared_ptr<Node> makeDequantization(
             shape,
             dequantizationOperations.subtract.values);
 
-        if ((dequantizationOperations.subtract.outPrecision == element::undefined) ||
-            (dequantizationOperations.subtract.outPrecision == parent.get_element_type())) {
+        if (((dequantizationOperations.subtract.outPrecision == element::undefined) ||
+            (dequantizationOperations.subtract.outPrecision == parent.get_element_type())) &&
+            ((dequantizationOperations.subtract.constantPrecision == element::undefined) ||
+            (dequantizationOperations.subtract.constantPrecision == parent.get_element_type()))) {
             subtract = std::make_shared<ngraph::pass::low_precision::DequantizationSubtract>(parent, subtractConst);
         } else {
             subtract = std::make_shared<op::TypeRelaxed<ngraph::pass::low_precision::DequantizationSubtract>>(
@@ -83,10 +85,14 @@ std::shared_ptr<Node> makeDequantization(
         }
 
         std::shared_ptr<ngraph::opset1::Multiply> multiply;
-        if ((dequantizationOperations.multiply.outPrecision == element::undefined) ||
-            (dequantizationOperations.multiply.outPrecision == parent.get_element_type())) {
+        if (((dequantizationOperations.multiply.outPrecision == element::undefined) ||
+            (dequantizationOperations.multiply.outPrecision == parent.get_element_type())) &&
+            ((dequantizationOperations.multiply.constantPrecision == element::undefined) ||
+            (dequantizationOperations.multiply.constantPrecision == parent.get_element_type()))) {
             const std::shared_ptr<ngraph::opset1::Constant> constant = std::make_shared<ngraph::opset1::Constant>(
-                parent.get_element_type(),
+                dequantizationOperations.multiply.constantPrecision != element::undefined ?
+                    dequantizationOperations.multiply.constantPrecision :
+                    parent.get_element_type(),
                 shape,
                 dequantizationOperations.multiply.values);
 
index 89e0788..9893351 100644 (file)
@@ -59,13 +59,17 @@ DequantizationOperations::Subtract::Subtract(
     const std::vector<float>& values,
     const ngraph::element::Type outPrecision,
     const ngraph::Shape& constantShape,
-    const bool addDequantizationAttribute) :
+    const bool addDequantizationAttribute,
+    const size_t constantIndex,
+    const ngraph::element::Type constantPrecision) :
     isEmpty(false),
     values(values),
     outPrecision(outPrecision),
     constantShape(constantShape),
     constantShapeIsDefined(true),
-    addDequantizationAttribute(addDequantizationAttribute) {
+    addDequantizationAttribute(addDequantizationAttribute),
+    constantIndex(constantIndex),
+    constantPrecision(constantPrecision) {
 }
 
 bool DequantizationOperations::Subtract::empty() const noexcept {
@@ -109,13 +113,15 @@ DequantizationOperations::Multiply::Multiply(
     const ngraph::element::Type outPrecision,
     const ngraph::Shape& constantShape,
     const bool addDequantizationAttribute,
-    const size_t constantIndex) :
+    const size_t constantIndex,
+    ngraph::element::Type constantPrecision) :
     isEmpty(false),
     values(values),
     outPrecision(outPrecision),
     constantShape(constantShape),
     addDequantizationAttribute(addDequantizationAttribute),
     constantIndex(constantIndex),
+    constantPrecision(constantPrecision),
     constantShapeIsDefined(true) {
 }
 
index ffdc619..421ff90 100644 (file)
@@ -153,23 +153,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediate(
     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
     fakeQuantize2->set_friendly_name("fakeQuantize2");
 
-    const std::vector<size_t> kernel = { 3, 3 };
-    const std::vector<size_t> stride = { 1, 1 };
-    const std::vector<size_t> padBegin = { 0, 0 };
-    const std::vector<size_t> padEnd = { 0, 0 };
-    const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-    const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
-    std::shared_ptr<ngraph::op::Op> intermediateOp;
-
+    std::shared_ptr<Node> intermediateOp;
     if (transparentIntermediate) {
-        intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize2->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
     } else {
         auto weights = ngraph::opset1::Constant::create(
             precision,
@@ -307,23 +293,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalSelectionWithInterm
     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
     fakeQuantize2->set_friendly_name("fakeQuantize2");
 
-    const std::vector<size_t> kernel = { 3, 3 };
-    const std::vector<size_t> stride = { 1, 1 };
-    const std::vector<size_t> padBegin = { 0, 0 };
-    const std::vector<size_t> padEnd = { 0, 0 };
-    const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-    const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
-    std::shared_ptr<ngraph::op::Op> intermediateOp;
-
+    std::shared_ptr<Node> intermediateOp;
     if (transparentIntermediate) {
-        intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize2->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
     } else {
         auto weights = ngraph::opset1::Constant::create(
             precision,
@@ -451,21 +423,7 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediateWit
     std::shared_ptr<ngraph::op::Op> intermediateOp;
 
     if (transparentIntermediate) {
-        const std::vector<size_t> kernel = { 3, 3 };
-        const std::vector<size_t> stride = { 1, 1 };
-        const std::vector<size_t> padBegin = { 0, 0 };
-        const std::vector<size_t> padEnd = { 0, 0 };
-        const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-        const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
-
-        const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize1->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        const auto pooling = makeMaxPool(fakeQuantize1->output(0), { 3, 3 });
 
         ngraph::op::v0::InterpolateAttrs attributes;
         attributes.axes = ngraph::AxisSet{ 2, 3 };
@@ -502,6 +460,55 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediateWit
     return function;
 }
 
+std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithReshapeAtTheEndTransformation(
+    const ngraph::element::Type precision,
+    const ngraph::Shape& inputShape,
+    const FakeQuantizeOnDataWithConstant& fqOnData1,
+    const FakeQuantizeOnDataWithConstant& fqOnData2,
+    const FakeQuantizeOnDataWithConstant& fqOnData3) {
+    const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input1->set_friendly_name("input1");
+    const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
+    fakeQuantize1->set_friendly_name("fakeQuantize1");
+
+    const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input2->set_friendly_name("input2");
+    const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
+    fakeQuantize2->set_friendly_name("fakeQuantize2");
+
+    const std::shared_ptr<ngraph::opset1::Concat> concat1 = std::make_shared<ngraph::opset1::Concat>(
+        ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
+    concat1->set_friendly_name("concat1");
+
+    const std::shared_ptr<Node> intermediate = makeMaxPool(concat1->output(0), {1ul, 1ul});
+
+    const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input3->set_friendly_name("input3");
+    const auto fakeQuantize3 = makeFakeQuantizeTypeRelaxed(input3, precision, fqOnData3);
+    fakeQuantize3->set_friendly_name("fakeQuantize3");
+
+    const std::shared_ptr<ngraph::opset1::Concat> concat2 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{ fakeQuantize3, intermediate }, 1);
+    concat2->set_friendly_name("concat2");
+
+    const Shape concat2Shape = concat2->output(0).get_shape();
+    const std::shared_ptr<Node> maxPool = makeMaxPool(concat2->output(0), {concat2Shape[2], concat2Shape[3]});
+    const std::shared_ptr<Node> reshape = std::make_shared<ngraph::opset1::Reshape>(
+        maxPool,
+        std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{2ul}, std::vector<size_t>{0, 0}),
+        true);
+    reshape->set_friendly_name("output");
+
+
+    ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(reshape)};
+
+    std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
+        results,
+        ngraph::ParameterVector{ input1, input2, input3 },
+        "OriginalWithReshapeAtTheEndTransformation");
+
+    return function;
+}
+
 std::shared_ptr<ngraph::Function> ConcatFunction::getReference(
     const ngraph::element::Type precision,
     const ngraph::Shape& inputShape,
@@ -706,23 +713,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediate(
     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
     fakeQuantize2->set_friendly_name("fakeQuantize2");
 
-    const std::vector<size_t> kernel = { 3, 3 };
-    const std::vector<size_t> stride = { 1, 1 };
-    const std::vector<size_t> padBegin = { 0, 0 };
-    const std::vector<size_t> padEnd = { 0, 0 };
-    const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-    const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
     std::shared_ptr<Node> intermediateOp;
-
     if (transparentIntermediate) {
-        intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize2->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
     } else {
         auto weights = ngraph::opset1::Constant::create(
             precision,
@@ -926,23 +919,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceSelectionWithInter
     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
     fakeQuantize2->set_friendly_name("fakeQuantize2");
 
-    const std::vector<size_t> kernel = { 3, 3 };
-    const std::vector<size_t> stride = { 1, 1 };
-    const std::vector<size_t> padBegin = { 0, 0 };
-    const std::vector<size_t> padEnd = { 0, 0 };
-    const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-    const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
-    std::shared_ptr<ngraph::op::Op> intermediateOp;
-
+    std::shared_ptr<Node> intermediateOp;
     if (transparentIntermediate) {
-        intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize2->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
     } else {
         auto weights = ngraph::opset1::Constant::create(
             precision,
@@ -1135,21 +1114,7 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediateWi
 
     if (transparentIntermediate) {
         const auto deqBefore = makeDequantization(fakeQuantize1->output(0), dequantizationBefore);
-        const std::vector<size_t> kernel = { 3, 3 };
-        const std::vector<size_t> stride = { 1, 1 };
-        const std::vector<size_t> padBegin = { 0, 0 };
-        const std::vector<size_t> padEnd = { 0, 0 };
-        const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
-        const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
-
-        const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
-            fakeQuantize1->output(0),
-            stride,
-            padBegin,
-            padEnd,
-            kernel,
-            roundingType,
-            padType);
+        const auto pooling = makeMaxPool(fakeQuantize1->output(0), { 3, 3 });
 
         ngraph::op::v0::InterpolateAttrs attributes;
         attributes.axes = ngraph::AxisSet{ 2, 3 };
@@ -1192,6 +1157,75 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediateWi
     return function;
 }
 
+std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithReshapeAtTheEndTransformation(
+    const ngraph::element::Type precision,
+    const ngraph::Shape& inputShape,
+    const FakeQuantizeOnDataWithConstant& fqOnData1,
+    const FakeQuantizeOnDataWithConstant& fqOnData2,
+    const FakeQuantizeOnDataWithConstant& fqOnData3,
+    const DequantizationOperations& dequantizationOperations) {
+    const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input1->set_friendly_name("input1");
+    const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
+    fakeQuantize1->set_friendly_name("fakeQuantize1");
+
+    const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input2->set_friendly_name("input2");
+    const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
+    fakeQuantize2->set_friendly_name("fakeQuantize2");
+
+    const std::shared_ptr<ngraph::opset1::Concat> concat1 = std::make_shared<ngraph::opset1::Concat>(
+        ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
+    concat1->set_friendly_name("concat1");
+
+    std::shared_ptr<Node> intermediate = makeMaxPool(concat1->output(0), {1ul, 1ul});
+
+    const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input3->set_friendly_name("input3");
+    const auto fakeQuantize3 = makeFakeQuantizeTypeRelaxed(input3, precision, fqOnData3);
+    fakeQuantize3->set_friendly_name("fakeQuantize3");
+
+    const std::shared_ptr<ngraph::opset1::Concat> concat2 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{ fakeQuantize3, intermediate }, 1);
+    concat2->set_friendly_name("concat2");
+
+    const Shape concat2Shape = concat2->output(0).get_shape();
+    const std::shared_ptr<Node> maxPool = makeMaxPool(concat2->output(0), {concat2Shape[2], concat2Shape[3]});
+    const std::shared_ptr<Node> reshape = std::make_shared<ngraph::opset1::Reshape>(
+        maxPool,
+        std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{2ul}, std::vector<size_t>{0, 0}),
+        true);
+    reshape->set_friendly_name("output_original");
+
+    const auto dequantization = makeDequantization(reshape->output(0), dequantizationOperations);
+    dequantization->set_friendly_name("output");
+
+    ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(dequantization)};
+
+    std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
+        results,
+        ngraph::ParameterVector{ input1, input2, input3 },
+        "ReferenceWithReshapeAtTheEndTransformation");
+
+    return function;
+}
+
+std::shared_ptr<Node> ConcatFunction::makeMaxPool(const Output<Node>& parent, const std::vector<size_t>& kernel) {
+    const std::vector<size_t> stride = { 1, 1 };
+    const std::vector<size_t> padBegin = { 0, 0 };
+    const std::vector<size_t> padEnd = { 0, 0 };
+    const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
+    const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
+    const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
+        parent,
+        stride,
+        padBegin,
+        padEnd,
+        kernel,
+        roundingType,
+        padType);
+    return pooling;
+}
+
 }  // namespace subgraph
 }  // namespace builder
 }  // namespace ngraph
diff --git a/inference-engine/tests/ngraph_functions/src/low_precision_transformations/move_dequantization_after_with_int_constant_function.cpp b/inference-engine/tests/ngraph_functions/src/low_precision_transformations/move_dequantization_after_with_int_constant_function.cpp
new file mode 100644 (file)
index 0000000..f774a4c
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp"
+#include "low_precision/network_helper.hpp"
+
+#include <ngraph/opsets/opset1.hpp>
+#include "ngraph_functions/subgraph_builders.hpp"
+#include "ngraph_functions/low_precision_transformations/common/builders.hpp"
+
+using namespace ngraph::pass::low_precision;
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+    std::shared_ptr<ngraph::Function> MoveDequantizationAfterWithIntConstantFunction::getOriginal(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const ngraph::builder::subgraph::DequantizationOperations dequantization) {
+        const auto input = std::make_shared<ngraph::op::v0::Parameter>(precision, inputShape);
+
+        const auto deq = makeDequantization(input, dequantization);
+        const auto avgPool = std::make_shared<op::TypeRelaxed<opset1::AvgPool>>(
+            ngraph::opset1::AvgPool(
+                deq,
+                Strides{ 1, 1 },
+                Shape{ 1, 1 },
+                Shape{ 0, 0 },
+                Shape{ 2, 2 },
+                true,
+                op::RoundingType::FLOOR),
+            std::vector<element::Type>{ element::f32, element::f32 },
+            std::vector<element::Type>{});
+
+        auto& rtInfo = avgPool->get_rt_info();
+        rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("targetOp");
+
+        return std::make_shared<ngraph::Function>(
+            ngraph::ResultVector{ std::make_shared<ngraph::opset1::Result>(avgPool) },
+            ngraph::ParameterVector{ input },
+            "MoveDequantizationAfterFunction");
+    }
+
+    std::shared_ptr<ngraph::Function> MoveDequantizationAfterWithIntConstantFunction::getReference(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const ngraph::builder::subgraph::DequantizationOperations dequantizationBefore,
+        const ngraph::element::Type precisionAfterOperation,
+        const ngraph::builder::subgraph::DequantizationOperations dequantizationAfter) {
+        const auto input = std::make_shared<ngraph::op::v0::Parameter>(precision, inputShape);
+
+        const auto deqBefore = makeDequantization(input, dequantizationBefore);
+        const auto targetOp = std::make_shared<op::TypeRelaxed<opset1::AvgPool>>(
+            ngraph::opset1::AvgPool(
+                deqBefore,
+                Strides{ 1, 1 },
+                Shape{ 1, 1 },
+                Shape{ 0, 0 },
+                Shape{ 2, 2 },
+                true,
+                op::RoundingType::FLOOR),
+            std::vector<element::Type>{ element::f32, element::f32 },
+            std::vector<element::Type>{});
+        ngraph::pass::low_precision::NetworkHelper::setOutDataPrecisionForTypeRelaxed(targetOp, precisionAfterOperation);
+        auto& rtInfo = targetOp->get_rt_info();
+        rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("targetOp");
+
+        const auto deqAfter = makeDequantization(targetOp, dequantizationAfter);
+
+        return std::make_shared<ngraph::Function>(
+            ngraph::ResultVector{ std::make_shared<ngraph::opset1::Result>(deqAfter) },
+            ngraph::ParameterVector{ input },
+            "MoveDequantizationAfterFunction");
+    }
+
+}  // namespace subgraph
+}  // namespace builder
+}  // namespace ngraph