[LPT] Support ONNX quantized models coming from ORT PTQ (#14811)
* [LPT] FakeQuantize fuse * GPU & CPU tests alignment * refactoring & comments * doc quick fix * quick fix
This commit is contained in:
1 parent
de2e9faa58
commit
8bdc5bc85f
24 files changed
+1209
-469
No files matched your search
@@ -69,6 +69,7 @@
|
||||
<tab type="user" title="VariadicSplitTransformation" url="@ref openvino_docs_OV_UG_lpt_VariadicSplitTransformation"/>
|
||||
</tab>
|
||||
<tab type="user" title="Step 4. Cleanup transformations" url="@ref openvino_docs_OV_UG_lpt_step4_cleanup">
|
||||
<tab type="user" title="EliminateFakeQuantizeTransformation" url="@ref openvino_docs_OV_UG_lpt_EliminateFakeQuantizeTransformation"/>
|
||||
<tab type="user" title="FoldConvertTransformation" url="@ref openvino_docs_OV_UG_lpt_FoldConvertTransformation"/>
|
||||
<tab type="user" title="FoldFakeQuantizeTransformation" url="@ref openvino_docs_OV_UG_lpt_FoldFakeQuantizeTransformation"/>
|
||||
<tab type="user" title="FuseConvertTransformation" url="@ref openvino_docs_OV_UG_lpt_FuseConvertTransformation"/>
|
||||
|
||||
@@ -253,6 +253,7 @@ LPT cleanup transformations is final stage in LPT pipeline. In this step LPT tra
|
||||
|
||||
Transformations:
|
||||
|
||||
* :doc:`EliminateFakeQuantizeTransformation <openvino_docs_OV_UG_lpt_EliminateFakeQuantizeTransformation>`
|
||||
* :doc:`FoldConvertTransformation <openvino_docs_OV_UG_lpt_FoldConvertTransformation>`
|
||||
* :doc:`FoldFakeQuantizeTransformation <openvino_docs_OV_UG_lpt_FoldFakeQuantizeTransformation>`
|
||||
* :doc:`FuseConvertTransformation <openvino_docs_OV_UG_lpt_FuseConvertTransformation>`
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
|
||||
@sphinxdirective
|
||||
|
||||
* :doc:`EliminateFakeQuantizeTransformation <openvino_docs_OV_UG_lpt_EliminateFakeQuantizeTransformation>`
|
||||
* :doc:`FoldConvertTransformation <openvino_docs_OV_UG_lpt_FoldConvertTransformation>`
|
||||
* :doc:`FoldFakeQuantizeTransformation <openvino_docs_OV_UG_lpt_FoldFakeQuantizeTransformation>`
|
||||
* :doc:`FuseConvertTransformation <openvino_docs_OV_UG_lpt_FuseConvertTransformation>`
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# EliminateFakeQuantizeTransformation transformation {#openvino_docs_OV_UG_lpt_EliminateFakeQuantizeTransformation}
|
||||
|
||||
ngraph::pass::low_precision::EliminateFakeQuantizeTransformation class represents the `EliminateFakeQuantizeTransformation` transformation.
|
||||
@@ -14,6 +14,7 @@ openvino_docs_OV_UG_lpt_convolutiontransformation.rst
|
||||
openvino_docs_OV_UG_lpt_createattribute.rst
|
||||
openvino_docs_OV_UG_lpt_createprecisionsdependentattribute.rst
|
||||
openvino_docs_OV_UG_lpt_depthtospacetransformation.rst
|
||||
openvino_docs_OV_UG_lpt_eliminatefakequantizetransformation.rst
|
||||
openvino_docs_OV_UG_lpt_fakequantizedecompositiontransformation.rst
|
||||
openvino_docs_OV_UG_lpt_fakequantizetransformation.rst
|
||||
openvino_docs_OV_UG_lpt_foldconverttransformation.rst
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include "low_precision/layer_transformation.hpp"
|
||||
|
||||
namespace ngraph {
|
||||
namespace pass {
|
||||
namespace low_precision {
|
||||
|
||||
/**
|
||||
* @ingroup ie_transformation_common_api
|
||||
* @brief EliminateFakeQuantizeTransformation removes FakeQuantize operations.
|
||||
*
|
||||
* For more details about the transformation, refer to
|
||||
* [EliminateFakeQuantizeTransformation](@ref openvino_docs_OV_UG_lpt_EliminateFakeQuantizeTransformation) page
|
||||
* in the Inference Engine Developer Guide.
|
||||
*/
|
||||
class LP_TRANSFORMATIONS_API EliminateFakeQuantizeTransformation : public LayerTransformation {
|
||||
public:
|
||||
OPENVINO_RTTI("EliminateFakeQuantizeTransformation", "0");
|
||||
EliminateFakeQuantizeTransformation(const Params& params = Params());
|
||||
bool transform(TransformationContext& context, ngraph::pattern::Matcher &m) override;
|
||||
bool canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> layer) const override;
|
||||
bool isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept override;
|
||||
};
|
||||
|
||||
} // namespace low_precision
|
||||
} // namespace pass
|
||||
} // namespace ngraph
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision/eliminate_fake_quantize.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include <ngraph/pattern/op/wrap_type.hpp>
|
||||
#include "itt.hpp"
|
||||
|
||||
namespace ngraph {
|
||||
namespace pass {
|
||||
namespace low_precision {
|
||||
|
||||
EliminateFakeQuantizeTransformation::EliminateFakeQuantizeTransformation(const Params& params) : LayerTransformation(params) {
|
||||
MATCHER_SCOPE(FuseMultiplyToFakeQuantizeTransformation);
|
||||
const auto matcher = pattern::wrap_type<opset1::FakeQuantize>({
|
||||
pattern::any_input(),
|
||||
pattern::wrap_type<opset1::Constant>(),
|
||||
pattern::wrap_type<opset1::Constant>(),
|
||||
pattern::wrap_type<opset1::Constant>(),
|
||||
pattern::wrap_type<opset1::Constant>()
|
||||
});
|
||||
|
||||
ngraph::graph_rewrite_callback callback = [this](pattern::Matcher& m) {
|
||||
const auto op = m.get_match_root();
|
||||
if (transformation_callback(op)) {
|
||||
return false;
|
||||
}
|
||||
return transform(*context, m);
|
||||
};
|
||||
|
||||
const auto m = std::make_shared<ngraph::pattern::Matcher>(matcher, matcher_name);
|
||||
this->register_matcher(m, callback);
|
||||
}
|
||||
|
||||
bool EliminateFakeQuantizeTransformation::transform(TransformationContext& context, ngraph::pattern::Matcher& m) {
|
||||
const auto root = m.get_match_root();
|
||||
if (!canBeTransformed(context, root)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return replace_output_update_name(root->output(0), root->input_value(0));
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool check_interval(const std::shared_ptr<opset1::Constant>& constant, const float value) noexcept {
|
||||
const auto& constant_values = constant->cast_vector<float>();
|
||||
for (const auto constant_value : constant_values) {
|
||||
if (std::fabs(constant_value - value) > std::numeric_limits<float>::epsilon()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_intervals(const std::shared_ptr<opset1::FakeQuantize>& fakeQuantize) {
|
||||
const auto& element_type = fakeQuantize->get_output_element_type(0);
|
||||
const auto min_value = DataPrecision::getMinValue(element_type, fakeQuantize->get_levels());
|
||||
const auto max_value = DataPrecision::getMaxValue(element_type, fakeQuantize->get_levels());
|
||||
return
|
||||
check_interval(ov::as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(1)), min_value) &&
|
||||
check_interval(ov::as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(2)), max_value) &&
|
||||
check_interval(ov::as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(3)), min_value) &&
|
||||
check_interval(ov::as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(4)), max_value);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool EliminateFakeQuantizeTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> operation) const {
|
||||
const auto fakeQuantize = ov::as_type_ptr<opset1::FakeQuantize>(operation);
|
||||
OPENVINO_ASSERT(fakeQuantize != nullptr, "unexpected operation type");
|
||||
|
||||
const auto& input_type = fakeQuantize->get_input_element_type(0);
|
||||
const auto& output_type = fakeQuantize->get_output_element_type(0);
|
||||
if ((input_type != output_type) || (!check_intervals(fakeQuantize))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EliminateFakeQuantizeTransformation::isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace low_precision
|
||||
} // namespace pass
|
||||
} // namespace ngraph
|
||||
@@ -77,6 +77,7 @@
|
||||
// cleanup transformations
|
||||
#include "itt.hpp"
|
||||
#include "low_precision/convert.hpp"
|
||||
#include "low_precision/eliminate_fake_quantize.hpp"
|
||||
#include "low_precision/fold_fake_quantize.hpp"
|
||||
#include "low_precision/fuse_convert.hpp"
|
||||
#include "low_precision/fuse_multiply_to_fake_quantize.hpp"
|
||||
@@ -268,6 +269,7 @@ bool ngraph::pass::low_precision::LowPrecision::run_on_model(const std::shared_p
|
||||
ADD_MATCHER(common, VariadicSplitTransformation, params)
|
||||
|
||||
std::shared_ptr<ngraph::pass::GraphRewrite> cleanup = manager.register_pass<ngraph::pass::GraphRewrite>();
|
||||
ADD_MATCHER(cleanup, EliminateFakeQuantizeTransformation, params)
|
||||
ADD_MATCHER(cleanup, FoldConvertTransformation, params)
|
||||
ADD_MATCHER(cleanup, FuseConvertTransformation, params)
|
||||
ADD_MATCHER(cleanup, FuseSubtractToFakeQuantizeTransformation, params)
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "common_test_utils/ngraph_test_utils.hpp"
|
||||
#include "layer_transformation.hpp"
|
||||
#include "low_precision/eliminate_fake_quantize.hpp"
|
||||
#include "low_precision/fake_quantize.hpp"
|
||||
#include "low_precision/fake_quantize_decomposition.hpp"
|
||||
#include "low_precision/max_pool.hpp"
|
||||
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
|
||||
#include "lpt_ngraph_functions/fuse_fake_quantize_function.hpp"
|
||||
#include "simple_low_precision_transformer.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace testing;
|
||||
using namespace ngraph;
|
||||
using namespace ngraph::pass;
|
||||
|
||||
class TransformationTestValues {
|
||||
public:
|
||||
class Actual {
|
||||
public:
|
||||
ngraph::element::Type precisionBefore;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData1;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData2;
|
||||
};
|
||||
|
||||
class Expected {
|
||||
public:
|
||||
ngraph::element::Type precisionBefore;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData1;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData2;
|
||||
ngraph::builder::subgraph::DequantizationOperations dequantizationOperations2;
|
||||
};
|
||||
|
||||
ngraph::PartialShape inputShape;
|
||||
TestTransformationParams params;
|
||||
Actual actual;
|
||||
Expected expected;
|
||||
};
|
||||
|
||||
class EliminateFakeQuantizeTransformation : public LayerTransformation,
|
||||
public testing::WithParamInterface<TransformationTestValues> {
|
||||
public:
|
||||
void SetUp() override {
|
||||
const TransformationTestValues testValues = GetParam();
|
||||
|
||||
actualFunction = ngraph::builder::subgraph::FuseFakeQuantizeFunction::get(testValues.inputShape,
|
||||
testValues.actual.precisionBefore,
|
||||
testValues.actual.fakeQuantizeOnData1,
|
||||
testValues.actual.fakeQuantizeOnData2,
|
||||
{});
|
||||
|
||||
SimpleLowPrecisionTransformer transformer;
|
||||
transformer
|
||||
.add<ngraph::pass::low_precision::FakeQuantizeDecompositionTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.add<ngraph::pass::low_precision::MaxPoolTransformation, ngraph::opset1::MaxPool>(testValues.params);
|
||||
transformer.add<ngraph::pass::low_precision::FakeQuantizeTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.add<ngraph::pass::low_precision::EliminateFakeQuantizeTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.transform(actualFunction);
|
||||
|
||||
referenceFunction =
|
||||
ngraph::builder::subgraph::FuseFakeQuantizeFunction::get(testValues.inputShape,
|
||||
testValues.expected.precisionBefore,
|
||||
testValues.expected.fakeQuantizeOnData1,
|
||||
testValues.expected.fakeQuantizeOnData2,
|
||||
testValues.expected.dequantizationOperations2);
|
||||
}
|
||||
|
||||
static std::string getTestCaseName(testing::TestParamInfo<TransformationTestValues> obj) {
|
||||
const TransformationTestValues testValues = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << testValues.inputShape << "_" << testValues.params.updatePrecisions << "_"
|
||||
<< testValues.actual.precisionBefore << "_" << testValues.actual.fakeQuantizeOnData1 << "_"
|
||||
<< testValues.actual.fakeQuantizeOnData2 << "_" << testValues.expected.precisionBefore << "_"
|
||||
<< testValues.expected.fakeQuantizeOnData1 << "_" << testValues.expected.fakeQuantizeOnData2 << "_";
|
||||
return result.str();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(EliminateFakeQuantizeTransformation, CompareFunctions) {
|
||||
actualFunction->validate_nodes_and_infer_types();
|
||||
auto res = compare_functions(actualFunction, referenceFunction, true, true);
|
||||
ASSERT_TRUE(res.first) << res.second;
|
||||
|
||||
ASSERT_TRUE(LayerTransformation::allNamesAreUnique(actualFunction)) << "Not all names are unique";
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
const std::vector<TransformationTestValues> testValues = {
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
TestTransformationParams(true, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}},
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::u8},
|
||||
{},
|
||||
{ ov::element::f32, {}, {{0.01f}, ov::element::f32, {}} }
|
||||
}
|
||||
},
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
TestTransformationParams(true, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}},
|
||||
{256ul, {}, {0.f}, {2.55f / 2.f}, {0.f}, {2.55f / 2.f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::u8},
|
||||
{256ul, {}, {0.f}, {127.5f}, {0.f}, {255.f}, element::u8},
|
||||
{ ov::element::f32, {}, {{0.005f}, ov::element::f32, {}} }
|
||||
}
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT,
|
||||
EliminateFakeQuantizeTransformation,
|
||||
::testing::ValuesIn(testValues),
|
||||
EliminateFakeQuantizeTransformation::getTestCaseName);
|
||||
|
||||
} // namespace
|
||||
+556
@@ -0,0 +1,556 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <low_precision/fake_quantize.hpp>
|
||||
#include <low_precision/fake_quantize_decomposition.hpp>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <transformations/init_node_info.hpp>
|
||||
#include <transformations/utils/utils.hpp>
|
||||
|
||||
#include "common_test_utils/ngraph_test_utils.hpp"
|
||||
#include "layer_transformation.hpp"
|
||||
#include "lpt_ngraph_functions/common/add.hpp"
|
||||
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
|
||||
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
|
||||
#include "lpt_ngraph_functions/fuse_fake_quantize_function.hpp"
|
||||
#include "simple_low_precision_transformer.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace testing;
|
||||
using namespace ngraph;
|
||||
using namespace ngraph::pass;
|
||||
|
||||
class FuseDequantizeToFakeQuantizeTransformationTestValues {
|
||||
public:
|
||||
class Actual {
|
||||
public:
|
||||
ngraph::element::Type precisionBeforeAdd;
|
||||
ngraph::builder::subgraph::Add add;
|
||||
ngraph::element::Type precisionBeforeDequantization;
|
||||
ngraph::builder::subgraph::DequantizationOperations dequantization;
|
||||
ngraph::element::Type precisionAfterDequantization;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantizeOnData;
|
||||
};
|
||||
|
||||
class Expected {
|
||||
public:
|
||||
ngraph::element::Type precisionBeforeAdd;
|
||||
ngraph::builder::subgraph::Add add;
|
||||
ngraph::element::Type precisionBeforeDequantization;
|
||||
ngraph::builder::subgraph::DequantizationOperations dequantization;
|
||||
ngraph::element::Type precisionAfterDequantization;
|
||||
ngraph::element::Type precisionFakeQuantizeOnData;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantizeOnData;
|
||||
};
|
||||
|
||||
ngraph::PartialShape inputShape;
|
||||
TestTransformationParams params;
|
||||
Actual actual;
|
||||
Expected expected;
|
||||
};
|
||||
|
||||
class FuseDequantizeToFakeQuantizeTransformation
|
||||
: public LayerTransformation,
|
||||
public testing::WithParamInterface<FuseDequantizeToFakeQuantizeTransformationTestValues> {
|
||||
public:
|
||||
void SetUp() override {
|
||||
const FuseDequantizeToFakeQuantizeTransformationTestValues testValues = GetParam();
|
||||
|
||||
actualFunction = ngraph::builder::subgraph::FuseFakeQuantizeFunction::getOriginal(
|
||||
testValues.inputShape,
|
||||
testValues.actual.precisionBeforeAdd,
|
||||
testValues.actual.add,
|
||||
testValues.actual.precisionBeforeDequantization,
|
||||
testValues.actual.dequantization,
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.fakeQuantizeOnData);
|
||||
|
||||
SimpleLowPrecisionTransformer transformer;
|
||||
transformer
|
||||
.add<ngraph::pass::low_precision::FakeQuantizeDecompositionTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.transform(actualFunction);
|
||||
|
||||
transformer.add<ngraph::pass::low_precision::FakeQuantizeTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.transform(actualFunction);
|
||||
|
||||
referenceFunction = ngraph::builder::subgraph::FuseFakeQuantizeFunction::getReference(
|
||||
testValues.inputShape,
|
||||
testValues.expected.precisionBeforeAdd,
|
||||
testValues.expected.add,
|
||||
testValues.expected.precisionBeforeDequantization,
|
||||
testValues.expected.dequantization,
|
||||
testValues.expected.precisionAfterDequantization,
|
||||
testValues.expected.precisionFakeQuantizeOnData,
|
||||
testValues.expected.fakeQuantizeOnData);
|
||||
}
|
||||
|
||||
static std::string getTestCaseName(
|
||||
testing::TestParamInfo<FuseDequantizeToFakeQuantizeTransformationTestValues> obj) {
|
||||
const FuseDequantizeToFakeQuantizeTransformationTestValues testValues = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << testValues.inputShape << "_" << testValues.params.updatePrecisions << "_"
|
||||
<< testValues.actual.precisionBeforeAdd << "_" << testValues.actual.add.values.size() << "_"
|
||||
<< testValues.actual.add.outPrecision << "_" << testValues.actual.add.constantShape << "_"
|
||||
<< testValues.actual.precisionBeforeDequantization << testValues.actual.dequantization << "_"
|
||||
<< testValues.actual.precisionBeforeDequantization << "_" << testValues.actual.fakeQuantizeOnData << "_"
|
||||
<< testValues.expected.dequantization << "_" << testValues.expected.add.values.size() << "_"
|
||||
<< testValues.expected.add.outPrecision << "_" << testValues.expected.add.constantShape;
|
||||
return result.str();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(FuseDequantizeToFakeQuantizeTransformation, CompareFunctions) {
|
||||
actualFunction->validate_nodes_and_infer_types();
|
||||
auto res = compare_functions(actualFunction, referenceFunction, true, true);
|
||||
ASSERT_TRUE(res.first) << res.second;
|
||||
|
||||
ASSERT_TRUE(LayerTransformation::allNamesAreUnique(actualFunction)) << "Not all names are unique";
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
const std::vector<FuseDequantizeToFakeQuantizeTransformationTestValues> testValues = {
|
||||
// Convert: U8 -> FP32, updatePrecisions = true
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
TestTransformationParams(true, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::u8}
|
||||
}
|
||||
},
|
||||
// Convert: U8 -> FP32, updatePrecisions = false
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
TestTransformationParams(false, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::f32}
|
||||
}
|
||||
},
|
||||
// 1) Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {255.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}}, {0.f, 0.f, 0.f}, {255.f, 127.5f, 85.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Per-channel multiply and dynamic shape
|
||||
{
|
||||
{Dimension::dynamic(), 3, Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}}, {0.f, 0.f, 0.f}, {255.f, 127.5f, 85.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Per-channel multiply and dynamic shape with dynamic channels
|
||||
{
|
||||
{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Multiply with different input and output shape
|
||||
{
|
||||
{128, 1},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// Dynamic shape
|
||||
{
|
||||
{Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Multiply + 2) Add
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{{128}, element::f32},
|
||||
element::f32,
|
||||
{{}, {}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Subtract + Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Convert + Subtract + Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{}, {}, {}},
|
||||
element::u8,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// 1) Convert + Subtract + Multiply 2) Add
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// Dynamic shape
|
||||
{
|
||||
{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// Dynamic rank
|
||||
{
|
||||
PartialShape::dynamic(),
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// negative multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {-128}, {-0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {-128}, {-0.01f}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// issue #40611 for FP32
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f32}, {}, {}},
|
||||
ngraph::element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f32}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// issue #40611 for FP16
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f16}, {}, {}},
|
||||
ngraph::element::f16,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f16}, {}, {}},
|
||||
element::f16,
|
||||
element::f16,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// multiply by zero
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {{-128, -128, -128}}, {{0.01f, 0.f, 0.01f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {{-128, -128, -128}}, {{0.01f, 0.f, 0.01f}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
// non per-channel operation
|
||||
{
|
||||
{1, 3, 4},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{
|
||||
{element::f32},
|
||||
{{-128, -128, -128, -128}, ngraph::element::f32, {1, 1, 4}},
|
||||
{{0.01f, 0.02f, 0.03f, 0.04f}, ngraph::element::f32, {1, 1, 4}}
|
||||
},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
},
|
||||
{
|
||||
element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{
|
||||
{element::f32},
|
||||
{{-128, -128, -128, -128}, ngraph::element::f32, {1, 1, 4}},
|
||||
{{0.01f, 0.02f, 0.03f, 0.04f}, ngraph::element::f32, {1, 1, 4}}
|
||||
},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}
|
||||
}
|
||||
},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT,
|
||||
FuseDequantizeToFakeQuantizeTransformation,
|
||||
::testing::ValuesIn(testValues),
|
||||
FuseDequantizeToFakeQuantizeTransformation::getTestCaseName);
|
||||
|
||||
} // namespace
|
||||
@@ -1,424 +0,0 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <low_precision/fake_quantize.hpp>
|
||||
#include <low_precision/fake_quantize_decomposition.hpp>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <transformations/init_node_info.hpp>
|
||||
#include <transformations/utils/utils.hpp>
|
||||
|
||||
#include "common_test_utils/ngraph_test_utils.hpp"
|
||||
#include "layer_transformation.hpp"
|
||||
#include "lpt_ngraph_functions/common/add.hpp"
|
||||
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
|
||||
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
|
||||
#include "lpt_ngraph_functions/fuse_fake_quantize_function.hpp"
|
||||
#include "simple_low_precision_transformer.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace testing;
|
||||
using namespace ngraph;
|
||||
using namespace ngraph::pass;
|
||||
|
||||
class FuseFakeQuantizeTransformationTestValues {
|
||||
public:
|
||||
class Actual {
|
||||
public:
|
||||
ngraph::element::Type precisionBeforeAdd;
|
||||
ngraph::builder::subgraph::Add add;
|
||||
ngraph::element::Type precisionBeforeDequantization;
|
||||
ngraph::builder::subgraph::DequantizationOperations dequantization;
|
||||
ngraph::element::Type precisionAfterDequantization;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantizeOnData;
|
||||
};
|
||||
|
||||
class Expected {
|
||||
public:
|
||||
ngraph::element::Type precisionBeforeAdd;
|
||||
ngraph::builder::subgraph::Add add;
|
||||
ngraph::element::Type precisionBeforeDequantization;
|
||||
ngraph::builder::subgraph::DequantizationOperations dequantization;
|
||||
ngraph::element::Type precisionAfterDequantization;
|
||||
ngraph::element::Type precisionFakeQuantizeOnData;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantizeOnData;
|
||||
};
|
||||
|
||||
ngraph::PartialShape inputShape;
|
||||
TestTransformationParams params;
|
||||
Actual actual;
|
||||
Expected expected;
|
||||
};
|
||||
|
||||
class FuseFakeQuantizeTransformation : public LayerTransformation,
|
||||
public testing::WithParamInterface<FuseFakeQuantizeTransformationTestValues> {
|
||||
public:
|
||||
void SetUp() override {
|
||||
const FuseFakeQuantizeTransformationTestValues testValues = GetParam();
|
||||
|
||||
actualFunction = ngraph::builder::subgraph::FuseFakeQuantizeFunction::getOriginal(
|
||||
testValues.inputShape,
|
||||
testValues.actual.precisionBeforeAdd,
|
||||
testValues.actual.add,
|
||||
testValues.actual.precisionBeforeDequantization,
|
||||
testValues.actual.dequantization,
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.fakeQuantizeOnData);
|
||||
|
||||
SimpleLowPrecisionTransformer transformer;
|
||||
transformer
|
||||
.add<ngraph::pass::low_precision::FakeQuantizeDecompositionTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.transform(actualFunction);
|
||||
|
||||
transformer.add<ngraph::pass::low_precision::FakeQuantizeTransformation, ngraph::opset1::FakeQuantize>(
|
||||
testValues.params);
|
||||
transformer.transform(actualFunction);
|
||||
|
||||
referenceFunction = ngraph::builder::subgraph::FuseFakeQuantizeFunction::getReference(
|
||||
testValues.inputShape,
|
||||
testValues.expected.precisionBeforeAdd,
|
||||
testValues.expected.add,
|
||||
testValues.expected.precisionBeforeDequantization,
|
||||
testValues.expected.dequantization,
|
||||
testValues.expected.precisionAfterDequantization,
|
||||
testValues.expected.precisionFakeQuantizeOnData,
|
||||
testValues.expected.fakeQuantizeOnData);
|
||||
}
|
||||
|
||||
static std::string getTestCaseName(testing::TestParamInfo<FuseFakeQuantizeTransformationTestValues> obj) {
|
||||
const FuseFakeQuantizeTransformationTestValues testValues = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << testValues.inputShape << "_" << testValues.params.updatePrecisions << "_"
|
||||
<< testValues.actual.precisionBeforeAdd << "_" << testValues.actual.add.values.size() << "_"
|
||||
<< testValues.actual.add.outPrecision << "_" << testValues.actual.add.constantShape << "_"
|
||||
<< testValues.actual.precisionBeforeDequantization << testValues.actual.dequantization << "_"
|
||||
<< testValues.actual.precisionBeforeDequantization << "_" << testValues.actual.fakeQuantizeOnData << "_"
|
||||
<< testValues.expected.dequantization << "_" << testValues.expected.add.values.size() << "_"
|
||||
<< testValues.expected.add.outPrecision << "_" << testValues.expected.add.constantShape;
|
||||
return result.str();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(FuseFakeQuantizeTransformation, CompareFunctions) {
|
||||
actualFunction->validate_nodes_and_infer_types();
|
||||
auto res = compare_functions(actualFunction, referenceFunction, true, true);
|
||||
ASSERT_TRUE(res.first) << res.second;
|
||||
|
||||
ASSERT_TRUE(LayerTransformation::allNamesAreUnique(actualFunction)) << "Not all names are unique";
|
||||
}
|
||||
|
||||
const std::vector<FuseFakeQuantizeTransformationTestValues> testValues = {
|
||||
// Convert: U8 -> FP32, updatePrecisions = true
|
||||
{{1, 3, 16, 16},
|
||||
TestTransformationParams(true, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::u8}}},
|
||||
// Convert: U8 -> FP32, updatePrecisions = false
|
||||
{{1, 3, 16, 16},
|
||||
TestTransformationParams(false, {ngraph::element::u8}, {ngraph::element::i8}),
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, element::f32}}},
|
||||
// 1) Multiply
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32, {}, element::f32, {{}, {}, {0.01f}}, element::f32, {256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {255.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Multiply
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}}, {0.f, 0.f, 0.f}, {255.f, 127.5f, 85.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Per-channel multiply and dynamic shape
|
||||
{{Dimension::dynamic(), 3, Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}}, {0.f, 0.f, 0.f}, {255.f, 127.5f, 85.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Per-channel multiply and dynamic shape with dynamic channels
|
||||
{{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.02f, 0.03f}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// 1) Multiply with different input and output shape
|
||||
{{128, 1},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// Dynamic shape
|
||||
{{Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {{0.01f, 0.1f, 1.f}, ngraph::element::f32, {1, 3}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// 1) Multiply + 2) Add
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{{128}, element::f32},
|
||||
element::f32,
|
||||
{{}, {}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Subtract + Multiply
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32, {}, element::f32, {{}, {-128}, {0.01f}}, element::f32, {256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Convert + Subtract + Multiply
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{}, {}, {}},
|
||||
element::u8,
|
||||
element::f32,
|
||||
{256ul, {}, {-128.f}, {127.f}, {0.f}, {2.55f}}}},
|
||||
// 1) Convert + Subtract + Multiply 2) Add
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}}},
|
||||
// Dynamic shape
|
||||
{{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}}},
|
||||
// Dynamic rank
|
||||
{PartialShape::dynamic(),
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{{127}, element::f32},
|
||||
element::f32,
|
||||
{{element::f32}, {-128}, {0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {-255.f}, {0.f}, {0.f}, {2.55f}}}},
|
||||
// negative multiply
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {-128}, {-0.01f}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::f32,
|
||||
{{}, {-128}, {-0.01f}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// issue #40611 for FP32
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f32}, {}, {}},
|
||||
ngraph::element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f32}, {}, {}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// issue #40611 for FP16
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f16}, {}, {}},
|
||||
ngraph::element::f16,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{{},
|
||||
{},
|
||||
ngraph::element::i32,
|
||||
{{ngraph::element::f16}, {}, {}},
|
||||
element::f16,
|
||||
element::f16,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// multiply by zero
|
||||
{{1, 3, 16, 16},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {{-128, -128, -128}}, {{0.01f, 0.f, 0.01f}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32}, {{-128, -128, -128}}, {{0.01f, 0.f, 0.01f}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
// non per-channel operation
|
||||
{{1, 3, 4},
|
||||
LayerTransformation::createParamsU8I8(),
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32},
|
||||
{{-128, -128, -128, -128}, ngraph::element::f32, {1, 1, 4}},
|
||||
{{0.01f, 0.02f, 0.03f, 0.04f}, ngraph::element::f32, {1, 1, 4}}},
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}},
|
||||
{element::f32,
|
||||
{},
|
||||
element::u8,
|
||||
{{element::f32},
|
||||
{{-128, -128, -128, -128}, ngraph::element::f32, {1, 1, 4}},
|
||||
{{0.01f, 0.02f, 0.03f, 0.04f}, ngraph::element::f32, {1, 1, 4}}},
|
||||
element::f32,
|
||||
element::f32,
|
||||
{256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f}}}},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT,
|
||||
FuseFakeQuantizeTransformation,
|
||||
::testing::ValuesIn(testValues),
|
||||
FuseFakeQuantizeTransformation::getTestCaseName);
|
||||
|
||||
} // namespace
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/eliminate_fake_quantize_transformation.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace LayerTestsDefinitions;
|
||||
using namespace InferenceEngine::details;
|
||||
|
||||
namespace {
|
||||
|
||||
const std::vector<EliminateFakeQuantizeTransformationTestValues> testValues = {
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8(),
|
||||
{
|
||||
ngraph::element::f32,
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 },
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 }
|
||||
},
|
||||
{
|
||||
{ "fakeQuantize1" },
|
||||
{ "fakeQuantize2" }, // was fused to fakeQuantize1
|
||||
2ull
|
||||
}
|
||||
},
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8(),
|
||||
{
|
||||
ngraph::element::f32,
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 },
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.1f }, { 0.f }, { 255.f / 2.1f }, ngraph::element::f32 }
|
||||
},
|
||||
{
|
||||
{ "fakeQuantize1", "fakeQuantize2" }, // not fused
|
||||
{ },
|
||||
2ull
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT,
|
||||
EliminateFakeQuantizeTransformation,
|
||||
::testing::Combine(
|
||||
::testing::Values(CommonTestUtils::DEVICE_CPU),
|
||||
::testing::ValuesIn(testValues)),
|
||||
EliminateFakeQuantizeTransformation::getTestCaseName);
|
||||
|
||||
} // namespace
|
||||
+6
-4
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/fuse_fake_quantize_transformation.hpp"
|
||||
#include "low_precision_transformations/fuse_dequantize_to_fake_quantize_transformation.hpp"
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -11,7 +11,8 @@ using namespace InferenceEngine::details;
|
||||
|
||||
namespace {
|
||||
|
||||
const std::vector<FuseFakeQuantizeTransformationTestValues> testValues = {
|
||||
// clang-format off
|
||||
const std::vector<FuseDequantizeToFakeQuantizeTransformationTestValues> testValues = {
|
||||
// 1) Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
@@ -103,10 +104,11 @@ const std::vector<FuseFakeQuantizeTransformationTestValues> testValues = {
|
||||
}
|
||||
},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT, FuseFakeQuantizeTransformation,
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT, FuseDequantizeToFakeQuantizeTransformation,
|
||||
::testing::Combine(
|
||||
::testing::Values(CommonTestUtils::DEVICE_CPU),
|
||||
::testing::ValuesIn(testValues)),
|
||||
FuseFakeQuantizeTransformation::getTestCaseName);
|
||||
FuseDequantizeToFakeQuantizeTransformation::getTestCaseName);
|
||||
} // namespace
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/eliminate_fake_quantize_transformation.hpp"
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace LayerTestsDefinitions;
|
||||
using namespace InferenceEngine::details;
|
||||
|
||||
namespace {
|
||||
const std::vector<EliminateFakeQuantizeTransformationTestValues> testValues = {
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8(),
|
||||
{
|
||||
ngraph::element::f32,
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 },
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 }
|
||||
},
|
||||
{
|
||||
{ "fakeQuantize1" },
|
||||
{ "fakeQuantize2" }, // was fused to fakeQuantize1
|
||||
2ull
|
||||
}
|
||||
},
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8(),
|
||||
{
|
||||
ngraph::element::f32,
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.f }, { 0.f }, { 255.f / 2.f }, ngraph::element::f32 },
|
||||
{ 256ul, {}, { 0.f }, { 255.f / 2.1f }, { 0.f }, { 255.f / 2.1f }, ngraph::element::f32 }
|
||||
},
|
||||
{
|
||||
{ "fakeQuantize1", "fakeQuantize2" }, // not fused
|
||||
{ },
|
||||
2ull
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT,
|
||||
EliminateFakeQuantizeTransformation,
|
||||
::testing::Combine(
|
||||
::testing::Values(CommonTestUtils::DEVICE_GPU),
|
||||
::testing::ValuesIn(testValues)),
|
||||
EliminateFakeQuantizeTransformation::getTestCaseName);
|
||||
|
||||
} // namespace
|
||||
+8
-5
@@ -1,8 +1,8 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// Copyright (C) 2018-2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/fuse_fake_quantize_transformation.hpp"
|
||||
#include "low_precision_transformations/fuse_dequantize_to_fake_quantize_transformation.hpp"
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -10,7 +10,9 @@ using namespace LayerTestsDefinitions;
|
||||
using namespace InferenceEngine::details;
|
||||
|
||||
namespace {
|
||||
const std::vector<FuseFakeQuantizeTransformationTestValues> testValues = {
|
||||
|
||||
// clang-format off
|
||||
const std::vector<FuseDequantizeToFakeQuantizeTransformationTestValues> testValues = {
|
||||
// 1) Multiply
|
||||
{
|
||||
{1, 3, 16, 16},
|
||||
@@ -103,10 +105,11 @@ const std::vector<FuseFakeQuantizeTransformationTestValues> testValues = {
|
||||
}
|
||||
},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT, FuseFakeQuantizeTransformation,
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_LPT, FuseDequantizeToFakeQuantizeTransformation,
|
||||
::testing::Combine(
|
||||
::testing::Values(CommonTestUtils::DEVICE_GPU),
|
||||
::testing::ValuesIn(testValues)),
|
||||
FuseFakeQuantizeTransformation::getTestCaseName);
|
||||
FuseDequantizeToFakeQuantizeTransformation::getTestCaseName);
|
||||
} // namespace
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include "lpt_ngraph_functions/common/add.hpp"
|
||||
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
|
||||
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
|
||||
#include "shared_test_classes/base/low_precision_transformations/layer_transformation.hpp"
|
||||
|
||||
namespace LayerTestsDefinitions {
|
||||
|
||||
class EliminateFakeQuantizeTransformationTestValues {
|
||||
public:
|
||||
class Actual {
|
||||
public:
|
||||
ngraph::element::Type precisionBefore;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData1;
|
||||
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData2;
|
||||
};
|
||||
|
||||
class Expected {
|
||||
public:
|
||||
std::set<std::string> exist;
|
||||
std::set<std::string> absent;
|
||||
size_t int8_convolutions;
|
||||
};
|
||||
|
||||
ngraph::PartialShape inputShape;
|
||||
ngraph::pass::low_precision::LayerTransformation::Params params;
|
||||
Actual actual;
|
||||
Expected expected;
|
||||
};
|
||||
|
||||
typedef std::tuple<
|
||||
std::string,
|
||||
EliminateFakeQuantizeTransformationTestValues> EliminateFakeQuantizeTransformationParams;
|
||||
|
||||
class EliminateFakeQuantizeTransformation
|
||||
: public testing::WithParamInterface<EliminateFakeQuantizeTransformationParams>,
|
||||
public LayerTestsUtils::LayerTransformation {
|
||||
public:
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<EliminateFakeQuantizeTransformationParams>& obj);
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
};
|
||||
|
||||
} // namespace LayerTestsDefinitions
|
||||
+6
-6
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace LayerTestsDefinitions {
|
||||
|
||||
class FuseFakeQuantizeTransformationTestValues {
|
||||
class FuseDequantizeToFakeQuantizeTransformationTestValues {
|
||||
public:
|
||||
class Actual {
|
||||
public:
|
||||
@@ -33,13 +33,13 @@ public:
|
||||
|
||||
typedef std::tuple<
|
||||
std::string,
|
||||
FuseFakeQuantizeTransformationTestValues> FuseFakeQuantizeTransformationParams;
|
||||
FuseDequantizeToFakeQuantizeTransformationTestValues> FuseDequantizeToFakeQuantizeTransformationParams;
|
||||
|
||||
class FuseFakeQuantizeTransformation :
|
||||
public testing::WithParamInterface<FuseFakeQuantizeTransformationParams>,
|
||||
public LayerTestsUtils::LayerTransformation {
|
||||
class FuseDequantizeToFakeQuantizeTransformation
|
||||
: public testing::WithParamInterface<FuseDequantizeToFakeQuantizeTransformationParams>,
|
||||
public LayerTestsUtils::LayerTransformation {
|
||||
public:
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<FuseFakeQuantizeTransformationParams>& obj);
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<FuseDequantizeToFakeQuantizeTransformationParams>& obj);
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/eliminate_fake_quantize_transformation.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <transformations/init_node_info.hpp>
|
||||
#include "openvino/util/common_util.hpp"
|
||||
#include "lpt_ngraph_functions/fuse_fake_quantize_function.hpp"
|
||||
|
||||
namespace LayerTestsDefinitions {
|
||||
|
||||
std::string EliminateFakeQuantizeTransformation::getTestCaseName(const testing::TestParamInfo<EliminateFakeQuantizeTransformationParams>& obj) {
|
||||
std::string targetDevice;
|
||||
EliminateFakeQuantizeTransformationTestValues testValues;
|
||||
std::tie(targetDevice, testValues) = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << targetDevice << "_" <<
|
||||
testValues.actual.precisionBefore << "_" <<
|
||||
testValues.actual.fakeQuantizeOnData1 << "_" <<
|
||||
testValues.actual.fakeQuantizeOnData2;
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void EliminateFakeQuantizeTransformation::SetUp() {
|
||||
EliminateFakeQuantizeTransformationTestValues testValues;
|
||||
std::tie(targetDevice, testValues) = this->GetParam();
|
||||
|
||||
// Convolution is used in a model as operation with specific precision requirements on data branch
|
||||
// to test the transformation place in LPT pipeline:
|
||||
// markup transformations and FakeQuantize operation decomposition transformation have to handle FakeQuantize as usual
|
||||
function = ngraph::builder::subgraph::FuseFakeQuantizeFunction::get(
|
||||
testValues.inputShape,
|
||||
testValues.actual.precisionBefore,
|
||||
testValues.actual.fakeQuantizeOnData1,
|
||||
testValues.actual.fakeQuantizeOnData2,
|
||||
{});
|
||||
|
||||
ov::pass::InitNodeInfo().run_on_model(function);
|
||||
}
|
||||
|
||||
TEST_P(EliminateFakeQuantizeTransformation, CompareWithRefImpl) {
|
||||
Run();
|
||||
|
||||
EliminateFakeQuantizeTransformationTestValues testValues;
|
||||
std::tie(targetDevice, testValues) = this->GetParam();
|
||||
|
||||
const auto& rtInfo = LayerTestsCommon::getRuntimeInfo();
|
||||
|
||||
auto exist = testValues.expected.exist;
|
||||
auto absent = testValues.expected.absent;
|
||||
auto int8_convolutions = 0ull;
|
||||
for (const auto& it : rtInfo) {
|
||||
const auto& nameIt = it.second.find("originalLayersNames");
|
||||
const auto& fused_name = nameIt->second.as<std::string>();
|
||||
|
||||
const auto names = ov::util::split(fused_name, ',', true);
|
||||
for (const auto& name : names) {
|
||||
ASSERT_TRUE(absent.find(name) == absent.end());
|
||||
exist.erase(name);
|
||||
}
|
||||
|
||||
const auto& type_it = it.second.find("layerType");
|
||||
const auto& type = type_it->second.as<std::string>();
|
||||
|
||||
if (type == "Convolution") {
|
||||
const auto& precision_it = it.second.find("runtimePrecision");
|
||||
const auto& precision = precision_it->second.as<std::string>();
|
||||
if (precision == "U8") {
|
||||
int8_convolutions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(exist.empty());
|
||||
ASSERT_EQ(testValues.expected.int8_convolutions, int8_convolutions);
|
||||
};
|
||||
|
||||
} // namespace LayerTestsDefinitions
|
||||
+8
-10
@@ -1,8 +1,8 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// Copyright (C) 2018-2022 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "low_precision_transformations/fuse_fake_quantize_transformation.hpp"
|
||||
#include "low_precision_transformations/fuse_dequantize_to_fake_quantize_transformation.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
namespace LayerTestsDefinitions {
|
||||
|
||||
std::string FuseFakeQuantizeTransformation::getTestCaseName(const testing::TestParamInfo<FuseFakeQuantizeTransformationParams>& obj) {
|
||||
std::string FuseDequantizeToFakeQuantizeTransformation::getTestCaseName(const testing::TestParamInfo<FuseDequantizeToFakeQuantizeTransformationParams>& obj) {
|
||||
std::string targetDevice;
|
||||
FuseFakeQuantizeTransformationTestValues testValues;
|
||||
FuseDequantizeToFakeQuantizeTransformationTestValues testValues;
|
||||
std::tie(targetDevice, testValues) = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << "targetDevice=" << targetDevice << "_" <<
|
||||
result << targetDevice << "_" <<
|
||||
testValues.actual.precisionBeforeAdd << "_" <<
|
||||
testValues.actual.add.values.size() << "_" <<
|
||||
testValues.actual.add.outPrecision << "_" <<
|
||||
@@ -32,8 +32,8 @@ std::string FuseFakeQuantizeTransformation::getTestCaseName(const testing::TestP
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void FuseFakeQuantizeTransformation::SetUp() {
|
||||
FuseFakeQuantizeTransformationTestValues testValues;
|
||||
void FuseDequantizeToFakeQuantizeTransformation::SetUp() {
|
||||
FuseDequantizeToFakeQuantizeTransformationTestValues testValues;
|
||||
std::tie(targetDevice, testValues) = this->GetParam();
|
||||
|
||||
function = ngraph::builder::subgraph::FuseFakeQuantizeFunction::getOriginal(
|
||||
@@ -45,11 +45,9 @@ void FuseFakeQuantizeTransformation::SetUp() {
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.precisionAfterDequantization,
|
||||
testValues.actual.fakeQuantizeOnData);
|
||||
|
||||
ov::pass::InitNodeInfo().run_on_model(function);
|
||||
}
|
||||
|
||||
TEST_P(FuseFakeQuantizeTransformation, CompareWithRefImpl) {
|
||||
TEST_P(FuseDequantizeToFakeQuantizeTransformation, CompareWithRefImpl) {
|
||||
Run();
|
||||
};
|
||||
|
||||
@@ -744,6 +744,7 @@ void Comparator::compare_inputs(ngraph::Node* node1, ngraph::Node* node2, std::o
|
||||
auto const2 = ngraph::as_type_ptr<Constant>(node2->get_input_node_shared_ptr(i));
|
||||
if (const1 && const2 && !equal_value(const1, const2)) {
|
||||
err_log << "Different Constant values detected\n"
|
||||
<< const1->get_friendly_name() << " & " << const2->get_friendly_name() << "\n"
|
||||
<< node1->description() << " Input(" << i << ") and " << node2->description() << " Input(" << i
|
||||
<< ")" << std::endl;
|
||||
}
|
||||
|
||||
+18
-11
@@ -1,13 +1,13 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include "low_precision/layer_transformation.hpp"
|
||||
|
||||
#include "common/add.hpp"
|
||||
#include "common/fake_quantize_on_data.hpp"
|
||||
#include "common/dequantization_operations.hpp"
|
||||
@@ -36,14 +36,21 @@ public:
|
||||
const FakeQuantizeOnDataWithConstant& fqOnData);
|
||||
|
||||
static std::shared_ptr<ngraph::Function> getReference(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBeforeAdd,
|
||||
const Add& add,
|
||||
const ngraph::element::Type precisionBeforeDequantization,
|
||||
const DequantizationOperations& dequantization,
|
||||
const ngraph::element::Type precisionAfterDequantization,
|
||||
const ngraph::element::Type precisionFqOnData,
|
||||
const FakeQuantizeOnDataWithConstant& fqOnData);
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBeforeAdd,
|
||||
const Add& add,
|
||||
const ngraph::element::Type precisionBeforeDequantization,
|
||||
const DequantizationOperations& dequantization,
|
||||
const ngraph::element::Type precisionAfterDequantization,
|
||||
const ngraph::element::Type precisionFqOnData,
|
||||
const FakeQuantizeOnDataWithConstant& fqOnData);
|
||||
|
||||
static std::shared_ptr<ngraph::Function> get(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBefore,
|
||||
const FakeQuantizeOnData& fqOnData1,
|
||||
const FakeQuantizeOnData& fqOnData2,
|
||||
const DequantizationOperations& dequantizationOperations2);
|
||||
|
||||
static std::shared_ptr<ngraph::Function> get(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
|
||||
@@ -194,11 +194,11 @@ std::shared_ptr<Node> makeTranspose(const Output<Node>& data, const Transpose& t
|
||||
|
||||
std::shared_ptr<ngraph::opset1::FakeQuantize> makeFakeQuantize(
|
||||
const Output<Node>& output,
|
||||
const ngraph::element::Type precision,
|
||||
const ngraph::element::Type constantType,
|
||||
const FakeQuantizeOnData& fqOnData) {
|
||||
return ov::as_type_ptr<ngraph::opset1::FakeQuantize>(ngraph::builder::makeFakeQuantize(
|
||||
output,
|
||||
precision,
|
||||
constantType,
|
||||
fqOnData.quantizationLevel,
|
||||
fqOnData.constantShape,
|
||||
fqOnData.inputLowValues,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#include <ngraph/opsets/opset1.hpp>
|
||||
#include "ov_ops/type_relaxed.hpp"
|
||||
#include "ngraph_functions/subgraph_builders.hpp"
|
||||
#include "low_precision/network_helper.hpp"
|
||||
#include "ngraph_functions/subgraph_builders.hpp"
|
||||
|
||||
#include "lpt_ngraph_functions/common/builders.hpp"
|
||||
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
|
||||
@@ -47,6 +47,39 @@ std::shared_ptr<ngraph::Function> FuseFakeQuantizeFunction::getOriginal(
|
||||
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "FuseFakeQuantizeFunction");
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::shared_ptr<ngraph::opset1::Convolution> make_convolution(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBefore,
|
||||
const std::shared_ptr<Node>& parent,
|
||||
const size_t index) {
|
||||
const ov::Shape shape = inputShape.to_shape();
|
||||
const ov::Shape weightsShape({ shape[1], shape[1], 1ull, 1ull });
|
||||
auto weightsConstant = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, weightsShape, std::vector<float>(9, 1.f));
|
||||
auto weights = makeFakeQuantize(
|
||||
weightsConstant,
|
||||
precisionBefore,
|
||||
FakeQuantizeOnData(
|
||||
255,
|
||||
ov::Shape({ shape[1], 1ull, 1ull, 1ull }),
|
||||
{ -1.27f, -1.27f, -1.27f },
|
||||
{ 1.28f, 1.28f, 1.28f },
|
||||
{ -1.27f, -1.27f, -1.27f },
|
||||
{ 1.28f, 1.28f, 1.28f },
|
||||
precisionBefore));
|
||||
|
||||
auto convolution = std::make_shared<ngraph::opset1::Convolution>(
|
||||
parent,
|
||||
weights,
|
||||
ngraph::Strides{ 1, 1 },
|
||||
ngraph::CoordinateDiff{ 0, 0 },
|
||||
ngraph::CoordinateDiff{ 0, 0 },
|
||||
ngraph::Strides{ 1, 1 });
|
||||
convolution->set_friendly_name("convolution" + std::to_string(index));
|
||||
return convolution;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<ngraph::Function> FuseFakeQuantizeFunction::getReference(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBeforeAdd,
|
||||
@@ -87,6 +120,56 @@ std::shared_ptr<ngraph::Function> FuseFakeQuantizeFunction::getOriginal(
|
||||
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "FuseFakeQuantizeFunction");
|
||||
}
|
||||
|
||||
std::shared_ptr<ngraph::Function> FuseFakeQuantizeFunction::get(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const ngraph::element::Type precisionBefore,
|
||||
const FakeQuantizeOnData& fqOnData1,
|
||||
const FakeQuantizeOnData& fqOnData2,
|
||||
const DequantizationOperations& dequantizationOperations2) {
|
||||
const auto input = std::make_shared<ngraph::opset1::Parameter>(precisionBefore, inputShape);
|
||||
input->set_friendly_name("input");
|
||||
|
||||
std::shared_ptr<Node> parent = input;
|
||||
|
||||
if (!fqOnData1.empty()) {
|
||||
parent = fqOnData1.outputPrecision == precisionBefore ?
|
||||
makeFakeQuantize(parent, precisionBefore, fqOnData1) :
|
||||
makeFakeQuantizeTypeRelaxed(parent, precisionBefore, fqOnData1);
|
||||
parent->set_friendly_name("fakeQuantize1");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
parent = std::make_shared<ngraph::opset1::MaxPool>(
|
||||
parent,
|
||||
stride,
|
||||
padBegin,
|
||||
padEnd,
|
||||
kernel,
|
||||
roundingType,
|
||||
padType);
|
||||
|
||||
if (!fqOnData2.empty()) {
|
||||
parent = makeFakeQuantize(parent, precisionBefore, fqOnData2);
|
||||
parent->set_friendly_name("fakeQuantize2");
|
||||
}
|
||||
|
||||
if (!dequantizationOperations2.empty()) {
|
||||
parent = makeDequantization(parent, dequantizationOperations2);
|
||||
}
|
||||
|
||||
ngraph::ResultVector results{
|
||||
std::make_shared<ngraph::opset1::Result>(make_convolution(inputShape, precisionBefore, parent, 0)),
|
||||
std::make_shared<ngraph::opset1::Result>(make_convolution(inputShape, precisionBefore, parent, 1))
|
||||
};
|
||||
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "FuseFakeQuantizeFunction");
|
||||
}
|
||||
|
||||
std::shared_ptr<ngraph::Function> FuseFakeQuantizeFunction::get(
|
||||
const ngraph::PartialShape& inputShape,
|
||||
const std::vector<Branch>& branches,
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace ngraph {
|
||||
namespace builder {
|
||||
|
||||
std::shared_ptr<Node> makeFakeQuantize(const ngraph::Output<Node> &in,
|
||||
const element::Type &type,
|
||||
const element::Type &constantType,
|
||||
std::size_t levels,
|
||||
std::vector<size_t> constShapes,
|
||||
const std::vector<float> &inputLowData,
|
||||
const std::vector<float> &inputHighData,
|
||||
const std::vector<float> &outputLowData,
|
||||
const std::vector<float> &outputHighData) {
|
||||
auto inputLowNode = makeConstant(type, constShapes, inputLowData, inputLowData.empty());
|
||||
auto inputHighNode = makeConstant(type, constShapes, inputHighData, inputHighData.empty());
|
||||
auto outputLowNode = makeConstant(type, constShapes, outputLowData, outputLowData.empty());
|
||||
auto outputHighNode = makeConstant(type, constShapes, outputHighData, outputHighData.empty());
|
||||
auto inputLowNode = makeConstant(constantType, constShapes, inputLowData, inputLowData.empty());
|
||||
auto inputHighNode = makeConstant(constantType, constShapes, inputHighData, inputHighData.empty());
|
||||
auto outputLowNode = makeConstant(constantType, constShapes, outputLowData, outputLowData.empty());
|
||||
auto outputHighNode = makeConstant(constantType, constShapes, outputHighData, outputHighData.empty());
|
||||
|
||||
auto fq = std::make_shared<ngraph::opset1::FakeQuantize>(in, inputLowNode, inputHighNode, outputLowNode, outputHighNode, levels);
|
||||
|
||||
|
||||
Reference in new issue
Block a user