fix special FQ node (#14594)

* fix special FQ with zero range in quantized models

* fix format & comments

* Add test case

* remove dot interval test case from smoke_LPT/FakeQuantizeTransformation.CompareFunctions

* Remove dot interval gpu test case because Pooling is also folded

* handle review comment

* fix code style

* update docs

* remove fold_zero_multiply
This commit is contained in:
Tingqian Li authored and GitHub committed 2023-03-15 10:13:29 +00:00
1 parent f0c153858b
commit fdc2664b24
6 files changed
+94 -15

No files matched your search

@@ -26,6 +26,7 @@ public:
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;
bool isConstantOutput(std::shared_ptr<ngraph::Node> op) const;
};
} // namespace low_precision
@@ -9,6 +9,7 @@
#include <vector>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/pattern/op/or.hpp>
#include "low_precision/network_helper.hpp"
#include "itt.hpp"
@@ -59,8 +60,27 @@ bool FoldFakeQuantizeTransformation::transform(TransformationContext& context, n
return false;
}
bool FoldFakeQuantizeTransformation::isConstantOutput(std::shared_ptr<ngraph::Node> node) const {
const auto fakeQuantize = ov::as_type_ptr<opset1::FakeQuantize>(node);
if (!fakeQuantize) {
return false;
}
const auto outputLow = as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(3));
const auto outputHigh = as_type_ptr<opset1::Constant>(fakeQuantize->get_input_node_shared_ptr(4));
if (outputLow == nullptr || outputHigh == nullptr) {
return false;
}
const auto vecLow = outputLow->cast_vector<float>();
const auto vecHigh = outputHigh->cast_vector<float>();
return vecLow == vecHigh;
}
bool FoldFakeQuantizeTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> op) const {
return NetworkHelper::isConstantPath(op);
return NetworkHelper::isConstantPath(op) || isConstantOutput(op);
}
bool FoldFakeQuantizeTransformation::isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept {
@@ -742,6 +742,26 @@ std::shared_ptr<Node> NetworkHelper::foldFakeQuantize(
foldConvert(fq->input_value(3), element::f32));
}
// y = FakeQuantize(x, inputLow, inputHigh, outputLow, outputHigh)
// given:
// outputLow is const
// outputHigh is const
// outputLow == outputHigh
// => y = Broadcast(Convert(outputLow, typeof(y))), ShapeOf(x))
if (ov::is_type<opset1::Constant>(fq->get_input_node_shared_ptr(3)) &&
ov::is_type<opset1::Constant>(fq->get_input_node_shared_ptr(4))) {
const auto outputLowValues =
ov::as_type_ptr<opset1::Constant>(fq->get_input_node_shared_ptr(3))->cast_vector<float>();
const auto outputHighValues =
ov::as_type_ptr<opset1::Constant>(fq->get_input_node_shared_ptr(4))->cast_vector<float>();
if (outputLowValues == outputHighValues) {
const auto data_shape_node = fold<opset1::ShapeOf>(fq->input_value(0));
const auto cvt_output_low = foldConvert(fq->input_value(3), fq->get_output_element_type(0));
return fold<opset1::Broadcast>(cvt_output_low, data_shape_node);
}
}
auto constant = ov::as_type_ptr<opset1::Constant>(fq->get_input_node_shared_ptr(0));
if (constant) {
@@ -183,13 +183,6 @@ const std::vector<FakeQuantizeTransformationTestValues> fakeQuantizeTransformati
ngraph::element::i8,
{{ngraph::element::f32, {{}, {-128.f}, {0.01f}}}, {ngraph::element::f16, {{}, {-128.f}, {0.01f}}}},
true},
// dot interval
{LayerTransformation::createParamsI8I8(),
{256ul, {}, {0.f}, {2.55f}, {2.55f}, {2.55f}},
{256ul, {}, {0.f}, {2.55f}, {1.f}, {1.f}},
ngraph::element::Type_t::i8,
{{ngraph::element::f32, {{}, {}, {2.55f}}}},
true},
// efficientnet-b0: efficientnet-b0/model/blocks_2/depthwise_conv2d/depthwise/fq_input_0, interval: -0.504395 - +0.5
// I8 symmetric: max ratio = 0.000907078
@@ -67,12 +67,23 @@ public:
const auto params = TestTransformationParams(testValues.params).setUpdatePrecisions(testValues.updatePrecision);
const auto constant = std::make_shared<ngraph::opset1::Constant>(testValues.actual.constPrecision,
testValues.constShape,
testValues.actual.constValues);
std::shared_ptr<ngraph::Node> dataSource;
std::shared_ptr<ngraph::opset1::Parameter> parameter;
bool useParameterAsDataSource = (testValues.actual.constValues.size() == 0);
if (useParameterAsDataSource) {
// for data-independent const folding
parameter =
std::make_shared<ngraph::opset1::Parameter>(testValues.actual.constPrecision, testValues.constShape);
dataSource = parameter;
} else {
dataSource = std::make_shared<ngraph::opset1::Constant>(testValues.actual.constPrecision,
testValues.constShape,
testValues.actual.constValues);
}
std::shared_ptr<Node> fq =
ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(constant,
ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(dataSource,
element::f32,
testValues.actual.fakeQuantize);
ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(as_type_ptr<opset1::FakeQuantize>(fq),
@@ -80,8 +91,10 @@ public:
fq = ngraph::pass::low_precision::NetworkHelper::fold_fake_quantize(as_type_ptr<opset1::FakeQuantize>(fq),
testValues.roundValues);
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(fq)};
actualFunction =
std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{}, "FoldFakeQuantizeFunction");
actualFunction = std::make_shared<ngraph::Function>(
results,
parameter ? ngraph::ParameterVector{parameter} : ngraph::ParameterVector{},
"FoldFakeQuantizeFunction");
referenceFunction =
ngraph::builder::subgraph::FoldFakeQuantizeFunction::getReference(testValues.expected.constPrecision,
@@ -189,6 +202,37 @@ const std::vector<FoldFakeQuantizeInTransformationsTestValues> testValues = {
ngraph::element::i8},
{{-127, -128, -51, -3, 126, -28, -128, -1, -128, -64, -127, 127, -121, -128, -119, -128}, ngraph::element::i8},
},
{
Shape{2, 2, 2, 2},
LayerTransformation::createParamsU8I8(),
true,
false,
{{
// use empty constValues for data independent const folding
},
ngraph::element::u8,
{256ul, {}, {0.f}, {255.f}, {127.f}, {127.f}},
ngraph::element::i8},
{{
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
127,
},
ngraph::element::i8},
},
};
INSTANTIATE_TEST_SUITE_P(smoke_LPT,