From 05c23dfd94850b2bb155dc7cd6bedecfa4b4a129 Mon Sep 17 00:00:00 2001 From: Vladislav Golubev Date: Fri, 23 Apr 2021 13:26:53 +0300 Subject: [PATCH] [LPT][CommonOptimizations] ShuffleChannelsTransformation and ShuffleChannelsFusion (#4916) * [nGraph] op::v0::ShuffleChannels: added type_info macros * [LPT] ShuffleChannelsTransformation * [CPU] ShuffleChannels decomposition disabled * [LPT][TESTS] ShuffleChannelsTransformation functional tests * [LPT][TESTS] ShuffleChannelsTransformation plugin tests * [CommonOptimizations] Added ShuffleChannelsFusion transformation * [CommonOptimizations][TESTS] ShuffleChannelsFusion tests * refactoring and adding comments * [CommonOptimizations] ShuffleChannelsFusion refactoring and fixes * [CommonOptimizations] ShuffleChannelsFusion: removed unnecessary check * [CommonOptimizations] transformation refactored and test-cases with dynamic shape added --- .../low_precision/layer_transformation.hpp | 2 +- .../low_precision/shuffle_channels.hpp | 25 ++ .../src/layer_transformation.cpp | 2 +- .../src/mat_mul.cpp | 2 +- .../src/shuffle_channels.cpp | 93 ++++++ .../src/transformer.cpp | 2 + .../src/mkldnn_plugin/mkldnn_plugin.cpp | 2 + .../shuffle_channels_fusion.hpp | 40 +++ .../common_optimizations.cpp | 2 + .../shuffle_channels_fusion.cpp | 121 ++++++++ .../shuffle_channels_transformation.cpp | 290 ++++++++++++++++++ .../shuffle_channels_fusion_test.cpp | 126 ++++++++ .../shuffle_channels_transformation.cpp | 101 ++++++ .../shuffle_channels_transformation.cpp | 88 ++++++ .../shuffle_channels_transformation.hpp | 43 +++ .../shuffle_channels_transformation.cpp | 62 ++++ .../shuffle_channels_function.hpp | 46 +++ .../src/shuffle_channels_function.cpp | 83 +++++ .../include/ngraph/op/shuffle_channels.hpp | 4 +- ngraph/core/src/op/shuffle_channels.cpp | 4 +- 20 files changed, 1132 insertions(+), 6 deletions(-) create mode 100644 inference-engine/src/low_precision_transformations/include/low_precision/shuffle_channels.hpp create mode 100644 inference-engine/src/low_precision_transformations/src/shuffle_channels.cpp create mode 100644 inference-engine/src/transformations/include/transformations/common_optimizations/shuffle_channels_fusion.hpp create mode 100644 inference-engine/src/transformations/src/transformations/common_optimizations/shuffle_channels_fusion.cpp create mode 100644 inference-engine/tests/functional/inference_engine/lp_transformations/shuffle_channels_transformation.cpp create mode 100644 inference-engine/tests/functional/inference_engine/transformations/shuffle_channels_fusion_test.cpp create mode 100644 inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp create mode 100644 inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/shuffle_channels_transformation.hpp create mode 100644 inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/shuffle_channels_transformation.cpp create mode 100644 inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/shuffle_channels_function.hpp create mode 100644 inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/shuffle_channels_function.cpp diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp index e401bf8d6f7..54fadb9d738 100644 --- a/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp +++ b/inference-engine/src/low_precision_transformations/include/low_precision/layer_transformation.hpp @@ -342,7 +342,7 @@ protected: void addPattern(ngraph::pass::GraphRewrite& pass, TransformationContext& context, std::shared_ptr patternRoot) const; //TODO: replace with canBeTransformed when quantization by special dimension is supported for all transformations - bool canBeTransformedSpecialDimension(const TransformationContext& context, std::shared_ptr layer) const; + bool canBeTransformedSpatialDimension(const TransformationContext& context, std::shared_ptr layer) const; template void addSingleNodePattern(ngraph::pass::GraphRewrite& pass, TransformationContext& context) const { diff --git a/inference-engine/src/low_precision_transformations/include/low_precision/shuffle_channels.hpp b/inference-engine/src/low_precision_transformations/include/low_precision/shuffle_channels.hpp new file mode 100644 index 00000000000..42124d4b7b1 --- /dev/null +++ b/inference-engine/src/low_precision_transformations/include/low_precision/shuffle_channels.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include "low_precision/layer_transformation.hpp" + +namespace ngraph { +namespace pass { +namespace low_precision { + +class TRANSFORMATIONS_API ShuffleChannelsTransformation : public LayerTransformation { +public: + ShuffleChannelsTransformation(const Params& params); + void registerMatcherIn(GraphRewrite& pass, TransformationContext& context) const override; + bool transform(TransformationContext& context, ngraph::pattern::Matcher& m) const override; + bool isPrecisionPreserved(std::shared_ptr layer) const noexcept override; + bool canBeTransformed(const TransformationContext& context, std::shared_ptr op) const override; +}; + +} // namespace low_precision +} // namespace pass +} // namespace ngraph diff --git a/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp b/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp index a3d3b3b15d2..dbbb8206b4d 100644 --- a/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp +++ b/inference-engine/src/low_precision_transformations/src/layer_transformation.cpp @@ -115,7 +115,7 @@ bool LayerTransformation::canBeTransformed(const TransformationContext& context, return true; } -bool LayerTransformation::canBeTransformedSpecialDimension(const TransformationContext& context, std::shared_ptr layer) const { +bool LayerTransformation::canBeTransformedSpatialDimension(const TransformationContext& context, std::shared_ptr layer) const { if (!isQuantized(layer)) { return false; } diff --git a/inference-engine/src/low_precision_transformations/src/mat_mul.cpp b/inference-engine/src/low_precision_transformations/src/mat_mul.cpp index 8bb6cfa5d60..80e752448e4 100644 --- a/inference-engine/src/low_precision_transformations/src/mat_mul.cpp +++ b/inference-engine/src/low_precision_transformations/src/mat_mul.cpp @@ -163,7 +163,7 @@ bool MatMulTransformation::isPrecisionPreserved(std::shared_ptr layer) con } bool MatMulTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr layer) const { - if (!LayerTransformation::canBeTransformedSpecialDimension(context, layer)) { + if (!LayerTransformation::canBeTransformedSpatialDimension(context, layer)) { return false; } diff --git a/inference-engine/src/low_precision_transformations/src/shuffle_channels.cpp b/inference-engine/src/low_precision_transformations/src/shuffle_channels.cpp new file mode 100644 index 00000000000..2ed3e54a86b --- /dev/null +++ b/inference-engine/src/low_precision_transformations/src/shuffle_channels.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision/shuffle_channels.hpp" + +#include +#include +#include + +#include "low_precision/network_helper.hpp" + +namespace ngraph { +namespace pass { +namespace low_precision { +ShuffleChannelsTransformation::ShuffleChannelsTransformation(const Params& params) : LayerTransformation(params) {} + +void ShuffleChannelsTransformation::registerMatcherIn(GraphRewrite& pass, TransformationContext& context) const { + addPattern( + pass, + context, + make_op_pattern({ make_op_label() })); +} + +bool ShuffleChannelsTransformation::transform(TransformationContext& context, ngraph::pattern::Matcher& m) const { + if (!canBeTransformed(context, m.get_match_root())) { + return false; + } + + const auto shuffleChannels = as_type_ptr(NetworkHelper::separateInStandaloneBranch(m.get_match_root())); + auto dequantization = NetworkHelper::getDequantization(shuffleChannels); + + const auto shuffleDequantizationConstant = [&](const std::shared_ptr& eltwise) { + const auto normalizedConst = NetworkHelper::normalizeDequantizationShape(eltwise); + const auto constShape = normalizedConst->get_shape(); + + if (shape_size(constShape) == 1ul) { + return NetworkHelper::toScalar(normalizedConst); + } else { + const size_t normalizedAxis = ngraph::normalize_axis( + shuffleChannels->get_friendly_name(), + shuffleChannels->get_axis(), + shuffleChannels->get_input_partial_shape(0).rank()); + + if (constShape[normalizedAxis] == 1ul) { + return normalizedConst; + } else { + const auto group = shuffleChannels->get_group(); + const auto shuffledConst = fold(normalizedConst, normalizedAxis, group); + return as_type_ptr(shuffledConst); + } + } + }; + + if (dequantization.subtract) { + const auto shuffledSubConst = shuffleDequantizationConstant(dequantization.subtract); + replace_node(dequantization.subtractConstant, shuffledSubConst); + dequantization.subtractConstant = shuffledSubConst; + } + + const auto shuffledMulConst = shuffleDequantizationConstant(dequantization.multiply); + replace_node(dequantization.multiplyConstant, shuffledMulConst); + dequantization.multiplyConstant = shuffledMulConst; + + moveDequantizationAfter(context, shuffleChannels, dequantization, false); + return true; +} + +bool ShuffleChannelsTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr op) const { + if (!LayerTransformation::canBeTransformedSpatialDimension(context, op)) { + return false; + } + + const auto shuffleChannels = as_type_ptr(op); + if (shuffleChannels == nullptr) { + return false; + } + + const FakeQuantizeDequantization dequantization = NetworkHelper::getDequantization(shuffleChannels); + if (dequantization.empty()) { + return false; + } + + return true; +} + +bool ShuffleChannelsTransformation::isPrecisionPreserved(std::shared_ptr layer) const noexcept { + return true; +} + +} // namespace low_precision +} // namespace pass +} // namespace ngraph diff --git a/inference-engine/src/low_precision_transformations/src/transformer.cpp b/inference-engine/src/low_precision_transformations/src/transformer.cpp index d66263bdf07..18b49018760 100644 --- a/inference-engine/src/low_precision_transformations/src/transformer.cpp +++ b/inference-engine/src/low_precision_transformations/src/transformer.cpp @@ -45,6 +45,7 @@ #include "low_precision/prelu.hpp" #include "low_precision/reshape.hpp" #include "low_precision/relu.hpp" +#include "low_precision/shuffle_channels.hpp" #include "low_precision/squeeze.hpp" #include "low_precision/subtract.hpp" #include "low_precision/split.hpp" @@ -228,6 +229,7 @@ LowPrecisionTransformations LowPrecisionTransformer::getAllTransformations(const add(params). add(params). add(params). + add(params). add(params). add(params). add(params). diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index 5dd4fa84f1d..7f043c40361 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +270,7 @@ static void Transformation(CNNNetwork& clonedNetwork, const Config& conf) { // List of enabled/disabled transformations pass_config->disable(); + pass_config->disable(); pass_config->disable(); pass_config->disable(); pass_config->disable(); diff --git a/inference-engine/src/transformations/include/transformations/common_optimizations/shuffle_channels_fusion.hpp b/inference-engine/src/transformations/include/transformations/common_optimizations/shuffle_channels_fusion.hpp new file mode 100644 index 00000000000..0efd7e2b0d7 --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/common_optimizations/shuffle_channels_fusion.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include + +#include + +namespace ngraph { +namespace pass { + + class TRANSFORMATIONS_API ShuffleChannelsFusion; + +} // namespace pass +} // namespace ngraph + +/** + * @ingroup ie_transformation_common_api + * @brief ShuffleChannelsFusion transformation detects Reshape-Transpose-Reshape pattern + * and tries to fuse it into a single ShuffleChannels layer with axis = 1. + * + * x' = reshape(x, [N, group, C / group, H, W]) or reshape(x, [N, group, C / group, H * W]) + * x'' = transpose(x', [0, 2, 1, 3, 4]) or transpose(x', [0, 2, 1, 3]) + * y = reshape(x'', [N, C, H, W]) + * + * @param reshape_constants_check the flag that defines the need for additional checks of reshapes constant + * Additional checks are required when ShuffleChannelsFusion using inside offline transformations + * and are not necessary when ShuffleChannelsFusion using inside CommonOptimizations + */ + +class ngraph::pass::ShuffleChannelsFusion : public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + ShuffleChannelsFusion(const bool reshape_constants_check); +}; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp index 2df73b3a6a7..1e281888b98 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp @@ -32,6 +32,7 @@ #include "transformations/common_optimizations/clamp_fusion.hpp" #include "transformations/common_optimizations/pad_fusion.hpp" #include "transformations/common_optimizations/eliminate_unsqueeze_gather.hpp" +#include "transformations/common_optimizations/shuffle_channels_fusion.hpp" #include "transformations/common_optimizations/softmax_fusion.hpp" #include "transformations/common_optimizations/mvn_fusion.hpp" #include "transformations/common_optimizations/binarize_weights.hpp" @@ -104,6 +105,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptradd_matcher(); common_fusions->add_matcher(); common_fusions->add_matcher(); + common_fusions->add_matcher(false); common_fusions->add_matcher(); common_fusions->add_matcher(); common_fusions->add_matcher(); diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/shuffle_channels_fusion.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/shuffle_channels_fusion.cpp new file mode 100644 index 00000000000..054fb411f33 --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/shuffle_channels_fusion.cpp @@ -0,0 +1,121 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/common_optimizations/shuffle_channels_fusion.hpp" +#include "itt.hpp" + +#include +#include + +#include +#include +#include + +bool check_shapes(const ngraph::Shape& shape_input, const ngraph::Shape& shape_reshape_before, + const ngraph::AxisVector& transpose_constant_values, const ngraph::Shape& shape_reshape_after) { + // x: [N, C, H, W] + bool is_transformation_valid = (shape_input.size() == 4); + + // x'= reshape(x, [N, group, C / group, H * W]) or reshape(x, [N, group, C / group, H, W]) + bool is_reshape_before_valid = (shape_reshape_before.size() == 4 || shape_reshape_before.size() == 5); + if (is_reshape_before_valid) { + size_t group = shape_reshape_before[1]; + ngraph::Shape expected_reshape_before = { shape_input[0], group, shape_input[1] / group }; + + if (shape_reshape_before.size() == 4) { + expected_reshape_before.push_back(shape_input[2] * shape_input[3]); + } else { + expected_reshape_before.push_back(shape_input[2]); + expected_reshape_before.push_back(shape_input[3]); + } + + is_reshape_before_valid &= (expected_reshape_before == shape_reshape_before); + } + + // x''= transpose(x', [0, 2, 1, 3]) or transpose(x', [0, 2, 1, 3, 4]) + bool is_transpose_valid = (transpose_constant_values.size() == 4 || transpose_constant_values.size() == 5); + if (is_transpose_valid) { + ngraph::AxisVector expected_transpose_values{ 0, 2, 1, 3 }; + if (transpose_constant_values.size() == 5) { + expected_transpose_values.push_back(4); + } + + is_transpose_valid &= (expected_transpose_values == transpose_constant_values); + } + + // y = reshape(x'', [N, C, H, W]) + bool is_reshape_after_valid = (shape_input == shape_reshape_after); + + is_transformation_valid &= is_reshape_before_valid & is_transpose_valid & is_reshape_after_valid; + return is_transformation_valid; +} + +NGRAPH_RTTI_DEFINITION(ngraph::pass::ShuffleChannelsFusion, "ShuffleChannelsFusion", 0); + +ngraph::pass::ShuffleChannelsFusion::ShuffleChannelsFusion(const bool reshape_constants_check) { + MATCHER_SCOPE(ShuffleChannelsFusion); + auto input = ngraph::pattern::any_input(pattern::has_static_shape()); + auto reshape_before_const_pattern = ngraph::pattern::wrap_type(); + auto transpose_const_pattern = ngraph::pattern::wrap_type(); + auto reshape_after_const_pattern = ngraph::pattern::wrap_type(); + + auto has_static_shape_and_single_consumer = [](const Output& output) { + return pattern::has_static_shape()(output) && pattern::consumers_count(1)(output); + }; + auto reshape_before_pattern = ngraph::pattern::wrap_type({input, reshape_before_const_pattern}, + has_static_shape_and_single_consumer); + auto transpose_pattern = ngraph::pattern::wrap_type({reshape_before_pattern, transpose_const_pattern}, + has_static_shape_and_single_consumer); + auto reshape_after_pattern = ngraph::pattern::wrap_type({transpose_pattern, reshape_after_const_pattern}, + pattern::has_static_shape()); + + ngraph::matcher_pass_callback callback = [=](pattern::Matcher& m) { + const auto& pattern_map = m.get_pattern_value_map(); + + auto data = pattern_map.at(input); + auto reshape_before = std::dynamic_pointer_cast(pattern_map.at(reshape_before_pattern).get_node_shared_ptr()); + auto transpose = std::dynamic_pointer_cast(pattern_map.at(transpose_pattern).get_node_shared_ptr()); + auto reshape_after = std::dynamic_pointer_cast(pattern_map.at(reshape_after_pattern).get_node_shared_ptr()); + if (!reshape_after || !transpose || !reshape_after) + return false; + + if (reshape_constants_check) { + auto reshape_before_constant = std::dynamic_pointer_cast( + pattern_map.at(reshape_before_const_pattern).get_node_shared_ptr()); + auto reshape_after_constant = std::dynamic_pointer_cast( + pattern_map.at(reshape_after_const_pattern).get_node_shared_ptr()); + + if (!reshape_before_constant || !reshape_after_constant) + return false; + + const auto& reshape_before_values = reshape_before_constant->cast_vector(); + const auto& reshape_after_values = reshape_after_constant->cast_vector(); + if (std::any_of(reshape_before_values.cbegin(), reshape_before_values.cend(), [](const int64_t& value) { return value == -1; }) || + std::any_of(reshape_after_values.cbegin(), reshape_after_values.cend(), [](const int64_t& value) { return value == -1; })) { + return false; + } + } + + auto shape_input = reshape_before->get_input_shape(0); + auto shape_reshape_before = reshape_before->get_output_shape(0); + auto shape_reshape_after = reshape_after->get_output_shape(0); + + auto transpose_constant = std::dynamic_pointer_cast(pattern_map.at(transpose_const_pattern).get_node_shared_ptr()); + auto transpose_constant_values = transpose_constant->get_axis_vector_val(); + if (!check_shapes(shape_input, shape_reshape_before, transpose_constant_values, shape_reshape_after)) + return false; + + int64_t axis = 1ul; + int64_t group = shape_reshape_before[1]; + + auto shuffle_shannels = std::make_shared(data, axis, group); + shuffle_shannels->set_friendly_name(reshape_after->get_friendly_name()); + ngraph::copy_runtime_info({ reshape_before, transpose, reshape_after }, shuffle_shannels); + ngraph::replace_node(reshape_after, shuffle_shannels); + return true; + }; + + auto m = std::make_shared(reshape_after_pattern, matcher_name); + register_matcher(m, callback); +} diff --git a/inference-engine/tests/functional/inference_engine/lp_transformations/shuffle_channels_transformation.cpp b/inference-engine/tests/functional/inference_engine/lp_transformations/shuffle_channels_transformation.cpp new file mode 100644 index 00000000000..88a205089d6 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/lp_transformations/shuffle_channels_transformation.cpp @@ -0,0 +1,290 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "layer_transformation.hpp" + +#include +#include + +#include + +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" +#include "simple_low_precision_transformer.hpp" +#include "lpt_ngraph_functions/shuffle_channels_function.hpp" +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" + +namespace { +using namespace testing; +using namespace ngraph::pass; + +class ShuffleChannelsTransformationTestValues { +public: +public: + class Actual { + public: + ngraph::element::Type inputPrecision; + ngraph::builder::subgraph::DequantizationOperations dequantization; + }; + + class Expected { + public: + ngraph::element::Type inputPrecision; + ngraph::builder::subgraph::DequantizationOperations dequantizationBefore; + ngraph::element::Type preicsionAfterOperation; + ngraph::builder::subgraph::DequantizationOperations dequantizationAfter; + }; + + ngraph::pass::low_precision::LayerTransformation::Params params; + std::int64_t axis; + std::int64_t group; + Actual actual; + Expected expected; +}; + +typedef std::tuple< + ngraph::Shape, + ShuffleChannelsTransformationTestValues> ShuffleChannelsTransformationParams; + +class ShuffleChannelsTransformation : public LayerTransformation, public testing::WithParamInterface { +public: + void SetUp() override { + ngraph::Shape inputShape = std::get<0>(GetParam()); + ShuffleChannelsTransformationTestValues testValues = std::get<1>(GetParam()); + + actualFunction = ngraph::builder::subgraph::ShuffleChannelsFunction::getOriginal( + testValues.actual.inputPrecision, + inputShape, + testValues.actual.dequantization, + testValues.axis, + testValues.group); + + SimpleLowPrecisionTransformer transform; + transform.add(testValues.params); + transform.transform(actualFunction); + + referenceFunction = ngraph::builder::subgraph::ShuffleChannelsFunction::getReference( + testValues.expected.inputPrecision, + inputShape, + testValues.expected.dequantizationBefore, + testValues.axis, + testValues.group, + testValues.expected.preicsionAfterOperation, + testValues.expected.dequantizationAfter); + } + + static std::string getTestCaseName(testing::TestParamInfo obj) { + ngraph::Shape inputShape = std::get<0>(obj.param); + ShuffleChannelsTransformationTestValues testValues = std::get<1>(obj.param); + + std::ostringstream result; + result << + LayerTransformation::getTestCaseNameByParams(testValues.actual.inputPrecision, inputShape, testValues.params) << "_" << + testValues.actual.dequantization << "_axis_" << + testValues.axis << "_group_" << testValues.group; + + return result.str(); + } +}; + +TEST_P(ShuffleChannelsTransformation, CompareFunctions) { + actualFunction->validate_nodes_and_infer_types(); + auto res = compare_functions(referenceFunction, actualFunction, true, true); + ASSERT_TRUE(res.first) << res.second; +} + +const std::vector inputShapes = { + { 1, 3, 8, 10 }, + { 4, 3, 8, 10 }, +}; + +const std::vector testValues = { + // U8 per tensor quantization + { + LayerTransformation::createParamsU8I8(), + 1, // axis + 1, // group + { + ngraph::element::u8, + {{ngraph::element::f32}, {128.f}, {0.02f}} + }, + { + ngraph::element::u8, + {}, + ngraph::element::u8, + {{ngraph::element::f32}, {128.f}, {0.02f}} + } + }, + // U8 per channel quantization + { + LayerTransformation::createParamsU8I8(), + 1, + 1, + { + ngraph::element::u8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + }, + { + ngraph::element::u8, + {}, + ngraph::element::u8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + } + }, + // U8 quantization by special dimension, shuffling by the same dimension + { + LayerTransformation::createParamsU8I8(), + 2, + 4, + { + ngraph::element::u8, + { + {ngraph::element::f32}, + {{121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f, 128.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}}, + {{1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}} + } + }, + { + ngraph::element::u8, + {}, + ngraph::element::u8, + { + {ngraph::element::f32}, + {{121.f, 123.f, 125.f, 127.f, 122.f, 124.f, 126.f, 128.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}}, + {{1.f, 3.f, 5.f, 7.f, 2.f, 4.f, 6.f, 8.f}, ngraph::element::f32, ngraph::Shape {1, 1, 8, 1}}, + } + } + }, + // U8 per channel quantization, shuffling by special dimension + { + LayerTransformation::createParamsU8I8(), + -2, + 4, + { + ngraph::element::u8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + }, + { + ngraph::element::u8, + {}, + ngraph::element::u8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + } + }, + // I8 per tensor quantization + { + LayerTransformation::createParamsI8I8(), + 1, + 1, + { + ngraph::element::i8, + {{ngraph::element::f32}, {128.f}, {0.02f}} + }, + { + ngraph::element::i8, + {}, + ngraph::element::i8, + {{ngraph::element::f32}, {128.f}, {0.02f}} + } + }, + // I8 per channel quantization + { + LayerTransformation::createParamsI8I8(), + 1, + 1, + { + ngraph::element::i8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + }, + { + ngraph::element::i8, + {}, + ngraph::element::i8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + } + }, + // I8 quantization by special dimension, shuffling by the same dimension + { + LayerTransformation::createParamsI8I8(), + 2, + 4, + { + ngraph::element::i8, + { + {ngraph::element::f32}, + {{121.f, 122.f, 123.f, 124.f, 125.f, 126.f, 127.f, 128.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}}, + {{1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}} + } + }, + { + ngraph::element::i8, + {}, + ngraph::element::i8, + { + {ngraph::element::f32}, + {{121.f, 123.f, 125.f, 127.f, 122.f, 124.f, 126.f, 128.f}, ngraph::element::f32, ngraph::Shape{1, 1, 8, 1}}, + {{1.f, 3.f, 5.f, 7.f, 2.f, 4.f, 6.f, 8.f}, ngraph::element::f32, ngraph::Shape {1, 1, 8, 1}}, + } + } + }, + // I8 per channel quantization, shuffling by special dimension + { + LayerTransformation::createParamsI8I8(), + -2, + 4, + { + ngraph::element::i8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + }, + { + ngraph::element::i8, + {}, + ngraph::element::i8, + {{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{0.01f, 0.02f, 0.03f}}} + } + }, + // U8 per tensor quantization, not update precision + { + LayerTransformation::createParamsU8I8().setUpdatePrecisions(false), + 3, + 5, + { + ngraph::element::f32, + {{}, {128.f}, {0.02f}} + }, + { + ngraph::element::f32, + {}, + ngraph::element::f32, + {{}, {128.f}, {0.02f}} + } + }, + // U8 without dequantization operations + { + LayerTransformation::createParamsU8I8(), + 2, + 4, + { + ngraph::element::u8, + {{}, {}, {}} + }, + { + ngraph::element::u8, + {}, + ngraph::element::u8, + {{}, {}, {}} + } + }, +}; + +INSTANTIATE_TEST_CASE_P( + smoke_LPT, + ShuffleChannelsTransformation, + ::testing::Combine( + ::testing::ValuesIn(inputShapes), + ::testing::ValuesIn(testValues)), + ShuffleChannelsTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/inference_engine/transformations/shuffle_channels_fusion_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/shuffle_channels_fusion_test.cpp new file mode 100644 index 00000000000..f8e9c6ec259 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/shuffle_channels_fusion_test.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "common_test_utils/test_common.hpp" +#include +#include + +#include +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +namespace { +using namespace testing; +using namespace ngraph; + +class ShuffleChannelsFusionTestValues { +public: + bool dynamicShape; + std::vector reshape_before_val; + std::vector transpose_val; + std::vector reshape_after_val; + size_t batch_size; + bool check_reshape_values; + bool fuse_happened; +}; + +template +inline std::ostream& operator<<(std::ostream& os, const std::vector& values) { + os << "{ "; + for (size_t i = 0; i < values.size(); ++i) { + os << values[i]; + if (i != (values.size() - 1ul)) { + os << ", "; + } + } + os << " }"; + return os; +} + +class ShuffleChannelsFusion : public ::testing::Test, public testing::WithParamInterface { +public: + void SetUp() override { + const auto values = GetParam(); + { + const PartialShape inputPartialShape = values.dynamicShape ? PartialShape::dynamic() : Shape{ values.batch_size, 128, 720, 480 }; + auto input0 = std::make_shared(element::f32, inputPartialShape); + auto shape_reshape_before = opset6::Constant::create(element::i64, Shape{ values.reshape_before_val.size() }, values.reshape_before_val); + auto permutation = opset6::Constant::create(element::i64, Shape{ values.transpose_val.size() }, values.transpose_val); + auto shape_reshape_after = opset6::Constant::create(element::i64, Shape{ values.reshape_after_val.size() }, values.reshape_after_val); + + auto reshape_before = std::make_shared(input0, shape_reshape_before, false); + auto permute = std::make_shared(reshape_before, permutation); + auto reshape_after = std::make_shared(permute, shape_reshape_after, false); + f = std::make_shared(ngraph::NodeVector{ reshape_after }, ngraph::ParameterVector{ input0 }); + + ngraph::pass::Manager manager; + auto pass_config = manager.get_pass_config(); + manager.register_pass(); + manager.register_pass(values.check_reshape_values); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + if (values.fuse_happened) { + auto input0 = std::make_shared(ngraph::element::f32, ngraph::Shape{ values.batch_size, 128, 720, 480 }); + auto shuffle_channels = std::make_shared(input0, 1, values.reshape_before_val[1]); + f_ref = std::make_shared(ngraph::NodeVector{ shuffle_channels }, ngraph::ParameterVector{ input0 }); + } else { + f_ref = f; + } + } + + static std::string getTestCaseName(testing::TestParamInfo obj) { + const ShuffleChannelsFusionTestValues testValues = obj.param; + + std::ostringstream result; + if (testValues.dynamicShape) { + result << "_dynamic_shape_"; + } else { + result << "_batch_size_" << testValues.batch_size; + } + + result << "_before_" << testValues.reshape_before_val + << "_transpose_" << testValues.transpose_val << "_after_" << testValues.reshape_after_val + << (testValues.check_reshape_values ? "check_reshape_values" : ""); + + return result.str(); + } + +protected: + std::shared_ptr f; + std::shared_ptr f_ref; +}; + +TEST_P(ShuffleChannelsFusion, CompareFunctions) { + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +const std::vector testValues = { + { true, {1, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, 128, 720, 480}, 1, false, false }, + { false, {1, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, 128, 720, 480}, 1, false, true }, + { false, {1, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, 128, 720, 480}, 1, true, true }, + { false, {1, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, -1, 720, 480}, 1, false, true }, + { false, {4, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, -1, 720, 480}, 4, false, false }, + { false, {1, 2, 64, 720, 480}, {0, 2, 1, 3, 4}, {1, -1, 720, 480}, 1, true, false }, + { true, {1, 4, 32, 720 * 480}, {0, 2, 1, 3}, {1, 128, 720, 480}, 1, false, false }, + { false, {1, 4, 32, 720 * 480}, {0, 2, 1, 3}, {1, 128, 720, 480}, 1, false, true }, + { false, {1, 2, 64, 720 * 480}, {0, 2, 1, 3}, {1, 128, 720, 480}, 1, true, true }, + { false, {1, 2, 64, 720 * 480}, {0, 2, 1, 3}, {1, -1, 720, 480}, 1, false, true }, + { false, {4, 2, 64, 720 * 480}, {0, 2, 1, 3}, {1, -1, 720, 480}, 4, false, false }, + { false, {1, 2, 64, 720 * 480}, {0, 2, 1, 3}, {1, -1, 720, 480}, 1, true, false }, +}; +INSTANTIATE_TEST_CASE_P( + TransformationTests, + ShuffleChannelsFusion, + ::testing::ValuesIn(testValues), + ShuffleChannelsFusion::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp new file mode 100644 index 00000000000..6d2e97a0008 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/shuffle_channels_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32, + // ngraph::element::f16 +}; + +const std::vector inputShapes = { + { 1, 3, 16, 16 }, + { 4, 3, 16, 16 } +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams().setUpdatePrecisions(true), +}; + +const std::vector params = { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + 0, + 1, + "output_original", + "U8" + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + -3, + 1, + "output_original", + "U8" + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { 0.f, 0.f, 0.f }, + { 25.5f / 2.f, 25.5f / 4.f, 25.5f } + }, + -3, + 1, + "output_original", + "U8" + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { -4.f, -3.f, 0.f }, + { 10.f, 12.f, 25.5f } + }, + -3, + 1, + "output_original", + "U8" + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + 2, + 4, + "output_original", + "U8" + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { 0.f, 0.f, 0.f }, + { 25.5f / 2.f, 25.5f / 4.f, 25.5f } + }, + -1, + 8, + "output_original", + "U8" + }, +}; + +INSTANTIATE_TEST_CASE_P(smoke_LPT, ShuffleChannelsTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(inputShapes), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(params)), + ShuffleChannelsTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp new file mode 100644 index 00000000000..e1fae4213e9 --- /dev/null +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/low_precision_transformations/shuffle_channels_transformation.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision_transformations/shuffle_channels_transformation.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { +const std::vector netPrecisions = { + ngraph::element::f32, + ngraph::element::f16 +}; + +const std::vector inputShapes = { + { 1, 3, 16, 16 } +}; + +const std::vector trasformationParamValues = { + LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParams(), +}; + +const std::vector params = { + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + 0, + 1, + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + -3, + 1, + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { 0.f, 0.f, 0.f }, + { 25.5f / 2.f, 25.5f / 4.f, 25.5f } + }, + -3, + 1, + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { -4.f, -3.f, 0.f }, + { 10.f, 12.f, 25.5f } + }, + -3, + 1, + }, + { + { 256ul, ngraph::Shape { 1, 1, 1, 1 }, { 0.f }, { 255.f }, { 0.f }, { 25.5f } }, + 2, + 4, + }, + { + { + 256ul, + ngraph::Shape { 1, 3, 1, 1 }, + { 0.f }, + { 25.5f }, + { 0.f, 0.f, 0.f }, + { 25.5f / 2.f, 25.5f / 4.f, 25.5f } + }, + -1, + 8, + }, +}; + +INSTANTIATE_TEST_CASE_P(smoke_LPT, ShuffleChannelsTransformation, + ::testing::Combine( + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(inputShapes), + ::testing::Values(CommonTestUtils::DEVICE_GPU), + ::testing::ValuesIn(trasformationParamValues), + ::testing::ValuesIn(params)), + ShuffleChannelsTransformation::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/shuffle_channels_transformation.hpp b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/shuffle_channels_transformation.hpp new file mode 100644 index 00000000000..217eb2f7ea9 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/low_precision_transformations/shuffle_channels_transformation.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include "shared_test_classes/base/low_precision_transformations/layer_transformation.hpp" +#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp" + +namespace LayerTestsDefinitions { + +class ShuffleChannelsTransformationParam { +public: + ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantizeOnData; + std::int64_t axis; + std::int64_t group; + std::string layerName; + std::string expectedKernelType; +}; + +typedef std::tuple< + ngraph::element::Type, + ngraph::Shape, + std::string, + ngraph::pass::low_precision::LayerTransformation::Params, + ShuffleChannelsTransformationParam +> ShuffleChannelsTransformationParams; + +class ShuffleChannelsTransformation : + public testing::WithParamInterface, + public LayerTestsUtils::LayerTransformation { +public: + static std::string getTestCaseName(testing::TestParamInfo obj); + +protected: + void SetUp() override; + void Run() override; +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/shuffle_channels_transformation.cpp b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/shuffle_channels_transformation.cpp new file mode 100644 index 00000000000..06d502a69d8 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/low_precision_transformations/shuffle_channels_transformation.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "low_precision_transformations/shuffle_channels_transformation.hpp" + +#include +#include +#include +#include + +#include + +#include "common_test_utils/common_utils.hpp" +#include "functional_test_utils/plugin_cache.hpp" +#include "shared_test_classes/base/layer_test_utils.hpp" +#include "lpt_ngraph_functions/shuffle_channels_function.hpp" + +namespace LayerTestsDefinitions { + +std::string ShuffleChannelsTransformation::getTestCaseName(testing::TestParamInfo obj) { + ngraph::element::Type netPrecision; + ngraph::Shape inputShape; + std::string targetDevice; + ngraph::pass::low_precision::LayerTransformation::Params params; + ShuffleChannelsTransformationParam param; + std::tie(netPrecision, inputShape, targetDevice, params, param) = obj.param; + + std::ostringstream result; + result << getTestCaseNameByParams(netPrecision, inputShape, targetDevice, params) << "_" << + param.fakeQuantizeOnData << "_axis_" << param.axis << "_group_" << param.group; + return result.str(); +} + +void ShuffleChannelsTransformation::SetUp() { + ngraph::element::Type netPrecision; + ngraph::Shape inputShape; + ngraph::pass::low_precision::LayerTransformation::Params params; + ShuffleChannelsTransformationParam param; + std::tie(netPrecision, inputShape, targetDevice, params, param) = this->GetParam(); + + function = ngraph::builder::subgraph::ShuffleChannelsFunction::getOriginal( + netPrecision, + inputShape, + param.fakeQuantizeOnData, + param.axis, + param.group); +} + +void ShuffleChannelsTransformation::Run() { + LayerTestsCommon::Run(); + + const auto params = std::get<4>(GetParam()); + const auto actualType = getRuntimePrecision(params.layerName); + EXPECT_EQ(actualType, params.expectedKernelType); +} + +TEST_P(ShuffleChannelsTransformation, CompareWithRefImpl) { + Run(); +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/shuffle_channels_function.hpp b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/shuffle_channels_function.hpp new file mode 100644 index 00000000000..6ebd3bcda99 --- /dev/null +++ b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/include/lpt_ngraph_functions/shuffle_channels_function.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "lpt_ngraph_functions/common/dequantization_operations.hpp" +#include "lpt_ngraph_functions/common/builders.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { + +class ShuffleChannelsFunction { +public: + static std::shared_ptr getOriginal( + const ngraph::element::Type inputPrecision, + const ngraph::Shape& inputShape, + const ngraph::builder::subgraph::DequantizationOperations& deqBefore, + const std::int64_t axis, + const std::int64_t group); + + static std::shared_ptr getOriginal( + const ngraph::element::Type inputPrecision, + const ngraph::Shape& inputShape, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData, + const std::int64_t axis, + const std::int64_t group); + + static std::shared_ptr getReference( + const ngraph::element::Type inputPrecision, + const ngraph::Shape& inputShape, + const ngraph::builder::subgraph::DequantizationOperations& deqBefore, + const std::int64_t axis, + const std::int64_t group, + const ngraph::element::Type precisionAfterOperation, + const ngraph::builder::subgraph::DequantizationOperations& deqAfter); +}; + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/shuffle_channels_function.cpp b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/shuffle_channels_function.cpp new file mode 100644 index 00000000000..5d3eb571204 --- /dev/null +++ b/inference-engine/tests/ngraph_helpers/lpt_ngraph_functions/src/shuffle_channels_function.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "low_precision/network_helper.hpp" +#include "lpt_ngraph_functions/common/builders.hpp" + +#include "lpt_ngraph_functions/shuffle_channels_function.hpp" +#include "ngraph_functions/subgraph_builders.hpp" + +namespace ngraph { +namespace builder { +namespace subgraph { +std::shared_ptr ShuffleChannelsFunction::getOriginal( + const element::Type inputPrecision, + const Shape& inputShape, + const builder::subgraph::DequantizationOperations& deqBefore, + const std::int64_t axis, + const std::int64_t group) { + const auto input = std::make_shared(inputPrecision, inputShape); + const auto dequantization = makeDequantization(input, deqBefore); + + const auto shuffleChannels = std::make_shared(dequantization, axis, group); + shuffleChannels->set_friendly_name("output"); + + const auto function = std::make_shared( + ResultVector{ std::make_shared(shuffleChannels) }, + ParameterVector{ input }, + "ShuffleChannelsFunction"); + + return function; +} + +std::shared_ptr ShuffleChannelsFunction::getOriginal( + const ngraph::element::Type inputPrecision, + const ngraph::Shape& inputShape, + const ngraph::builder::subgraph::FakeQuantizeOnData& fqOnData, + const std::int64_t axis, + const std::int64_t group) { + const auto input = std::make_shared(inputPrecision, inputShape); + const auto fakeQuantize = makeFakeQuantize(input, inputPrecision, fqOnData); + + const auto shuffleChannels = std::make_shared(fakeQuantize, axis, group); + shuffleChannels->set_friendly_name("output"); + + const auto function = std::make_shared( + ResultVector{ std::make_shared(shuffleChannels) }, + ParameterVector{ input }, + "ShuffleChannelsFunction"); + + return function; +} + +std::shared_ptr ShuffleChannelsFunction::getReference( + const ngraph::element::Type inputPrecision, + const ngraph::Shape& inputShape, + const ngraph::builder::subgraph::DequantizationOperations& deqBefore, + const std::int64_t axis, + const std::int64_t group, + const ngraph::element::Type precisionAfterOperation, + const ngraph::builder::subgraph::DequantizationOperations& deqAfter) { + const auto input = std::make_shared(inputPrecision, inputShape); + const auto dequantizationBefore = makeDequantization(input, deqBefore); + + const auto shuffleChannels = std::make_shared(dequantizationBefore, axis, group); + ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(shuffleChannels, precisionAfterOperation); + + const auto dequantizationAfter = makeDequantization(shuffleChannels, deqAfter); + dequantizationAfter->set_friendly_name("output"); + + const auto function = std::make_shared( + ResultVector{ std::make_shared(dequantizationAfter) }, + ParameterVector{ input }, + "ShuffleChannelsFunction"); + + return function; +} + +} // namespace subgraph +} // namespace builder +} // namespace ngraph diff --git a/ngraph/core/include/ngraph/op/shuffle_channels.hpp b/ngraph/core/include/ngraph/op/shuffle_channels.hpp index 0cfcad09d8d..4bccd9c231a 100644 --- a/ngraph/core/include/ngraph/op/shuffle_channels.hpp +++ b/ngraph/core/include/ngraph/op/shuffle_channels.hpp @@ -19,8 +19,8 @@ namespace ngraph class NGRAPH_API ShuffleChannels : public Op { public: - static constexpr NodeTypeInfo type_info{"ShuffleChannels", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + NGRAPH_RTTI_DECLARATION; + ShuffleChannels() = default; /// \brief Constructs a ShuffleChannels node. /// diff --git a/ngraph/core/src/op/shuffle_channels.cpp b/ngraph/core/src/op/shuffle_channels.cpp index 205addd4ffe..5c2e2cb7837 100644 --- a/ngraph/core/src/op/shuffle_channels.cpp +++ b/ngraph/core/src/op/shuffle_channels.cpp @@ -16,7 +16,9 @@ using namespace std; using namespace ngraph; -constexpr NodeTypeInfo op::ShuffleChannels::type_info; +NGRAPH_SUPPRESS_DEPRECATED_START + +NGRAPH_RTTI_DEFINITION(op::v0::ShuffleChannels, "ShuffleChannels", 0); op::ShuffleChannels::ShuffleChannels(const Output& data, const int64_t axis,