diff --git a/inference-engine/src/cldnn_engine/cldnn_engine.cpp b/inference-engine/src/cldnn_engine/cldnn_engine.cpp index 0bea81eface..4aa53beb1e5 100644 --- a/inference-engine/src/cldnn_engine/cldnn_engine.cpp +++ b/inference-engine/src/cldnn_engine/cldnn_engine.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -381,6 +382,9 @@ InferenceEngine::CNNNetwork clDNNEngine::CloneAndTransformNetwork(const Inferenc .add(LayerTransformation::Params(params) .setSupportAsymmetricQuantization(false) .setSupport3DTensorOnActivations(false)) + .add(LayerTransformation::Params(params) + .setSupportAsymmetricQuantization(false) + .setDeconvolutionSpecificChannelsRatio(true)) // INT8 StridedSlice not supported .remove()); diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/convolution_backprop_data.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/convolution_backprop_data.hpp new file mode 100644 index 00000000000..d6bbe504dc6 --- /dev/null +++ b/inference-engine/src/low_precision_transformations/include/low_precision/convolution_backprop_data.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include "weightable_layer_transformation.hpp" + +namespace ngraph { +namespace pass { +namespace low_precision { + +class TRANSFORMATIONS_API ConvolutionBackpropDataTransformation : public WeightableLayerTransformation { +public: + ConvolutionBackpropDataTransformation(const Params& params); + void registerMatcherIn(GraphRewrite& pass, TransformationContext& context) const override; + bool transform(TransformationContext& context, ngraph::pattern::Matcher &m) const override; + bool canBeTransformed(const TransformationContext& context, std::shared_ptr op) const override; + bool isQuantized(std::shared_ptr layer) const noexcept override; +}; + +} // namespace low_precision +} // namespace pass +} // namespace ngraph diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp index 36b1293cd42..06a37ab8b22 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp @@ -45,6 +45,13 @@ class TRANSFORMATIONS_API DataPrecision { public: DataPrecision() : precision(element::undefined), min(0.f), max(0.f), hasZeroPoint(false) {} + explicit DataPrecision(const element::Type& precision) { + this->precision = precision; + min = getMinValue(precision, 256); + max = getMaxValue(precision, 256); + hasZeroPoint = false; + } + DataPrecision(const element::Type precision, const float min, const float max, const bool hasZeroPoint) : precision(precision), min(min), @@ -122,29 +129,6 @@ public: static element::Type getPrecision(const size_t /* quantizationLevels */, const bool signedInterval) { return signedInterval ? element::i8 : element::u8; } - - static float getMin(const size_t quantizationLevels, const bool signedInterval) { - if (quantizationLevels == 255) { - return signedInterval ? -127.0f : 0.0f; - } else if (quantizationLevels == 256) { - return signedInterval ? -128.0f : 0.0f; - } else { - // THROW_TRANSFORMATION_EXCEPTION << "quantization level " << quantizationLevels << " is not supported"; - // FIXME: not completed - return signedInterval ? -128.0f : 0.0f; - } - } - - static float getMax(const size_t quantizationLevels, const bool signedInterval) { - if ((quantizationLevels == 255) || (quantizationLevels == 256)) { - return signedInterval ? 127.0f : 255.0f; - } else { - // THROW_TRANSFORMATION_EXCEPTION << "quantization level " << quantizationLevels << " is not supported"; - // FIXME: not completed - // return quantizationLevels - 1.0; - return signedInterval ? 127.0f : 255.0f; - } - } }; inline bool operator==(const DataPrecision& value1, const DataPrecision& value2) { @@ -181,7 +165,8 @@ public: std::vector precisionsOnActivations = { element::u8, element::i8 }, std::vector precisionsOnWeights = { element::i8 }, element::Type deqPrecision = element::f32, - bool support3DTensorOnActivations = true) : + bool support3DTensorOnActivations = true, + bool deconvolutionSpecificChannelsRatio = false) : updatePrecisions(updatePrecisions), quantizedTensorAlignmentOnActivations(quantizedTensorAlignmentOnActivations), quantizedTensorAlignmentOnWeights(quantizedTensorAlignmentOnWeights), @@ -189,7 +174,8 @@ public: precisionsOnActivations(precisionsOnActivations), precisionsOnWeights(precisionsOnWeights), deqPrecision(deqPrecision), - support3DTensorOnActivations(support3DTensorOnActivations) { + support3DTensorOnActivations(support3DTensorOnActivations), + deconvolutionSpecificChannelsRatio(deconvolutionSpecificChannelsRatio) { if (precisionsOnActivations.size() == 0ul) { THROW_TRANSFORMATION_EXCEPTION << "precisions on activations are not specisifed"; } @@ -234,6 +220,11 @@ public: return *this; } + Params& setDeconvolutionSpecificChannelsRatio(const bool deconvolutionSpecificChannelsRatio) { + this->deconvolutionSpecificChannelsRatio = deconvolutionSpecificChannelsRatio; + return *this; + } + bool updatePrecisions; QuantizedTensorAlignment quantizedTensorAlignmentOnActivations; QuantizedTensorAlignment quantizedTensorAlignmentOnWeights; @@ -242,6 +233,7 @@ public: std::vector precisionsOnWeights; element::Type deqPrecision; bool support3DTensorOnActivations; + bool deconvolutionSpecificChannelsRatio; }; class PrecisionDetails { @@ -318,6 +310,7 @@ protected: std::vector precisionsOnWeights; element::Type deqPrecision; bool support3DTensorOnActivations; + bool deconvolutionSpecificChannelsRatio; // absolute value, used to determine quantization interval asymmetry float quantizationIntervalAsymmetryThreshold; diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/network_helper.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/network_helper.hpp index 9846ef50d6a..8cf52a13fe2 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision/network_helper.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision/network_helper.hpp @@ -109,7 +109,8 @@ public: const float max, const bool hasZeroPoint, const bool updatePrecision, - const element::Type deqPrecision = element::f32); + const element::Type deqPrecision = element::f32, + const size_t outChannelsShapeIndex = 0); static std::shared_ptr updateFakeQuantize( std::shared_ptr fq, @@ -183,7 +184,7 @@ public: static std::shared_ptr toScalarIfPossible(std::shared_ptr node); static std::shared_ptr fold_fake_quantize(const std::shared_ptr& fq); - static std::shared_ptr fold_fake_quantize(const std::shared_ptr& fq, const bool roundValues); + static std::shared_ptr fold_fake_quantize(const std::shared_ptr& fq, const bool roundValues, int outChannelsShapeIndex = 0); static FakeQuantizeDequantization foldDequantization(const std::shared_ptr& node, const size_t branchIndex, const bool inPlace = false); @@ -191,8 +192,16 @@ public: static std::shared_ptr fuseConvert(const std::shared_ptr& fakeQuantize); + static std::vector precisionIntersection( + const std::vector& v1, + const std::vector& v2) noexcept; + private: - static std::shared_ptr foldFakeQuantize(const std::shared_ptr& fq, const bool roundValues, const bool roundValuesWasSet); + static std::shared_ptr foldFakeQuantize( + const std::shared_ptr& fq, + const bool roundValues, + const bool roundValuesWasSet, + int outChannelsShapeIndex = 0); // 1 - on weights // 0 - weightable layer was not found diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/transformer.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/transformer.hpp index 7a10d1daeb1..8de3fba36d5 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision/transformer.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision/transformer.hpp @@ -303,10 +303,6 @@ private: std::map>> transformations, GraphRewrite& pass, TransformationContext& context); - - std::vector precisionIntersection( - const std::vector& v1, - const std::vector& v2) const noexcept; }; class TRANSFORMATIONS_API TypeRelaxedReplacer : public GraphRewrite { diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/weightable_layer_transformation.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/weightable_layer_transformation.hpp index 94b81f2b2af..aeb0a6d9abd 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision/weightable_layer_transformation.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision/weightable_layer_transformation.hpp @@ -22,7 +22,7 @@ public: bool isPrecisionPreserved(std::shared_ptr layer) const noexcept override; protected: - void decomposeFakeQuantizeForWeightsPath(std::shared_ptr weightableLayer) const; + void decomposeFakeQuantizeForWeightsPath(const std::shared_ptr& weightableLayer, size_t outChannelsShapeIndex = 0ul) const; static bool isGroup(const std::shared_ptr& node); static bool isDepthwise(const std::shared_ptr& node); diff --git a/inference-engine/src/low_precision_transformations/src/add.cpp b/inference-engine/src/low_precision_transformations/src/add.cpp index 85aef194893..915e87d2f60 100644 --- a/inference-engine/src/low_precision_transformations/src/add.cpp +++ b/inference-engine/src/low_precision_transformations/src/add.cpp @@ -42,6 +42,7 @@ std::shared_ptr replaceToSubtract(const std::shared_ptr& const auto parent = add->get_input_node_shared_ptr(dataBranchIndex); if (is_type(parent) || is_type(parent) || + is_type(parent) || (is_type(parent) && (is_type(parent->get_input_node_ptr(0)) || is_type(parent->get_input_node_ptr(1))))) { return nullptr; diff --git a/inference-engine/src/low_precision_transformations/src/concat.cpp b/inference-engine/src/low_precision_transformations/src/concat.cpp index 24cc5940c1b..4988e29b1e2 100644 --- a/inference-engine/src/low_precision_transformations/src/concat.cpp +++ b/inference-engine/src/low_precision_transformations/src/concat.cpp @@ -50,14 +50,14 @@ bool ConcatTransformation::transform(TransformationContext& context, ngraph::pat return false; } - DataPrecision dataPrecision = getDataPrecision(fq, QuantizationDetails::getDetails(fq), false); - if (dataPrecision.precision == ngraph::element::undefined) { + std::vector concatParentsChildrensPrecisions = precisionsOnActivations; + fillAvailablePrecisions(subgraph.quantizationLayers[0], concatParentsChildrensPrecisions); + if (concatParentsChildrensPrecisions.empty()) { return false; } - std::unordered_map dequantizations; for (size_t i = 0; i < subgraph.quantizationLayers.size(); ++i) { - const std::shared_ptr fq = ngraph::as_type_ptr(subgraph.quantizationLayers[i]); + fq = ngraph::as_type_ptr(subgraph.quantizationLayers[i]); if (fq == nullptr) { return false; } @@ -72,21 +72,20 @@ bool ConcatTransformation::transform(TransformationContext& context, ngraph::pat if (quantizationDetails.inputHighValues.size() != 1ul) { return false; } + std::vector fqChildrensPrecisions = precisionsOnActivations; + fillAvailablePrecisions(subgraph.quantizationLayers[i], fqChildrensPrecisions); + concatParentsChildrensPrecisions = NetworkHelper::precisionIntersection(concatParentsChildrensPrecisions, fqChildrensPrecisions); - const DataPrecision dataPrecision2 = getDataPrecision(subgraph.quantizationLayers[i]->shared_from_this(), quantizationDetails, false); - if (dataPrecision2.precision == ngraph::element::undefined) { + if (concatParentsChildrensPrecisions.empty()) { return false; } - - if (dataPrecision.precision != dataPrecision2.precision) { - // quantization levels are the same, difference can be in sign - // wider interval (precision) is preferable: use signed if least one interval is signed - dataPrecision = dataPrecision.precision.is_signed() ? dataPrecision : dataPrecision2; - } } - if (dataPrecision.precision == ngraph::element::undefined) { - return false; + DataPrecision dataPrecision; + if (std::find(concatParentsChildrensPrecisions.begin(), concatParentsChildrensPrecisions.end(), element::i8) != concatParentsChildrensPrecisions.end()) { + dataPrecision = DataPrecision(element::i8); + } else { + dataPrecision = DataPrecision(concatParentsChildrensPrecisions[0]); } std::vector quantizationLayersDetails; diff --git a/inference-engine/src/low_precision_transformations/src/concat_multi_channels.cpp b/inference-engine/src/low_precision_transformations/src/concat_multi_channels.cpp index 62d958d22b4..dc81d51cd71 100644 --- a/inference-engine/src/low_precision_transformations/src/concat_multi_channels.cpp +++ b/inference-engine/src/low_precision_transformations/src/concat_multi_channels.cpp @@ -27,7 +27,9 @@ bool ConcatMultiChannelsTransformation::isMultiChannel(const std::vector& concat : concatLayers) { const std::vector> children = getChildrenRecursivelyExceptPrecisionPreserved(concat); for (const std::shared_ptr& child : children) { - if (is_type(child.get())) { + if ((is_type(child.get()) || + is_type(child.get())) && + this->layerTransformationsManager->isQuantized(child)) { return false; } } diff --git a/inference-engine/src/low_precision_transformations/src/convolution.cpp b/inference-engine/src/low_precision_transformations/src/convolution.cpp index ff5ca944df5..6496ee4ee54 100644 --- a/inference-engine/src/low_precision_transformations/src/convolution.cpp +++ b/inference-engine/src/low_precision_transformations/src/convolution.cpp @@ -42,7 +42,27 @@ bool ConvolutionTransformation::transform(TransformationContext &context, ngraph auto convolution = m.get_match_root(); if (!canConvolutionBeTransformed(context, convolution)) { - return false; + auto weightInput = convolution->get_input_node_shared_ptr(1); + std::shared_ptr reshapeFromWeights = as_type_ptr(weightInput); + FakeQuantizeDequantization dequantization = reshapeFromWeights == nullptr ? + NetworkHelper::getDequantization(convolution, 1ul) : + NetworkHelper::getDequantization(reshapeFromWeights); + if (dequantization.empty()) { + const auto fqOnWeights = getFakeQuantizeOnWeights(convolution); + std::shared_ptr resultConstant = NetworkHelper::fold_fake_quantize(fqOnWeights); + if (reshapeFromWeights != nullptr) { + resultConstant = fold_reshape( + resultConstant, + reshapeFromWeights->input_value(1), + false); + } + if (as_type_ptr(resultConstant)) { + replace_node(weightInput, resultConstant); + } + } else { + NetworkHelper::foldDequantization(dequantization.multiply, 0, true); + } + return true; } convolution = NetworkHelper::separateInStandaloneBranch(convolution); diff --git a/inference-engine/src/low_precision_transformations/src/convolution_backprop_data.cpp b/inference-engine/src/low_precision_transformations/src/convolution_backprop_data.cpp new file mode 100644 index 00000000000..a73ee1de155 --- /dev/null +++ b/inference-engine/src/low_precision_transformations/src/convolution_backprop_data.cpp @@ -0,0 +1,218 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision/convolution_backprop_data.hpp" + +#include +#include +#include +#include +#include + +#include "low_precision/network_helper.hpp" +#include "low_precision/common/dequantization_op.hpp" + +namespace ngraph { +namespace pass { +namespace low_precision { + +ConvolutionBackpropDataTransformation::ConvolutionBackpropDataTransformation(const Params& params) : WeightableLayerTransformation(params) { +} + +void ConvolutionBackpropDataTransformation::registerMatcherIn(GraphRewrite &pass, TransformationContext &context) const { + addPattern( + pass, + context, + make_op_pattern({ make_op_label(), make_op_label() })); + addPattern( + pass, + context, + make_op_pattern({ make_op_label(), make_op_label() })); + addPattern( + pass, + context, + make_op_pattern( + { make_op_label(), make_op_label(), make_op_label() })); + addPattern( + pass, + context, + make_op_pattern( + { make_op_label(), make_op_label(), make_op_label() })); +} + +bool ConvolutionBackpropDataTransformation::isQuantized(std::shared_ptr layer) const noexcept { + if (deconvolutionSpecificChannelsRatio) { + size_t inputChannels = layer->get_input_shape(0)[1]; + size_t outputChannels = layer->get_output_shape(0)[1]; + if (inputChannels % 4 != 0 || outputChannels % 16 != 0) { + return false; + } + } + return WeightableLayerTransformation::isQuantized(layer, false); +} + +bool ConvolutionBackpropDataTransformation::transform(TransformationContext &context, ngraph::pattern::Matcher &m) const { + auto convolutionBackpropData = m.get_match_root(); + + if (!canBeTransformed(context, convolutionBackpropData)) { + auto weightsInput = convolutionBackpropData->get_input_node_shared_ptr(1); + std::shared_ptr reshapeFromWeights = as_type_ptr(weightsInput); + FakeQuantizeDequantization dequantization = reshapeFromWeights == nullptr ? + NetworkHelper::getDequantization(convolutionBackpropData, 1ul) : + NetworkHelper::getDequantization(reshapeFromWeights); + if (dequantization.empty()) { + const auto fqOnWeights = getFakeQuantizeOnWeights(convolutionBackpropData); + std::shared_ptr resultConstant = NetworkHelper::fold_fake_quantize(fqOnWeights); + if (reshapeFromWeights != nullptr) { + resultConstant = fold_reshape( + resultConstant, + reshapeFromWeights->input_value(1), + false); + } + if (as_type_ptr(resultConstant)) { + replace_node(weightsInput, resultConstant); + } + } else { + NetworkHelper::foldDequantization(dequantization.multiply, 0, true); + } + return true; + } + + convolutionBackpropData = NetworkHelper::separateInStandaloneBranch(convolutionBackpropData); + FakeQuantizeDequantization dequantization = NetworkHelper::getDequantization(convolutionBackpropData); + { + if (dequantization.subtract != nullptr) { + std::shared_ptr layer = dequantization.subtract; + ngraph::pass::low_precision::NetworkHelper::cleanRunTimeInfo(layer); + + NetworkHelper::optimizeSubtract(dequantization.subtract); + } + std::shared_ptr reducedConstant = as_type_ptr(dequantization.multiplyConstant); + std::shared_ptr newMultiplyAfterConst = std::make_shared( + reducedConstant->get_output_element_type(0), + Shape{ 1 }, + reducedConstant->cast_vector()[0]); + auto inputs = convolutionBackpropData->input_values(); + inputs[0] = dequantization.multiply->input_value(0); + const auto copyNode = convolutionBackpropData->copy_with_new_inputs(inputs); + + const auto relaxedConvolutionBackpropData = std::make_shared>( + *as_type_ptr(copyNode), + std::vector{deqPrecision, deqPrecision}, + std::vector{deqPrecision}); + + const auto newMultiplyAfter = std::make_shared>( + std::vector{ deqPrecision, deqPrecision }, + std::vector{ dequantization.multiply->get_output_element_type(0) }, + ngraph::op::TemporaryReplaceOutputType(relaxedConvolutionBackpropData, deqPrecision).get(), + ngraph::op::TemporaryReplaceOutputType(newMultiplyAfterConst, deqPrecision).get()); + + replace_node(convolutionBackpropData, newMultiplyAfter); + convolutionBackpropData = newMultiplyAfter->input_value(0).get_node_shared_ptr(); + inputs[0] = convolutionBackpropData->get_input_node_ptr(0)->input_value(0); + if (is_type(convolutionBackpropData->get_input_node_ptr(0))) { + auto newConvolution = convolutionBackpropData->copy_with_new_inputs(inputs); + replace_node(convolutionBackpropData, newConvolution); + convolutionBackpropData = newConvolution; + } + } + + { + decomposeFakeQuantizeForWeightsPath(convolutionBackpropData, 1ul); + + dequantization = NetworkHelper::getDequantization(convolutionBackpropData, 1ul); + + if (is_type(dequantization.data.get_node())) { + const std::shared_ptr fq = as_type_ptr(dequantization.data.get_node_shared_ptr()); + std::shared_ptr newFQ = NetworkHelper::fold_fake_quantize(fq, true); + NetworkHelper::copyInfo(fq, newFQ); + replace_node(fq, newFQ); + } + + std::shared_ptr multiplyFromWeights = as_type_ptr( + convolutionBackpropData->input_value(1).get_node_shared_ptr()); + std::shared_ptr subtractFromWeights = as_type_ptr(multiplyFromWeights->get_input_node_shared_ptr(0)); + + { + Shape newScaleShape = multiplyFromWeights->get_input_shape(1); + auto inputs = convolutionBackpropData->input_values(); + inputs[1] = multiplyFromWeights->input_value(0); + auto newMultiplyAfter = std::make_shared( + convolutionBackpropData->copy_with_new_inputs(inputs), + foldConvert( + fold_reshape( + multiplyFromWeights->input_value(1), + std::make_shared(element::u64, Shape{ newScaleShape.size() }, newScaleShape), + false), + convolutionBackpropData->get_output_element_type(0))); + replace_node(convolutionBackpropData, newMultiplyAfter); + convolutionBackpropData = newMultiplyAfter->input_value(0).get_node_shared_ptr(); + } + + if (subtractFromWeights != nullptr) { + // optimize zero point on weights + auto optimizedSubtract = NetworkHelper::optimizeSubtract(subtractFromWeights); + if (optimizedSubtract == nullptr) { + subtractFromWeights = nullptr; + } else { + subtractFromWeights = as_type_ptr(optimizedSubtract); + + const Shape weightsShape = subtractFromWeights->input(0).get_shape(); + Shape zeroPointShape(weightsShape.size(), 1ul); + zeroPointShape[1] = weightsShape[1]; + + auto zeroPointConstant = fold( + subtractFromWeights->get_input_node_shared_ptr(1), + std::make_shared(element::i32, Shape{zeroPointShape.size()}, zeroPointShape)); + replace_node(subtractFromWeights->get_input_node_shared_ptr(1), zeroPointConstant); + } + } + + std::shared_ptr convertFromWeights = + as_type_ptr( + subtractFromWeights == nullptr ? + multiplyFromWeights->get_input_node_shared_ptr(0) : + subtractFromWeights->get_input_node_shared_ptr(0)); + if (convertFromWeights != nullptr) { + auto inputs = convolutionBackpropData->input_values(); + inputs[1] = convolutionBackpropData->get_input_node_ptr(1)->input_value(0); + // remove Convert on weights + auto newConvolution = convolutionBackpropData->clone_with_new_inputs(inputs); + replace_node(convolutionBackpropData, newConvolution); + convolutionBackpropData = newConvolution; + } + } + std::shared_ptr finalDequantization = NetworkHelper::optimizeMultipliesAfter( + convolutionBackpropData->output(0).get_target_inputs().begin()->get_node()->shared_from_this()); + ngraph::copy_runtime_info({ convolutionBackpropData, finalDequantization }, finalDequantization); + updateOutput(context, finalDequantization, convolutionBackpropData); + + auto onWeights = convolutionBackpropData->get_input_node_shared_ptr(1); + if (is_type(onWeights)) { + onWeights = onWeights->get_input_node_shared_ptr(0); + } + + if (is_type(onWeights)) { + auto& rt = onWeights->get_rt_info(); + rt["DISABLED_CONSTANT_FOLDING"] = std::make_shared>(""); + } + + return true; +} + +bool ConvolutionBackpropDataTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr op) const { + if (deconvolutionSpecificChannelsRatio) { + size_t inputChannels = op->get_input_shape(0)[1]; + size_t outputChannels = op->get_output_shape(0)[1]; + if (inputChannels % 4 != 0 || outputChannels % 16 != 0) { + return false; + } + } + + return canConvolutionBeTransformed(context, op); +} + +} // namespace low_precision +} // namespace pass +} // namespace ngraph diff --git a/inference-engine/src/low_precision_transformations/src/fake_quantize.cpp b/inference-engine/src/low_precision_transformations/src/fake_quantize.cpp index 41b9851d5e3..53fe2702984 100644 --- a/inference-engine/src/low_precision_transformations/src/fake_quantize.cpp +++ b/inference-engine/src/low_precision_transformations/src/fake_quantize.cpp @@ -20,7 +20,7 @@ void FakeQuantizeTransformation::registerMatcherIn(GraphRewrite& pass, Transform bool FakeQuantizeTransformation::transform(TransformationContext& context, ngraph::pattern::Matcher &m) const { std::shared_ptr layer = std::dynamic_pointer_cast(m.get_match_root()); - if (!NetworkHelper::isQuantizeSupported(layer)) { + if (!QuantizationDetails::outputLayoutIsSupported(layer)) { return false; } @@ -149,7 +149,9 @@ std::shared_ptr FakeQuantizeTransformation::fuseElementwis inputHighConst_f32 = fq::updateShape(fold(inputHighConst_f32, value), fakeQuantize->get_output_shape(0)); } else if (is_type(eltwise) && checkElementwise(eltwise)) { if (is_type(fq::getData(eltwise)) || - is_type(fq::getData(eltwise))) { + is_type(fq::getData(eltwise)) || + is_type(fq::getData(eltwise)) || + is_type(fq::getData(eltwise))) { return nullptr; } diff --git a/inference-engine/src/low_precision_transformations/src/fuse_multiply_to_fake_quantize.cpp b/inference-engine/src/low_precision_transformations/src/fuse_multiply_to_fake_quantize.cpp index c1b7f4e907b..734d9abec43 100644 --- a/inference-engine/src/low_precision_transformations/src/fuse_multiply_to_fake_quantize.cpp +++ b/inference-engine/src/low_precision_transformations/src/fuse_multiply_to_fake_quantize.cpp @@ -45,11 +45,18 @@ bool FuseMultiplyToFakeQuantizeTransformation::transform(TransformationContext& const auto fakeQuantizeParent = fakeQuantize->get_input_node_shared_ptr(0); const size_t parentIndex = NetworkHelper::getParentOutputIndex(fakeQuantizeParent, fakeQuantize); + const auto inputLow = foldConvert(fakeQuantize->input_value(1), deqPrecision); + const auto inputHigh = foldConvert(fakeQuantize->input_value(2), deqPrecision); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(1), inputLow); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(2), inputHigh); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(3), outputLowConst_f32); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(4), outputHighConst_f32); + auto newFakeQuantize = std::make_shared>( opset1::FakeQuantize( fakeQuantizeParent->output(parentIndex), - foldConvert(fakeQuantize->input_value(1), deqPrecision), - foldConvert(fakeQuantize->input_value(2), deqPrecision), + inputLow, + inputHigh, outputLowConst_f32, outputHighConst_f32, fakeQuantize->get_levels()), diff --git a/inference-engine/src/low_precision_transformations/src/fuse_subtract_to_fake_quantize.cpp b/inference-engine/src/low_precision_transformations/src/fuse_subtract_to_fake_quantize.cpp index 2e3f2e23d3f..8d8d9968802 100644 --- a/inference-engine/src/low_precision_transformations/src/fuse_subtract_to_fake_quantize.cpp +++ b/inference-engine/src/low_precision_transformations/src/fuse_subtract_to_fake_quantize.cpp @@ -45,11 +45,18 @@ bool FuseSubtractToFakeQuantizeTransformation::transform(TransformationContext& const auto fakeQuantizeParent = fakeQuantize->get_input_node_shared_ptr(0); const size_t parentIndex = NetworkHelper::getParentOutputIndex(fakeQuantizeParent, fakeQuantize); + const auto inputLow = foldConvert(fakeQuantize->input_value(1), deqPrecision); + const auto inputHigh = foldConvert(fakeQuantize->input_value(2), deqPrecision); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(1), inputLow); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(2), inputHigh); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(3), outputLowConst_f32); + NetworkHelper::copyInfo(fakeQuantize->get_input_node_shared_ptr(4), outputHighConst_f32); + auto newFakeQuantize = std::make_shared>( opset1::FakeQuantize( fakeQuantizeParent->output(parentIndex), - foldConvert(fakeQuantize->input_value(1), deqPrecision), - foldConvert(fakeQuantize->input_value(2), deqPrecision), + inputLow, + inputHigh, outputLowConst_f32, outputHighConst_f32, fakeQuantize->get_levels()), @@ -76,7 +83,8 @@ bool FuseSubtractToFakeQuantizeTransformation::canBeTransformed(const Transforma for (const auto& target : children) { const auto convolution = is_type(target.get_node()); const auto groupConvolution = is_type(target.get_node()); - if (convolution || groupConvolution) { + const auto convolutionBackpropData = is_type(target.get_node()); + if (convolution || groupConvolution || convolutionBackpropData) { return false; } } diff --git a/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp b/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp index 834aa6931c5..0fc0a9dc4fc 100644 --- a/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp +++ b/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp @@ -32,6 +32,7 @@ LayerTransformation::LayerTransformation(const Params& params) : precisionsOnWeights(params.precisionsOnWeights), deqPrecision(params.deqPrecision), support3DTensorOnActivations(params.support3DTensorOnActivations), + deconvolutionSpecificChannelsRatio(params.deconvolutionSpecificChannelsRatio), quantizationIntervalAsymmetryThreshold(0.002f), zeroThreshold(1.e-6f), minQuantizationLevels(2ul), diff --git a/inference-engine/src/low_precision_transformations/src/network_helper.cpp b/inference-engine/src/low_precision_transformations/src/network_helper.cpp index dbca7606e73..4a1e942e575 100644 --- a/inference-engine/src/low_precision_transformations/src/network_helper.cpp +++ b/inference-engine/src/low_precision_transformations/src/network_helper.cpp @@ -69,7 +69,8 @@ bool NetworkHelper::isConstantPath(const std::shared_ptr& op) { return is_type(node) || is_type(node) || is_type(node) || - is_type(node); + is_type(node) || + is_type(node); }; if (isNotConstantPathOperation(op)) { @@ -440,8 +441,11 @@ std::shared_ptr NetworkHelper::fold_fake_quantize(const std::shared_ptr NetworkHelper::fold_fake_quantize(const std::shared_ptr& fq, const bool roundValues) { - return foldFakeQuantize(fq, roundValues, true); +std::shared_ptr NetworkHelper::fold_fake_quantize( + const std::shared_ptr& fq, + const bool roundValues, + const int outChannelsShapeIndex) { + return foldFakeQuantize(fq, roundValues, true, outChannelsShapeIndex); } FakeQuantizeDequantization NetworkHelper::foldDequantization(const std::shared_ptr& node, const size_t branchIndex, const bool inPlace) { @@ -591,7 +595,8 @@ std::shared_ptr NetworkHelper::fuseConvert(const std::shar std::shared_ptr NetworkHelper::foldFakeQuantize( const std::shared_ptr& fq, const bool roundValuesArg, - const bool roundValuesWasSet) { + const bool roundValuesWasSet, + const int outChannelsShapeIndex) { if (is_type(fq->get_input_node_shared_ptr(0)) && is_type(fq->get_input_node_shared_ptr(1)) && is_type(fq->get_input_node_shared_ptr(2)) && @@ -630,10 +635,20 @@ std::shared_ptr NetworkHelper::foldFakeQuantize( if (constShape.empty() || constShape.size() > 5lu) { THROW_IE_LPT_EXCEPTION(*fq) << "Unexpected dimensions count " << constShape.size(); } + if (outChannelsShapeIndex != 0 && outChannelsShapeIndex != 1) { + THROW_IE_LPT_EXCEPTION(*fq) << "Unexpected outChannelsShapeIndex " << outChannelsShapeIndex; + } - // OIDHW - const size_t OC = constShape[0]; - const size_t IC = constShape.size() > 1lu ? constShape[1] : 1; + size_t OC; + size_t IC; + // OIDHW or IODHW + if (constShape.size() == 1) { + OC = constShape[0]; + IC = 1; + } else { + OC = constShape[outChannelsShapeIndex]; + IC = constShape[outChannelsShapeIndex == 0 ? 1 : 0]; + } const size_t D = constShape.size() > 4lu ? constShape[constShape.size() - 3] : 1; const size_t H = constShape.size() > 2lu ? constShape.size() == 3lu ? constShape[2] : constShape[constShape.size() - 2] : 1; const size_t W = constShape.size() > 3lu ? constShape[constShape.size() - 1] : 1; @@ -667,29 +682,35 @@ std::shared_ptr NetworkHelper::foldFakeQuantize( auto levels_1 = fq->get_levels() - 1.f; - //const size_t DHW = D * H * W; + const size_t DHW = D * H * W; const size_t IDHW = IC * D * H * W; const auto values = constant->cast_vector(); std::vector quantizedValues(OC * IC * D * H * W); for (size_t oc = 0; oc < OC; ++oc) { - for (size_t iidx = 0; iidx < IDHW; ++iidx) { - const float inputLow = inputLowValues[isInputLowBroadcasted ? 0 : oc]; - const float inputHigh = inputHighValues[isInputHighBroadcasted ? 0 : oc]; - const float outputLow = outputLowValues[isOutputLowBroadcasted ? 0 : oc]; - const float outputHigh = outputHighValues[isOutputHighBroadcasted ? 0 : oc]; + const float inputLow = inputLowValues[isInputLowBroadcasted ? 0 : oc]; + const float inputHigh = inputHighValues[isInputHighBroadcasted ? 0 : oc]; + const float outputLow = outputLowValues[isOutputLowBroadcasted ? 0 : oc]; + const float outputHigh = outputHighValues[isOutputHighBroadcasted ? 0 : oc]; + for (size_t ic = 0; ic < IC; ++ic) { + for (size_t iidx = 0; iidx < DHW; ++iidx) { + size_t idx; + if (outChannelsShapeIndex == 0) { + idx = oc * IDHW + ic * DHW + iidx; + } else { + idx = ic * IDHW + oc * DHW + iidx; + } - const size_t idx = oc * IDHW + iidx; - - if (values[idx] <= inputLow) { - quantizedValues[idx] = roundValues ? std::roundf(outputLow) : outputLow; - } else if (values[idx] > inputHigh) { - quantizedValues[idx] = roundValues ? std::roundf(outputHigh) : outputHigh; - } else { - const float value = std::roundf((values[idx] - inputLow) / (inputHigh - inputLow) * levels_1) / - levels_1 * (outputHigh - outputLow) + outputLow; - quantizedValues[idx] = roundValues ? std::roundf(value) : value; + if (values[idx] <= inputLow) { + quantizedValues[idx] = roundValues ? std::roundf(outputLow) : outputLow; + } else if (values[idx] > inputHigh) { + quantizedValues[idx] = roundValues ? std::roundf(outputHigh) : outputHigh; + } else { + const float value = std::roundf((values[idx] - inputLow) / (inputHigh - inputLow) * levels_1) / + levels_1 * (outputHigh - outputLow) + outputLow; + quantizedValues[idx] = roundValues ? std::roundf(value) : value; + } } } } @@ -818,7 +839,8 @@ std::tuple, std::shared_ptr> NetworkHelper::decompos const float max, const bool hasZeroPoint, const bool updatePrecision, - const element::Type deqPrecision) { + const element::Type deqPrecision, + const size_t outChannelsShapeIndex) { using std::make_shared; const auto outputLow = fq->input_value(3); @@ -898,7 +920,8 @@ std::tuple, std::shared_ptr> NetworkHelper::decompos newMax->output(0), fq->get_levels(), fq->get_auto_broadcast()), - true); + true, + outChannelsShapeIndex); NetworkHelper::copyInfo(fq, newFQ); std::shared_ptr convert2; @@ -1548,12 +1571,12 @@ bool NetworkHelper::checkZeroPoint(const std::shared_ptr& node, const Data if (is_type(node)) { const auto parent = node->get_input_node_shared_ptr(0); const auto intNode = is_type(parent) ? parent : node; - const auto intType = intNode->get_input_element_type(0); - if (intType == element::u8 || intType == element::i8) { - min = DataPrecision::getMinValue(intType, 256) - 0.5f; - max = DataPrecision::getMaxValue(intType, 256) + 0.5f; + const auto type = intNode->get_input_element_type(0); + if (type == element::u8 || type == element::i8) { + min = DataPrecision::getMinValue(type, 256) - 0.5f; + max = DataPrecision::getMaxValue(type, 256) + 0.5f; } else { - return false; + return type == element::f32 || type == element::f16; } auto subtract1input = node->get_input_node_shared_ptr(1); if (is_type(subtract1input)) { @@ -1595,6 +1618,23 @@ bool NetworkHelper::checkZeroPoint(const std::shared_ptr& node, const Data return true; } +std::vector NetworkHelper::precisionIntersection( + const std::vector& v1, + const std::vector& v2) noexcept { + std::vector v3; + + auto v1Copy = v1; + auto v2Copy = v2; + + std::sort(v1Copy.begin(), v1Copy.end()); + std::sort(v2Copy.begin(), v2Copy.end()); + + std::set_intersection(v1Copy.begin(), v1Copy.end(), + v2Copy.begin(), v2Copy.end(), + std::back_inserter(v3)); + return v3; +} + } // namespace low_precision } // namespace pass } // namespace ngraph diff --git a/inference-engine/src/low_precision_transformations/src/transformer.cpp b/inference-engine/src/low_precision_transformations/src/transformer.cpp index d8b484bcbce..4debb5868b6 100644 --- a/inference-engine/src/low_precision_transformations/src/transformer.cpp +++ b/inference-engine/src/low_precision_transformations/src/transformer.cpp @@ -34,6 +34,7 @@ #include "low_precision/avg_pool.hpp" #include "low_precision/clamp.hpp" #include "low_precision/convolution.hpp" +#include "low_precision/convolution_backprop_data.hpp" #include "low_precision/depth_to_space.hpp" #include "low_precision/fake_quantize.hpp" #include "low_precision/group_convolution.hpp" @@ -220,6 +221,7 @@ LowPrecisionTransformations LowPrecisionTransformer::getAllTransformations(const add(params). add(params). add(params). + add(params). add(params). add(params). add(params). @@ -338,6 +340,7 @@ TypeRelaxedReplacer::TypeRelaxedReplacer() { make_matcher_type_relaxed(this); make_matcher_type_relaxed(this); make_matcher_type_relaxed(this); + make_matcher_type_relaxed(this); make_matcher_type_relaxed(this); make_matcher_type_relaxed(this); make_matcher_type_relaxed(this); @@ -430,23 +433,6 @@ void LowPrecisionTransformer::transform(std::shared_ptr network) { network->validate_nodes_and_infer_types(); } -std::vector LowPrecisionTransformer::precisionIntersection( - const std::vector& v1, - const std::vector& v2) const noexcept { - std::vector v3; - - auto v1Copy = v1; - auto v2Copy = v2; - - std::sort(v1Copy.begin(), v1Copy.end()); - std::sort(v2Copy.begin(), v2Copy.end()); - - std::set_intersection(v1Copy.begin(), v1Copy.end(), - v2Copy.begin(), v2Copy.end(), - std::back_inserter(v3)); - return v3; -} - std::vector LowPrecisionTransformer::getPrecisionsOnActivations(const Node& op) const noexcept { const std::string operantionType = LowPrecisionTransformations::getType(op); const std::vector transformation = transformations.find(operantionType); @@ -456,7 +442,7 @@ std::vector LowPrecisionTransformer::getPrecisionsOnActivations(c std::vector precisions = transformation[0]->getPrecisionsOnActivations(); for (const auto& transform : transformation) { - precisions = precisionIntersection(precisions, transform->getPrecisionsOnActivations()); + precisions = NetworkHelper::precisionIntersection(precisions, transform->getPrecisionsOnActivations()); } return precisions; } diff --git a/inference-engine/src/low_precision_transformations/src/weightable_layer_transformation.cpp b/inference-engine/src/low_precision_transformations/src/weightable_layer_transformation.cpp index b3651cdf231..726fc893975 100644 --- a/inference-engine/src/low_precision_transformations/src/weightable_layer_transformation.cpp +++ b/inference-engine/src/low_precision_transformations/src/weightable_layer_transformation.cpp @@ -26,7 +26,7 @@ bool WeightableLayerTransformation::canConvolutionBeTransformed(const Transforma return false; } - if (updatePrecisions && !NetworkHelper::checkZeroPoint(dequantization.subtract)) { + if (!NetworkHelper::checkZeroPoint(dequantization.subtract)) { return false; } @@ -46,24 +46,10 @@ bool WeightableLayerTransformation::canConvolutionBeTransformed(const Transforma return false; } if (!NetworkHelper::checkZeroPoint(fqOnWeights, dataPrecision)) { - const std::shared_ptr resultConstant = NetworkHelper::fold_fake_quantize(fqOnWeights); - if (as_type_ptr(resultConstant)) { - replace_node(fqOnWeights, resultConstant); - } return false; } } else { if (!NetworkHelper::checkZeroPoint(dequantization.subtract)) { - const auto resultDequantization = NetworkHelper::foldDequantization(dequantization.multiply, 0, true); - if (resultDequantization.empty() && reshapeFromWeights) { - const auto foldedReshape = fold( - reshapeFromWeights->get_input_node_shared_ptr(0), - reshapeFromWeights->get_input_node_shared_ptr(1), - reshapeFromWeights->get_special_zero()); - if (is_type(foldedReshape)) { - replace_node(reshapeFromWeights, foldedReshape); - } - } return false; } } @@ -170,9 +156,11 @@ bool WeightableLayerTransformation::canBeTransformed(const TransformationContext return false; } - if ( // Check if all dimensions of scale except the first one (which is O-Output channels dimension) are all ones - (shape_size(constOutputShape) != constOutputShape[0]) || - ((constOutputShape[0] != 1ul) && (fqFromWeights->get_output_shape(0)[0] != constOutputShape[0]))) { + const size_t outChannelsShapeIndex = is_type(layer) ? 1ul : 0ul; + if ( // Check if all dimensions of scale except the output channels are all ones + (shape_size(constOutputShape) != constOutputShape[outChannelsShapeIndex]) || + ((constOutputShape[outChannelsShapeIndex] != 1ul) && + (fqFromWeights->get_output_shape(0)[outChannelsShapeIndex] != constOutputShape[outChannelsShapeIndex]))) { return false; } } else { @@ -256,7 +244,7 @@ bool WeightableLayerTransformation::isPrecisionPreserved(std::shared_ptr l return false; } -void WeightableLayerTransformation::decomposeFakeQuantizeForWeightsPath(std::shared_ptr node) const { +void WeightableLayerTransformation::decomposeFakeQuantizeForWeightsPath(const std::shared_ptr& node, const size_t outChannelsShapeIndex) const { const auto fq = getFakeQuantizeOnWeights(node); if (fq == nullptr) { return; @@ -270,7 +258,9 @@ void WeightableLayerTransformation::decomposeFakeQuantizeForWeightsPath(std::sha dataPrecision.min, dataPrecision.max, dataPrecision.hasZeroPoint, - updatePrecisions); + updatePrecisions, + element::f32, + outChannelsShapeIndex); std::shared_ptr fqOnWeights = std::get<0>(tuple); if (as_type_ptr(fqOnWeights) == nullptr) { diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index 32efc8d09ac..3ab7622ac91 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -328,7 +329,8 @@ static void Transformation(CNNNetwork& clonedNetwork, const Config& conf) { .add( LayerTransformation::Params(params).setPrecisionsOnActivations({ ngraph::element::u8 }).setSupportAsymmetricQuantization(true)) .addStandaloneCleanup( - LayerTransformation::Params(params).setPrecisionsOnActivations({ ngraph::element::u8 }))); + LayerTransformation::Params(params).setPrecisionsOnActivations({ ngraph::element::u8 })) + .remove()); transformer.transform(nGraphFunc); } diff --git a/inference-engine/src/transformations/include/ngraph_ops/deconvolution_ie.hpp b/inference-engine/src/transformations/include/ngraph_ops/deconvolution_ie.hpp index 96422f61e3b..3aa4a6492d1 100644 --- a/inference-engine/src/transformations/include/ngraph_ops/deconvolution_ie.hpp +++ b/inference-engine/src/transformations/include/ngraph_ops/deconvolution_ie.hpp @@ -29,6 +29,7 @@ public: const Strides& dilations, const CoordinateDiff& pads_begin, const CoordinateDiff& pads_end, + const element::Type output_type, const size_t& group = 1, const PadType& auto_pad = PadType::EXPLICIT, const CoordinateDiff& output_padding = {}, @@ -41,6 +42,7 @@ public: const Strides& dilations, const CoordinateDiff& pads_begin, const CoordinateDiff& pads_end, + const element::Type output_type, const size_t& group = 1, const PadType& auto_pad = PadType::EXPLICIT, const CoordinateDiff& output_padding = {}, @@ -79,6 +81,7 @@ protected: size_t m_group; CoordinateDiff m_output_padding; std::shared_ptr m_output_shape; + element::Type m_output_type; }; } // namespace op diff --git a/inference-engine/src/transformations/src/ngraph_ops/deconvolution_ie.cpp b/inference-engine/src/transformations/src/ngraph_ops/deconvolution_ie.cpp index ef9bc90bd1e..e8940700dbe 100644 --- a/inference-engine/src/transformations/src/ngraph_ops/deconvolution_ie.cpp +++ b/inference-engine/src/transformations/src/ngraph_ops/deconvolution_ie.cpp @@ -13,6 +13,7 @@ #include "ngraph/util.hpp" #include "ngraph/validation_util.hpp" #include "ngraph/opsets/opset1.hpp" +#include "ngraph_ops/type_relaxed.hpp" using namespace std; using namespace ngraph; @@ -25,6 +26,7 @@ op::DeconvolutionIE::DeconvolutionIE(const Output& data, const Strides& dilations, const CoordinateDiff& pads_begin, const CoordinateDiff& pads_end, + const element::Type output_type, const size_t& group, const PadType& auto_pad, const CoordinateDiff& output_padding, @@ -37,7 +39,8 @@ op::DeconvolutionIE::DeconvolutionIE(const Output& data, , m_auto_pad(auto_pad) , m_group(group) , m_output_padding(output_padding) - , m_output_shape(output_shape) { + , m_output_shape(output_shape) + , m_output_type(output_type) { constructor_validate_and_infer_types(); } @@ -48,6 +51,7 @@ op::DeconvolutionIE::DeconvolutionIE(const Output& data, const Strides& dilations, const CoordinateDiff& pads_begin, const CoordinateDiff& pads_end, + const element::Type output_type, const size_t& group, const PadType& auto_pad, const CoordinateDiff& output_padding, @@ -60,7 +64,8 @@ op::DeconvolutionIE::DeconvolutionIE(const Output& data, , m_auto_pad(auto_pad) , m_group(group) , m_output_padding(output_padding) - , m_output_shape(output_shape) { + , m_output_shape(output_shape) + , m_output_type(output_type) { constructor_validate_and_infer_types(); } @@ -81,13 +86,32 @@ void op::DeconvolutionIE::validate_and_infer_types() { } Output conv; if (m_output_shape) { - conv = std::make_shared(input_value(0), weights, m_output_shape, - m_strides, m_pads_begin, m_pads_end, m_dilations, m_auto_pad, m_output_padding); + conv = std::make_shared>( + std::vector{ element::f32, element::f32 }, + std::vector{ element::f32 }, + ngraph::op::TemporaryReplaceOutputType(input_value(0), element::f32).get(), + ngraph::op::TemporaryReplaceOutputType(weights, element::f32).get(), + m_output_shape, + m_strides, + m_pads_begin, + m_pads_end, + m_dilations, + m_auto_pad, + m_output_padding); } else { - conv = std::make_shared(input_value(0), weights, - m_strides, m_pads_begin, m_pads_end, m_dilations, m_auto_pad, m_output_padding); + conv = std::make_shared>( + std::vector{ element::f32, element::f32 }, + std::vector{ element::f32 }, + ngraph::op::TemporaryReplaceOutputType(input_value(0), element::f32).get(), + ngraph::op::TemporaryReplaceOutputType(weights, element::f32).get(), + m_strides, + m_pads_begin, + m_pads_end, + m_dilations, + m_auto_pad, + m_output_padding); } - set_output_type(0, conv.get_element_type(), conv.get_partial_shape()); + set_output_type(0, m_output_type, conv.get_partial_shape()); } shared_ptr op::DeconvolutionIE::clone_with_new_inputs(const ngraph::OutputVector &new_args) const { @@ -99,6 +123,7 @@ shared_ptr op::DeconvolutionIE::clone_with_new_inputs(const ngraph::Output m_dilations, m_pads_begin, m_pads_end, + m_output_type, m_group, m_auto_pad, m_output_padding, @@ -111,6 +136,7 @@ shared_ptr op::DeconvolutionIE::clone_with_new_inputs(const ngraph::Output m_dilations, m_pads_begin, m_pads_end, + m_output_type, m_group, m_auto_pad, m_output_padding, diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_convolutions.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_convolutions.cpp index 5b7965762a5..1f0fb32ae6b 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/convert_convolutions.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_convolutions.cpp @@ -113,6 +113,7 @@ ngraph::pass::ConvertDeconvolution::ConvertDeconvolution() { deconv->get_dilations(), deconv->get_pads_begin(), deconv->get_pads_end(), + deconv->get_output_element_type(0), 1 /* groups */, deconv->get_auto_pad(), deconv->get_output_padding(), @@ -158,6 +159,7 @@ ngraph::pass::ConvertGroupDeconvolution::ConvertGroupDeconvolution() { gconv->get_dilations(), gconv->get_pads_begin(), gconv->get_pads_end(), + gconv->get_output_element_type(0), group, gconv->get_auto_pad(), gconv->get_output_padding(), diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_subtract.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_subtract.cpp index 7080688b09c..b5507ee205f 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/convert_subtract.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_subtract.cpp @@ -38,11 +38,14 @@ ngraph::pass::ConvertSubtract::ConvertSubtract() { const std::shared_ptr child = subChildren.begin()->get_node()->shared_from_this(); if (child != nullptr) { if (is_type(child) || + is_type(child) || is_type(child) || + is_type(child) || is_type(child) || - (is_type(child) && + (is_type(child) && (child->output(0).get_target_inputs().size() == 1ul) && - is_type(child->output(0).get_target_inputs().begin()->get_node()->shared_from_this()))) { + (is_type(child->output(0).get_target_inputs().begin()->get_node()->shared_from_this()) || + is_type(child->output(0).get_target_inputs().begin()->get_node()->shared_from_this())))) { const auto input1Type = sub->input(0).get_element_type(); const auto input2Type = sub->input(1).get_element_type(); if (((input1Type == element::u8) && (input2Type == element::u8)) || diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_backprop_data_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_backprop_data_transformation.cpp new file mode 100644 index 00000000000..283adb5bf45 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_backprop_data_transformation.cpp @@ -0,0 +1,334 @@ +// Copyright (C) 2021 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 "simple_low_precision_transformer.hpp" +#include "lpt_ngraph_functions/convolution_backprop_data_function.hpp" + +using namespace testing; +using namespace ngraph; +using namespace ngraph::pass; + +class ConvolutionBackpropDataTransformationTestValues { +public: + class Actual { + public: + ngraph::element::Type precisionBeforeDequantization; + ngraph::builder::subgraph::DequantizationOperations dequantizationOnActivations; + builder::subgraph::FakeQuantizeOnWeights fakeQuantizeOnWeights; + builder::subgraph::DequantizationOperations dequantizationOnWeights; + std::shared_ptr weights; + + Actual() = default; + Actual( + const ngraph::element::Type& precisionBeforeDequantization, + const ngraph::builder::subgraph::DequantizationOperations& dequantizationOnActivations, + const builder::subgraph::FakeQuantizeOnWeights& fakeQuantizeOnWeights, + const std::shared_ptr& weights) : + precisionBeforeDequantization(precisionBeforeDequantization), + dequantizationOnActivations(dequantizationOnActivations), + fakeQuantizeOnWeights(fakeQuantizeOnWeights), + weights(weights) {} + Actual( + const ngraph::element::Type& precisionBeforeDequantization, + const ngraph::builder::subgraph::DequantizationOperations& dequantizationOnActivations, + const builder::subgraph::DequantizationOperations& dequantizationOnWeights, + const std::shared_ptr& weights) : + precisionBeforeDequantization(precisionBeforeDequantization), + dequantizationOnActivations(dequantizationOnActivations), + dequantizationOnWeights(dequantizationOnWeights), + weights(weights) {} + }; + + class Expected { + public: + ngraph::element::Type precisionBeforeDequantization; + ngraph::builder::subgraph::DequantizationOperations dequantizationOnActivations; + builder::subgraph::DequantizationOperations dequantizationOnWeights; + ngraph::builder::subgraph::DequantizationOperations dequantizationAfter; + std::shared_ptr weights; + bool transformed; + }; + + ngraph::pass::low_precision::LayerTransformation::Params params; + Actual actual; + Expected expected; +}; + +typedef std::tuple< + element::Type, + ngraph::Shape, + ConvolutionBackpropDataTransformationTestValues> ConvolutionBackpropDataTransformationParams; + +class ConvolutionBackpropDataTransformation : public LayerTransformation, public testing::WithParamInterface { +public: + void SetUp() override { + const auto netPrecision = std::get<0>(GetParam()); + const auto inputShape = std::get<1>(GetParam()); + auto outputShape = inputShape; + outputShape[1] /= 4; + outputShape[2] *= 2; + outputShape[3] *= 2; + auto testValues = std::get<2>(GetParam()); + + std::shared_ptr actualWeights = pass::low_precision::fold( + testValues.actual.weights, + opset1::Constant::create( + element::i64, + Shape{inputShape.size()}, + Shape{inputShape[1], outputShape[1], 1, 1})); + if (!testValues.actual.fakeQuantizeOnWeights.empty()) { + actualWeights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + outputShape, + netPrecision, + testValues.actual.fakeQuantizeOnWeights, + as_type_ptr(actualWeights)); + } else { + actualWeights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + outputShape, + netPrecision, + testValues.actual.dequantizationOnWeights, + as_type_ptr(actualWeights)); + } + + actualFunction = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getOriginal( + testValues.actual.precisionBeforeDequantization, + netPrecision, + inputShape, + outputShape, + testValues.actual.dequantizationOnActivations, + actualWeights); + + SimpleLowPrecisionTransformer transform; + transform.add(testValues.params); + transform.transform(actualFunction); + std::shared_ptr refWeights = pass::low_precision::fold( + testValues.expected.weights, + opset1::Constant::create( + element::i64, + Shape{inputShape.size()}, + Shape{inputShape[1], outputShape[1], 1, 1})); + + if (!testValues.expected.transformed) { + refWeights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + outputShape, + netPrecision, + testValues.actual.fakeQuantizeOnWeights, + as_type_ptr(refWeights)); + } else { + refWeights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + outputShape, + netPrecision, + testValues.expected.dequantizationOnWeights, + as_type_ptr(refWeights)); + } + + referenceFunction = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getReference( + testValues.expected.precisionBeforeDequantization, + netPrecision, + inputShape, + outputShape, + testValues.expected.dequantizationOnActivations, + refWeights, + testValues.expected.dequantizationAfter); + } + + static std::string getTestCaseName(testing::TestParamInfo obj) { + const auto netPrecision = std::get<0>(obj.param); + auto inputShape = std::get<1>(obj.param); + ConvolutionBackpropDataTransformationTestValues testValues = std::get<2>(obj.param); + + std::ostringstream result; + result << toString(testValues.params) << "_" << + netPrecision << "_" << + inputShape << "_" << + testValues.actual.precisionBeforeDequantization << "_" << + testValues.actual.dequantizationOnActivations << "_" << + testValues.actual.dequantizationOnWeights << "_" << + testValues.actual.fakeQuantizeOnWeights << "_" <<"_weights_" << + testValues.actual.weights->get_element_type() << "_" << "{ " << + testValues.actual.weights->cast_vector()[0] << " }_"; + return result.str(); + } +}; + +TEST_P(ConvolutionBackpropDataTransformation, 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 netPrecisions = { + element::f32, + element::f16 +}; + +const std::vector shapes = { + ngraph::Shape({ 1, 8, 16, 16 }) +}; + +const std::vector testValues = { + // with zero point + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, { 128.f }, { 0.02f }}, + { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {{}, { { 128.f }, ngraph::element::f32, {}, false }, {}}, + {}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 1, 1, 1, 1 }}}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ -125.f }), + true + } + }, + // updatePrecisions = false + { + LayerTransformation::createParamsU8I8().setUpdatePrecisions(false), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, { 128.f }, { 0.02f }}, + { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {{}, { { 128.f }, ngraph::element::f32, {}, false }, {}}, + {}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 1, 1, 1, 1 }}}, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -125.f }), + true + } + }, + // QDq version + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, { 128.f }, { 0.02f }}, + {{ngraph::element::f32}, { 2.f }, { 0.01f }}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {{}, { { 128.f }, ngraph::element::f32, {}, false }, {}}, + {{}, { { 2.f }, ngraph::element::f32, {1, 2, 1, 1}, true, 1ul, element::i8, false, { "DISABLED_CONSTANT_FOLDING" } }, {}}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 1 }}}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }), + true + } + }, + // without zero point + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, {}, { 0.02f }}, + { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {}, + {}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 1, 1, 1, 1 }}}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ -125.f }), + true + } + }, + // QDq version + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, {}, { 0.02f }}, + {{ngraph::element::f32}, {}, { 0.01f }}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {}, + {}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, {1}}}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }), + true + } + }, + // per-channel dequantization with the same values + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, {}, { std::vector{0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f} }}, + { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {}, + {}, + {{}, {}, {{ 0.0002f }, ngraph::element::f32, { 1, 1, 1, 1 }}}, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ -125.f }), + true + } + }, + // per-channel dequantization with different values + { + LayerTransformation::createParamsU8I8(), + // ActualValues + { + ngraph::element::u8, + {{ngraph::element::f32}, {}, { std::vector{0.02f, 0.01f, 0.02f, 0.01f, 0.02f, 0.01f, 0.02f, 0.01f} }}, + { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::i8, ngraph::Shape{}, std::vector{ 2.f }) + }, + // ExpectedValues + { + ngraph::element::u8, + {{ngraph::element::f32}, {}, { std::vector{0.02f, 0.01f, 0.02f, 0.01f, 0.02f, 0.01f, 0.02f, 0.01f} }}, + {}, + {}, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + true + } + }, +}; + +INSTANTIATE_TEST_CASE_P( + smoke_LPT, + ConvolutionBackpropDataTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(shapes), + ::testing::ValuesIn(testValues)), + ConvolutionBackpropDataTransformation::getTestCaseName); diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_qdq_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_qdq_transformation.cpp index c52606641c4..75b1d965e53 100644 --- a/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_qdq_transformation.cpp +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_qdq_transformation.cpp @@ -231,7 +231,7 @@ const std::vector testValues = { } }, - // Actual & Transformed: + // Actual: // // Parameter Constant Constant Constant // |U8 |U8 |FP32 |I8 @@ -246,6 +246,22 @@ const std::vector testValues = { // \FP32 /FP32 // \ / // Convolution + // + // Transformed: + // + // Parameter Constant + // |U8 |U8 + // | | + // Convert Convert + // \FP32 /FP32 + // \ / + // Subtract Constant + // \FP32 /FP32 + // \ / + // Multiply Constant + // \FP32 /FP32 + // \ / + // Convolution { LayerTransformation::createParamsU8I8().setSupportAsymmetricQuantization(true), // ActualValues @@ -262,8 +278,8 @@ const std::vector testValues = { { ngraph::element::u8, {{ngraph::element::f32}, { {127.f}, element::f32, {}, false, 1ul, element::u8, true }, { 0.02f }}, - {{ngraph::element::f32}, { {127.f}, element::f32, {}, false, 1ul, element::i8, true }, { 0.03f }}, - { std::vector{ 2.f }, ngraph::element::f32}, + {}, + { std::vector{ -3.75f }, ngraph::element::f32}, {}, ngraph::element::f32, {} @@ -434,12 +450,8 @@ const std::vector testValues = { { {1000.f}, element::f32, {}, false }, { {0.02f}, element::f32, {}, false } }, - { - { ngraph::element::f32, false }, - { {127.f}, element::f32, {}, false }, - { {0.03f}, element::f32, {}, false } - }, - { std::vector{ 2.f }, ngraph::element::i8}, + {}, + { std::vector{ -3.75f }, ngraph::element::f32}, {}, ngraph::element::f32, {} diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_transformation.cpp index 4ccbc8f412a..8c2d42dfbf3 100644 --- a/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_transformation.cpp +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/convolution_transformation.cpp @@ -160,8 +160,8 @@ const std::vector testValues = { { ngraph::element::u8, {{ ngraph::element::f32 }, { 128.f }, { 0.02f }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, ngraph::element::f32, {} } @@ -288,13 +288,13 @@ const std::vector testValues = { {{ 128.f, 0.f, 128.f }, ngraph::element::f32, { 1, 3, 1, 1 }}, {{ 0.02f, 0.01f, 0.03f }, ngraph::element::f32, {1, 3, 1, 1}} }, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, ngraph::element::f32, {} } }, - // dequantization in second dimension + // float input { LayerTransformation::createParamsU8I8(), // ActualValues @@ -316,8 +316,8 @@ const std::vector testValues = { {{ 128.f }, ngraph::element::f32, { 1, 1, 1, 1 }}, {{ 0.02f }, ngraph::element::f32, {1, 1, 1, 1}} }, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, ngraph::element::f32, {} } @@ -356,8 +356,8 @@ const std::vector testValues = { { ngraph::element::f32, {{}, {}, { {0.02f}, element::f32 }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, ngraph::element::f32, {} } @@ -396,8 +396,8 @@ const std::vector testValues = { { ngraph::element::u8, {{element::f32}, { 1000.f }, { {0.02f}, element::f32 }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, ngraph::element::f32, {} } diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/group_convolution_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/group_convolution_transformation.cpp index 7ba3252999e..d90999bb8cc 100644 --- a/inference-engine/tests/functional/inference_engine/lp_transformations/group_convolution_transformation.cpp +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/group_convolution_transformation.cpp @@ -160,8 +160,8 @@ const std::vector testValues = { { ngraph::element::u8, {{ ngraph::element::f32 }, { 128.f }, { 0.02f }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, {}, ngraph::element::f32, {} @@ -286,8 +286,8 @@ const std::vector testValues = { { ngraph::element::f32, {{}, {}, { 0.02f }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, {}, ngraph::element::f32, {} @@ -459,8 +459,8 @@ const std::vector testValues = { { ngraph::element::f32, {{}, {}, { 0.02f }}, - op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ 2.f }), - { 255ul, Shape({ 1, 1, 1, 1 }), { 0.f }, { 254.f }, { -1.27f }, { 1.27f } }, + op::Constant::create(ngraph::element::f32, ngraph::Shape{}, std::vector{ -1.25f }), + {}, {}, ngraph::element::f32, {} diff --git a/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp index afe15697f0b..51f60318f18 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp @@ -60,7 +60,7 @@ private: auto input = std::make_shared(ngraph::element::f32, input_shape); auto weights = ngraph::opset1::Constant::create(ngraph::element::f32, weights_shape, {1}); auto conv = std::make_shared(input, weights, ngraph::Strides(spatial_dims, 1), ngraph::Strides(spatial_dims, 1), - ngraph::CoordinateDiff(spatial_dims, 0), ngraph::CoordinateDiff(spatial_dims, 0)); + ngraph::CoordinateDiff(spatial_dims, 0), ngraph::CoordinateDiff(spatial_dims, 0), ngraph::element::f32); return std::make_shared(ngraph::NodeVector{conv}, ngraph::ParameterVector{input}); } diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp new file mode 100644 index 00000000000..64ce304a247 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/convolution_backprop_data_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams().setUpdatePrecisions(true), + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams().setUpdatePrecisions(false) +}; + +const std::vector params = { + // FQ on weights + // with zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { -127.f }, { 127.f }}, + "", + "" + }, + // without zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { 0.f }, { 25.4f }}, + "", + "" + }, + // with incorrect zero point on activations + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { 0.f }, { 25.4f }}, + "", + "" + }, + // with incorrect zero point on weights + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, + "", + "" + }, + // QDq on weights + // with zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {{ngraph::element::f32}, { {12.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // without zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, + {{ngraph::element::f32}, {}, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // with incorrect zero point on activations + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, + {{ngraph::element::f32}, { {12.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // with incorrect zero point on weights + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {{ngraph::element::f32}, { {1000.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + } +}; + +const std::vector inputShapes = { + { 1, 8, 16, 16 } +}; + +const std::vector outputShapes = { + { 16, 16 } +}; + +INSTANTIATE_TEST_CASE_P(smoke_LPT, ConvolutionBackpropDataTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(inputShapes), + ::testing::ValuesIn(outputShapes), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(params)), + ConvolutionBackpropDataTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp new file mode 100644 index 00000000000..d33e3c42f9e --- /dev/null +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/convolution_backprop_data_transformation.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/convolution_backprop_data_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32, + ngraph::element::f16 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams().setUpdatePrecisions(true), + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams().setUpdatePrecisions(false) +}; + +const std::vector params = { + // FQ on weights + // with zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { -127.f }, { 127.f }}, + "", + "" + }, + // without zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, + {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { 0.f }, { 25.4f }}, + "", + "" + }, + // TODO: check fails in CI +// // with incorrect zero point on activations +// { +// {256ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, +// {255ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 254.f }, { 0.f }, { 25.4f }}, +// "", +// "" +// }, +// // with incorrect zero point on weights +// { +// {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, +// {255ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, +// "", +// "" +// }, + // QDq on weights + // with zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {{ngraph::element::f32}, { {12.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // without zero point + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { 0.f }, { 25.5f }}, + {{ngraph::element::f32}, {}, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // with incorrect zero point on activations + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 5.f }, { 6.f }, { 5.f }, { 6.f }}, + {{ngraph::element::f32}, { {12.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + }, + // with incorrect zero point on weights + { + {256ul, ngraph::Shape{1, 1, 1, 1}, { 0.f }, { 255.f }, { -12.7f }, { 12.8f }}, + {{ngraph::element::f32}, { {1000.f}, ngraph::element::f32, {}, false }, { {4.f}, ngraph::element::f32, {}, false }}, + "", + "" + } +}; + +const std::vector inputShapes = { + { 1, 8, 16, 16 }, + { 1, 32, 16, 16 } +}; + +const std::vector outputShapes = { + { 16, 16 } +}; + +INSTANTIATE_TEST_CASE_P(smoke_LPT, ConvolutionBackpropDataTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(inputShapes), + ::testing::ValuesIn(outputShapes), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(params)), + ConvolutionBackpropDataTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/convolution_backprop_data_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/convolution_backprop_data_transformation.hpp new file mode 100644 index 00000000000..39d5ea58391 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/convolution_backprop_data_transformation.hpp @@ -0,0 +1,65 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + + +#include "shared_test_classes/base/low_precision_transformations/layer_transformation.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_weights.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" + +namespace LayerTestsDefinitions { + +class ConvolutionBackpropDataTransformationParam { +public: + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData; + ngraph::builder::subgraph::FakeQuantizeOnWeights fakeQuantizeOnWeights; + ngraph::builder::subgraph::DequantizationOperations dequantizationOnWeights; + std::string layerName; + std::string expectedKernelType; + + ConvolutionBackpropDataTransformationParam() = default; + ConvolutionBackpropDataTransformationParam( + const ngraph::builder::subgraph::FakeQuantizeOnData& fakeQuantizeOnData, + const ngraph::builder::subgraph::FakeQuantizeOnWeights& fakeQuantizeOnWeights, + std::string layerName, + std::string expectedKernelType) : + fakeQuantizeOnData(fakeQuantizeOnData), fakeQuantizeOnWeights(fakeQuantizeOnWeights), + layerName(std::move(layerName)), expectedKernelType(std::move(expectedKernelType)) {} + ConvolutionBackpropDataTransformationParam( + const ngraph::builder::subgraph::FakeQuantizeOnData& fakeQuantizeOnData, + ngraph::builder::subgraph::DequantizationOperations dequantizationOnWeights, + std::string layerName, + std::string expectedKernelType) : + fakeQuantizeOnData(fakeQuantizeOnData), dequantizationOnWeights(std::move(dequantizationOnWeights)), + layerName(std::move(layerName)), expectedKernelType(std::move(expectedKernelType)) {} +}; + +typedef std::tuple< + ngraph::element::Type, // netPrecision + ngraph::Shape, // inputShape + ngraph::Shape, // outputShape + std::string, // targetDevice + ngraph::pass::low_precision::LayerTransformation::Params, + ConvolutionBackpropDataTransformationParam +> ConvolutionBackpropDataTransformationParams; + +class ConvolutionBackpropDataTransformation : + public testing::WithParamInterface, + public LayerTestsUtils::LayerTransformation { +public: + static std::string getTestCaseName(testing::TestParamInfo obj); + +protected: + void SetUp() override; + + void Run() override; +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/convolution_backprop_data_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/convolution_backprop_data_transformation.cpp new file mode 100644 index 00000000000..951af4fdd4e --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/convolution_backprop_data_transformation.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision_transformations/convolution_backprop_data_transformation.hpp" + +#include +#include +#include + +#include "lpt_ngraph_functions/convolution_backprop_data_function.hpp" + +namespace LayerTestsDefinitions { + +std::string ConvolutionBackpropDataTransformation::getTestCaseName(testing::TestParamInfo obj) { + ngraph::element::Type netPrecision; + ngraph::Shape inputShape; + ngraph::Shape outputShape; + std::string targetDevice; + ngraph::pass::low_precision::LayerTransformation::Params params; + ConvolutionBackpropDataTransformationParam param; + std::tie(netPrecision, inputShape, outputShape, targetDevice, params, param) = obj.param; + + std::ostringstream result; + result << getTestCaseNameByParams(netPrecision, inputShape, targetDevice, params) << "_" << + outputShape << "_" << + param.fakeQuantizeOnData << "_" << + param.fakeQuantizeOnWeights << "_" << + param.dequantizationOnWeights; + return result.str(); +} + +void ConvolutionBackpropDataTransformation::SetUp() { + threshold = 0.1f; + + ngraph::element::Type netPrecision; + ngraph::Shape inputShape; + ngraph::Shape outputShape; + ngraph::pass::low_precision::LayerTransformation::Params params; + ConvolutionBackpropDataTransformationParam param; + std::tie(netPrecision, inputShape, outputShape, targetDevice, params, param) = this->GetParam(); + + std::shared_ptr weights; + + if (!param.fakeQuantizeOnWeights.empty()) { + weights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + ngraph::Shape{inputShape[1], inputShape[1] / 2, 1, 1}, + netPrecision, + param.fakeQuantizeOnWeights); + } else { + weights = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::getWeights( + ngraph::Shape{inputShape[1], inputShape[1] / 2, 1, 1}, + netPrecision, + param.dequantizationOnWeights); + } + + function = ngraph::builder::subgraph::ConvolutionBackpropDataFunction::get( + netPrecision, + inputShape, + outputShape, + param.fakeQuantizeOnData, + weights); +} + +void ConvolutionBackpropDataTransformation::Run() { + LayerTestsCommon::Run(); + + const auto params = std::get<5>(GetParam()); + const auto actualType = getRuntimePrecision(params.layerName); + EXPECT_EQ(actualType, params.expectedKernelType); +} + +TEST_P(ConvolutionBackpropDataTransformation, CompareWithRefImpl) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/convolution_backprop_data_function.hpp b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/convolution_backprop_data_function.hpp new file mode 100644 index 00000000000..fa05d7b3cb1 --- /dev/null +++ b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/convolution_backprop_data_function.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include "lpt_ngraph_functions/common/fake_quantize_on_weights.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +class ConvolutionBackpropDataFunction { +public: + static std::shared_ptr getWeights( + const Shape& shape, + const element::Type& netPrecision, + const builder::subgraph::DequantizationOperations& dequantizationOnWeights, + const std::shared_ptr& value = nullptr); + static std::shared_ptr getWeights( + const Shape& shape, + const element::Type& netPrecision, + const builder::subgraph::FakeQuantizeOnWeights& fqOnWeights, + const std::shared_ptr& value = nullptr); + static std::shared_ptr get( + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::FakeQuantizeOnData& fqOnData, + const std::shared_ptr& weights); + static std::shared_ptr getOriginal( + const element::Type precision, + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::DequantizationOperations& dequantization, + const std::shared_ptr& weights); + static std::shared_ptr getReference( + const element::Type precision, + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::DequantizationOperations& dequantization, + const std::shared_ptr& weights, + const builder::subgraph::DequantizationOperations& dequantizationAfter); +}; +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/convolution_backprop_data_function.cpp b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/convolution_backprop_data_function.cpp new file mode 100644 index 00000000000..ae7d3847f69 --- /dev/null +++ b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/convolution_backprop_data_function.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "lpt_ngraph_functions/convolution_backprop_data_function.hpp" + +#include +#include +#include "ngraph_functions/subgraph_builders.hpp" +#include "low_precision/network_helper.hpp" + +#include "lpt_ngraph_functions/common/fake_quantize_on_weights.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "lpt_ngraph_functions/common/builders.hpp" +#include "low_precision/common/dequantization_op.hpp" +#include "low_precision/network_helper.hpp" + +using namespace ngraph::pass::low_precision; + +namespace ngraph { +namespace builder { +namespace subgraph { + +std::shared_ptr ConvolutionBackpropDataFunction::get( + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::FakeQuantizeOnData& fqOnData, + const std::shared_ptr& weights) { + const auto input = std::make_shared(netPrecision, inputShape); + const auto fq = makeFakeQuantize(input, netPrecision, fqOnData); + + auto convolutionBackpropData = std::make_shared( + fq, + weights, + Strides{ 1, 1 }, + CoordinateDiff{ 0, 0 }, + CoordinateDiff{ 0, 0 }, + Strides{ 1, 1 }); + + ngraph::ResultVector results{ std::make_shared(convolutionBackpropData) }; + return std::make_shared(results, ParameterVector{ input }, "ConvolutionBackpropDataTransformation"); +} + +std::shared_ptr ConvolutionBackpropDataFunction::getWeights( + const Shape& shape, + const element::Type& netPrecision, + const builder::subgraph::FakeQuantizeOnWeights& fqOnWeights, + const std::shared_ptr& value) { + const auto weights = value != nullptr ? + value : + std::make_shared( + element::i8, + shape, + std::vector(shape_size(shape), 1)); + const auto convert = std::make_shared(weights, netPrecision); + OutputVector convertedOutput(1); + convert->constant_fold(convertedOutput, convert->input_values()); + const auto convertedWeights = convertedOutput[0].get_node_shared_ptr(); + const auto fq = makeFakeQuantize(convertedWeights, netPrecision, fqOnWeights); + + return fq; +} + +std::shared_ptr ConvolutionBackpropDataFunction::getWeights( + const Shape& shape, + const element::Type& netPrecision, + const builder::subgraph::DequantizationOperations& dequantizationOnWeights, + const std::shared_ptr& value) { + auto weights = + value != nullptr ? + value : + std::make_shared( + element::i8, + shape, + std::vector(shape_size(shape), 1)); + auto dequantizationStructure = dequantizationOnWeights; + dequantizationStructure.setPrecision(netPrecision); + if (!dequantizationOnWeights.subtract.constantPrecision.is_real()) { + dequantizationStructure.subtract.constantPrecision = dequantizationOnWeights.subtract.constantPrecision; + } + if (weights->get_element_type().is_real()) { + weights = as_type_ptr(fold(weights, netPrecision)); + } + const auto dq = makeDequantization(weights, dequantizationStructure); + + return dq; +} + +std::shared_ptr ConvolutionBackpropDataFunction::getOriginal( + const element::Type precision, + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::DequantizationOperations& dequantization, + const std::shared_ptr& weights) { + const auto input = std::make_shared(precision, inputShape); + auto dequantizationStructure = dequantization; + dequantizationStructure.multiply.outPrecision = netPrecision; + const auto activations = makeDequantization(input, dequantizationStructure); + + auto convolutionBackpropData = std::make_shared( + activations, + weights, + Strides{ 1, 1 }, + CoordinateDiff{ 0, 0 }, + CoordinateDiff{ 0, 0 }, + Strides{ 1, 1 }); + + convolutionBackpropData->set_friendly_name("output"); + ngraph::ResultVector results{ std::make_shared(convolutionBackpropData) }; + return std::make_shared(results, ParameterVector{ input }, "ConvolutionBackpropDataTransformation"); +} + +std::shared_ptr ConvolutionBackpropDataFunction::getReference( + const element::Type precision, + const element::Type netPrecision, + const Shape& inputShape, + const Shape& outputShape, + const builder::subgraph::DequantizationOperations& dequantization, + const std::shared_ptr& weights, + const builder::subgraph::DequantizationOperations& dequantizationAfter) { + const auto input = std::make_shared(precision, inputShape); + auto dequantizationStructure = dequantization; + dequantizationStructure.multiply.outPrecision = netPrecision; + const auto activations = makeDequantization(input, dequantizationStructure); + + auto convolutionBackpropData = std::make_shared>( + std::vector{ element::f32, element::f32 }, + std::vector{ dequantizationAfter.empty() ? netPrecision : element::f32 }, + ngraph::op::TemporaryReplaceOutputType(activations, element::f32).get(), + ngraph::op::TemporaryReplaceOutputType(weights, element::f32).get(), + Strides{ 1, 1 }, + CoordinateDiff{ 0, 0 }, + CoordinateDiff{ 0, 0 }, + Strides{ 1, 1 }); + + auto dequantizationStructureAfter = dequantizationAfter; + dequantizationStructureAfter.multiply.outPrecision = netPrecision; + const auto result = makeDequantization(convolutionBackpropData, dequantizationStructureAfter); + result->set_friendly_name("output"); + ngraph::ResultVector results{ std::make_shared(result) }; + return std::make_shared(results, ParameterVector{ input }, "ConvolutionBackpropDataTransformation"); +} + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/ngraph/core/include/ngraph/op/convolution.hpp b/ngraph/core/include/ngraph/op/convolution.hpp index c6516a5572a..72a365be533 100644 --- a/ngraph/core/include/ngraph/op/convolution.hpp +++ b/ngraph/core/include/ngraph/op/convolution.hpp @@ -86,8 +86,8 @@ namespace ngraph class NGRAPH_API ConvolutionBackpropData : public Op { public: - static constexpr NodeTypeInfo type_info{"ConvolutionBackpropData", 1}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + NGRAPH_RTTI_DECLARATION; + /// \brief Constructs a batched-convolution data batch-backprop operation. ConvolutionBackpropData() = default; // clang-format off diff --git a/ngraph/core/include/ngraph/op/group_conv.hpp b/ngraph/core/include/ngraph/op/group_conv.hpp index 3c175b51297..ebda0392d96 100644 --- a/ngraph/core/include/ngraph/op/group_conv.hpp +++ b/ngraph/core/include/ngraph/op/group_conv.hpp @@ -85,8 +85,8 @@ namespace ngraph class NGRAPH_API GroupConvolutionBackpropData : public Op { public: - static constexpr NodeTypeInfo type_info{"GroupConvolutionBackpropData", 1}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + NGRAPH_RTTI_DECLARATION; + /// \brief Constructs a batched-convolution data batch-backprop operation. GroupConvolutionBackpropData(); // clang-format off diff --git a/ngraph/core/src/op/convolution.cpp b/ngraph/core/src/op/convolution.cpp index 667fa933046..6be59d5132e 100644 --- a/ngraph/core/src/op/convolution.cpp +++ b/ngraph/core/src/op/convolution.cpp @@ -102,12 +102,14 @@ shared_ptr op::v1::Convolution::clone_with_new_inputs(const OutputVector& m_auto_pad); } -constexpr NodeTypeInfo op::v1::ConvolutionBackpropData::type_info; shared_ptr op::v1::Convolution::get_default_value() const { return ngraph::make_constant_from_string("0", get_element_type(), get_shape()); } +// *** ConvolutionBackpropData OP SET 1 *** +NGRAPH_RTTI_DEFINITION(op::v1::ConvolutionBackpropData, "ConvolutionBackpropData", 1); + op::v1::ConvolutionBackpropData::ConvolutionBackpropData(const Output& data, const Output& filters, const Output& output_shape, diff --git a/ngraph/core/src/op/group_conv.cpp b/ngraph/core/src/op/group_conv.cpp index 4efbcae117e..b9d7cc4be10 100644 --- a/ngraph/core/src/op/group_conv.cpp +++ b/ngraph/core/src/op/group_conv.cpp @@ -286,7 +286,7 @@ shared_ptr op::v1::GroupConvolution::clone_with_new_inputs(const OutputVec // v1::GroupConvolutionBackpropData //------------------------------------------------------------------------------ -constexpr NodeTypeInfo op::v1::GroupConvolutionBackpropData::type_info; +NGRAPH_RTTI_DEFINITION(op::v1::GroupConvolutionBackpropData, "GroupConvolutionBackpropData", 1); op::v1::GroupConvolutionBackpropData::GroupConvolutionBackpropData() : Op()