} else if (eltwiseLayer->_operation == EltwiseLayer::eOperation::Prod) {
for (size_t i = 0ul; i < emptyPathDequantizationScales.size(); ++i) {
fullPathDequantizationScales[i] = fullPathDequantizationScales[i] * emptyPathDequantizationScales[i];
+ fullPathDequantizationShifts[i] = fullPathDequantizationShifts[i] * emptyPathDequantizationScales[i];
}
CNNNetworkHelper::updateBlobs(*fullPathDequantizationLayer, "weights", fullPathDequantizationScales);
+ CNNNetworkHelper::updateBlobs(*fullPathDequantizationLayer, "biases", fullPathDequantizationShifts);
} else {
THROW_IE_EXCEPTION << "unexpected operation '" << eltwiseLayer->_operation << "'";
}
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "low_precision_transformations/multiply_transformation.hpp"
+#include "common_test_utils/test_constants.hpp"
+
+using namespace LayerTestsDefinitions;
+
+namespace {
+const std::vector<InferenceEngine::Precision> netPrecisions = {
+ InferenceEngine::Precision::FP32,
+ InferenceEngine::Precision::FP16
+};
+
+const std::vector<LayerTestsDefinitions::MultiplyTestValues> params = {
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } },
+ false,
+ {InferenceEngine::Precision::I8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::I8}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ false,
+ {InferenceEngine::Precision::I8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::FP32}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -128.f }, { 127.f } },
+ true,
+ {InferenceEngine::Precision::I8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::FP32}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ true,
+ {InferenceEngine::Precision::I8}, {InferenceEngine::Precision::I8, InferenceEngine::Precision::FP32}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } },
+ false,
+ {InferenceEngine::Precision::U8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::FP32}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ false,
+ {InferenceEngine::Precision::U8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::U8}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { -127.f }, { 128.f } },
+ true,
+ {InferenceEngine::Precision::U8}, {InferenceEngine::Precision::U8, InferenceEngine::Precision::FP32}
+ },
+ {
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { -128.f }, { 127.f }, { -128.f }, { 127.f } },
+ { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 255.f } },
+ true,
+ {InferenceEngine::Precision::U8}, {InferenceEngine::Precision::FP32, InferenceEngine::Precision::FP32}
+ },
+ { {}, {}, false }, { {}, {}, true },
+};
+
+INSTANTIATE_TEST_CASE_P(LPT, MultiplyTransformation,
+ ::testing::Combine(
+ ::testing::ValuesIn(netPrecisions),
+ ::testing::Values(InferenceEngine::SizeVector({ 1, 3, 16, 16 })),
+ ::testing::Values(CommonTestUtils::DEVICE_CPU),
+ ::testing::ValuesIn(params)),
+ MultiplyTransformation::getTestCaseName);
+} // namespace
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <string>
+#include <memory>
+
+#include "functional_test_utils/low_precision_transformations/layer_transformation.hpp"
+#include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_data.hpp"
+
+namespace LayerTestsDefinitions {
+
+class MultiplyTestValues {
+public:
+ ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantize1;
+ ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantize2;
+ bool broadcast;
+ std::vector<InferenceEngine::Precision> precisionOnActivations;
+ std::vector<InferenceEngine::Precision> expectedPrecisions;
+};
+
+typedef std::tuple<
+ InferenceEngine::Precision,
+ InferenceEngine::SizeVector,
+ std::string,
+ MultiplyTestValues
+> MultiplyTransformationParams;
+
+class MultiplyTransformation :
+ public testing::WithParamInterface<MultiplyTransformationParams>,
+ public LayerTestsUtils::LayerTransformation {
+public:
+ static std::string getTestCaseName(testing::TestParamInfo<MultiplyTransformationParams> obj);
+
+protected:
+ void SetUp() override;
+
+private:
+ void validate();
+};
+
+} // namespace LayerTestsDefinitions
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "low_precision_transformations/multiply_transformation.hpp"
+
+#include <memory>
+#include <tuple>
+#include <vector>
+#include <string>
+
+#include <ie_core.hpp>
+
+#include "common_test_utils/common_utils.hpp"
+#include "functional_test_utils/plugin_cache.hpp"
+#include "functional_test_utils/layer_test_utils.hpp"
+#include "functional_test_utils/blob_utils.hpp"
+#include "ngraph_functions/pass/convert_prc.hpp"
+#include "ngraph_functions/low_precision_transformations/multiply_function.hpp"
+
+namespace LayerTestsDefinitions {
+
+std::string MultiplyTransformation::getTestCaseName(testing::TestParamInfo<MultiplyTransformationParams> obj) {
+ InferenceEngine::Precision netPrecision;
+ InferenceEngine::SizeVector inputShape;
+ std::string targetDevice;
+ InferenceEngine::details::LayerTransformation::Params params;
+ MultiplyTestValues param;
+
+ std::tie(netPrecision, inputShape, targetDevice, param) = obj.param;
+
+ std::ostringstream result;
+ result << netPrecision.name() << "_" <<
+ CommonTestUtils::vec2str(inputShape) << "_" <<
+ targetDevice << "_" <<
+ param.precisionOnActivations <<
+ (param.broadcast ? "_broadcast" : "");
+ if (!param.fakeQuantize1.empty()) {
+ result << "_on_branch1_" <<
+ param.fakeQuantize1.inputLowValues[0] << "_" <<
+ param.fakeQuantize1.inputHighValues[0] << "_" <<
+ param.fakeQuantize1.outputLowValues[0] << "_" <<
+ param.fakeQuantize1.outputHighValues[0];
+ }
+ if (!param.fakeQuantize2.empty()) {
+ result << "_on_branch2_" <<
+ param.fakeQuantize2.inputLowValues[0] << "_" <<
+ param.fakeQuantize2.inputHighValues[0] << "_" <<
+ param.fakeQuantize2.outputLowValues[0] << "_" <<
+ param.fakeQuantize2.outputHighValues[0];
+ }
+ return result.str();
+}
+
+void MultiplyTransformation::SetUp() {
+ threshold = 0.01f;
+
+ InferenceEngine::Precision netPrecision;
+ InferenceEngine::SizeVector inputShape1;
+ InferenceEngine::details::LayerTransformation::Params params;
+ MultiplyTestValues param;
+ std::tie(netPrecision, inputShape1, targetDevice, param) = this->GetParam();
+ auto precision = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+
+ InferenceEngine::SizeVector inputShape2 = inputShape1;
+
+ if (param.broadcast) {
+ inputShape2[2] = 1;
+ inputShape2[3] = 1;
+ }
+
+ function = ngraph::builder::subgraph::MultiplyFunction::getOriginal(
+ precision,
+ inputShape1,
+ inputShape2,
+ param.fakeQuantize1,
+ param.fakeQuantize2);
+
+ validate();
+}
+
+void MultiplyTransformation::validate() {
+ InferenceEngine::Precision netPrecision;
+ InferenceEngine::SizeVector inputShape;
+ std::string targetDevice;
+ InferenceEngine::details::LayerTransformation::Params params = LayerTestsUtils::LayerTransformationParamsFactory::createParams();
+ MultiplyTestValues param;
+ std::tie(netPrecision, inputShape, targetDevice, param) = this->GetParam();
+
+ params.precisionsOnActivations = param.precisionOnActivations;
+
+ const InferenceEngine::CNNNetwork network = transform(params);
+
+ IE_SUPPRESS_DEPRECATED_START
+
+ InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();
+ EXPECT_EQ(1, outputs.size());
+
+ std::map<std::string, InferenceEngine::DataPtr>::iterator it = outputs.begin();
+ const InferenceEngine::CNNLayerPtr outputLayer = getCreatorLayer(it->second).lock();
+ EXPECT_TRUE(outputLayer != nullptr);
+ EXPECT_EQ("Eltwise", outputLayer->type);
+
+ if (!((param.fakeQuantize1.empty()) || (param.fakeQuantize2.empty())) && params.updatePrecisions) {
+ const InferenceEngine::Precision precision1 =
+ InferenceEngine::details::CNNNetworkHelper::getParents(*outputLayer)[0]->outData[0]->getPrecision();
+ const InferenceEngine::Precision precision2 =
+ InferenceEngine::details::CNNNetworkHelper::getParents(*outputLayer)[1]->outData[0]->getPrecision();
+
+ EXPECT_EQ(precision1, param.expectedPrecisions[0]);
+ EXPECT_EQ(precision2, param.expectedPrecisions[1]);
+ }
+
+ IE_SUPPRESS_DEPRECATED_END
+}
+
+TEST_P(MultiplyTransformation, CompareWithRefImpl) {
+ Run();
+};
+
+} // namespace LayerTestsDefinitions
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <algorithm>
+#include <memory>
+#include <ngraph/ngraph.hpp>
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+class FakeQuantizeOnData {
+public:
+ FakeQuantizeOnData();
+
+ FakeQuantizeOnData(
+ const size_t quantizationLevel,
+ const ngraph::Shape& constantShape,
+ const std::vector<float>& inputLowValues,
+ const std::vector<float>& inputHighValues,
+ const std::vector<float>& outputLowValues,
+ const std::vector<float>& outputHighValues);
+
+ virtual ~FakeQuantizeOnData();
+
+ bool isSigned() const;
+ virtual bool empty() const;
+
+ size_t quantizationLevel;
+ ngraph::Shape constantShape;
+ std::vector<float> inputLowValues;
+ std::vector<float> inputHighValues;
+ std::vector<float> outputLowValues;
+ std::vector<float> outputHighValues;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const std::vector<float>& values) {
+ os << "{ ";
+ for (size_t i = 0; i < values.size(); ++i) {
+ os << values[i];
+ if (i != (values.size() - 1ul)) {
+ os << ", ";
+ }
+ }
+ os << " }";
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const FakeQuantizeOnData& data) {
+ return out << "_" << data.constantShape << "_" << data.outputLowValues << "_" << data.outputHighValues;
+}
+
+} // namespace subgraph
+} // namespace builder
+} // namespace ngraph
--- /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/fake_quantize_on_data.hpp"
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+class MultiplyFunction {
+public:
+ static std::shared_ptr<ngraph::Function> getOriginal(
+ const ngraph::element::Type precision,
+ const ngraph::Shape& inputShape1,
+ const ngraph::Shape& inputShape2,
+ const FakeQuantizeOnData& fakeQuantize1,
+ const FakeQuantizeOnData& fakeQuantize2);
+};
+
+} // 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/common/fake_quantize_on_data.hpp"
+#include <ngraph/opsets/opset1.hpp>
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+FakeQuantizeOnData::FakeQuantizeOnData() {
+ quantizationLevel = 0ul;
+}
+
+FakeQuantizeOnData::FakeQuantizeOnData(
+ const size_t quantizationLevel,
+ const ngraph::Shape& constantShape,
+ const std::vector<float>& inputLowValues,
+ const std::vector<float>& inputHighValues,
+ const std::vector<float>& outputLowValues,
+ const std::vector<float>& outputHighValues) :
+ quantizationLevel(quantizationLevel),
+ constantShape(constantShape),
+ inputLowValues(inputLowValues),
+ inputHighValues(inputHighValues),
+ outputLowValues(outputLowValues),
+ outputHighValues(outputHighValues)
+{}
+
+FakeQuantizeOnData::~FakeQuantizeOnData() {}
+
+bool FakeQuantizeOnData::isSigned() const {
+ return std::any_of(outputLowValues.begin(), outputLowValues.end(), [](const float value) { return value < 0.f; }) ||
+ std::any_of(outputHighValues.begin(), outputHighValues.end(), [](const float value) { return value < 0.f; });
+}
+
+bool FakeQuantizeOnData::empty() const {
+ return (quantizationLevel == 0ul) &&
+ constantShape.empty() &&
+ inputLowValues.empty() &&
+ inputHighValues.empty() &&
+ outputLowValues.empty() &&
+ outputHighValues.empty();
+}
+
+} // 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/multiply_function.hpp"
+
+#include <ngraph/opsets/opset1.hpp>
+#include "ngraph_functions/builders.hpp"
+
+namespace ngraph {
+namespace builder {
+namespace subgraph {
+
+std::shared_ptr<ngraph::Function> MultiplyFunction::getOriginal(
+ const ngraph::element::Type precision,
+ const ngraph::Shape& inputShape1,
+ const ngraph::Shape& inputShape2,
+ const FakeQuantizeOnData& fq1,
+ const FakeQuantizeOnData& fq2) {
+ const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
+ const auto fakeQuantize1 = fq1.empty() ?
+ nullptr :
+ ngraph::builder::makeFakeQuantize(
+ input1, precision, fq1.quantizationLevel, fq1.constantShape,
+ fq1.inputLowValues, fq1.inputHighValues, fq1.outputLowValues, fq1.outputHighValues);
+
+ const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
+ const auto fakeQuantize2 = fq2.empty() ?
+ nullptr :
+ ngraph::builder::makeFakeQuantize(
+ input2, precision, fq2.quantizationLevel, fq2.constantShape,
+ fq2.inputLowValues, fq2.inputHighValues, fq2.outputLowValues, fq2.outputHighValues);
+
+ const auto multiply = std::make_shared<ngraph::opset1::Multiply>(
+ fq1.empty() ? input1 : fakeQuantize1,
+ fq2.empty() ? input2 : fakeQuantize2);
+
+ ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(multiply) };
+ return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input1, input2 }, "MultiplyTransformation");
+}
+
+} // namespace subgraph
+} // namespace builder
+} // namespace ngraph