From 57da5ddab857b5c5c3f4872bb97cb96d32eb76e6 Mon Sep 17 00:00:00 2001 From: Edward Shogulin Date: Wed, 27 May 2020 21:53:50 +0300 Subject: [PATCH] [LPT] Concat complex graph support (#527) * [LPT] [Tests] LowPrecisionTransformations base test extending * [LPT] Concat complex (neighbor) graph support * [LPT] Multichannel concat: scale per channel support * [LPT] test improvements * [TEST] tests infrastructure improvements --- .../low_precision_transformations/concat.hpp | 24 +- .../concat_multi_channels.hpp | 20 +- .../network_helper.hpp | 17 + .../src/concat.cpp | 352 +++++------------ .../src/concat_multi_channels.cpp | 354 +++++------------- .../src/network_helper.cpp | 127 +++++++ ...oncat_neighboring_graph_transformation.cpp | 32 ++ .../concat_transformation.cpp | 10 +- ...oncat_with_intermediate_transformation.cpp | 37 ++ ...oncat_neighboring_graph_transformation.cpp | 29 ++ .../concat_transformation.cpp | 11 +- ...oncat_with_intermediate_transformation.cpp | 34 ++ ...oncat_neighboring_graph_transformation.hpp | 26 ++ .../concat_transformation.hpp | 5 +- ...oncat_with_intermediate_transformation.hpp | 32 ++ ...oncat_neighboring_graph_transformation.cpp | 146 ++++++++ .../concat_transformation.cpp | 49 +-- ...oncat_with_intermediate_transformation.cpp | 194 ++++++++++ .../common_test_utils/data_utils.hpp | 22 +- .../functional_test_utils/blob_utils.hpp | 30 +- .../layer_test_utils.cpp | 6 +- .../layer_test_utils.hpp | 4 +- .../layer_transformation.cpp | 99 +++-- .../layer_transformation.hpp | 77 +++- 24 files changed, 1092 insertions(+), 645 deletions(-) create mode 100644 inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_neighboring_graph_transformation.hpp create mode 100644 inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_with_intermediate_transformation.hpp create mode 100644 inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_neighboring_graph_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_with_intermediate_transformation.cpp diff --git a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat.hpp b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat.hpp index a5865f839..7dc29da5d 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat.hpp @@ -8,6 +8,8 @@ #include #include #include + +#include "low_precision_transformations/network_helper.hpp" #include "low_precision_transformations/layer_transformation.hpp" namespace InferenceEngine { @@ -20,25 +22,15 @@ public: ConcatTransformation(const Params& params) : LayerTransformation(params) {} ~ConcatTransformation() override {}; void transform(TransformationContext& context, CNNLayer& layer) const override; - static bool getQuantizeLayers( - CNNLayerPtr layer, - std::vector& childNameOurAfterQuantizeLayers, - std::vector& quantizeLayers, - std::vector>>& intermediateLayers, - std::vector& concatLayers, - CNNLayerPtr child, - std::vector& sideOutputLayers, - std::vector& childrenNameSideOutputLayers); protected: - void addDequantizationForQuantize( + void addDequantizationLayers( TransformationContext& context, - const CNNLayer& concat, - const std::vector& quantizeLayers, - const std::vector>>& intermediateLayers, - const std::vector& childNameOurAfterQuantizeLayers, - const std::unordered_map>& dequantizationScalesLayers, - const std::unordered_map>& dequantizationShiftsLayers) const; + Subgraph& subgraph, + std::function& dequantizationScales, + std::vector& dequantizationShifts)> getLayerDequantizationCallback) const; private: size_t getMinQuantizationLevels( diff --git a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat_multi_channels.hpp b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat_multi_channels.hpp index f12dbfe71..de7468a91 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat_multi_channels.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/concat_multi_channels.hpp @@ -16,20 +16,20 @@ namespace details { IE_SUPPRESS_DEPRECATED_START class INFERENCE_ENGINE_API_CLASS(ConcatMultiChannelsTransformation) : public ConcatTransformation { -private: public: ConcatMultiChannelsTransformation(const Params& params) : ConcatTransformation(params) {} ~ConcatMultiChannelsTransformation() override {}; void transform(TransformationContext& context, CNNLayer& layer) const override; - static bool getQuantizeLayers( - CNNLayerPtr layer, - std::vector& childNameOurAfterQuantizeLayers, - std::vector& quantizeLayers, - std::vector > >& intermediateLayers, - std::vector& concatLayers, - CNNLayerPtr child, - std::vector& sideOutputLayers, - std::vector& childrenNameSideOutputLayers); + +private: + static void fillDequantization( + const CNNLayer& layer, + const std::unordered_map>& dequantizationScalesLayers, + const std::unordered_map>& dequantizationShiftsLayers, + std::vector& dequantizationScales, + std::vector& dequantizationShifts); + + static void fillQuantization(const CNNLayer& layer, std::vector& fakeQuantizes); }; IE_SUPPRESS_DEPRECATED_END diff --git a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/network_helper.hpp b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/network_helper.hpp index 87254086d..9d87a1dfd 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision_transformations/network_helper.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision_transformations/network_helper.hpp @@ -21,11 +21,28 @@ namespace details { IE_SUPPRESS_DEPRECATED_START +class INFERENCE_ENGINE_API_CLASS(Subgraph) { +public: + bool fillSubgraphForConcat(const CNNLayerPtr& concat, std::unordered_set& handledLayers); + bool empty() const; + + std::vector quantizationLayers; + std::vector concatLayers; + std::unordered_map layers; + +private: + bool fillSubgraphForQuantization(const CNNLayerPtr& fakeQuantize, std::unordered_set& handledLayers); + bool fillSubgraphForIntermediate(const CNNLayerPtr& intermediate, std::unordered_set& handledLayers); + bool fill(const CNNLayerPtr& concat, std::unordered_set& handledLayers); +}; + /** * @brief CNNNetworkHelper class encapsulates manipulations with CNN Network. */ class INFERENCE_ENGINE_API_CLASS(CNNNetworkHelper) { public: + static Subgraph getSubgraph(const CNNLayer& concat); + static CNNLayerPtr getLayer(const ICNNNetwork& network, const std::string& layerName); static Blob::Ptr makeNewBlobPtr(const TensorDesc& desc); diff --git a/inference-engine/src/low_precision_transformations/src/concat.cpp b/inference-engine/src/low_precision_transformations/src/concat.cpp index 833b43e24..418dc5283 100644 --- a/inference-engine/src/low_precision_transformations/src/concat.cpp +++ b/inference-engine/src/low_precision_transformations/src/concat.cpp @@ -21,67 +21,11 @@ #include "ie_util_internal.hpp" #include "low_precision_transformations/common/ie_lpt_exception.hpp" -#include "low_precision_transformations/network_helper.hpp" #include "low_precision_transformations/quantization_details.hpp" using namespace InferenceEngine; using namespace InferenceEngine::details; -bool ConcatTransformation::getQuantizeLayers( - CNNLayerPtr layer, - std::vector& childNameOurAfterQuantizeLayers, - std::vector& quantizeLayers, - std::vector>>& intermediateLayers, - std::vector& concatLayers, - CNNLayerPtr child, - std::vector& sideOutputLayers, - std::vector& childrenNameSideOutputLayers) { - if (!CaselessEq()(layer->type, "FakeQuantize") && - !CaselessEq()(layer->type, "Quantize")) { - do { - if (CaselessEq()(layer->type, "Pooling") || CaselessEq()(layer->type, "Resample")) { - intermediateLayers.back().push_back(std::pair( - layer, - concatLayers.empty() ? child : concatLayers.back())); - child = layer; - layer = CNNNetworkHelper::getParent(*layer, 0); - } else if (CaselessEq()(layer->type, "Concat")) { - concatLayers.push_back(layer); - - if (layer->outData[0]->getInputTo().size() != 1) { - sideOutputLayers.push_back(layer); - childrenNameSideOutputLayers.push_back(child->name); - } - int size = layer->insData.size(); - child = layer; - for (int i = 0; i < size; i++) { - CNNLayerPtr layer1 = CNNNetworkHelper::getParent(*layer, i); - intermediateLayers.push_back({}); - if (!getQuantizeLayers( - layer1, - childNameOurAfterQuantizeLayers, - quantizeLayers, - intermediateLayers, - concatLayers, - child, - sideOutputLayers, - childrenNameSideOutputLayers)) { - return false; - } - } - return true; - } else { - return false; - } - } while (!CaselessEq()(layer->type, "FakeQuantize") && - !CaselessEq()(layer->type, "Quantize")); - } - - childNameOurAfterQuantizeLayers.push_back(child->name); - quantizeLayers.push_back(layer); - return true; -} - void ConcatTransformation::transform(TransformationContext& context, CNNLayer& concat) const { if (!canBeTransformed(context, concat)) { return; @@ -99,60 +43,31 @@ void ConcatTransformation::transform(TransformationContext& context, CNNLayer& c THROW_IE_EXCEPTION << "layer inputs '" << concat.insData.size() << "' is not correct"; } - std::vector children = CNNNetworkHelper::getChildren(concat); - if (CNNNetworkHelper::IsChild(children, { "Concat" }, { "Pooling", "Resample" })) { + Subgraph subgraph = CNNNetworkHelper::getSubgraph(concat); + if (subgraph.empty()) { return; } - std::vector quantizeLayers; - std::vector>> intermediateLayers; - std::vector concatLayers; - const auto inputDataNumber = concat.insData.size(); - std::vector childNameOurAfterQuantizeLayers; - std::vector quantizationLayersDetails; - std::vector sideOutputLayers; - std::vector childrenNameSideOutputLayers; - for (size_t index = 0lu; index < inputDataNumber; index++) { - DataPtr quantizeOnData = concat.insData[index].lock(); - if (quantizeOnData == nullptr) { - THROW_IE_EXCEPTION << "input is absent"; - } - auto parentLayer = quantizeOnData->getCreatorLayer().lock(); - intermediateLayers.push_back({}); - if (!getQuantizeLayers( - parentLayer, - childNameOurAfterQuantizeLayers, - quantizeLayers, - intermediateLayers, - concatLayers, - std::make_shared(concat), - sideOutputLayers, - childrenNameSideOutputLayers)) { + for (const CNNLayerPtr& quantizationLayer : subgraph.quantizationLayers) { + if (context.quantizedFakeQuantizeNames.find(quantizationLayer->name) != context.quantizedFakeQuantizeNames.end()) { return; } } - if (quantizeLayers.empty()) { - return; - } - - for (const CNNLayerPtr& quantizeLayer : quantizeLayers) { - if (!QuantizationDetails::outputLayoutIsSupported(*quantizeLayer)) { - return; - } - } - - DataPrecision dataPrecision = getDataPrecision(*quantizeLayers[0], QuantizationDetails::getDetails(*quantizeLayers[0]), false, false); + DataPrecision dataPrecision = getDataPrecision( + *subgraph.quantizationLayers[0], + QuantizationDetails::getDetails(*subgraph.quantizationLayers[0]), false, false); if (dataPrecision.precision == Precision::UNSPECIFIED) { return; } - const QuantizationDetails& quantizationDetails1 = QuantizationDetails::getDetails(*quantizeLayers[0]); - const QuantizationDetails& quantizationDetails2 = QuantizationDetails::getDetails(*quantizeLayers[1]); + // TODO: FQ output I8 but Convolution U8 before <- we should handle that avoid asymmetric quantization + + std::vector quantizationLayersDetails; size_t quantizationLevels = 0lu; - for (int i = 0; i < quantizeLayers.size(); i++) { - const QuantizationDetails& quantizationDetails = QuantizationDetails::getDetails(*quantizeLayers[i]); + for (int i = 0; i < subgraph.quantizationLayers.size(); i++) { + const QuantizationDetails& quantizationDetails = QuantizationDetails::getDetails(*subgraph.quantizationLayers[i]); if (!QuantizationDetails::isSupportedLevel(quantizationDetails.levels)) continue; if (quantizationLevels == 0lu) { quantizationLevels = quantizationDetails.levels; @@ -162,7 +77,7 @@ void ConcatTransformation::transform(TransformationContext& context, CNNLayer& c quantizationLayersDetails.push_back(quantizationDetails); - const DataPrecision dataPrecision2 = getDataPrecision(*quantizeLayers[i], quantizationDetails, false, false); + const DataPrecision dataPrecision2 = getDataPrecision(*subgraph.quantizationLayers[i], quantizationDetails, false, false); if (dataPrecision2.precision == Precision::UNSPECIFIED) { return; } @@ -183,26 +98,21 @@ void ConcatTransformation::transform(TransformationContext& context, CNNLayer& c return; } - std::vector dequantizationScales; - std::vector dequantizationShifts; - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(concat); - dequantizationScales.resize(outputChannelsCount); - dequantizationShifts.resize(outputChannelsCount); - const auto parentsCount = quantizeLayers.size(); - - std::unordered_map> dequantizationScalesLayers; - std::unordered_map> dequantizationShiftsLayers; + float dequantizationScale; + float dequantizationShift; if ((quantizationLayersDetails[0].inputHighValues.size() == 1)) { float outputLowValue = quantizationLayersDetails[0].outputLowValues[0]; float outputHighValue = quantizationLayersDetails[0].outputHighValues[0]; - for (size_t index = 0lu; index < parentsCount; index++) { - if (outputLowValue > quantizationLayersDetails[index].outputLowValues[0]) { - outputLowValue = quantizationLayersDetails[index].outputLowValues[0]; + + for (size_t index = 0lu; index < subgraph.quantizationLayers.size(); index++) { + const QuantizationDetails& quantizationDetails = quantizationLayersDetails[index]; + if (outputLowValue > quantizationDetails.outputLowValues[0]) { + outputLowValue = quantizationDetails.outputLowValues[0]; } - if (outputHighValue < quantizationLayersDetails[index].outputHighValues[0]) { - outputHighValue = quantizationLayersDetails[index].outputHighValues[0]; + if (outputHighValue < quantizationDetails.outputHighValues[0]) { + outputHighValue = quantizationDetails.outputHighValues[0]; } } @@ -224,19 +134,17 @@ void ConcatTransformation::transform(TransformationContext& context, CNNLayer& c } - const float dequantizationScale = maxOutputInterval / (dataPrecision.max - dataPrecision.min); + dequantizationScale = maxOutputInterval / (dataPrecision.max - dataPrecision.min); const float max = maxOutputInterval / ((dataPrecision.max - dataPrecision.min) / dataPrecision.max); const float min = maxOutputInterval / ((dataPrecision.max - dataPrecision.min) / dataPrecision.min); - const float dequantizationShift = outputLowValue - min; + dequantizationShift = outputLowValue - min; const float quantizationScale = 1.f / dequantizationScale; const float quantizationShift = - dequantizationShift * quantizationScale; - for (int index = 0; index < parentsCount; index++) { - if (quantizeLayers[index] == nullptr) - continue; - CNNLayer& fakeQuantizeLayer = *quantizeLayers[index]; - const QuantizationDetails quantizationDetails = quantizationLayersDetails[index]; + for (int index = 0; index < subgraph.quantizationLayers.size(); index++) { + CNNLayer& fakeQuantizeLayer = *subgraph.quantizationLayers[index]; + const QuantizationDetails& quantizationDetails = quantizationLayersDetails[index]; switch (quantizedTensorAlignmentOnActivations) { case QuantizedTensorAlignment::None: { @@ -285,172 +193,84 @@ void ConcatTransformation::transform(TransformationContext& context, CNNLayer& c THROW_IE_EXCEPTION << "unexpected value " << quantizedTensorAlignmentOnActivations; } } - - if (updatePrecisions) { - CNNNetworkHelper::setOutDataPrecision(fakeQuantizeLayer, dataPrecision.precision); - } - - const size_t fakeQuantizeOutputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(fakeQuantizeLayer); - - const std::vector fakeQuantizeDequantizationScales(fakeQuantizeOutputChannelsCount, dequantizationScale); - dequantizationScalesLayers[fakeQuantizeLayer.name] = fakeQuantizeDequantizationScales; - - const std::vector fakeQuantizeDequantizationShifts(fakeQuantizeOutputChannelsCount, dequantizationShift); - dequantizationShiftsLayers[fakeQuantizeLayer.name] = fakeQuantizeDequantizationShifts; } - - dequantizationScales.resize(outputChannelsCount); - std::fill(dequantizationScales.begin(), dequantizationScales.end(), dequantizationScale); - - dequantizationShifts.resize(outputChannelsCount); - std::fill(dequantizationShifts.begin(), dequantizationShifts.end(), dequantizationShift); } else { return; } - addDequantizationForQuantize( - context, - concat, - quantizeLayers, - intermediateLayers, - childNameOurAfterQuantizeLayers, - dequantizationScalesLayers, - dequantizationShiftsLayers); - if (updatePrecisions) { - for (const std::vector>& intermediateLayersList : intermediateLayers) { - for (const std::pair& pair : intermediateLayersList) { - CNNLayerPtr intermediateLayer = pair.first; - CNNNetworkHelper::setOutDataPrecision(*intermediateLayer, dataPrecision.precision); - } - } - - CNNNetworkHelper::setOutDataPrecision(concat, dataPrecision.precision); - for (const CNNLayerPtr& concatLayer : concatLayers) { - // TODO: check if the same precision is used: U8 or S8 for all concat layers - CNNNetworkHelper::setOutDataPrecision(*concatLayer, dataPrecision.precision); + for (const auto it : subgraph.layers) { + const CNNLayer* layer = it.second; + CNNNetworkHelper::setOutDataPrecision(*layer, dataPrecision.precision); } } - // Add scaleshift at outputs of our layers - children = CNNNetworkHelper::getChildren(concat); - if (children.size() == 0) { - const std::string originalName = concat.name; - CNNNetworkHelper::renameLayer(context.network, concat.name, concat.name + LayerTransformation::lastLayerPrefix); - - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(concat), - nullptr, - DequantizationDetails(dequantizationScales, dequantizationShifts, outputChannelsCount), originalName); - context.dequantizationLayersNames.insert(dequantizationLayer->name); - } else { - for (const CNNLayerPtr& child : children) { - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(concat), - child, - DequantizationDetails(dequantizationScales, dequantizationShifts, outputChannelsCount)); - context.dequantizationLayersNames.insert(dequantizationLayer->name); - } - } + auto dequantizationValuesCallback = [&]( + const CNNLayer& layer, + std::vector& layerDequantizationScales, + std::vector& layerDequantizationShifts + ) { + const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(layer); - // Add scaleshift at outputs of side branches - for (int index = 0; index < sideOutputLayers.size(); index++) { - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(*sideOutputLayers[index]); - std::vector children = CNNNetworkHelper::getChildren(*sideOutputLayers[index], childrenNameSideOutputLayers[index]); - for (int i = 0; i < children.size(); i++) { - std::vector dequantizationScales1(outputChannelsCount, dequantizationScales[0]); - std::vector dequantizationShifts1(outputChannelsCount, dequantizationShifts[0]); - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(*sideOutputLayers[index]), - children[i], - DequantizationDetails(dequantizationScales1, dequantizationShifts1, outputChannelsCount)); - context.dequantizationLayersNames.insert(dequantizationLayer->name); - } - } -} + layerDequantizationScales.resize(outputChannelsCount); + std::fill(layerDequantizationScales.begin(), layerDequantizationScales.end(), dequantizationScale); -void ConcatTransformation::addDequantizationForQuantize( - TransformationContext& context, - const CNNLayer& concat, - const std::vector& quantizeLayers, - const std::vector>>& intermediateLayers, - const std::vector& childNameOurAfterQuantizeLayers, - const std::unordered_map>& dequantizationScalesLayers, - const std::unordered_map>& dequantizationShiftsLayers) const { - const size_t parentsCount = quantizeLayers.size(); - for (int index = 0; index < parentsCount; index++) { - CNNLayer& fakeQuantize = *quantizeLayers[index]; - context.quantizedFakeQuantizeNames.insert(quantizeLayers[index]->name); - if (quantizeLayers[index]->outData[0]->getInputTo().size() != 1) { - std::vector children = CNNNetworkHelper::getChildren(*quantizeLayers[index], childNameOurAfterQuantizeLayers[index]); - - for (int i = 0; i < children.size(); i++) { - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(*quantizeLayers[index]); - - auto dequantizationScalesIt = dequantizationScalesLayers.find(fakeQuantize.name); - if (dequantizationScalesIt == dequantizationScalesLayers.end()) { - THROW_IE_EXCEPTION << "dequantization scales not found for layer " << fakeQuantize.name; - } + layerDequantizationShifts.resize(outputChannelsCount); + std::fill(layerDequantizationShifts.begin(), layerDequantizationShifts.end(), dequantizationShift); + }; - auto dequantizationShiftIt = dequantizationShiftsLayers.find(fakeQuantize.name); - if (dequantizationShiftIt == dequantizationShiftsLayers.end()) { - THROW_IE_EXCEPTION << "dequantization shifts not found for layer " << fakeQuantize.name; - } + addDequantizationLayers(context, subgraph, dequantizationValuesCallback); - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(*quantizeLayers[index]), - children[i], - DequantizationDetails(dequantizationScalesIt->second, dequantizationShiftIt->second, outputChannelsCount)); - context.dequantizationLayersNames.insert(dequantizationLayer->name); - } - } + for (const CNNLayerPtr& quantizationLayer : subgraph.quantizationLayers) { + context.quantizedFakeQuantizeNames.insert(quantizationLayer->name); } +} - for (const std::vector>& intermediateLayersList : intermediateLayers) { - for (auto it = intermediateLayersList.rbegin(); it != intermediateLayersList.rend(); ++it) { - const std::pair intermediateLayerPair = *it; - const CNNLayerPtr intermediateLayer = intermediateLayerPair.first; - const CNNLayerPtr concatLayer = intermediateLayerPair.second; - - const CNNLayerPtr nextIntermediateLayer = (it + 1) != intermediateLayersList.rend() ? (*(it + 1)).first : concatLayer; - const std::vector children = CNNNetworkHelper::getChildren(*intermediateLayer, nextIntermediateLayer->name); - if (!children.empty()) { - CNNLayerPtr layer = intermediateLayer; - while (layer->type != "FakeQuantize") { - std::vector parents = CNNNetworkHelper::getParents(*layer); - if (parents.empty()) { - THROW_IE_LPT_EXCEPTION(*intermediateLayer) << "intermediate layer doesn't have parents"; - } - if (parents.size() > 1ul) { - THROW_IE_LPT_EXCEPTION(*intermediateLayer) << "intermediate layer has several parents"; - } - - layer = parents[0]; - } - const CNNLayerPtr fakeQuantize = layer; - - for (int childIndex = 0; childIndex < children.size(); childIndex++) { - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(*intermediateLayer); - - const auto dequantizationScalesIt = dequantizationScalesLayers.find(fakeQuantize->name); - if (dequantizationScalesIt == dequantizationScalesLayers.end()) { - THROW_IE_EXCEPTION << "dequantization scales not found for layer " << fakeQuantize->name; - } +void ConcatTransformation::addDequantizationLayers( + TransformationContext& context, + Subgraph& subgraph, + std::function& dequantizationScales, + std::vector& dequantizationShifts)> getLayerDequantizationCallback) const { + std::unordered_map notHandledSubgraphLayers = subgraph.layers; + while (notHandledSubgraphLayers.size() != 0ul) { + const auto it = notHandledSubgraphLayers.begin(); + CNNLayer* layer = it->second; + notHandledSubgraphLayers.erase(it); + + const std::vector& children = CNNNetworkHelper::getChildren(*layer); + if (children.size() == 0) { + const std::string originalName = layer->name; + const std::string newName = layer->name + LayerTransformation::lastLayerPrefix; + CNNNetworkHelper::renameLayer(context.network, originalName, newName); + layer->name = newName; + subgraph.layers[layer->name] = layer; + + std::vector layerDequantizationScales; + std::vector layerDequantizationShifts; + getLayerDequantizationCallback(*layer, layerDequantizationScales, layerDequantizationShifts); - const auto dequantizationShiftIt = dequantizationShiftsLayers.find(fakeQuantize->name); - if (dequantizationShiftIt == dequantizationShiftsLayers.end()) { - THROW_IE_EXCEPTION << "dequantization shifts not found for layer " << fakeQuantize->name; - } + CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( + context, + std::make_shared(*layer), + nullptr, + DequantizationDetails(layerDequantizationScales, layerDequantizationShifts, layerDequantizationScales.size()), + originalName); + context.dequantizationLayersNames.insert(dequantizationLayer->name); + subgraph.layers[dequantizationLayer->name] = dequantizationLayer.get(); + } else { + for (const CNNLayerPtr& child : children) { + if (subgraph.layers.find(child->name) == subgraph.layers.end()) { + std::vector layerDequantizationScales; + std::vector layerDequantizationShifts; + getLayerDequantizationCallback(*layer, layerDequantizationScales, layerDequantizationShifts); CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( context, - intermediateLayer, - children[childIndex], - DequantizationDetails(dequantizationScalesIt->second, dequantizationShiftIt->second, outputChannelsCount)); + std::make_shared(*layer), + child, + DequantizationDetails(layerDequantizationScales, layerDequantizationShifts, layerDequantizationScales.size())); context.dequantizationLayersNames.insert(dequantizationLayer->name); } } 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 db5d47db7..ffad5f900 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,50 +27,6 @@ using namespace InferenceEngine; using namespace InferenceEngine::details; -size_t getQuantizationLevel(const std::vector& fakeQuantizeLayers) { - size_t quantizationLevels = 0lu; - for (int i = 0; i < fakeQuantizeLayers.size(); i++) { - const CNNLayerPtr fakeQuantizeLayer = fakeQuantizeLayers[i]; - if (fakeQuantizeLayer->type != "FakeQuantize") { - THROW_IE_EXCEPTION << "not expected layer type " << fakeQuantizeLayer->type; - } - - const QuantizationDetails& quantizationDetails = QuantizationDetails::getDetails(*fakeQuantizeLayer); - if (!QuantizationDetails::isSupportedLevel(quantizationDetails.levels)) { - continue; - } - if (quantizationLevels == 0lu) { - quantizationLevels = quantizationDetails.levels; - } else if (quantizationLevels != quantizationDetails.levels) { - THROW_IE_EXCEPTION << "different quantization levels " << quantizationLevels << " are not supported"; - } - } - - return quantizationLevels; -} - -bool isCascade(const std::vector& concatLayers) { - for (size_t index = 0ul; index < (concatLayers.size() - 1); ++index) { - const CNNLayerPtr childConcatLayer = concatLayers[index]; - const CNNLayerPtr parentConcatLayer = concatLayers[index + 1]; - std::vector parents = - CNNNetworkHelper::getParentsRecursivelyExceptTypes(*childConcatLayer, {"Pooling", "Resample"}); - - bool parentConcatLayerWasFound = false; - for (const CNNLayerPtr& parent : parents) { - if (parent->name == parentConcatLayer->name) { - parentConcatLayerWasFound = true; - break; - } - } - - if (!parentConcatLayerWasFound) { - return false; - } - } - return true; -} - bool isMultiChannel(const std::vector& concatLayers) { for (const CNNLayerPtr& concat : concatLayers) { const std::vector children = CNNNetworkHelper::getChildrenRecursivelyExceptTypes(*concat, {"Pooling", "Resample"}); @@ -81,72 +37,6 @@ bool isMultiChannel(const std::vector& concatLayers) { return true; } -bool ConcatMultiChannelsTransformation::getQuantizeLayers( - CNNLayerPtr layer, - std::vector& childNameOurAfterQuantizeLayers, - std::vector& quantizeLayers, - std::vector > > &intermediateLayers, - std::vector& concatLayers, - CNNLayerPtr child, - std::vector& sideOutputLayers, - std::vector& childrenNameSideOutputLayers) { - if (!CaselessEq()(layer->type, "FakeQuantize") && - !CaselessEq()(layer->type, "Quantize")) { - do { - if ((CaselessEq()(layer->type, "Pooling")) || (CaselessEq()(layer->type, "Resample"))) { - intermediateLayers.back().push_back(std::pair( - layer, - concatLayers.empty() ? child : concatLayers.back())); - std::vector children = CNNNetworkHelper::getChildrenRecursivelyExceptTypes(*layer, {"Pooling", "Resample"}); - CNNLayerPtr concat; - for (const CNNLayerPtr& child : children) { - if (child->type == "Concat") { - if (concat != nullptr) { - THROW_IE_EXCEPTION << "several concat children layers are not supported"; - } - concat = child; - } - } - - child = concat; - layer = CNNNetworkHelper::getParent(*layer, 0); - } else if (CaselessEq()(layer->type, "Concat")) { - concatLayers.push_back(layer); - - if (layer->outData[0]->getInputTo().size() != 1) { - sideOutputLayers.push_back(layer); - childrenNameSideOutputLayers.push_back(child->name); - } - int size = layer->insData.size(); - child = layer; - for (int i = 0; i < size; i++) { - CNNLayerPtr layer1 = CNNNetworkHelper::getParent(*layer, i); - intermediateLayers.push_back({}); - if (!getQuantizeLayers( - layer1, - childNameOurAfterQuantizeLayers, - quantizeLayers, - intermediateLayers, - concatLayers, - child, - sideOutputLayers, - childrenNameSideOutputLayers)) { - return false; - } - } - return true; - } else { - return false; - } - } while (!CaselessEq()(layer->type, "FakeQuantize") && - !CaselessEq()(layer->type, "Quantize")); - } - - childNameOurAfterQuantizeLayers.push_back(child->name); - quantizeLayers.push_back(layer); - return true; -} - void ConcatMultiChannelsTransformation::transform(TransformationContext& context, CNNLayer& concat) const { if (!canBeTransformed(context, concat)) { return; @@ -164,201 +54,129 @@ void ConcatMultiChannelsTransformation::transform(TransformationContext& context return; } - std::vector children = CNNNetworkHelper::getChildren(concat); - if (CNNNetworkHelper::IsChild(children, {"Concat"}, {"Pooling", "Resample"})) { + Subgraph subgraph = CNNNetworkHelper::getSubgraph(concat); + if (subgraph.empty()) { return; } - std::vector quantizeLayers; - std::vector > > intermediateLayers; - std::vector concatLayers; - std::vector childNameOurAfterQuantizeLayers; - std::vector sideOutputLayers; - std::vector childrenNameSideOutputLayers; - const auto inputDataNumber = concat.insData.size(); - for (size_t index = 0lu; index < inputDataNumber; index++) { - DataPtr quantizeOnData = concat.insData[index].lock(); - if (quantizeOnData == nullptr) { - THROW_IE_EXCEPTION << "input is absent"; - } - auto parentLayer = quantizeOnData->getCreatorLayer().lock(); - intermediateLayers.push_back({}); - if (!getQuantizeLayers( - parentLayer, - childNameOurAfterQuantizeLayers, - quantizeLayers, - intermediateLayers, - concatLayers, - std::make_shared(concat), - sideOutputLayers, - childrenNameSideOutputLayers)) { + for (const CNNLayerPtr& quantizationLayer : subgraph.quantizationLayers) { + if (context.quantizedFakeQuantizeNames.find(quantizationLayer->name) != context.quantizedFakeQuantizeNames.end()) { return; } } - concatLayers.insert(concatLayers.begin(), std::make_shared(concat)); - if (quantizeLayers.empty()) { - return; - } - - for (const CNNLayerPtr& quantizeLayer : quantizeLayers) { - if (!QuantizationDetails::outputLayoutIsSupported(*quantizeLayer)) { - return; - } - } - - if ((!isCascade(concatLayers)) || (!isMultiChannel(concatLayers))) { + if (!isMultiChannel(subgraph.concatLayers)) { ConcatTransformation::transform(context, concat); return; } + // TODO: update later // TODO: check if precisions are different and return - std::vector>> fakeQuantizeForConcatLayers; - const DataPrecision dataPrecision = getDataPrecision(*quantizeLayers[0], QuantizationDetails::getDetails(*quantizeLayers[0]), false, false); + const DataPrecision dataPrecision = getDataPrecision( + *subgraph.quantizationLayers[0], + QuantizationDetails::getDetails(*subgraph.quantizationLayers[0]), + false, + false); if (dataPrecision.precision == Precision::UNSPECIFIED) { return; } - std::vector finalDequantizationScales; - std::vector finalDequantizationShifts; - const auto parentsCount = quantizeLayers.size(); - std::unordered_map> dequantizationScalesLayers; std::unordered_map> dequantizationShiftsLayers; - for (int index = (concatLayers.size() - 1); index >= 0; --index) { - const CNNLayerPtr concatLayer = concatLayers[index]; - - const std::vector parents = CNNNetworkHelper::getParentsRecursivelyExceptTypes( - *concatLayer, - { "Pooling", "Resample" }); - for (const CNNLayerPtr& parent : parents) { - if ((parent->type != "FakeQuantize") && (parent->type != "Concat")) { - // TODO: handle - THROW_IE_EXCEPTION << "layer type '" << parent->type << "' not supported"; - } + for (const CNNLayerPtr& fakeQuantizeLayer : subgraph.quantizationLayers) { + if (fakeQuantizeLayer->type != "FakeQuantize") { + continue; } - for (const CNNLayerPtr fakeQuantizeLayer : parents) { - if (fakeQuantizeLayer->type != "FakeQuantize") { - continue; - } - - const QuantizationDetails quantizationDetails = QuantizationDetails::getDetails(*fakeQuantizeLayer); - const size_t channelsCount = CNNNetworkHelper::getOutputChannelsCount(*fakeQuantizeLayer); - std::vector dequantizationScales(channelsCount); - std::vector dequantizationShifts(channelsCount); - for (size_t i = 0ul; i < channelsCount; ++i) { - dequantizationScales[i] = QuantizationDetails::isSupportedLevel(quantizationDetails.levels) ? - (quantizationDetails.outputHighValues[0] - quantizationDetails.outputLowValues[0]) / (dataPrecision.max - dataPrecision.min) : - 1.0; - - dequantizationShifts[i] = QuantizationDetails::isSupportedLevel(quantizationDetails.levels) ? - (quantizationDetails.outputHighValues[0] - (quantizationDetails.outputHighValues[0] - quantizationDetails.outputLowValues[0]) * - (dataPrecision.max / (dataPrecision.max - dataPrecision.min))) : - 0.f; - } - checkAndUpdateDequantizationShiftWithZero(quantizationDetails, dequantizationShifts); - - finalDequantizationScales.insert(finalDequantizationScales.end(), dequantizationScales.begin(), dequantizationScales.end()); - finalDequantizationShifts.insert(finalDequantizationShifts.end(), dequantizationShifts.begin(), dequantizationShifts.end()); + const QuantizationDetails& quantizationDetails = QuantizationDetails::getDetails(*fakeQuantizeLayer); + const size_t channelsCount = CNNNetworkHelper::getOutputChannelsCount(*fakeQuantizeLayer); + std::vector dequantizationScales(channelsCount); + std::vector dequantizationShifts(channelsCount); + for (size_t i = 0ul; i < channelsCount; ++i) { + dequantizationScales[i] = QuantizationDetails::isSupportedLevel(quantizationDetails.levels) ? + (quantizationDetails.getOutputHighValue(i) - quantizationDetails.getOutputLowValue(i)) / (dataPrecision.max - dataPrecision.min) : + 1.0; - dequantizationScalesLayers[fakeQuantizeLayer->name] = dequantizationScales; - dequantizationShiftsLayers[fakeQuantizeLayer->name] = dequantizationShifts; + dequantizationShifts[i] = QuantizationDetails::isSupportedLevel(quantizationDetails.levels) ? + (quantizationDetails.getOutputHighValue(i) - (quantizationDetails.getOutputHighValue(i) - quantizationDetails.getOutputLowValue(i)) * + (dataPrecision.max / (dataPrecision.max - dataPrecision.min))) : + 0.f; + } + checkAndUpdateDequantizationShiftWithZero(quantizationDetails, dequantizationShifts); - if (QuantizationDetails::isSupportedLevel(quantizationDetails.levels)) { - CNNNetworkHelper::updateBlobs(*fakeQuantizeLayer, 3, dataPrecision.min); - CNNNetworkHelper::updateBlobs(*fakeQuantizeLayer, 4, dataPrecision.max); + dequantizationScalesLayers[fakeQuantizeLayer->name] = dequantizationScales; + dequantizationShiftsLayers[fakeQuantizeLayer->name] = dequantizationShifts; - if (updatePrecisions) { - CNNNetworkHelper::setOutDataPrecision(*fakeQuantizeLayer, dataPrecision.precision); - } - } - } + CNNNetworkHelper::updateBlobs(*fakeQuantizeLayer, 3, dataPrecision.min); + CNNNetworkHelper::updateBlobs(*fakeQuantizeLayer, 4, dataPrecision.max); } - addDequantizationForQuantize( - context, - concat, - quantizeLayers, - intermediateLayers, - childNameOurAfterQuantizeLayers, - dequantizationScalesLayers, - dequantizationShiftsLayers); - if (updatePrecisions) { - for (const std::vector>& intermediateLayersList : intermediateLayers) { - for (const std::pair& pair : intermediateLayersList) { - CNNLayerPtr intermediateLayer = pair.first; - CNNNetworkHelper::setOutDataPrecision(*intermediateLayer, dataPrecision.precision); - } + for (const auto it : subgraph.layers) { + const CNNLayer* layer = it.second; + CNNNetworkHelper::setOutDataPrecision(*layer, dataPrecision.precision); } + } - CNNNetworkHelper::setOutDataPrecision(concat, dataPrecision.precision); - for (const CNNLayerPtr& concatLayer : concatLayers) { - if (concatLayer->name == concat.name) { - continue; - } + auto dequantizationValuesCallback = [&]( + const CNNLayer& layer, + std::vector& dequantizationScales, + std::vector& dequantizationShifts + ) { + fillDequantization( + layer, + dequantizationScalesLayers, dequantizationShiftsLayers, + dequantizationScales, dequantizationShifts); + }; - // TODO: check if the same precision is used: U8 or S8 for all concat layers - // TODO: fix & remove - const DataPtr insData = concatLayer->insData[0].lock(); - if (insData == nullptr) { - THROW_IE_LPT_EXCEPTION(*concatLayer) << "insert data is absent"; - } - insData->setPrecision(dataPrecision.precision); - // TODO: workaround - concatLayer->precision = dataPrecision.precision; - CNNNetworkHelper::setOutDataPrecision(*concatLayer, dataPrecision.precision); - } - } + addDequantizationLayers(context, subgraph, dequantizationValuesCallback); - // Add scaleshift at outputs of our layers - children = CNNNetworkHelper::getChildren(concat); - if (children.size() == 0) { - const std::string originalName = concat.name; - CNNNetworkHelper::renameLayer(context.network, concat.name, concat.name + LayerTransformation::lastLayerPrefix); + for (const CNNLayerPtr& quantizationLayer : subgraph.quantizationLayers) { + context.quantizedFakeQuantizeNames.insert(quantizationLayer->name); + } +} - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(concat); - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(concat), - nullptr, - DequantizationDetails(finalDequantizationScales, finalDequantizationShifts, outputChannelsCount), - originalName); - context.dequantizationLayersNames.insert(dequantizationLayer->name); +void ConcatMultiChannelsTransformation::fillDequantization( + const CNNLayer& layer, + const std::unordered_map>& dequantizationScalesLayers, + const std::unordered_map>& dequantizationShiftsLayers, + std::vector& dequantizationScales, + std::vector& dequantizationShifts) { + std::vector fakeQuantizes; + if (layer.type == "FakeQuantize") { + fakeQuantizes.push_back(std::make_shared(layer)); } else { - const size_t outputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(concat); - for (const CNNLayerPtr& child : children) { - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(concat), - child, - DequantizationDetails(finalDequantizationScales, finalDequantizationShifts, outputChannelsCount)); - context.dequantizationLayersNames.insert(dequantizationLayer->name); - } + fillQuantization(layer, fakeQuantizes); } - // Add scaleshift at outputs of side branches - for (int index = 0; index < sideOutputLayers.size(); index++) { - const CNNLayerPtr concatLayer = sideOutputLayers[index]; - - const size_t concatOutputChannelsCount = CNNNetworkHelper::getOutputChannelsCount(*concatLayer); - std::vector dequantizationScales1(concatOutputChannelsCount); - std::vector dequantizationShifts1(concatOutputChannelsCount); - for (size_t index_ = 0; index_ < concatOutputChannelsCount; ++index_) { - dequantizationScales1[index_] = finalDequantizationScales[index_]; - dequantizationShifts1[index_] = finalDequantizationShifts[index_]; + for (const CNNLayerPtr fakeQuantize : fakeQuantizes) { + { + const auto scalesIt = dequantizationScalesLayers.find(fakeQuantize->name); + if (scalesIt == dequantizationScalesLayers.end()) { + THROW_IE_LPT_EXCEPTION(*fakeQuantize) << "dequantization scale values are not found"; + } + const std::vector& fakeQuantizeDequantizationScales = scalesIt->second; + dequantizationScales.insert(dequantizationScales.end(), fakeQuantizeDequantizationScales.begin(), fakeQuantizeDequantizationScales.end()); } + { + const auto shiftsIt = dequantizationShiftsLayers.find(fakeQuantize->name); + if (shiftsIt == dequantizationShiftsLayers.end()) { + THROW_IE_LPT_EXCEPTION(*fakeQuantize) << "dequantization shift values are not found"; + } + const std::vector& fakeQuantizeDequantizationShifts = shiftsIt->second; + dequantizationShifts.insert(dequantizationShifts.end(), fakeQuantizeDequantizationShifts.begin(), fakeQuantizeDequantizationShifts.end()); + } + } +} - std::vector children = CNNNetworkHelper::getChildren(*concatLayer, childrenNameSideOutputLayers[index]); - for (int i = 0; i < children.size(); i++) { - CNNLayerPtr dequantizationLayer = CNNNetworkHelper::addScaleShiftBetween( - context, - std::make_shared(*sideOutputLayers[index]), - children[i], - DequantizationDetails(dequantizationScales1, dequantizationShifts1, concatOutputChannelsCount)); - context.dequantizationLayersNames.insert(dequantizationLayer->name); +void ConcatMultiChannelsTransformation::fillQuantization(const CNNLayer& layer, std::vector& fakeQuantizes) { + const std::vector parents = CNNNetworkHelper::getParents(layer); + for (const CNNLayerPtr parent : parents) { + if (parent->type == "FakeQuantize") { + fakeQuantizes.push_back(parent); + } else { + fillQuantization(*parent, fakeQuantizes); } } } 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 c59f900c6..d718736e4 100644 --- a/inference-engine/src/low_precision_transformations/src/network_helper.cpp +++ b/inference-engine/src/low_precision_transformations/src/network_helper.cpp @@ -27,6 +27,133 @@ using namespace InferenceEngine; using namespace InferenceEngine::details; +static const std::unordered_set intermediateLayers{ + "Pooling", + "Resample" +}; + +bool Subgraph::fillSubgraphForQuantization(const CNNLayerPtr& fakeQuantize, std::unordered_set& handledLayers) { + if (fakeQuantize->type != "FakeQuantize") { + THROW_IE_EXCEPTION << "unexpected layer type " << fakeQuantize->type; + } + + if (!QuantizationDetails::outputLayoutIsSupported(*fakeQuantize)) { + return false; + } + + quantizationLayers.push_back(fakeQuantize); + handledLayers.insert(fakeQuantize->name); + layers.emplace(fakeQuantize->name, fakeQuantize.get()); + + const std::vector children = CNNNetworkHelper::getChildren(*fakeQuantize); + for (const CNNLayerPtr& child : children) { + if (handledLayers.find(child->name) != handledLayers.end()) { + continue; + } + + if (child->type == "Concat") { + if (!fillSubgraphForConcat(child, handledLayers)) { + return false; + } + } else if (child->type == "FakeQuantize") { + // + } else if (intermediateLayers.find(child->type) != intermediateLayers.end()) { + if (!fillSubgraphForIntermediate(child, handledLayers)) { + return false; + } + } + } + + return true; +} + +bool Subgraph::fill(const CNNLayerPtr& layer, std::unordered_set& handledLayers) { + const std::vector parents = CNNNetworkHelper::getParents(*layer); + for (const CNNLayerPtr& parent : parents) { + if (handledLayers.find(parent->name) != handledLayers.end()) { + continue; + } + + if (parent->type == "Concat") { + if (!fillSubgraphForConcat(parent, handledLayers)) { + return false; + } + } else if (parent->type == "FakeQuantize") { + if (!fillSubgraphForQuantization(parent, handledLayers)) { + return false; + } + } else if (intermediateLayers.find(parent->type) != intermediateLayers.end()) { + if (!fillSubgraphForIntermediate(parent, handledLayers)) { + return false; + } + } else { + return false; + } + } + + const std::vector children = CNNNetworkHelper::getChildren(*layer); + for (const CNNLayerPtr& child : children) { + if (handledLayers.find(child->name) != handledLayers.end()) { + continue; + } + + if (child->type == "Concat") { + if (!fillSubgraphForConcat(child, handledLayers)) { + return false; + } + } else if (child->type == "FakeQuantize") { + // + } else if (intermediateLayers.find(child->type) != intermediateLayers.end()) { + if (!fillSubgraphForIntermediate(child, handledLayers)) { + return false; + } + } + } + + return true; +} + +bool Subgraph::fillSubgraphForIntermediate(const CNNLayerPtr& intermediate, std::unordered_set& handledLayers) { + if (intermediateLayers.find(intermediate->type) == intermediateLayers.end()) { + THROW_IE_EXCEPTION << "unexpected layer type " << intermediate->type; + } + + handledLayers.insert(intermediate->name); + layers.emplace(intermediate->name, intermediate.get()); + + return fill(intermediate, handledLayers); +} + +bool Subgraph::empty() const { + return quantizationLayers.empty(); +} + +bool Subgraph::fillSubgraphForConcat(const CNNLayerPtr& concat, std::unordered_set& handledLayers) { + if (concat->type != "Concat") { + THROW_IE_EXCEPTION << "unexpected layer type " << concat->type; + } + + concatLayers.push_back(concat); + handledLayers.insert(concat->name); + layers.emplace(concat->name, concat.get()); + + return fill(concat, handledLayers); +} + +Subgraph CNNNetworkHelper::getSubgraph(const CNNLayer& concat) { + if (concat.type != "Concat") { + THROW_IE_EXCEPTION << "unexpected layer type " << concat.type; + } + + Subgraph subgraph; + std::unordered_set handledLayers; + if (!subgraph.fillSubgraphForConcat(std::make_shared(concat), handledLayers)) { + return Subgraph(); + } + + return subgraph; +} + CNNLayerPtr CNNNetworkHelper::getLayer(const ICNNNetwork& network, const std::string& layerName) { std::vector layers = InferenceEngine::details::CNNNetSortTopologically(network); for (CNNLayerPtr layer : layers) { diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp new file mode 100644 index 000000000..23a38b7dd --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/concat_neighboring_graph_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::FP16 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamCpu(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamI8I8(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamU8I8() +}; + +INSTANTIATE_TEST_CASE_P(LPT, ConcatNeighboringGraphTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::SizeVector({ 1, 3, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(trasformationParamValues)), + ConcatNeighboringGraphTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp index 34b5eb94b..f77cedbbf 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp @@ -8,6 +8,7 @@ #include "common_test_utils/test_constants.hpp" using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; namespace { const std::vector netPrecisions = { @@ -15,10 +16,17 @@ const std::vector netPrecisions = { InferenceEngine::Precision::FP16 }; +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamCpu(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamI8I8(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamU8I8() +}; + INSTANTIATE_TEST_CASE_P(LPT, ConcatTransformation, ::testing::Combine( ::testing::ValuesIn(netPrecisions), ::testing::Values(InferenceEngine::SizeVector({ 1, 1024, 16, 16 })), - ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(trasformationParamValues)), ConcatTransformation::getTestCaseName); } // namespace diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp new file mode 100644 index 000000000..3e739a791 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/concat_with_intermediate_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::FP16 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamCpu(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamI8I8(), + LayerTestsUtils::LayerTransformationParamsFactory::createParamU8I8() +}; + +const std::vector transparentIntermediateValues = { true, false }; +const std::vector multiChannelValues = { /*true,*/ false }; + +INSTANTIATE_TEST_CASE_P(LPT, ConcatWithIntermediateTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::SizeVector({ 1, 1024, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(transparentIntermediateValues), + ::testing::ValuesIn(multiChannelValues)), + ConcatWithIntermediateTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp new file mode 100644 index 000000000..b7d0c6b30 --- /dev/null +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_neighboring_graph_transformation.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/concat_neighboring_graph_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + InferenceEngine::Precision::FP32 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamGpu() +}; + +INSTANTIATE_TEST_CASE_P(LPT, ConcatNeighboringGraphTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::SizeVector({ 1, 1024, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(trasformationParamValues)), + ConcatNeighboringGraphTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp index d4e0c3c77..fbfd91601 100644 --- a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_transformation.cpp @@ -8,17 +8,22 @@ #include "common_test_utils/test_constants.hpp" using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; namespace { const std::vector netPrecisions = { - InferenceEngine::Precision::FP32, - InferenceEngine::Precision::FP16 + InferenceEngine::Precision::FP32 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamGpu() }; INSTANTIATE_TEST_CASE_P(LPT, ConcatTransformation, ::testing::Combine( ::testing::ValuesIn(netPrecisions), ::testing::Values(InferenceEngine::SizeVector({ 1, 1024, 16, 16 })), - ::testing::Values(CommonTestUtils::DEVICE_GPU)), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(trasformationParamValues)), ConcatTransformation::getTestCaseName); } // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp new file mode 100644 index 000000000..c0a975124 --- /dev/null +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/concat_with_intermediate_transformation.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/concat_with_intermediate_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; +using namespace InferenceEngine::details; + +namespace { +const std::vector netPrecisions = { + InferenceEngine::Precision::FP32 +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsFactory::createParamGpu() +}; + +const std::vector transparentIntermediates = { true, false }; +const std::vector multiChannelValues = { true, false }; + +INSTANTIATE_TEST_CASE_P(LPT, ConcatWithIntermediateTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::SizeVector({ 1, 1024, 16, 16 })), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(transparentIntermediates), + ::testing::ValuesIn(multiChannelValues)), + ConcatWithIntermediateTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_neighboring_graph_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_neighboring_graph_transformation.hpp new file mode 100644 index 000000000..84e1e35b4 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_neighboring_graph_transformation.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include "functional_test_utils/low_precision_transformations/layer_transformation.hpp" + +namespace LayerTestsDefinitions { + +class ConcatNeighboringGraphTransformation : public LayerTestsUtils::LayerTransformation { +public: + static std::string getTestCaseName(testing::TestParamInfo obj); + InferenceEngine::Blob::Ptr GenerateInput(const InferenceEngine::InputInfo &info) const override; + +protected: + void SetUp() override; + +private: + void validate(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_transformation.hpp index 9c848ed15..1ccb97890 100644 --- a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_transformation.hpp +++ b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_transformation.hpp @@ -11,15 +11,14 @@ namespace LayerTestsDefinitions { -class ConcatTransformation : public LayerTestsUtils::LayerTransformation { +class ConcatTransformation : public LayerTestsUtils::LayerTransformation { public: - static std::string getTestCaseName(testing::TestParamInfo obj); + static std::string getTestCaseName(testing::TestParamInfo obj); protected: void SetUp() override; private: - std::shared_ptr makeFakeQuantize(const ngraph::Output& output); void validate(); }; diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_with_intermediate_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_with_intermediate_transformation.hpp new file mode 100644 index 000000000..30224a72f --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/concat_with_intermediate_transformation.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include "functional_test_utils/low_precision_transformations/layer_transformation.hpp" + +namespace LayerTestsDefinitions { + +typedef std::tuple< + InferenceEngine::Precision, + InferenceEngine::SizeVector, + std::string, // target device: CPU, GPU + InferenceEngine::details::LayerTransformation::Params, // transformation parameters + bool, // transparent intermediate + // multichannel + bool> ConcatWithIntermediateTransformationParams; + +class ConcatWithIntermediateTransformation : public LayerTestsUtils::LayerTransformation { +public: + static std::string getTestCaseName(testing::TestParamInfo obj); + +protected: + void SetUp() override; + void validate(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_neighboring_graph_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_neighboring_graph_transformation.cpp new file mode 100644 index 000000000..46053e77c --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_neighboring_graph_transformation.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision_transformations/concat_neighboring_graph_transformation.hpp" + +#include +#include +#include +#include + +#include + +#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/builders.hpp" + +namespace LayerTestsDefinitions { + +std::pair getInterval(const std::vector& precisions) { + const bool unsignedInterval = std::find(precisions.begin(), precisions.end(), InferenceEngine::Precision::U8) != precisions.end(); + const float low = unsignedInterval ? 0.f : -128.f; + const float hight = unsignedInterval ? 255.f : 127.f; + return std::make_pair(low, hight); +} +std::string ConcatNeighboringGraphTransformation::getTestCaseName(testing::TestParamInfo obj) { + InferenceEngine::Precision netPrecision; + InferenceEngine::SizeVector inputShapes; + std::string targetDevice; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShapes, targetDevice, params) = obj.param; + + std::ostringstream result; + result << netPrecision.name() << "_" << targetDevice << "_" << toString(params); + return result.str(); +} + +InferenceEngine::Blob::Ptr ConcatNeighboringGraphTransformation::GenerateInput(const InferenceEngine::InputInfo &info) const { + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + std::string targetDevice; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShape, targetDevice, params) = this->GetParam(); + + const float k = (info.name() == "input1") ? 1.f : (info.name() == "input2" ? 2.f : 3.f); + + const auto interval = getInterval(params.precisionsOnActivations); + const float low = interval.first / k; + const float hight = interval.second / k; + + InferenceEngine::Blob::Ptr input = FuncTestUtils::createAndFillBlobConsistently(info.getTensorDesc(), hight - low, static_cast(low), 1ul); + const auto buffer = input->buffer().as(); + return input; +} + +void ConcatNeighboringGraphTransformation::SetUp() { + threshold = 2.e-2; + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShape, targetDevice, params) = this->GetParam(); + const auto ngPrecision = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); + + const auto interval = getInterval(params.precisionsOnActivations); + const float low = interval.first; + const float hight = interval.second; + + const auto input1 = std::make_shared(ngPrecision, ngraph::Shape(inputShape)); + input1->set_friendly_name("input1"); + const auto fakeQuantize1 = ngraph::builder::makeFakeQuantize( + input1, ngPrecision, 256ul, { 1ul }, + { low }, { hight }, { low }, { hight }); + fakeQuantize1->set_friendly_name("fakeQuantize1"); + + const auto input2 = std::make_shared(ngPrecision, ngraph::Shape(inputShape)); + input2->set_friendly_name("input2"); + const auto fakeQuantize2 = ngraph::builder::makeFakeQuantize( + input2, ngPrecision, 256ul, { 1ul }, + { low / 2.f }, { hight / 2.f }, { low / 2.f }, { hight / 2.f }); + fakeQuantize2->set_friendly_name("fakeQuantize2"); + + const auto input3 = std::make_shared(ngPrecision, ngraph::Shape(inputShape)); + input3->set_friendly_name("input3"); + const auto fakeQuantize3 = ngraph::builder::makeFakeQuantize( + input3, ngPrecision, 256ul, { 1ul }, + { low / 3.f }, { hight / 3.f }, { low / 3.f }, { hight / 3.f }); + fakeQuantize3->set_friendly_name("fakeQuantize3"); + + const auto concat1 = std::make_shared(ngraph::OutputVector{ + fakeQuantize1->output(0), + fakeQuantize2->output(0) }, + 1ull); + concat1->set_friendly_name("concat1"); + + const auto concat2 = std::make_shared(ngraph::OutputVector{ + fakeQuantize2->output(0), + fakeQuantize3->output(0) }, + 1ull); + concat2->set_friendly_name("concat2"); + + const ngraph::ResultVector results { + std::make_shared(concat1), + std::make_shared(concat2) + }; + + function = std::make_shared( + results, + ngraph::ParameterVector { input1, input2, input3 }, + "ConcatNeighboringGraphTransformation"); + + // TODO: move to some another place + validate(); +} + +void ConcatNeighboringGraphTransformation::validate() { + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShape, targetDevice, params) = this->GetParam(); + + const InferenceEngine::CNNNetwork network = transform(params); + + IE_SUPPRESS_DEPRECATED_START + + InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo(); + EXPECT_EQ(2, outputs.size()); + + for (const auto it : outputs) { + const InferenceEngine::CNNLayerPtr outputLayer = it.second->getCreatorLayer().lock(); + EXPECT_TRUE(outputLayer != nullptr); + EXPECT_EQ("ScaleShift", outputLayer->type); + } + + // check quantized FQ layers map: should includes all FQ + + IE_SUPPRESS_DEPRECATED_START +} + +TEST_P(ConcatNeighboringGraphTransformation, CompareWithRefImpl) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_transformation.cpp index 02e28e6e7..022473e64 100644 --- a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_transformation.cpp +++ b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_transformation.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include "low_precision_transformations/concat_transformation.hpp" + #include #include #include @@ -13,24 +15,20 @@ #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 "low_precision_transformations/concat_transformation.hpp" - +#include "ngraph_functions/builders.hpp" namespace LayerTestsDefinitions { -std::string ConcatTransformation::getTestCaseName(testing::TestParamInfo obj) { +std::string ConcatTransformation::getTestCaseName(testing::TestParamInfo obj) { InferenceEngine::Precision netPrecision; InferenceEngine::SizeVector inputShapes; std::string targetDevice; - std::tie(netPrecision, inputShapes, targetDevice) = obj.param; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShapes, targetDevice, params) = obj.param; std::ostringstream result; - result << "inputShapes=" << CommonTestUtils::vec2str(inputShapes) << "_"; - result << "netPrecision=" << netPrecision.name() << "_"; - result << "targetDevice=" << targetDevice; + result << netPrecision.name() << "_" << targetDevice << "_" << toString(params); return result.str(); } @@ -39,16 +37,17 @@ void ConcatTransformation::SetUp() { InferenceEngine::SizeVector inputShape; InferenceEngine::Precision netPrecision; - std::tie(netPrecision, inputShape, targetDevice) = this->GetParam(); - auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShape, targetDevice, params) = this->GetParam(); + const auto ngPrecision = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); - const auto paramNode1 = std::make_shared(ngPrc, ngraph::Shape(inputShape)); - const auto fakeQuantize1 = makeFakeQuantize(paramNode1->output(0)); + const auto paramNode1 = std::make_shared(ngPrecision, ngraph::Shape(inputShape)); + const auto fakeQuantize1 = ngraph::builder::makeFakeQuantize(paramNode1, ngPrecision, 256ul, { 1ul }); const std::vector inputShape2 = { inputShape[0], inputShape[1], inputShape[2] / 2, inputShape[3] / 2 }; - const auto paramNode2 = std::make_shared(ngPrc, ngraph::Shape(inputShape2)); + const auto paramNode2 = std::make_shared(ngPrecision, ngraph::Shape(inputShape2)); + const auto fakeQuantize2 = ngraph::builder::makeFakeQuantize(paramNode2, ngPrecision, 256ul, { 1ul }); - const auto fakeQuantize2 = makeFakeQuantize(paramNode2->output(0)); const auto interpolateShape = std::make_shared( ngraph::element::i64, ngraph::Shape{ 2 }, @@ -72,17 +71,13 @@ void ConcatTransformation::SetUp() { validate(); } -std::shared_ptr ConcatTransformation::makeFakeQuantize(const ngraph::Output& input) { - auto inputLowConst = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 1, 1, 1 }, std::vector({ 1.f })); - auto inputHighConst = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 1, 1, 1 }, std::vector({ 1.f })); - auto outputLowConst = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 1, 1, 1 }, std::vector({ 1.f })); - auto outputHighConst = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 1, 1, 1 }, std::vector({ 1.f })); - auto fakeQuantize = std::make_shared(input, inputLowConst, inputHighConst, outputLowConst, outputHighConst, 256ul); - return fakeQuantize; -} - void ConcatTransformation::validate() { - const InferenceEngine::CNNNetwork network = transform(); + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + InferenceEngine::details::LayerTransformation::Params params; + std::tie(netPrecision, inputShape, targetDevice, params) = this->GetParam(); + + const InferenceEngine::CNNNetwork network = transform(params); IE_SUPPRESS_DEPRECATED_START @@ -99,10 +94,6 @@ void ConcatTransformation::validate() { TEST_P(ConcatTransformation, CompareWithRefImpl) { Run(); - - if (targetDevice == std::string{CommonTestUtils::DEVICE_GPU}) { - PluginCache::get().reset(); - } }; } // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_with_intermediate_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_with_intermediate_transformation.cpp new file mode 100644 index 000000000..ec274f033 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/concat_with_intermediate_transformation.cpp @@ -0,0 +1,194 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision_transformations/concat_with_intermediate_transformation.hpp" + +#include +#include +#include +#include + +#include +#include + +#include "ngraph_functions/pass/convert_prc.hpp" +#include "low_precision_transformations/network_helper.hpp" +#include "low_precision_transformations/concat.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/builders.hpp" + +using namespace InferenceEngine; +using namespace InferenceEngine::details; + +namespace LayerTestsDefinitions { + +std::string ConcatWithIntermediateTransformation::getTestCaseName(testing::TestParamInfo obj) { + InferenceEngine::Precision netPrecision; + InferenceEngine::SizeVector inputShapes; + std::string targetDevice; + InferenceEngine::details::LayerTransformation::Params params; + bool transparentIntermediate; + bool multichannel; + std::tie(netPrecision, inputShapes, targetDevice, params, transparentIntermediate, multichannel) = obj.param; + + std::ostringstream result; + result << + netPrecision.name() << "_" << + targetDevice << "_" << + toString(params) << + (transparentIntermediate ? "" : "_notTransparentIntermediate") << + (multichannel ? "_multichannel" : ""); + + return result.str(); +} + +/* +* FQ FQ +* \ / +* \ Intermediate (MaxPooling or Convolution) +* \ / \ +* Concat Convolution +*/ + +void ConcatWithIntermediateTransformation::SetUp() { + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + InferenceEngine::details::LayerTransformation::Params trasformationParams; + bool transparentIntermediate; + bool multichannel; + std::tie(netPrecision, inputShape, targetDevice, trasformationParams, transparentIntermediate, multichannel) = this->GetParam(); + const auto ngPrecision = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); + + const std::vector inputShape1 = { + inputShape[0], + inputShape[1], + inputShape[2] - (transparentIntermediate ? 2 : 0), + inputShape[3] - (transparentIntermediate ? 2 : 0) + }; + + const auto paramNode1 = std::make_shared(ngPrecision, ngraph::Shape(inputShape1)); + paramNode1->set_friendly_name("input1"); + const auto fakeQuantize1 = ngraph::builder::makeFakeQuantize(paramNode1, ngPrecision, 256ul, { 1ul }, { 0.f }, { 3.f }, { 0.f }, { 3.f }); + fakeQuantize1->set_friendly_name("fakeQuantize1"); + + const std::vector inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] }; + const auto paramNode2 = std::make_shared(ngPrecision, ngraph::Shape(inputShape2)); + paramNode2->set_friendly_name("input2"); + + const auto fakeQuantize2 = ngraph::builder::makeFakeQuantize(paramNode2, ngPrecision, 256ul, { 1ul }, { 0.f }, { 9.f }, { 0.f }, { 9.f }); + fakeQuantize2->set_friendly_name("fakeQuantize2"); + + const std::vector kernel = { 3, 3 }; + const std::vector stride = { 1, 1 }; + const std::vector padBegin = { 0, 0 }; + const std::vector padEnd = { 0, 0 }; + const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET; + const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR; + std::shared_ptr intermediateOp; + + if (transparentIntermediate) { + intermediateOp = std::make_shared( + fakeQuantize2->output(0), + stride, + padBegin, + padEnd, + kernel, + roundingType, + padType); + } else { + auto weights = ngraph::opset1::Constant::create( + ngPrecision, + ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, + std::vector(inputShape[1] * inputShape[1], 1)); + + intermediateOp = std::make_shared( + fakeQuantize2->output(0), + weights, + ngraph::Strides{ 1, 1 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::Strides{ 1, 1 }); + } + + intermediateOp->set_friendly_name("intermediate"); + + const std::shared_ptr concat = std::make_shared( + ngraph::OutputVector{ fakeQuantize1->output(0), intermediateOp->output(0) }, 1); + concat->set_friendly_name("concat"); + + + auto weights = ngraph::opset1::Constant::create(ngPrecision, ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, { 1 }); + auto convolution = std::make_shared( + intermediateOp, + weights, + ngraph::Strides{ 1, 1 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::CoordinateDiff{ 0, 0 }, + ngraph::Strides{ 1, 1 }); + convolution->set_friendly_name("convolution"); + + ngraph::ResultVector results { + std::make_shared(concat), + std::make_shared(convolution) + }; + function = std::make_shared(results, ngraph::ParameterVector { paramNode1, paramNode2 }, "ConcatWithIntermediateTransformation"); + + // TODO: move to some another place + validate(); +} + +void ConcatWithIntermediateTransformation::validate() { + InferenceEngine::SizeVector inputShape; + InferenceEngine::Precision netPrecision; + InferenceEngine::details::LayerTransformation::Params params; + bool transparentIntermediate; + bool multichannel; + std::tie(netPrecision, inputShape, targetDevice, params, transparentIntermediate, multichannel) = this->GetParam(); + + InferenceEngine::details::LowPrecisionTransformations transformations = getLowPrecisionTransformations(params); + if (!multichannel) { + transformations.addBranchSpecific(params, "Concat"); + } + const InferenceEngine::CNNNetwork network = transform(transformations); + + IE_SUPPRESS_DEPRECATED_START + + InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo(); + EXPECT_EQ(2, outputs.size()); + + const CNNLayerPtr intermediate = CNNNetworkHelper::getLayer(network, "intermediate"); + if (transparentIntermediate) { + std::vector children = CNNNetworkHelper::getChildren(*intermediate); + EXPECT_EQ(2ul, children.size()); + EXPECT_TRUE( + ((children[0]->type == "ScaleShift") && (children[1]->type == "Concat")) || + ((children[0]->type == "Concat") && (children[1]->type == "ScaleShift"))); + + const CNNLayerPtr concat = CNNNetworkHelper::getLayer(network, "concat_original"); + children = CNNNetworkHelper::getChildren(*concat); + EXPECT_EQ(1ul, children.size()); + EXPECT_EQ("ScaleShift", children[0]->type); + } else { + std::vector children = CNNNetworkHelper::getChildren(*intermediate); + EXPECT_EQ(2ul, children.size()); + EXPECT_TRUE( + ((children[0]->type == "Convolution") && (children[1]->type == "Concat")) || + ((children[0]->type == "Concat") && (children[1]->type == "Convolution"))); + + const CNNLayerPtr concat = CNNNetworkHelper::getLayer(network, "concat"); + children = CNNNetworkHelper::getChildren(*concat); + EXPECT_EQ(0ul, children.size()); + } + + IE_SUPPRESS_DEPRECATED_END +} + +TEST_P(ConcatWithIntermediateTransformation, CompareWithRefImpl) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/ie_test_utils/common_test_utils/data_utils.hpp b/inference-engine/tests/ie_test_utils/common_test_utils/data_utils.hpp index f6bc41752..a5b1efd25 100644 --- a/inference-engine/tests/ie_test_utils/common_test_utils/data_utils.hpp +++ b/inference-engine/tests/ie_test_utils/common_test_utils/data_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Intel Corporation +// Copyright (C) 2019-2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // #pragma once @@ -91,6 +91,26 @@ void inline fill_data_random(InferenceEngine::Blob::Ptr &blob, const uint32_t r } } +template +void inline fill_data_consistently(InferenceEngine::Blob::Ptr &blob, const uint32_t range = 10, int32_t start_from = 0, const int32_t k = 1) { + using dataType = typename InferenceEngine::PrecisionTrait::value_type; + auto *rawBlobDataPtr = blob->buffer().as(); + if (start_from < 0 && !std::is_signed::value) { + start_from = 0; + } + + int64_t value = start_from; + const int64_t maxValue = start_from + range; + for (size_t i = 0; i < blob->size(); i++) { + rawBlobDataPtr[i] = static_cast(value); + if (value < (maxValue - k)) { + value += k; + } else { + value = start_from; + } + } +} + template void inline fill_data_random_float(InferenceEngine::Blob::Ptr &blob, const uint32_t range, int32_t start_from, const int32_t k, const int seed = 1) { diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/blob_utils.hpp b/inference-engine/tests/ie_test_utils/functional_test_utils/blob_utils.hpp index 851343e77..0e679607e 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/blob_utils.hpp +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/blob_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Intel Corporation +// Copyright (C) 2019-2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // #pragma once @@ -39,7 +39,7 @@ enum CompareType{ * @param ref Pointer to reference blob * @param resSize Size of considered blob * @param refSize Size of reference blob - * @param compareType Defines an algorithm of comparision + * @param compareType Defines an algorithm of comparison * @param thr1 First threshold of difference * @param thr2 Second threshold of difference * @param printData A flag if data printing is demanded @@ -477,6 +477,32 @@ InferenceEngine::Blob::Ptr inline createAndFillBlob(const InferenceEngine::Tenso return blob; } +InferenceEngine::Blob::Ptr inline createAndFillBlobConsistently( + const InferenceEngine::TensorDesc &td, + const uint32_t range, + const int32_t start_from, + const int32_t resolution) { + InferenceEngine::Blob::Ptr blob = make_blob_with_precision(td); + blob->allocate(); + switch (td.getPrecision()) { +#define CASE(X) case X: CommonTestUtils::fill_data_consistently(blob, range, start_from, resolution); break; + CASE(InferenceEngine::Precision::FP32) + CASE(InferenceEngine::Precision::FP16) + CASE(InferenceEngine::Precision::U8) + CASE(InferenceEngine::Precision::U16) + CASE(InferenceEngine::Precision::I8) + CASE(InferenceEngine::Precision::I16) + CASE(InferenceEngine::Precision::I64) + CASE(InferenceEngine::Precision::BIN) + CASE(InferenceEngine::Precision::I32) + CASE(InferenceEngine::Precision::BOOL) +#undef CASE + default: + THROW_IE_EXCEPTION << "Wrong precision specified: " << td.getPrecision().name(); + } + return blob; +} + InferenceEngine::Blob::Ptr inline convertBlobLayout(const InferenceEngine::Blob::Ptr& in, InferenceEngine::Layout layout) { IE_ASSERT(in != nullptr) << "Got NULL pointer"; diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.cpp b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.cpp index f49f8cda3..257976e74 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.cpp +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Intel Corporation +// Copyright (C) 2019-2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // @@ -6,7 +6,7 @@ namespace LayerTestsUtils { -LayerTestsCommon::LayerTestsCommon() { +LayerTestsCommon::LayerTestsCommon() : threshold(1e-2f) { core = PluginCache::get().ie(targetDevice); } @@ -43,7 +43,7 @@ void LayerTestsCommon::Compare(const std::vector &expected, const switch (precision) { case InferenceEngine::Precision::FP32: Compare(reinterpret_cast(expectedBuffer), reinterpret_cast(actualBuffer), - size, 1e-2f); + size, threshold); break; case InferenceEngine::Precision::I32: Compare(reinterpret_cast(expectedBuffer), diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.hpp b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.hpp index 4c4822f1a..095f27559 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.hpp +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Intel Corporation +// Copyright (C) 2019-2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // @@ -249,7 +249,6 @@ protected: for (std::size_t i = 0; i < size; ++i) { const auto &ref = expected[i]; const auto &res = actual[i]; - const auto absoluteDifference = std::abs(res - ref); if (absoluteDifference <= threshold) { continue; @@ -281,6 +280,7 @@ protected: InferenceEngine::Precision outPrc = InferenceEngine::Precision::UNSPECIFIED; InferenceEngine::ExecutableNetwork executableNetwork; std::vector inputs; + float threshold; virtual void Validate(); diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.cpp b/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.cpp index 175937457..0d0ece709 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.cpp +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Intel Corporation +// Copyright (C) 2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // @@ -23,43 +23,70 @@ namespace LayerTestsUtils { - InferenceEngine::details::LowPrecisionTransformations LayerTransformation::getLowPrecisionTransformations( - const InferenceEngine::details::LayerTransformation::Params& params) const { - if (targetDevice == "CPU") { - return InferenceEngine::details::LowPrecisionTransformer::getAllTransformations(params). - add(InferenceEngine::details::LayerTransformation::Params(params). - setPrecisionsOnActivations({ InferenceEngine::Precision::U8 }), "Convolution"). - addCleanup( - InferenceEngine::details::LayerTransformation::Params(params).setPrecisionsOnActivations({ InferenceEngine::Precision::U8 }), - "ScaleShift"); - } else if (targetDevice == "GPU") { - return InferenceEngine::details::LowPrecisionTransformer::getAllTransformations(params); - } else { - THROW_IE_EXCEPTION << "unknown target device " << targetDevice; - } - } +InferenceEngine::details::LayerTransformation::Params LayerTransformationParamsFactory::createParamU8I8() { + return InferenceEngine::details::LayerTransformation::Params( + false, + true, + true, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + false, + true, + true, + { InferenceEngine::Precision::U8 }, + { InferenceEngine::Precision::I8 }); +} - InferenceEngine::details::LowPrecisionTransformer LayerTransformation::getLowPrecisionTransformer( - const InferenceEngine::details::LayerTransformation::Params& params) const { - InferenceEngine::details::LowPrecisionTransformer transformer(getLowPrecisionTransformations(params)); - return transformer; - } +InferenceEngine::details::LayerTransformation::Params LayerTransformationParamsFactory::createParamU8U8() { + return InferenceEngine::details::LayerTransformation::Params( + false, + true, + true, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + false, + true, + true, + { InferenceEngine::Precision::U8 }, + { InferenceEngine::Precision::U8 }); +} - InferenceEngine::CNNNetwork LayerTransformation::transform() { - InferenceEngine::details::CNNNetworkImplPtr cnnNetworkImp = cloneNet(InferenceEngine::CNNNetwork(function)); +InferenceEngine::details::LayerTransformation::Params LayerTransformationParamsFactory::createParamI8I8() { + return InferenceEngine::details::LayerTransformation::Params( + false, + true, + true, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + false, + true, + true, + { InferenceEngine::Precision::I8 }, + { InferenceEngine::Precision::I8 }); +} - InferenceEngine::details::LayerTransformation::Params params = InferenceEngine::details::LayerTransformation::Params( - true, // updatePrecisions - true, // quantizeOutputs - true, // weightsToConst - InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::UpdateLevel, // quantizedTensorAlignmentOnActivations - InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, // quantizedTensorAlignmentOnWeights - true, // roundQuantizedValues - true, // updateBiases - true); // supportAsymmetricQuantization - auto transformer = getLowPrecisionTransformer(params); - transformer.transform(*cnnNetworkImp); +InferenceEngine::details::LayerTransformation::Params LayerTransformationParamsFactory::createParamCpu() { + return InferenceEngine::details::LayerTransformation::Params( + true, + true, + true, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::UpdateLevel, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + true, + true, + true); +} - return InferenceEngine::CNNNetwork(cnnNetworkImp); - } +InferenceEngine::details::LayerTransformation::Params LayerTransformationParamsFactory::createParamGpu() { + // not completed + return InferenceEngine::details::LayerTransformation::Params( + true, + true, + true, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::UpdateLevel, + InferenceEngine::details::LayerTransformation::QuantizedTensorAlignment::None, + true, + true, + true); +} } // namespace LayerTestsUtils diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.hpp b/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.hpp index 782256966..81a3a82fb 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.hpp +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/low_precision_transformations/layer_transformation.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Intel Corporation +// Copyright (C) 2020 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // @@ -7,17 +7,84 @@ #include "functional_test_utils/layer_test_utils.hpp" #include "low_precision_transformations/transformer.hpp" +#include "ie_util_internal.hpp" +#include "low_precision_transformations/convolution.hpp" +#include "low_precision_transformations/scaleshift_to_convolution.hpp" + namespace LayerTestsUtils { -class LayerTransformation : public testing::WithParamInterface, public LayerTestsUtils::LayerTestsCommon { +typedef std::tuple< + InferenceEngine::Precision, + InferenceEngine::SizeVector, + std::string, + InferenceEngine::details::LayerTransformation::Params> LayerTransformationParams; + +class LayerTransformationParamsFactory { +public: + static InferenceEngine::details::LayerTransformation::Params createParamU8I8(); + static InferenceEngine::details::LayerTransformation::Params createParamU8U8(); + static InferenceEngine::details::LayerTransformation::Params createParamI8I8(); + static InferenceEngine::details::LayerTransformation::Params createParamCpu(); + static InferenceEngine::details::LayerTransformation::Params createParamGpu(); +}; + +template +class LayerTransformation : public testing::WithParamInterface, public LayerTestsUtils::LayerTestsCommon { public: InferenceEngine::details::LowPrecisionTransformations getLowPrecisionTransformations( - const InferenceEngine::details::LayerTransformation::Params& params) const; + const InferenceEngine::details::LayerTransformation::Params& params) const { + if (targetDevice == "CPU") { + return InferenceEngine::details::LowPrecisionTransformer::getAllTransformations(params). + add(InferenceEngine::details::LayerTransformation::Params(params). + setPrecisionsOnActivations({ InferenceEngine::Precision::U8 }), "Convolution"). + addCleanup( + InferenceEngine::details::LayerTransformation::Params(params).setPrecisionsOnActivations({ InferenceEngine::Precision::U8 }), + "ScaleShift"); + } else if (targetDevice == "GPU") { + return InferenceEngine::details::LowPrecisionTransformer::getAllTransformations(params); + } else { + THROW_IE_EXCEPTION << "unknown target device " << targetDevice; + } + } InferenceEngine::details::LowPrecisionTransformer getLowPrecisionTransformer( - const InferenceEngine::details::LayerTransformation::Params& params) const; + const InferenceEngine::details::LayerTransformation::Params& params) const { + InferenceEngine::details::LowPrecisionTransformer transformer(getLowPrecisionTransformations(params)); + return transformer; + } + + InferenceEngine::CNNNetwork transform() { + return transform(LayerTransformationParamsFactory::createParamCpu()); + } + + InferenceEngine::CNNNetwork transform(InferenceEngine::details::LayerTransformation::Params& params) { + InferenceEngine::details::CNNNetworkImplPtr cnnNetworkImp = cloneNet(InferenceEngine::CNNNetwork(function)); + + auto transformer = getLowPrecisionTransformer(params); + transformer.transform(*cnnNetworkImp); + + return InferenceEngine::CNNNetwork(cnnNetworkImp); + } + + InferenceEngine::CNNNetwork transform(const InferenceEngine::details::LowPrecisionTransformations& transformations) { + InferenceEngine::details::CNNNetworkImplPtr cnnNetworkImp = cloneNet(InferenceEngine::CNNNetwork(function)); + + InferenceEngine::details::LowPrecisionTransformer transformer(transformations); + transformer.transform(*cnnNetworkImp); + + return InferenceEngine::CNNNetwork(cnnNetworkImp); + } + + static std::string toString(const InferenceEngine::details::LayerTransformation::Params& params) { + std::ostringstream result; + result << + (params.supportAsymmetricQuantization ? "asymmetric" : "symmetric") << "_" << + params.precisionsOnActivations << "_" << + params.precisionsOnWeights << "_" << + params.quantizedTensorAlignmentOnActivations; - InferenceEngine::CNNNetwork transform(); + return result.str(); + } }; } // namespace LayerTestsUtils -- 2.34.1