diff --git a/inference-engine/src/transformations/include/transformations/convert_opset1_to_legacy/convert_mul_or_add_finally.hpp b/inference-engine/src/transformations/include/transformations/convert_opset1_to_legacy/convert_mul_or_add_finally.hpp index d4ff43c469d1f9..9f213d4110b6a6 100755 --- a/inference-engine/src/transformations/include/transformations/convert_opset1_to_legacy/convert_mul_or_add_finally.hpp +++ b/inference-engine/src/transformations/include/transformations/convert_opset1_to_legacy/convert_mul_or_add_finally.hpp @@ -153,14 +153,14 @@ ngraph::graph_rewrite_callback get_callback() { auto res = check_constant(const_node, data_node.get_partial_shape()); - if (res == CONVERSION_RESULT::NONE || (res == CONVERSION_RESULT::SCALE_SHIFT && output_shape_rank < 4)) { + bool is_dequantization = lin_op->get_rt_info().count("DEQUANTIZATION") != 0; + + if (!is_dequantization && (res == CONVERSION_RESULT::NONE || (res == CONVERSION_RESULT::SCALE_SHIFT && output_shape_rank < 4))) { return convert_to_eltwise(lin_op, lin_op->input(0).get_source_output(), lin_op->input(1).get_source_output()); } - bool is_dequantization = lin_op->get_rt_info().count("DEQUANTIZATION") != 0; - // TODO: if all values in Constant are equal the best way is to convert this Eltwise to Power if (res == CONVERSION_RESULT::SCALE_SHIFT || is_dequantization) { auto weights_et = const_node->get_element_type(); diff --git a/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/convert_mul_add_to_scaleshift_or_power.cpp b/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/convert_mul_add_to_scaleshift_or_power.cpp index 9f649ecbb6430d..39cecb1f1b778e 100644 --- a/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/convert_mul_add_to_scaleshift_or_power.cpp +++ b/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/convert_mul_add_to_scaleshift_or_power.cpp @@ -137,15 +137,14 @@ void ngraph::pass::ConvertMulAddToScaleShiftOrPower::convert_mul_add_to_scaleshi const auto output_shape = add_node->get_output_partial_shape(0); const auto output_shape_rank = output_shape.rank().get_length(); + bool is_dequantization = + (add_node->get_rt_info().count("DEQUANTIZATION") != 0 || mul_node->get_rt_info().count("DEQUANTIZATION") != 0); + if (res1 == CONVERSION_RESULT::NONE || res2 == CONVERSION_RESULT::NONE || - ((res1 == CONVERSION_RESULT::SCALE_SHIFT || res2 == CONVERSION_RESULT::SCALE_SHIFT) && - (output_shape_rank == 1 || output_shape_rank > 4))) { + ((res1 == CONVERSION_RESULT::SCALE_SHIFT || res2 == CONVERSION_RESULT::SCALE_SHIFT) && !is_dequantization && output_shape_rank < 4)) { return false; } - bool is_dequantization = - (add_node->get_rt_info().count("DEQUANTIZATION") != 0 || mul_node->get_rt_info().count("DEQUANTIZATION") != 0); - // TODO: in case if scale and shift constants has equal values the best way is to convert them to Power if (res1 == CONVERSION_RESULT::SCALE_SHIFT || res2 == CONVERSION_RESULT::SCALE_SHIFT || is_dequantization) { NodeVector new_ops; @@ -176,7 +175,7 @@ void ngraph::pass::ConvertMulAddToScaleShiftOrPower::convert_mul_add_to_scaleshi new_ops.push_back(biases_in); } - auto scaleshift = std::make_shared(data_node, weights_in, biases_in); + auto scaleshift = std::make_shared(data_node, weights_in, biases_in, weights_in->get_element_type()); new_ops.push_back(scaleshift); scaleshift->set_friendly_name(add_node->get_friendly_name()); diff --git a/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/reshape_fully_connected.cpp b/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/reshape_fully_connected.cpp index 0cc2be96e2d304..11430431f43ec4 100644 --- a/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/reshape_fully_connected.cpp +++ b/inference-engine/src/transformations/src/transformations/convert_opset1_to_legacy/reshape_fully_connected.cpp @@ -52,7 +52,8 @@ ngraph::pass::ReshapeFullyConnected::ReshapeFullyConnected() { auto fc_new = std::make_shared(reshape, fc->input_value(1), fc->input_value(2), - output_shape_new); + output_shape_new, + fc->get_output_type()); new_ops.push_back(fc_new); if (output_shape != output_shape_new) { @@ -73,4 +74,4 @@ ngraph::pass::ReshapeFullyConnected::ReshapeFullyConnected() { auto m = std::make_shared(fc, "ReshapeFullyConnected"); this->register_matcher(m, callback); -} \ No newline at end of file +} diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/convert_mul_or_add_finally_transformation_with_dequantization.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/convert_mul_or_add_finally_transformation_with_dequantization.cpp new file mode 100644 index 00000000000000..e2f96b75975771 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/convert_mul_or_add_finally_transformation_with_dequantization.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "layer_transformation.hpp" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +#include "ngraph_functions/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.hpp" + +using namespace testing; +using namespace ngraph::pass; + +namespace { + +inline std::ostream& operator<<(std::ostream& os, const std::vector& values) { + os << "{ "; + for (size_t i = 0; i < values.size(); ++i) { + os << values[i]; + if (i != (values.size() - 1ul)) { + os << ", "; + } + } + os << " }"; + return os; +} + +class ConvertMulOrAddFinallyTransformationWithDequantizationTestValues { +public: + std::vector multiplyConstValues; + ngraph::Shape inputShape; + ngraph::element::Type inputPrecision; + ngraph::pass::low_precision::LayerTransformation::Params params; +}; + +using TestValuesType = ConvertMulOrAddFinallyTransformationWithDequantizationTestValues; + +class ConvertMulOrAddFinallyTransformationWithDequantization : public LayerTransformation, public testing::WithParamInterface { +public: + void SetUp() override { + using namespace ngraph::builder::subgraph; + const ConvertMulOrAddFinallyTransformationWithDequantizationTestValues testValues = GetParam(); + + actualFunction = ConvertMulOrAddWithDequantizationFunction::getOriginal(testValues.inputShape, + testValues.inputPrecision, + testValues.multiplyConstValues); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + + manager.run_passes(actualFunction); + + referenceFunction = ConvertMulOrAddWithDequantizationFunction::getReference(testValues.inputShape, + testValues.inputPrecision, + testValues.multiplyConstValues); + } + + static std::string getTestCaseName(testing::TestParamInfo obj) { + const ConvertMulOrAddFinallyTransformationWithDequantizationTestValues testValues = obj.param; + std::ostringstream result; + result << LayerTransformation::getTestCaseNameByParams(testValues.inputPrecision, testValues.inputShape, testValues.params) << "_" << + testValues.multiplyConstValues; + return result.str(); + } +}; + +TEST_P(ConvertMulOrAddFinallyTransformationWithDequantization, CompareFunctions) { + actualFunction->validate_nodes_and_infer_types(); + auto res = compare_functions(referenceFunction, actualFunction, true, true, true); + ASSERT_TRUE(res.first) << res.second; +} + +std::vector testValues = { + { + { -1.0 }, + { 1, 1000 }, + ngraph::element::f32, + LayerTransformation::createParamsU8I8() + }, + { + { 128.0 }, + { 1, 10 }, + ngraph::element::f32, + LayerTransformation::createParamsU8I8() + }, + { + { -64.5 }, + { 1, 10 }, + ngraph::element::i8, + LayerTransformation::createParamsU8I8() + }, + { + { 1.2 }, + { 1, 100 }, + ngraph::element::u8, + LayerTransformation::createParamsI8I8() + } +}; + +INSTANTIATE_TEST_CASE_P( + LPT, + ConvertMulOrAddFinallyTransformationWithDequantization, + ::testing::ValuesIn(testValues), + ConvertMulOrAddFinallyTransformationWithDequantization::getTestCaseName); +} // namespace \ No newline at end of file diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.hpp new file mode 100644 index 00000000000000..b5a191a8a9d7fd --- /dev/null +++ b/inference-engine/tests/ngraph_functions/include/ngraph_functions/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_data.hpp" +#include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +class ConvertMulOrAddWithDequantizationFunction { +public: + static std::shared_ptr getOriginal( + const ngraph::Shape& inputShape, + const ngraph::element::Type inputPrecision, + const std::vector& multiplyConst); + + static std::shared_ptr getReference( + const ngraph::Shape& inputShape, + const ngraph::element::Type inputPrecision, + const std::vector& multiplyConst); +}; +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/inference-engine/tests/ngraph_functions/src/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.cpp b/inference-engine/tests/ngraph_functions/src/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.cpp new file mode 100644 index 00000000000000..4402518bbd317d --- /dev/null +++ b/inference-engine/tests/ngraph_functions/src/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph_functions/low_precision_transformations/convert_mul_or_add_finally_with_dequantization_function.hpp" + +#include +#include +#include + + +#include +#include +#include "ngraph_functions/subgraph_builders.hpp" +#include "ngraph_functions/low_precision_transformations/common/builders.hpp" +#include "transformations/low_precision/network_helper.hpp" +#include "ngraph_ops/scaleshift.hpp" +#include "transformations/low_precision/common/dequantization_op.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +using namespace ngraph::pass; + +std::shared_ptr ConvertMulOrAddWithDequantizationFunction::getOriginal( + const ngraph::Shape& inputShape, + const ngraph::element::Type inputPrecision, + const std::vector& multiplyConst) { + const auto input = std::make_shared(inputPrecision, inputShape); + const auto reluOriginal = ngraph::opset1::Relu( + ngraph::op::TemporaryReplaceOutputType(input, element::f32).get()); + + std::shared_ptr relu = std::make_shared>( + reluOriginal, + std::vector{ element::f32, element::f32 }, + std::vector{}); + + + const auto multiply = std::make_shared(relu, + std::make_shared(element::f32, inputShape, multiplyConst)); + + multiply->set_friendly_name("output"); + + ngraph::ResultVector results{ std::make_shared(multiply) }; + return std::make_shared(results, ngraph::ParameterVector{ input }, + "ConvertMulOrAddTransformationWithDequantization"); +} + +std::shared_ptr ConvertMulOrAddWithDequantizationFunction::getReference( + const ngraph::Shape& inputShape, + const ngraph::element::Type inputPrecision, + const std::vector& multiplyConst) { + const auto input = std::make_shared(inputPrecision, inputShape); + const auto reluOriginal = ngraph::opset1::Relu( + ngraph::op::TemporaryReplaceOutputType(input, element::f32).get()); + + std::shared_ptr relu = std::make_shared>( + reluOriginal, + std::vector{ element::f32, element::f32 }, + std::vector{}); + + const auto weights = std::make_shared(element::f32, inputShape, multiplyConst); + const auto bias = std::make_shared(element::f32, inputShape, 0.0); + const auto scaleShift = std::make_shared(relu, weights, bias); + + scaleShift->set_friendly_name("output"); + + ngraph::ResultVector results{ std::make_shared(scaleShift) }; + return std::make_shared(results, ngraph::ParameterVector{ input }, "ConvertMulOrAddTransformationWithDequantization"); +} + +} // namespace subgraph +} // namespace builder +} // namespace ngraph