[LPT] FuseFakeQuantizeAndScaleShift transformation for last layer fix (#1291)
authorEdward Shogulin <edward.shogulin@intel.com>
Tue, 14 Jul 2020 15:55:06 +0000 (18:55 +0300)
committerGitHub <noreply@github.com>
Tue, 14 Jul 2020 15:55:06 +0000 (18:55 +0300)
* [LPT] FuseFakeQuantizeAndScaleShift transformation for last layer fix

* [LPT] refactoring

* [LPT] FuseFakeQuantizeAndScaleShift test: last layer name validation was added

inference-engine/src/low_precision_transformations/src/fuse_fake_quantize_and_scale_shift.cpp
inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp
inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp [new file with mode: 0644]
inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp [new file with mode: 0644]
inference-engine/tests/ngraph_functions/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.cpp [new file with mode: 0644]

index c97258d..a6cedb8 100644 (file)
@@ -38,6 +38,7 @@ void FuseFakeQuantizeAndScaleShiftTransformation::transform(
     }
 
     auto dScaleShift = dScaleShiftsVector[0];
+
     const Blob::Ptr scalesBlob = CNNNetworkHelper::getBlob(dScaleShift, "weights");
     auto scalesBufferPtr = CNNNetworkHelper::getFloatData(scalesBlob);
 
@@ -55,9 +56,21 @@ void FuseFakeQuantizeAndScaleShiftTransformation::transform(
             return;
     }
 
+    OutputsDataMap outputs;
+    context.network.getOutputsInfo(outputs);
+    const bool dScaleShiftIsLastLayer = outputs.find(dScaleShift->name) != outputs.end();
+    if (dScaleShiftIsLastLayer && (dScaleShiftsVector.size() > 1ul)) {
+        // not possible to fuse ScaleShifts if at least one is output
+        return;
+    }
+
     // All ScaleShifts must be equal
     for (size_t i = 1lu; i < dScaleShiftsVector.size(); i++) {
         auto ssLayer = dScaleShiftsVector[i];
+        if (outputs.find(ssLayer->name) != outputs.end()) {
+            // not possible to fuse ScaleShifts if at least one is output
+            return;
+        }
 
         const Blob::Ptr scBlob = CNNNetworkHelper::getBlob(ssLayer, "weights");
         auto scBufferPtr = CNNNetworkHelper::getFloatData(scBlob);
@@ -144,4 +157,9 @@ void FuseFakeQuantizeAndScaleShiftTransformation::transform(
         auto ssPrecision = dScaleShiftsVector[0]->outData[0]->getPrecision();
         fakeQuantizeLayer.outData[0]->setPrecision(ssPrecision);
     }
+
+
+    if (dScaleShiftIsLastLayer) {
+        CNNNetworkHelper::renameLayer(context.network, fakeQuantizeLayer.name, dScaleShift->name);
+    }
 }
diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp
new file mode 100644 (file)
index 0000000..bae3f9c
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp"
+#include "common_test_utils/test_constants.hpp"
+#include "ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp"
+
+using namespace LayerTestsDefinitions;
+using namespace InferenceEngine::details;
+
+namespace {
+const std::vector<InferenceEngine::Precision> netPrecisions = {
+    InferenceEngine::Precision::FP32
+};
+
+const std::vector<LayerTransformation::Params> trasformationParamValues = {
+    LayerTestsUtils::LayerTransformationParamsFactory::createParamsU8I8()
+};
+
+const std::vector<ngraph::builder::subgraph::FakeQuantizeOnData> fakeQuantizeOnDataValues = {
+    { 256ul, {}, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } },
+    {
+        256ul,
+        { 1ul, 3ul, 1ul, 1ul },
+        { 0.f, 0.f, 0.f },
+        { 2.55f / 10.f, 2.55f / 5.f, 2.55f / 2.f },
+        { 0.f, 0.f, 0.f },
+        { 2.55f / 10.f, 2.55f / 5.f, 2.55f / 2.f }
+    },
+};
+
+INSTANTIATE_TEST_CASE_P(LPT, FuseFakeQuantizeAndScaleShiftTransformation,
+    ::testing::Combine(
+        ::testing::ValuesIn(netPrecisions),
+        ::testing::Values(InferenceEngine::SizeVector({ 1, 3, 9, 9 })),
+        ::testing::Values(CommonTestUtils::DEVICE_CPU),
+        ::testing::ValuesIn(trasformationParamValues),
+        ::testing::ValuesIn(fakeQuantizeOnDataValues)),
+    FuseFakeQuantizeAndScaleShiftTransformation::getTestCaseName);
+}  // namespace
index 2846460..16f24cb 100644 (file)
@@ -21,7 +21,7 @@ std::vector<std::string> disabledTestPatterns() {
         R"(.*(QuantGroupConv2D).*)",
         R"(.*(QuantGroupConv3D).*)",
         // TODO: Issue 31845
-        R"(.*(FakeQuantize).*)",
+        R"(.*(FakeQuantizeLayerTest).*)",
         R"(.*(EltwiseLayerTest).*IS=\(.*\..*\..*\..*\..*\).*secondaryInputType=PARAMETER.*opType=SCALAR.*)",
         // TODO: Issue 32756
         R"(.*Transpose.*inputOrder=\(\).*)",
diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp
new file mode 100644 (file)
index 0000000..a9d90b7
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp"
+#include "common_test_utils/test_constants.hpp"
+#include "ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp"
+
+using namespace LayerTestsDefinitions;
+using namespace InferenceEngine::details;
+
+namespace {
+const std::vector<InferenceEngine::Precision> netPrecisions = {
+    InferenceEngine::Precision::FP32
+};
+
+const std::vector<LayerTransformation::Params> trasformationParamValues = {
+    LayerTestsUtils::LayerTransformationParamsFactory::createParamsU8I8()
+};
+
+const std::vector<ngraph::builder::subgraph::FakeQuantizeOnData> fakeQuantizeOnDataValues = {
+    { 256ul, {}, { 0.f }, { 2.55f }, { 0.f }, { 2.55f } },
+    {
+        256ul,
+        { 1ul, 3ul, 1ul, 1ul },
+        { 0.f, 0.f, 0.f },
+        { 2.55f / 10.f, 2.55f / 5.f, 2.55f / 2.f },
+        { 0.f, 0.f, 0.f },
+        { 2.55f / 10.f, 2.55f / 5.f, 2.55f / 2.f }
+    },
+};
+
+INSTANTIATE_TEST_CASE_P(LPT, FuseFakeQuantizeAndScaleShiftTransformation,
+    ::testing::Combine(
+        ::testing::ValuesIn(netPrecisions),
+        ::testing::Values(InferenceEngine::SizeVector({ 1, 3, 9, 9 })),
+        ::testing::Values(CommonTestUtils::DEVICE_GPU),
+        ::testing::ValuesIn(trasformationParamValues),
+        ::testing::ValuesIn(fakeQuantizeOnDataValues)),
+    FuseFakeQuantizeAndScaleShiftTransformation::getTestCaseName);
+}  // namespace
diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp
new file mode 100644 (file)
index 0000000..5d595a1
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <string>
+#include <memory>
+#include "ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp"
+#include "functional_test_utils/low_precision_transformations/layer_transformation.hpp"
+
+namespace LayerTestsDefinitions {
+
+typedef std::tuple<
+    InferenceEngine::Precision,
+    InferenceEngine::SizeVector,
+    std::string,
+    InferenceEngine::details::LayerTransformation::Params,
+    ngraph::builder::subgraph::FakeQuantizeOnData> FuseFakeQuantizeAndScaleShiftTransformationParams;
+
+class FuseFakeQuantizeAndScaleShiftTransformation :
+    public testing::WithParamInterface<FuseFakeQuantizeAndScaleShiftTransformationParams>,
+    public LayerTestsUtils::LayerTransformation {
+public:
+    static std::string getTestCaseName(testing::TestParamInfo<FuseFakeQuantizeAndScaleShiftTransformationParams> obj);
+
+protected:
+    void SetUp() override;
+
+private:
+    void validate(const std::string& referenceOutputLayerName);
+};
+
+}  // namespace LayerTestsDefinitions
diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.cpp
new file mode 100644 (file)
index 0000000..914a457
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "low_precision_transformations/fuse_fake_quantize_and_scale_shift_transformation.hpp"
+
+#include <memory>
+#include <tuple>
+#include <vector>
+#include <string>
+#include <ie_core.hpp>
+
+#include <transformations/init_node_info.hpp>
+
+namespace LayerTestsDefinitions {
+
+std::string FuseFakeQuantizeAndScaleShiftTransformation::getTestCaseName(testing::TestParamInfo<FuseFakeQuantizeAndScaleShiftTransformationParams> obj) {
+    InferenceEngine::Precision netPrecision;
+    InferenceEngine::SizeVector inputShapes;
+    std::string targetDevice;
+    InferenceEngine::details::LayerTransformation::Params params;
+    ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData;
+    std::tie(netPrecision, inputShapes, targetDevice, params, fakeQuantizeOnData) = obj.param;
+
+    std::ostringstream result;
+    result << netPrecision << "_" << targetDevice << "_" << fakeQuantizeOnData;
+    return result.str();
+}
+
+void FuseFakeQuantizeAndScaleShiftTransformation::SetUp() {
+    InferenceEngine::SizeVector inputShape;
+    InferenceEngine::Precision netPrecision;
+    InferenceEngine::details::LayerTransformation::Params params;
+    ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData;
+    std::tie(netPrecision, inputShape, targetDevice, params, fakeQuantizeOnData) = this->GetParam();
+
+    function = ngraph::builder::subgraph::FuseFakeQuantizeAndScaleShiftFunction::getOriginal(
+        FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision),
+        inputShape,
+        fakeQuantizeOnData);
+
+    ngraph::pass::InitNodeInfo().run_on_function(function);
+
+    EXPECT_EQ(1ul, function->get_output_size());
+    EXPECT_EQ(1ul, function->get_output_op(0)->get_input_size());
+    const std::string referenceOutputLayerName = function->get_output_op(0)->get_input_node_ptr(0)->get_friendly_name();
+
+    validate(referenceOutputLayerName);
+}
+
+void FuseFakeQuantizeAndScaleShiftTransformation::validate(const std::string& referenceOutputLayerName) {
+    InferenceEngine::SizeVector inputShape;
+    InferenceEngine::Precision netPrecision;
+    InferenceEngine::details::LayerTransformation::Params params;
+    ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData;
+    std::tie(netPrecision, inputShape, targetDevice, params, fakeQuantizeOnData) = this->GetParam();
+
+    auto transformations = getLowPrecisionTransformations(params);
+    const InferenceEngine::CNNNetwork network = transform(transformations);
+
+    IE_SUPPRESS_DEPRECATED_START
+
+    InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();
+    EXPECT_EQ(1, outputs.size());
+
+    std::map<std::string, InferenceEngine::DataPtr>::iterator it = outputs.begin();
+    const InferenceEngine::CNNLayerPtr outputLayer = getCreatorLayer(it->second).lock();
+    EXPECT_TRUE(outputLayer != nullptr);
+    EXPECT_EQ("FakeQuantize", outputLayer->type);
+    EXPECT_EQ(referenceOutputLayerName, outputLayer->name);
+
+    IE_SUPPRESS_DEPRECATED_END
+}
+
+TEST_P(FuseFakeQuantizeAndScaleShiftTransformation, CompareWithRefImpl) {
+    Run();
+};
+
+}  // namespace LayerTestsDefinitions
diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp
new file mode 100644 (file)
index 0000000..f903720
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <algorithm>
+#include <memory>
+#include <ngraph/ngraph.hpp>
+#include "common/fake_quantize_on_data.hpp"
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+class FuseFakeQuantizeAndScaleShiftFunction {
+public:
+    static std::shared_ptr<ngraph::Function> getOriginal(
+        const ngraph::element::Type precision,
+        const ngraph::Shape& inputShape,
+        const FakeQuantizeOnData& fakeQuantizeOnData);
+};
+
+}  // namespace subgraph
+}  // namespace builder
+}  // namespace ngraph
diff --git a/inference-engine/tests/ngraph_functions/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.cpp b/inference-engine/tests/ngraph_functions/src/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.cpp
new file mode 100644 (file)
index 0000000..8c55a31
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "ngraph_functions/low_precision_transformations/fuse_fake_quantize_and_scale_shift_function.hpp"
+
+#include <ngraph/opsets/opset1.hpp>
+#include "ngraph_functions/builders.hpp"
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+using namespace ngraph::pass;
+
+std::shared_ptr<ngraph::Function> FuseFakeQuantizeAndScaleShiftFunction::getOriginal(
+    const ngraph::element::Type precision,
+    const ngraph::Shape& inputShape,
+    const FakeQuantizeOnData& fakeQuantizeOnData) {
+    const auto input = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
+    input->set_friendly_name("input");
+
+    const std::shared_ptr<Node> fakeQuantize = ngraph::builder::makeFakeQuantize(
+        input, precision, fakeQuantizeOnData.quantizationLevel, fakeQuantizeOnData.constantShape,
+        fakeQuantizeOnData.inputLowValues, fakeQuantizeOnData.inputHighValues, fakeQuantizeOnData.outputLowValues, fakeQuantizeOnData.outputHighValues);
+    fakeQuantize->set_friendly_name("fakeQuantize");
+
+    const std::shared_ptr<Node> multiply = std::make_shared<ngraph::opset1::Multiply>(
+        fakeQuantize,
+        std::make_shared<ngraph::opset1::Constant>(precision, Shape{ 1, 1, 1, 1 }, std::vector<float>({ 150 })));
+
+    const std::shared_ptr<Node> add = std::make_shared<ngraph::opset1::Add>(
+        multiply,
+        std::make_shared<ngraph::opset1::Constant>(precision, Shape{ 1, 1, 1, 1 }, std::vector<float>({ 127.5 })));
+
+    const ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(add) };
+    return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "FuseFakeQuantizeAndScaleShiftFunction");
+}
+
+}  // namespace subgraph
+}  // namespace builder
+}  // namespace ngraph