[LPT] Dequantization constant output precision handling extending (#2987)

* [LPT] moveDequantizationAfter fix

* [LPT] ConcatTransformation fix: only intermediate operations are handled
This commit is contained in:
Edward Shogulin 2020-11-11 18:50:37 +03:00 committed by GitHub
parent 27c97a037f
commit 518c0b6bd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 748 additions and 107 deletions

View File

@ -30,6 +30,7 @@ public:
std::unordered_map<std::string, std::shared_ptr<ngraph::Node>> layers;
private:
bool atLeastOneIsIntermediate(const std::shared_ptr<ngraph::Node>& node) const;
bool fillSubgraphForQuantization(const std::shared_ptr<ngraph::opset1::FakeQuantize>& fakeQuantize, std::unordered_set<std::string>& handledLayers);
bool fillSubgraphForIntermediate(const std::shared_ptr<ngraph::Node>& intermediate, std::unordered_set<std::string>& handledLayers);
bool fill(const std::shared_ptr<ngraph::Node>& concat, std::unordered_set<std::string>& handledLayers);

View File

@ -138,7 +138,7 @@ bool ConcatTransformation::transform(TransformationContext& context, ngraph::pat
dequantizationSub,
subgraph.quantizationLayers[0]->get_output_element_type(0),
subgraph.quantizationLayers[0]->get_output_shape(0),
dataPrecision.precision,
updatePrecisions ? dataPrecision.precision : subgraph.quantizationLayers[0]->get_output_element_type(0),
dataPrecision.min,
dataPrecision.max);

View File

@ -951,14 +951,38 @@ NetworkHelper::InsertDequantizationResult NetworkHelper::moveDequantizationAfter
parent = std::make_shared<DequantizationConvert>(parent, dequantization.convert->get_output_element_type(0));
ngraph::copy_runtime_info({ newOperation, parent }, parent);
}
if (moveSubtract && (dequantization.subtract != nullptr)) {
auto subtractConstant = dequantization.subtract->get_input_node_shared_ptr(1);
parent = std::make_shared<DequantizationSubtract>(parent, subtractConstant);
const element::Type parentPrecision = parent->get_output_element_type(0);
if (parentPrecision.bitwidth() < subtractConstant->output(0).get_element_type().bitwidth()) {
THROW_IE_LPT_EXCEPTION(*parent) <<
"unexpected precisions: on data " << parent->get_friendly_name() << ":" << parentPrecision <<
", subtract dequantization constant " << subtractConstant->get_friendly_name() << ":" << subtractConstant->output(0).get_element_type();
}
parent = std::make_shared<DequantizationSubtract>(
parent,
subtractConstant->output(0).get_element_type() == parentPrecision ?
subtractConstant :
fold<opset1::Convert>(subtractConstant->output(0), parentPrecision));
ngraph::copy_runtime_info({ newOperation, parent }, parent);
}
if (dequantization.multiply != nullptr) {
auto multiplyConstant = dequantization.multiply->get_input_node_shared_ptr(1);
parent = std::make_shared<DequantizationMultiply>(parent, multiplyConstant);
const element::Type parentPrecision = parent->get_output_element_type(0);
if (parentPrecision.bitwidth() < multiplyConstant->output(0).get_element_type().bitwidth()) {
THROW_IE_LPT_EXCEPTION(*parent) <<
"unexpected precisions: on data " << parent->get_friendly_name() << ":" << parentPrecision <<
", multiply dequantization constant " << multiplyConstant->get_friendly_name() << ":" << multiplyConstant->output(0).get_element_type();
}
parent = std::make_shared<DequantizationMultiply>(
parent,
multiplyConstant->output(0).get_element_type() == parentPrecision ?
multiplyConstant :
fold<opset1::Convert>(multiplyConstant->output(0), parentPrecision));
ngraph::copy_runtime_info({ newOperation, parent }, parent);
}
replace_node(operation, parent);

View File

@ -36,6 +36,10 @@ bool isQuantizationPerChannel(const std::shared_ptr<ngraph::Node>& node) {
const Shape& in = input.get_shape();
const Shape& out = node->output(0).get_shape();
for (size_t i = 0; i < 2; ++i) {
if ((i >= in.size()) || (i >= out.size())) {
// all previous dimensions are equal
return true;
}
if (in[i] != out[i]) {
return false;
}
@ -86,6 +90,28 @@ bool Subgraph::fillSubgraphForQuantization(
return true;
}
bool Subgraph::atLeastOneIsIntermediate(const std::shared_ptr<ngraph::Node>& node) const {
for (size_t index = 0; index < node->get_output_size(); ++index) {
const auto childInputs = node->get_output_target_inputs(index);
for (const auto childInput : childInputs) {
auto child = childInput.get_node()->shared_from_this();
if (as_type_ptr<opset1::Concat>(child)) {
return true;
}
if (!layerTransformationsManager->isPrecisionPreserved(child) || !isQuantizationPerChannel(child)) {
// child branch is out of subgraph
continue;
}
if (atLeastOneIsIntermediate(child)) {
return true;
}
}
}
return false;
}
bool Subgraph::fill(const std::shared_ptr<ngraph::Node>& layer, std::unordered_set<std::string>& handledLayers) {
// if at least one parent is handled incorrectly then subgraph is not in low precision
for (size_t index = 0; index < layer->get_input_size(); ++index) {
@ -138,6 +164,11 @@ bool Subgraph::fill(const std::shared_ptr<ngraph::Node>& layer, std::unordered_s
return false;
}
} else {
// check if children branches between Concat operations
if (!atLeastOneIsIntermediate(child)) {
continue;
}
const std::shared_ptr<ngraph::opset1::FakeQuantize> fakeQuantizeChild = ngraph::as_type_ptr<ngraph::opset1::FakeQuantize>(child);
if (fakeQuantizeChild != nullptr) {
//
@ -175,4 +206,4 @@ bool Subgraph::fillSubgraphForConcat(const std::shared_ptr<ngraph::opset1::Conca
} // namespace low_precision
} // namespace pass
} // namespace ngraph
} // namespace ngraph

View File

@ -104,6 +104,11 @@ public:
transform.add<ngraph::pass::low_precision::ClampTransformation, ngraph::opset1::Clamp>(testValues.params);
transform.transform(actualFunction);
if (!updatePrecisions) {
// there is no Convert operation after MaxPool in FP32
testValues.result.dequantizationOperations2.convert = {};
}
referenceFunction = ngraph::builder::subgraph::ConcatFunction::getReferenceWithDifferentPrecisionOnChilds(
precision,
testValues.inputShape,

View File

@ -0,0 +1,214 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "layer_transformation.hpp"
#include <string>
#include <sstream>
#include <memory>
#include <gtest/gtest.h>
#include <transformations/utils/utils.hpp>
#include <transformations/init_node_info.hpp>
#include <low_precision/transformer.hpp>
#include <low_precision/concat.hpp>
#include <low_precision/concat_multi_channels.hpp>
#include <low_precision/max_pool.hpp>
#include <low_precision/reshape.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
#include "ngraph_functions/low_precision_transformations/concat_function.hpp"
#include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_data.hpp"
#include "simple_low_precision_transformer.hpp"
using namespace testing;
using namespace ngraph;
using namespace ngraph::pass;
namespace {
class ConcatTransformationActualValues {
public:
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize1;
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize2;
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize3;
};
inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationActualValues& values) {
return out << "_" << values.fakeQuantize1 << "_" << values.fakeQuantize2;
}
class ConcatTransformationResultValues {
public:
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize1;
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize2;
ngraph::builder::subgraph::FakeQuantizeOnDataWithConstant fakeQuantize3;
ngraph::builder::subgraph::DequantizationOperations dequantizationOperations;
};
inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationResultValues& values) {
return out << "_" << values.fakeQuantize1 << "_" << values.fakeQuantize2 << "_" << values.fakeQuantize3 << "_" << values.dequantizationOperations;
}
class ConcatTransformationTestValues {
public:
ngraph::pass::low_precision::LayerTransformation::Params params;
ConcatTransformationActualValues actual;
ConcatTransformationResultValues result;
};
inline std::ostream& operator<<(std::ostream& out, const ConcatTransformationTestValues& values) {
return out << "_" << values.actual << "_" << values.result;
}
typedef std::tuple <
ngraph::element::Type,
bool,
ngraph::Shape,
ConcatTransformationTestValues
> ConcatTransformationParams;
class ConcatWithReshapeAtTheEndTransformation : public LayerTransformation, public testing::WithParamInterface<ConcatTransformationParams> {
public:
void SetUp() override {
const ngraph::element::Type precision = std::get<0>(GetParam());
const bool updatePrecisions = std::get<1>(GetParam());
const ngraph::Shape shape = std::get<2>(GetParam());
ConcatTransformationTestValues testValues = std::get<3>(GetParam());
testValues.params.updatePrecisions = updatePrecisions;
if (!updatePrecisions) {
testValues.result.fakeQuantize1.outputPrecision = testValues.actual.fakeQuantize1.outputPrecision;
testValues.result.fakeQuantize2.outputPrecision = testValues.actual.fakeQuantize2.outputPrecision;
testValues.result.fakeQuantize3.outputPrecision = testValues.actual.fakeQuantize3.outputPrecision;
}
actualFunction = ngraph::builder::subgraph::ConcatFunction::getOriginalWithReshapeAtTheEndTransformation(
precision,
shape,
testValues.actual.fakeQuantize1,
testValues.actual.fakeQuantize2,
testValues.actual.fakeQuantize3);
SimpleLowPrecisionTransformer transform;
transform.add<ngraph::pass::low_precision::ConcatMultiChannelsTransformation, ngraph::opset1::Concat>(testValues.params);
transform.add<ngraph::pass::low_precision::MaxPoolTransformation, ngraph::opset1::MaxPool>(testValues.params);
transform.add<ngraph::pass::low_precision::ReshapeTransformation, ngraph::opset1::Reshape>(testValues.params);
transform.transform(actualFunction);
if (!testValues.params.updatePrecisions) {
// there is no Convert operation after MaxPool in FP32
testValues.result.dequantizationOperations.convert = {};
}
referenceFunction = ngraph::builder::subgraph::ConcatFunction::getReferenceWithReshapeAtTheEndTransformation(
precision,
shape,
testValues.result.fakeQuantize1,
testValues.result.fakeQuantize2,
testValues.result.fakeQuantize3,
testValues.result.dequantizationOperations);
}
static std::string getTestCaseName(testing::TestParamInfo<ConcatTransformationParams> obj) {
const ngraph::element::Type precision = std::get<0>(obj.param);
const bool updatePrecision = std::get<1>(obj.param);
const ngraph::Shape shape = std::get<2>(obj.param);
const ConcatTransformationTestValues testValues = std::get<3>(obj.param);
std::ostringstream result;
result <<
LayerTransformation::getTestCaseNameByParams(precision, shape, testValues.params) << "_" <<
(updatePrecision ? "updatePrecision_" : "notUpdatePrecision_") <<
testValues.actual << "_" <<
testValues.result << "_";
return result.str();
}
};
TEST_P(ConcatWithReshapeAtTheEndTransformation, CompareFunctions) {
actualFunction->validate_nodes_and_infer_types();
auto res = compare_functions(referenceFunction, actualFunction, true, true, true);
ASSERT_TRUE(res.first) << res.second;
}
const std::vector<ngraph::element::Type> precisions = {
ngraph::element::f32,
};
const std::vector<bool> updatePrecisions = { true, false };
const std::vector<ConcatTransformationTestValues> testValues = {
{
LayerTransformation::createParamsU8I8(),
{
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {2.55f} },
},
{
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
{ 256ul, {}, {0.f}, {2.55f}, {0.f}, {255.f}, ngraph::element::u8 },
{ ngraph::element::f32, {}, { 0.01f } }
}
},
{
LayerTransformation::createParamsU8I8(),
{
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
},
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
},
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}, {1, 3, 1, 1}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}
},
},
{
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f}, ngraph::element::u8
},
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f},
ngraph::element::u8
},
{
256ul,
{{1, 3, 1, 1}, {1, 3, 1, 1}, {}, {}},
{0.f, 0.f, 0.f}, {2.55f / 1.f, 2.55f / 2.f, 2.55f / 3.f}, {0.f}, {255.f},
ngraph::element::u8
},
{ ngraph::element::f32, {}, {{ 0.01f, 0.01f / 2.f, 0.01f / 3.f, 0.01f, 0.01f / 2.f, 0.01f / 3.f, 0.01f, 0.01f / 2.f, 0.01f / 3.f }} }
}
}
};
const std::vector<ngraph::Shape> shapes = {
{ 1, 3, 9, 9 },
{ 4, 3, 9, 9 }
};
INSTANTIATE_TEST_CASE_P(
LPT,
ConcatWithReshapeAtTheEndTransformation,
::testing::Combine(
::testing::ValuesIn(precisions),
::testing::ValuesIn(updatePrecisions),
::testing::ValuesIn(shapes),
::testing::ValuesIn(testValues)),
ConcatWithReshapeAtTheEndTransformation::getTestCaseName);
} // namespace

View File

@ -0,0 +1,183 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "layer_transformation.hpp"
#include <string>
#include <sstream>
#include <memory>
#include <gtest/gtest.h>
#include <utility>
#include <transformations/utils/utils.hpp>
#include <transformations/init_node_info.hpp>
#include <low_precision/network_helper.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
#include "ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp"
#include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
using namespace testing;
using namespace ngraph::pass;
using namespace ngraph::builder::subgraph;
class MoveDequantizationAfterTransformationParams {
public:
class Actual {
public:
ngraph::builder::subgraph::DequantizationOperations dequantization;
};
class Expected {
public:
ngraph::builder::subgraph::DequantizationOperations dequantizationBefore;
ngraph::element::Type precisionAfterOperation;
ngraph::builder::subgraph::DequantizationOperations dequantizationAfter;
};
ngraph::element::Type originalPrecision;
ngraph::pass::low_precision::LayerTransformation::Params params;
bool updatePrecision;
bool moveSubtract;
Actual actual;
Expected expected;
};
typedef std::tuple<
ngraph::Shape,
MoveDequantizationAfterTransformationParams> MoveDequantizationAfterTransformationTestValues;
class MoveDequantizationAfterWithIntConstantTransformation :
public LayerTransformation,
public testing::WithParamInterface<MoveDequantizationAfterTransformationTestValues> {
public:
void SetUp() override {
const auto inputShape = std::get<0>(GetParam());
const auto testValues = std::get<1>(GetParam());
actualFunction = ngraph::builder::subgraph::MoveDequantizationAfterWithIntConstantFunction::getOriginal(
testValues.originalPrecision,
inputShape,
testValues.actual.dequantization);
const auto targetNode = actualFunction->get_output_op(0)->get_input_node_shared_ptr(0);
const auto dequantization = ngraph::pass::low_precision::NetworkHelper::getDequantization(targetNode);
ngraph::pass::low_precision::NetworkHelper::moveDequantizationAfter(
targetNode,
dequantization,
testValues.updatePrecision,
testValues.moveSubtract);
referenceFunction = ngraph::builder::subgraph::MoveDequantizationAfterWithIntConstantFunction::getReference(
testValues.originalPrecision,
inputShape,
testValues.expected.dequantizationBefore,
testValues.expected.precisionAfterOperation,
testValues.expected.dequantizationAfter);
}
static std::string getTestCaseName(testing::TestParamInfo<MoveDequantizationAfterTransformationTestValues> obj) {
const auto inputShape = std::get<0>(obj.param);
const auto testValues = std::get<1>(obj.param);
std::ostringstream result;
result <<
testValues.originalPrecision << "_" <<
inputShape << "_" <<
testValues.actual.dequantization << "_" <<
(testValues.moveSubtract ? "move_subtract_" : "don't_move_subtract_") <<
(testValues.updatePrecision ? "updatePrecision" : "don't_update_precision");
return result.str();
}
};
TEST_P(MoveDequantizationAfterWithIntConstantTransformation, CompareFunctions) {
actualFunction->validate_nodes_and_infer_types();
auto res = compare_functions(referenceFunction, actualFunction, true, false, true);
ASSERT_TRUE(res.first) << res.second;
}
const std::vector<ngraph::Shape> inputShapes = {
{ 1, 3, 16, 16 },
{ 4, 3, 16, 16 }
};
const std::vector<MoveDequantizationAfterTransformationParams> testValues = {
// I8 & I8: Multiply
{
ngraph::element::i8,
LayerTransformation::createParamsU8I8(),
false,
true,
{
{ {}, {}, { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 } },
},
{
{ {}, {}, {} },
ngraph::element::f32,
{ {}, {}, { 10.f } },
},
},
// I8 & I8: Subtract + Multiply
{
ngraph::element::i8,
LayerTransformation::createParamsU8I8(),
false,
true,
{
{
{},
{ {5.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 },
{ {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::u8 }
},
},
{
{ {}, {}, {} },
ngraph::element::f32,
{ {}, {5.f}, { 10.f } },
},
},
// FP32 & I8: Multiply
{
ngraph::element::u8,
LayerTransformation::createParamsU8I8(),
false,
true,
{
{ {ngraph::element::f32}, {}, { {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 } },
},
{
{ {}, {}, {} },
ngraph::element::f32,
{ {}, {}, { 10.f } },
},
},
// FP32 & I8: Subtract + Multiply
{
ngraph::element::u8,
LayerTransformation::createParamsU8I8(),
false,
true,
{
{
{ngraph::element::f32},
{ {5.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 },
{ {10.f}, ngraph::element::f32, {}, true, 1ul, ngraph::element::i8 }
},
},
{
{ {}, {}, {} },
ngraph::element::f32,
{ {}, {5.f}, { 10.f } },
},
}
};
INSTANTIATE_TEST_CASE_P(
LPT,
MoveDequantizationAfterWithIntConstantTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::ValuesIn(testValues)),
MoveDequantizationAfterWithIntConstantTransformation::getTestCaseName);

View File

@ -34,7 +34,9 @@ public:
const std::vector<float>& values,
const ngraph::element::Type outPrecision,
const ngraph::Shape& constantShape,
const bool addDequantizationAttribute = true);
const bool addDequantizationAttribute = true,
const size_t constantIndex = 1ul,
const ngraph::element::Type constantPrecision = ngraph::element::undefined);
bool empty() const noexcept;
Subtract& setConstantPrecision(const ngraph::element::Type& precision);
@ -43,7 +45,9 @@ public:
ngraph::Shape constantShape;
bool constantShapeIsDefined;
bool addDequantizationAttribute;
size_t constantIndex = 1ul;
ngraph::element::Type constantPrecision = ngraph::element::undefined;
private:
bool isEmpty;
};
@ -59,7 +63,8 @@ public:
const ngraph::element::Type outPrecision,
const ngraph::Shape& constantShape,
const bool addDequantizationAttribute = true,
const size_t constantIndex = 1ul);
const size_t constantIndex = 1ul,
const ngraph::element::Type constantPrecision = ngraph::element::undefined);
bool empty() const noexcept;
Multiply& setConstantPrecision(const ngraph::element::Type& precision);
@ -70,6 +75,7 @@ public:
bool addDequantizationAttribute;
size_t constantIndex = 1ul;
ngraph::element::Type constantPrecision = ngraph::element::undefined;
private:
bool isEmpty;
};

View File

@ -69,6 +69,13 @@ public:
const FakeQuantizeOnData& fqOnData1,
const FakeQuantizeOnData& fqOnData2);
static std::shared_ptr<ngraph::Function> getOriginalWithReshapeAtTheEndTransformation(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const FakeQuantizeOnDataWithConstant& fqOnData1,
const FakeQuantizeOnDataWithConstant& fqOnData2,
const FakeQuantizeOnDataWithConstant& fqOnData3);
static std::shared_ptr<ngraph::Function> getReference(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
@ -138,6 +145,17 @@ public:
const ngraph::element::Type precisionAfterOperation,
const DequantizationOperations& dequantizationAfter,
const ngraph::element::Type precisionAfterDequantization);
static std::shared_ptr<ngraph::Function> getReferenceWithReshapeAtTheEndTransformation(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const FakeQuantizeOnDataWithConstant& fqOnData1,
const FakeQuantizeOnDataWithConstant& fqOnData2,
const FakeQuantizeOnDataWithConstant& fqOnData3,
const DequantizationOperations& dequantizationOperations);
private:
static std::shared_ptr<Node> makeMaxPool(const Output<Node>& parent, const std::vector<size_t>& kernel);
};
} // namespace subgraph

View File

@ -0,0 +1,34 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <ngraph/ngraph.hpp>
#include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
#include "ngraph_functions/subgraph_builders.hpp"
namespace ngraph {
namespace builder {
namespace subgraph {
class MoveDequantizationAfterWithIntConstantFunction {
public:
static std::shared_ptr<ngraph::Function> getOriginal(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::builder::subgraph::DequantizationOperations dequantization);
static std::shared_ptr<ngraph::Function> getReference(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::builder::subgraph::DequantizationOperations dequantizationBefore,
const ngraph::element::Type precisionAfterOperation,
const ngraph::builder::subgraph::DequantizationOperations dequantizationAfter);
};
} // namespace subgraph
} // namespace builder
} // namespace ngraph

View File

@ -51,8 +51,10 @@ std::shared_ptr<Node> makeDequantization(
shape,
dequantizationOperations.subtract.values);
if ((dequantizationOperations.subtract.outPrecision == element::undefined) ||
(dequantizationOperations.subtract.outPrecision == parent.get_element_type())) {
if (((dequantizationOperations.subtract.outPrecision == element::undefined) ||
(dequantizationOperations.subtract.outPrecision == parent.get_element_type())) &&
((dequantizationOperations.subtract.constantPrecision == element::undefined) ||
(dequantizationOperations.subtract.constantPrecision == parent.get_element_type()))) {
subtract = std::make_shared<ngraph::pass::low_precision::DequantizationSubtract>(parent, subtractConst);
} else {
subtract = std::make_shared<op::TypeRelaxed<ngraph::pass::low_precision::DequantizationSubtract>>(
@ -83,10 +85,14 @@ std::shared_ptr<Node> makeDequantization(
}
std::shared_ptr<ngraph::opset1::Multiply> multiply;
if ((dequantizationOperations.multiply.outPrecision == element::undefined) ||
(dequantizationOperations.multiply.outPrecision == parent.get_element_type())) {
if (((dequantizationOperations.multiply.outPrecision == element::undefined) ||
(dequantizationOperations.multiply.outPrecision == parent.get_element_type())) &&
((dequantizationOperations.multiply.constantPrecision == element::undefined) ||
(dequantizationOperations.multiply.constantPrecision == parent.get_element_type()))) {
const std::shared_ptr<ngraph::opset1::Constant> constant = std::make_shared<ngraph::opset1::Constant>(
parent.get_element_type(),
dequantizationOperations.multiply.constantPrecision != element::undefined ?
dequantizationOperations.multiply.constantPrecision :
parent.get_element_type(),
shape,
dequantizationOperations.multiply.values);

View File

@ -59,13 +59,17 @@ DequantizationOperations::Subtract::Subtract(
const std::vector<float>& values,
const ngraph::element::Type outPrecision,
const ngraph::Shape& constantShape,
const bool addDequantizationAttribute) :
const bool addDequantizationAttribute,
const size_t constantIndex,
const ngraph::element::Type constantPrecision) :
isEmpty(false),
values(values),
outPrecision(outPrecision),
constantShape(constantShape),
constantShapeIsDefined(true),
addDequantizationAttribute(addDequantizationAttribute) {
addDequantizationAttribute(addDequantizationAttribute),
constantIndex(constantIndex),
constantPrecision(constantPrecision) {
}
bool DequantizationOperations::Subtract::empty() const noexcept {
@ -109,13 +113,15 @@ DequantizationOperations::Multiply::Multiply(
const ngraph::element::Type outPrecision,
const ngraph::Shape& constantShape,
const bool addDequantizationAttribute,
const size_t constantIndex) :
const size_t constantIndex,
ngraph::element::Type constantPrecision) :
isEmpty(false),
values(values),
outPrecision(outPrecision),
constantShape(constantShape),
addDequantizationAttribute(addDequantizationAttribute),
constantIndex(constantIndex),
constantPrecision(constantPrecision),
constantShapeIsDefined(true) {
}

View File

@ -153,23 +153,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediate(
const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
std::shared_ptr<ngraph::op::Op> intermediateOp;
std::shared_ptr<Node> intermediateOp;
if (transparentIntermediate) {
intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize2->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
} else {
auto weights = ngraph::opset1::Constant::create(
precision,
@ -307,23 +293,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalSelectionWithInterm
const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
std::shared_ptr<ngraph::op::Op> intermediateOp;
std::shared_ptr<Node> intermediateOp;
if (transparentIntermediate) {
intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize2->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
} else {
auto weights = ngraph::opset1::Constant::create(
precision,
@ -451,21 +423,7 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediateWit
std::shared_ptr<ngraph::op::Op> intermediateOp;
if (transparentIntermediate) {
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize1->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
const auto pooling = makeMaxPool(fakeQuantize1->output(0), { 3, 3 });
ngraph::op::v0::InterpolateAttrs attributes;
attributes.axes = ngraph::AxisSet{ 2, 3 };
@ -502,6 +460,55 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediateWit
return function;
}
std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithReshapeAtTheEndTransformation(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const FakeQuantizeOnDataWithConstant& fqOnData1,
const FakeQuantizeOnDataWithConstant& fqOnData2,
const FakeQuantizeOnDataWithConstant& fqOnData3) {
const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input1->set_friendly_name("input1");
const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
fakeQuantize1->set_friendly_name("fakeQuantize1");
const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input2->set_friendly_name("input2");
const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::shared_ptr<ngraph::opset1::Concat> concat1 = std::make_shared<ngraph::opset1::Concat>(
ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
concat1->set_friendly_name("concat1");
const std::shared_ptr<Node> intermediate = makeMaxPool(concat1->output(0), {1ul, 1ul});
const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input3->set_friendly_name("input3");
const auto fakeQuantize3 = makeFakeQuantizeTypeRelaxed(input3, precision, fqOnData3);
fakeQuantize3->set_friendly_name("fakeQuantize3");
const std::shared_ptr<ngraph::opset1::Concat> concat2 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{ fakeQuantize3, intermediate }, 1);
concat2->set_friendly_name("concat2");
const Shape concat2Shape = concat2->output(0).get_shape();
const std::shared_ptr<Node> maxPool = makeMaxPool(concat2->output(0), {concat2Shape[2], concat2Shape[3]});
const std::shared_ptr<Node> reshape = std::make_shared<ngraph::opset1::Reshape>(
maxPool,
std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{2ul}, std::vector<size_t>{0, 0}),
true);
reshape->set_friendly_name("output");
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(reshape)};
std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
results,
ngraph::ParameterVector{ input1, input2, input3 },
"OriginalWithReshapeAtTheEndTransformation");
return function;
}
std::shared_ptr<ngraph::Function> ConcatFunction::getReference(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
@ -706,23 +713,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediate(
const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
std::shared_ptr<Node> intermediateOp;
if (transparentIntermediate) {
intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize2->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
} else {
auto weights = ngraph::opset1::Constant::create(
precision,
@ -926,23 +919,9 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceSelectionWithInter
const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
std::shared_ptr<ngraph::op::Op> intermediateOp;
std::shared_ptr<Node> intermediateOp;
if (transparentIntermediate) {
intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize2->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
intermediateOp = makeMaxPool(fakeQuantize2->output(0), { 3, 3 });
} else {
auto weights = ngraph::opset1::Constant::create(
precision,
@ -1135,21 +1114,7 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediateWi
if (transparentIntermediate) {
const auto deqBefore = makeDequantization(fakeQuantize1->output(0), dequantizationBefore);
const std::vector<size_t> kernel = { 3, 3 };
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
fakeQuantize1->output(0),
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
const auto pooling = makeMaxPool(fakeQuantize1->output(0), { 3, 3 });
ngraph::op::v0::InterpolateAttrs attributes;
attributes.axes = ngraph::AxisSet{ 2, 3 };
@ -1192,6 +1157,75 @@ std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediateWi
return function;
}
std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithReshapeAtTheEndTransformation(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const FakeQuantizeOnDataWithConstant& fqOnData1,
const FakeQuantizeOnDataWithConstant& fqOnData2,
const FakeQuantizeOnDataWithConstant& fqOnData3,
const DequantizationOperations& dequantizationOperations) {
const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input1->set_friendly_name("input1");
const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
fakeQuantize1->set_friendly_name("fakeQuantize1");
const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input2->set_friendly_name("input2");
const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
fakeQuantize2->set_friendly_name("fakeQuantize2");
const std::shared_ptr<ngraph::opset1::Concat> concat1 = std::make_shared<ngraph::opset1::Concat>(
ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
concat1->set_friendly_name("concat1");
std::shared_ptr<Node> intermediate = makeMaxPool(concat1->output(0), {1ul, 1ul});
const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
input3->set_friendly_name("input3");
const auto fakeQuantize3 = makeFakeQuantizeTypeRelaxed(input3, precision, fqOnData3);
fakeQuantize3->set_friendly_name("fakeQuantize3");
const std::shared_ptr<ngraph::opset1::Concat> concat2 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{ fakeQuantize3, intermediate }, 1);
concat2->set_friendly_name("concat2");
const Shape concat2Shape = concat2->output(0).get_shape();
const std::shared_ptr<Node> maxPool = makeMaxPool(concat2->output(0), {concat2Shape[2], concat2Shape[3]});
const std::shared_ptr<Node> reshape = std::make_shared<ngraph::opset1::Reshape>(
maxPool,
std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{2ul}, std::vector<size_t>{0, 0}),
true);
reshape->set_friendly_name("output_original");
const auto dequantization = makeDequantization(reshape->output(0), dequantizationOperations);
dequantization->set_friendly_name("output");
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(dequantization)};
std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
results,
ngraph::ParameterVector{ input1, input2, input3 },
"ReferenceWithReshapeAtTheEndTransformation");
return function;
}
std::shared_ptr<Node> ConcatFunction::makeMaxPool(const Output<Node>& parent, const std::vector<size_t>& kernel) {
const std::vector<size_t> stride = { 1, 1 };
const std::vector<size_t> padBegin = { 0, 0 };
const std::vector<size_t> padEnd = { 0, 0 };
const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
parent,
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType);
return pooling;
}
} // namespace subgraph
} // namespace builder
} // namespace ngraph

View File

@ -0,0 +1,79 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph_functions/low_precision_transformations/move_dequantization_after_with_int_constant_function.hpp"
#include "low_precision/network_helper.hpp"
#include <ngraph/opsets/opset1.hpp>
#include "ngraph_functions/subgraph_builders.hpp"
#include "ngraph_functions/low_precision_transformations/common/builders.hpp"
using namespace ngraph::pass::low_precision;
namespace ngraph {
namespace builder {
namespace subgraph {
std::shared_ptr<ngraph::Function> MoveDequantizationAfterWithIntConstantFunction::getOriginal(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::builder::subgraph::DequantizationOperations dequantization) {
const auto input = std::make_shared<ngraph::op::v0::Parameter>(precision, inputShape);
const auto deq = makeDequantization(input, dequantization);
const auto avgPool = std::make_shared<op::TypeRelaxed<opset1::AvgPool>>(
ngraph::opset1::AvgPool(
deq,
Strides{ 1, 1 },
Shape{ 1, 1 },
Shape{ 0, 0 },
Shape{ 2, 2 },
true,
op::RoundingType::FLOOR),
std::vector<element::Type>{ element::f32, element::f32 },
std::vector<element::Type>{});
auto& rtInfo = avgPool->get_rt_info();
rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("targetOp");
return std::make_shared<ngraph::Function>(
ngraph::ResultVector{ std::make_shared<ngraph::opset1::Result>(avgPool) },
ngraph::ParameterVector{ input },
"MoveDequantizationAfterFunction");
}
std::shared_ptr<ngraph::Function> MoveDequantizationAfterWithIntConstantFunction::getReference(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::builder::subgraph::DequantizationOperations dequantizationBefore,
const ngraph::element::Type precisionAfterOperation,
const ngraph::builder::subgraph::DequantizationOperations dequantizationAfter) {
const auto input = std::make_shared<ngraph::op::v0::Parameter>(precision, inputShape);
const auto deqBefore = makeDequantization(input, dequantizationBefore);
const auto targetOp = std::make_shared<op::TypeRelaxed<opset1::AvgPool>>(
ngraph::opset1::AvgPool(
deqBefore,
Strides{ 1, 1 },
Shape{ 1, 1 },
Shape{ 0, 0 },
Shape{ 2, 2 },
true,
op::RoundingType::FLOOR),
std::vector<element::Type>{ element::f32, element::f32 },
std::vector<element::Type>{});
ngraph::pass::low_precision::NetworkHelper::setOutDataPrecisionForTypeRelaxed(targetOp, precisionAfterOperation);
auto& rtInfo = targetOp->get_rt_info();
rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("targetOp");
const auto deqAfter = makeDequantization(targetOp, dequantizationAfter);
return std::make_shared<ngraph::Function>(
ngraph::ResultVector{ std::make_shared<ngraph::opset1::Result>(deqAfter) },
ngraph::ParameterVector{ input },
"MoveDequantizationAfterFunction");
}
} // namespace subgraph
} // namespace builder
} // namespace ngraph