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);
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);
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);
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;
}
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) {
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) {
//
} // namespace low_precision
} // namespace pass
-} // namespace ngraph
\ No newline at end of file
+} // namespace ngraph
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,
--- /dev/null
+// 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
--- /dev/null
+// 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);
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);
ngraph::Shape constantShape;
bool constantShapeIsDefined;
bool addDequantizationAttribute;
+ size_t constantIndex = 1ul;
ngraph::element::Type constantPrecision = ngraph::element::undefined;
+
private:
bool isEmpty;
};
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);
bool addDequantizationAttribute;
size_t constantIndex = 1ul;
ngraph::element::Type constantPrecision = ngraph::element::undefined;
+
private:
bool isEmpty;
};
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,
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
--- /dev/null
+// 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
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>>(
}
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);
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 {
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) {
}
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,
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,
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 };
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,
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,
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,
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 };
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
--- /dev/null
+// 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