From 57d49f32154a6f306ff7709e9178473448227920 Mon Sep 17 00:00:00 2001 From: Alexandra Sidorova Date: Fri, 21 May 2021 14:35:56 +0300 Subject: [PATCH] [CPU] Added MVN fusion for case with constants inside (#5644) --- .../mkldnn_plugin/nodes/mkldnn_mvn_node.cpp | 63 +++++----- .../src/mkldnn_plugin/nodes/mkldnn_mvn_node.h | 2 +- .../common_optimizations/mvn_fusion.hpp | 32 ++++- .../common_optimizations/mvn_fusion.cpp | 115 +++++++++++++++++- .../transformations/mvn_fusion_test.cpp | 46 +++++++ .../single_layer_tests/mvn.cpp | 3 + .../subgraph_tests/mvn_multiply_add.cpp | 94 ++++++++++++++ .../plugin/cpu/single_layer_tests/mvn.cpp | 57 +++++++++ .../subgraph_tests/mvn_multiply_add.hpp | 15 +++ .../subgraph/mvn_multiply_add.hpp | 34 ++++++ .../src/subgraph/mvn_multiply_add.cpp | 59 +++++++++ 11 files changed, 482 insertions(+), 38 deletions(-) create mode 100644 inference-engine/tests/functional/plugin/cpu/shared_tests_instances/subgraph_tests/mvn_multiply_add.cpp create mode 100644 inference-engine/tests/functional/plugin/shared/include/subgraph_tests/mvn_multiply_add.hpp create mode 100644 inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/subgraph/mvn_multiply_add.hpp create mode 100644 inference-engine/tests/functional/shared_test_classes/src/subgraph/mvn_multiply_add.cpp diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.cpp b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.cpp index 36d9942b09932f..0bac642158e09b 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.cpp @@ -691,37 +691,6 @@ MKLDNNMVNNode::MKLDNNMVNNode(const std::shared_ptr& op, const mkld epsMode_ = INSIDE_SQRT; acrossChannels_ = mvnOp->get_across_channels(); } - - transformTo5DCase(inDataShape); -} - -void MKLDNNMVNNode::transformTo5DCase(const ngraph::Shape& shape) { - switch (shape.size()) { - // for 1 and 2 rank, if acrossChannels_ is true, adjust shape to fully vectorize under unified 5d procedure. - // otherwise there are not enough data in spatial dimension to process in one kernel. - case 1 : // C - if (acrossChannels_) { - shape5D = std::make_tuple(1, 1, 1, 1, shape[0]); - acrossChannels_ = false; - break; - } else { - shape5D = std::make_tuple(1, shape[0], 1, 1, 1); - break; - } - case 2 : // NC - if (acrossChannels_) { - shape5D = std::make_tuple(1, shape[0], 1, shape[1], 1); - acrossChannels_ = false; - break; - } else { - shape5D = std::make_tuple(shape[0], shape[1], 1, 1, 1); - break; - } - case 3 : { shape5D = std::make_tuple(shape[0], shape[1], 1, shape[2], 1); break; } - case 4 : { shape5D = std::make_tuple(shape[0], shape[1], 1, shape[2], shape[3]); break; } - case 5 : { shape5D = std::make_tuple(shape[0], shape[1], shape[2], shape[3], shape[4]); break; } - default : { IE_THROW() << "MVN layer with name '" << getName() << "' doesn't support planar layout with rank: " << shape.size(); } - } } void MKLDNNMVNNode::getSupportedDescriptors() { @@ -840,6 +809,8 @@ void MKLDNNMVNNode::createPrimitive() { if (getSelectedPrimitiveDescriptor() == nullptr) IE_THROW() << "Preferable primitive descriptor is not set."; + const SizeVector in_dims = getParentEdgeAt(0)->getDims().ToSizeVector(); + transformTo5DCase(in_dims); auto selectedPD = getSelectedPrimitiveDescriptor(); auto jcp = jit_mvn_config_params(); jcp.src_prc = selectedPD->getConfig().inConfs[0].desc.getPrecision(); @@ -849,7 +820,6 @@ void MKLDNNMVNNode::createPrimitive() { jcp.planar_layout = MKLDNNMemory::GetPlainLayout(getChildEdgeAt(0)->getDims()) == selectedPD->getConfig().inConfs[0].desc.getLayout(); jcp.normalize_variance = normalizeVariance_; jcp.across_channels = acrossChannels_; - SizeVector in_dims = getParentEdgeAt(0)->getDims().ToSizeVector(); int N = 0; std::tie(N, jcp.C, jcp.D, jcp.H, jcp.W) = shape5D; @@ -892,6 +862,35 @@ void MKLDNNMVNNode::createPrimitive() { mvn_variance_kernel->create_ker(); } +void MKLDNNMVNNode::transformTo5DCase(const SizeVector& shape) { + switch (shape.size()) { + // for 1 and 2 rank, if acrossChannels_ is true, adjust shape to fully vectorize under unified 5d procedure. + // otherwise there are not enough data in spatial dimension to process in one kernel. + case 1 : // C + if (acrossChannels_) { + shape5D = std::make_tuple(1, 1, 1, 1, shape[0]); + acrossChannels_ = false; + break; + } else { + shape5D = std::make_tuple(1, shape[0], 1, 1, 1); + break; + } + case 2 : // NC + if (acrossChannels_) { + shape5D = std::make_tuple(1, shape[0], 1, shape[1], 1); + acrossChannels_ = false; + break; + } else { + shape5D = std::make_tuple(shape[0], shape[1], 1, 1, 1); + break; + } + case 3 : { shape5D = std::make_tuple(shape[0], shape[1], 1, shape[2], 1); break; } + case 4 : { shape5D = std::make_tuple(shape[0], shape[1], 1, shape[2], shape[3]); break; } + case 5 : { shape5D = std::make_tuple(shape[0], shape[1], shape[2], shape[3], shape[4]); break; } + default : { IE_THROW() << "MVN layer with name '" << getName() << "' doesn't support planar layout with rank: " << shape.size(); } + } +} + void MKLDNNMVNNode::setPostOps(mkldnn::primitive_attr &attr, bool initWeights) { mkldnn::post_ops ops; for (auto &node : fusedWith) { diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.h b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.h index 9ce7e784e406d0..dd0090c3d72079 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.h +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_mvn_node.h @@ -103,7 +103,7 @@ class MKLDNNMVNNode : public MKLDNNNode { void setPostOps(mkldnn::primitive_attr &attr, bool initWeights = false); - void transformTo5DCase(const ngraph::Shape& shape); + void transformTo5DCase(const InferenceEngine::SizeVector& shape); std::tuple shape5D; diff --git a/inference-engine/src/transformations/include/transformations/common_optimizations/mvn_fusion.hpp b/inference-engine/src/transformations/include/transformations/common_optimizations/mvn_fusion.hpp index 3de28fe67f9c52..c257c666214adf 100644 --- a/inference-engine/src/transformations/include/transformations/common_optimizations/mvn_fusion.hpp +++ b/inference-engine/src/transformations/include/transformations/common_optimizations/mvn_fusion.hpp @@ -16,7 +16,9 @@ namespace ngraph { namespace pass { - class TRANSFORMATIONS_API MVNFusion; +class TRANSFORMATIONS_API MVNFusion; +class TRANSFORMATIONS_API MVNFusionWithoutConstants; +class TRANSFORMATIONS_API MVNFusionWithConstantsInside; } // namespace pass } // namespace ngraph @@ -26,8 +28,32 @@ namespace pass { * @brief MVNFusion transformation replaces group of * operations: (x - ReduceMean(x, axes)) / (Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2)) + eps) to MVN op. */ -class ngraph::pass::MVNFusion : public ngraph::pass::MatcherPass { +class ngraph::pass::MVNFusionWithoutConstants : public ngraph::pass::MatcherPass { public: NGRAPH_RTTI_DECLARATION; - MVNFusion(); + MVNFusionWithoutConstants(); +}; + +/** + * @ingroup ie_transformation_common_api + * @brief MVNFusion transformation replaces group of + * operations: gamma * (x - ReduceMean(x, axes)) / (Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2)) + eps) + beta to MVN op. + */ +class ngraph::pass::MVNFusionWithConstantsInside : public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + MVNFusionWithConstantsInside(); +}; + +/** + * @ingroup ie_transformation_common_api + * @brief MVNFusion transformation replaces various sub-graphs with a MVN op. + */ +class ngraph::pass::MVNFusion: public ngraph::pass::GraphRewrite { +public: + NGRAPH_RTTI_DECLARATION; + MVNFusion() { + add_matcher(); + add_matcher(); + } }; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/mvn_fusion.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/mvn_fusion.cpp index 9ef143a614e664..374e7aeea24eb9 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/mvn_fusion.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/mvn_fusion.cpp @@ -27,8 +27,10 @@ std::function)> value_is_equal_to(const std::v }; } -ngraph::pass::MVNFusion::MVNFusion() { - MATCHER_SCOPE(MVNFusion); +NGRAPH_RTTI_DEFINITION(ngraph::pass::MVNFusionWithoutConstants, "MVNFusionWithoutConstants", 0); + +ngraph::pass::MVNFusionWithoutConstants::MVNFusionWithoutConstants() { + MATCHER_SCOPE(MVNFusionWithoutConstants); // Detect MVN decomposition pattern: // (x - ReduceMean(x, axes)) / (Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2)) + eps) auto x = pattern::any_input(); @@ -188,3 +190,112 @@ ngraph::pass::MVNFusion::MVNFusion() { auto m = std::make_shared(powerMulOrDiv, matcher_name); register_matcher(m, matcher_pass_callback); } + +NGRAPH_RTTI_DEFINITION(ngraph::pass::MVNFusionWithConstantsInside, "MVNFusionWithConstantsInside", 0); + +ngraph::pass::MVNFusionWithConstantsInside::MVNFusionWithConstantsInside() { + MATCHER_SCOPE(MVNFusionWithConstantsInside); + // Detect MVN decomposition pattern: + // (x - ReduceMean(x, axes)) * gamma / (Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2)) + eps) + beta + auto x = pattern::any_input(); + + // (x - ReduceMean(x, axes))^2 + // `------mean1-------' + auto mean1_axes = pattern::wrap_type(); + auto mean1 = pattern::wrap_type({ x, mean1_axes }); + + // (x - ReduceMean(x, axes))^2 + // `-squared_difference------' + auto squared_difference = pattern::wrap_type({ x, mean1 }); + + // 1 / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `---mean2--------------------------------' + auto mean2_axes = pattern::wrap_type(); + auto mean2 = pattern::wrap_type({ squared_difference, mean2_axes }); + + // 1 / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `------------------------------------------add--' + auto eps = pattern::wrap_type(); + auto add_eps = pattern::wrap_type({ mean2, eps }); + + // 1 / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `-power-------------------------------------------------' + auto const_0_5 = pattern::wrap_type(value_is_equal_to({-0.5})); + auto power = pattern::wrap_type({ add_eps, const_0_5 }); + + // gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `---mul1----------------------------------------------------' + auto gamma = pattern::wrap_type(); + auto mul1 = pattern::wrap_type({ power, gamma }); + + // x * gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `---mul2--------------------------------------------------------' + auto mul2 = pattern::wrap_type({ x, mul1 }); + + // ReduceMean(x, axes) * gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) - beta + // `-------------------mul3----------------------------------------------------------' + auto mul3 = pattern::wrap_type({ mul1, mean1 }); + + // beta - ReduceMean(x, axes) * gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + // `---sub-----------------------------------------------------------------------------------' + auto beta = pattern::wrap_type(); + auto sub = pattern::wrap_type({ beta, mul3 }); + + // Final Add + // x * gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + + // beta - ReduceMean(x, axes) * gamma / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) = + // gamma * (x - ReduceMean(x, axes)) / Sqrt(ReduceMean((x - ReduceMean(x, axes)) ^ 2) + eps) + beta + auto add = pattern::wrap_type({ mul2, sub }); + + ngraph::matcher_pass_callback matcher_pass_callback = [=](ngraph::pattern::Matcher& m) { + auto& pattern_to_output = m.get_pattern_value_map(); + auto x_output = pattern_to_output.at(x); + + auto const_0_5_node = std::dynamic_pointer_cast(pattern_to_output.at(const_0_5).get_node_shared_ptr()); + auto const_gamma_node = std::dynamic_pointer_cast(pattern_to_output.at(gamma).get_node_shared_ptr()); + auto const_beta_node = std::dynamic_pointer_cast(pattern_to_output.at(beta).get_node_shared_ptr()); + auto const_eps_node = std::dynamic_pointer_cast(pattern_to_output.at(eps).get_node_shared_ptr()); + if (!const_0_5_node || !const_beta_node || !const_gamma_node || !const_eps_node) { + return false; + } + + float eps_value; + bool valid_constant_values = op::util::has_constant_value(const_0_5_node, -0.5) && op::util::get_single_value(const_eps_node, eps_value); + if (!valid_constant_values) { + return false; + } + + auto axes_1_node = std::dynamic_pointer_cast(pattern_to_output.at(mean1_axes).get_node_shared_ptr()); + auto axes_2_node = std::dynamic_pointer_cast(pattern_to_output.at(mean2_axes).get_node_shared_ptr()); + if (!axes_1_node || !axes_2_node) { + return false; + } + + auto axes_1_value = axes_1_node->cast_vector(); + auto axes_2_value = axes_2_node->cast_vector(); + if (axes_1_value != axes_2_value) { + return false; + } + + auto mvn = std::make_shared(x_output, axes_1_node, true, eps_value, op::MVNEpsMode::INSIDE_SQRT); + auto mul_gamma = std::make_shared(mvn, const_gamma_node); + auto add_beta = std::make_shared(mul_gamma, const_beta_node); + + ngraph::copy_runtime_info({ pattern_to_output.at(mean1).get_node_shared_ptr(), + pattern_to_output.at(squared_difference).get_node_shared_ptr(), + pattern_to_output.at(add_eps).get_node_shared_ptr(), + pattern_to_output.at(power).get_node_shared_ptr(), + pattern_to_output.at(mul1).get_node_shared_ptr(), + pattern_to_output.at(mul2).get_node_shared_ptr(), + pattern_to_output.at(mul3).get_node_shared_ptr(), + pattern_to_output.at(sub).get_node_shared_ptr(), + pattern_to_output.at(add).get_node_shared_ptr() }, + { mvn, const_gamma_node, mul_gamma, const_beta_node, add_beta }); + add_beta->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::replace_node(m.get_match_root(), add_beta); + return true; + }; + + auto m = std::make_shared(add, matcher_name); + register_matcher(m, matcher_pass_callback); +} diff --git a/inference-engine/tests/functional/inference_engine/transformations/mvn_fusion_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/mvn_fusion_test.cpp index 21b2b695454449..e45258a63e67b3 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/mvn_fusion_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/mvn_fusion_test.cpp @@ -419,3 +419,49 @@ TEST(TransformationTests, MVNFusionTestAltDivInsideSqrt) { auto res = compare_functions(f, f_ref); ASSERT_TRUE(res.first) << res.second; } + +TEST(TransformationTests, MVNFusionTestWithParametersInside) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 3, 224 }); + auto mean1_axes = ngraph::opset6::Constant::create(ngraph::element::i32, ngraph::Shape{ 1 }, { 2 }); + auto mean1 = std::make_shared(input, mean1_axes, true); + auto squared_difference = std::make_shared(input, mean1); + auto mean2_axes = ngraph::opset6::Constant::create(ngraph::element::i32, ngraph::Shape{ 1 }, { 2 }); + auto mean2 = std::make_shared(squared_difference, mean2_axes, true); + auto eps = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { 1e-9 }); + auto add_eps = std::make_shared(mean2, eps); + auto const_0_5 = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { -0.5 }); + auto power_sqrt = std::make_shared(add_eps, const_0_5); + auto gamma = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { 1 }); + auto mul_gamma = std::make_shared(power_sqrt, gamma); + auto mul1 = std::make_shared(input, mul_gamma); + auto mul2 = std::make_shared(mul_gamma, mean1); + auto beta = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { -1 }); + auto sub = std::make_shared(beta, mul2); + auto add = std::make_shared(mul1, sub); + + f = std::make_shared(ngraph::NodeVector{ add }, ngraph::ParameterVector{ input }); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{ 1, 3, 224 }); + auto axes = ngraph::opset6::Constant::create(ngraph::element::i32, ngraph::Shape{ 1 }, { 2 }); + auto mvn = std::make_shared(input, axes, true, 1e-9, ngraph::op::MVNEpsMode::INSIDE_SQRT); + auto gamma = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { 1 }); + auto mul_gamma = std::make_shared(mvn, gamma); + auto beta = ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape{}, { -1 }); + auto add = std::make_shared(mul_gamma, beta); + + f_ref = std::make_shared(ngraph::NodeVector{ add }, ngraph::ParameterVector{ input }); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/mvn.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/mvn.cpp index 3975e3c0c10b6a..c633c1b6bc82dd 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/mvn.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/mvn.cpp @@ -10,6 +10,9 @@ using namespace LayerTestsDefinitions; const std::vector> inputShapes = { + {8}, + {1, 16}, + {3, 19}, {1, 32, 17}, {1, 37, 9}, {1, 16, 5, 8}, diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/subgraph_tests/mvn_multiply_add.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/subgraph_tests/mvn_multiply_add.cpp new file mode 100644 index 00000000000000..3150926b2a9ea9 --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/subgraph_tests/mvn_multiply_add.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "subgraph_tests/mvn_multiply_add.hpp" + +using namespace SubgraphTestsDefinitions; +using namespace InferenceEngine; + +namespace { + +const std::vector netPrecision = { + Precision::FP32 +}; + +std::vector idxPrecision = { + Precision::I64 +}; + +const std::vector acrossChannels = { + true, + false +}; + +const std::vector normalizeVariance = { + true, + false +}; + +const std::vector epsilon = { + 0.000000001 +}; + +const std::vector epsMode = { + "inside_sqrt", + "outside_sqrt" +}; + +const std::vector> shapes_1D = { + std::pair{ SizeVector{5}, SizeVector{5}}, + std::pair{ SizeVector{64}, SizeVector{64}}, +}; + +const std::vector> shapes_2D = { + std::pair{ SizeVector{1, 5}, SizeVector{1, 5}}, + std::pair{ SizeVector{2, 17}, SizeVector{1, 17}}, + std::pair{ SizeVector{9, 64}, SizeVector{1, 64}}, + std::pair{ SizeVector{5, 15}, SizeVector{1, 15}}, +}; + +const std::vector> shapes_3D = { + std::pair{ SizeVector{1, 5, 8}, SizeVector{1, 5, 8}}, + std::pair{ SizeVector{2, 17, 9}, SizeVector{1, 1, 9}}, + std::pair{ SizeVector{1, 1, 10}, SizeVector{1, 1, 10}}, + std::pair{ SizeVector{2, 3, 3}, SizeVector{2, 3, 3}}, +}; + +INSTANTIATE_TEST_CASE_P(smoke_MVNMultiplyAdd_1D, MVNMultiplyAdd, + ::testing::Combine( + ::testing::ValuesIn(shapes_1D), + ::testing::ValuesIn(netPrecision), + ::testing::ValuesIn(idxPrecision), + ::testing::Values(std::vector{0}), + ::testing::ValuesIn(normalizeVariance), + ::testing::ValuesIn(epsilon), + ::testing::ValuesIn(epsMode), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + MVNMultiplyAdd::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_MVNMultiplyAdd_2D, MVNMultiplyAdd, + ::testing::Combine( + ::testing::ValuesIn(shapes_2D), + ::testing::ValuesIn(netPrecision), + ::testing::ValuesIn(idxPrecision), + ::testing::Values(std::vector{1}), + ::testing::ValuesIn(normalizeVariance), + ::testing::ValuesIn(epsilon), + ::testing::ValuesIn(epsMode), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + MVNMultiplyAdd::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_MVNMultiplyAdd_3D, MVNMultiplyAdd, + ::testing::Combine( + ::testing::ValuesIn(shapes_3D), + ::testing::ValuesIn(netPrecision), + ::testing::ValuesIn(idxPrecision), + ::testing::Values(std::vector{2}), + ::testing::ValuesIn(normalizeVariance), + ::testing::ValuesIn(epsilon), + ::testing::ValuesIn(epsMode), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + MVNMultiplyAdd::getTestCaseName); + +} // namespace diff --git a/inference-engine/tests/functional/plugin/cpu/single_layer_tests/mvn.cpp b/inference-engine/tests/functional/plugin/cpu/single_layer_tests/mvn.cpp index db53819cdce2ad..31ca8b3cd09e55 100644 --- a/inference-engine/tests/functional/plugin/cpu/single_layer_tests/mvn.cpp +++ b/inference-engine/tests/functional/plugin/cpu/single_layer_tests/mvn.cpp @@ -78,6 +78,16 @@ TEST_P(MvnLayerCPUTest, CompareWithRefs) { } namespace { +const std::vector> inputShapes_1D = { + {5}, + {16}, +}; + +const std::vector> inputShapes_2D = { + {1, 32}, + {16, 64}, +}; + const std::vector> inputShapes_3D = { {1, 32, 17}, {1, 37, 9}, @@ -131,6 +141,36 @@ std::vector cpuParams_5D = { CPUSpecificParams({ncdhw}, {ncdhw}, {}, {}) }; +const auto Mvn1D = ::testing::Combine( + ::testing::Combine( + ::testing::ValuesIn(inputShapes_1D), + ::testing::Values(InferenceEngine::Precision::FP32), + ::testing::ValuesIn(acrossChannels), + ::testing::ValuesIn(normalizeVariance), + ::testing::ValuesIn(epsilon), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ::testing::Values(emptyCPUSpec), + ::testing::Values(emptyFusingSpec), + ::testing::ValuesIn(inpOutPrc), + ::testing::ValuesIn(inpOutPrc)); + +INSTANTIATE_TEST_CASE_P(smoke_CompareWithRefs_1D, MvnLayerCPUTest, Mvn1D, MvnLayerCPUTest::getTestCaseName); + +const auto Mvn2D = ::testing::Combine( + ::testing::Combine( + ::testing::ValuesIn(inputShapes_2D), + ::testing::Values(InferenceEngine::Precision::FP32), + ::testing::ValuesIn(acrossChannels), + ::testing::ValuesIn(normalizeVariance), + ::testing::ValuesIn(epsilon), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ::testing::Values(emptyCPUSpec), + ::testing::Values(emptyFusingSpec), + ::testing::ValuesIn(inpOutPrc), + ::testing::ValuesIn(inpOutPrc)); + +INSTANTIATE_TEST_CASE_P(smoke_CompareWithRefs_2D, MvnLayerCPUTest, Mvn2D, MvnLayerCPUTest::getTestCaseName); + const auto Mvn3D = ::testing::Combine( ::testing::Combine( ::testing::ValuesIn(inputShapes_3D), @@ -186,8 +226,25 @@ std::vector fusingParamsSet { fusingFakeQuantizePerChannel, fusingFakeQuantizePerChannelRelu, fusingFakeQuantizePerTensorRelu, + /* another patterns */ + fusingScaleShift, }; +const auto Mvn2DFuse = ::testing::Combine( + ::testing::Combine( + ::testing::ValuesIn(inputShapes_2D), + ::testing::Values(InferenceEngine::Precision::FP32), + ::testing::Values(false), + ::testing::Values(true), + ::testing::ValuesIn(epsilon), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ::testing::Values(emptyCPUSpec), + ::testing::ValuesIn(fusingParamsSet), + ::testing::ValuesIn(inpOutPrc), + ::testing::ValuesIn(inpOutPrc)); + +INSTANTIATE_TEST_CASE_P(smoke_CompareWithRefs_2D_Fuse, MvnLayerCPUTest, Mvn2DFuse, MvnLayerCPUTest::getTestCaseName); + const auto Mvn3DFuse = ::testing::Combine( ::testing::Combine( ::testing::ValuesIn(inputShapes_3D), diff --git a/inference-engine/tests/functional/plugin/shared/include/subgraph_tests/mvn_multiply_add.hpp b/inference-engine/tests/functional/plugin/shared/include/subgraph_tests/mvn_multiply_add.hpp new file mode 100644 index 00000000000000..0e41290e11328e --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/subgraph_tests/mvn_multiply_add.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "shared_test_classes/subgraph/mvn_multiply_add.hpp" + +namespace SubgraphTestsDefinitions { + +TEST_P(MVNMultiplyAdd, CompareWithRefs){ + Run(); +}; + +} // namespace SubgraphTestsDefinitions diff --git a/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/subgraph/mvn_multiply_add.hpp b/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/subgraph/mvn_multiply_add.hpp new file mode 100644 index 00000000000000..8898b4f1c18ebc --- /dev/null +++ b/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/subgraph/mvn_multiply_add.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "shared_test_classes/base/layer_test_utils.hpp" +#include "ngraph_functions/builders.hpp" + +namespace SubgraphTestsDefinitions { + +typedef std::tuple< + std::pair, // Input shape, Constant shape + InferenceEngine::Precision, // Data precision + InferenceEngine::Precision, // Axes precision + std::vector, // Axes + bool, // Normalize variance + float, // Epsilon + std::string, // Epsilon mode + std::string // Device name +> mvnMultiplyAddParams; + +class MVNMultiplyAdd: public testing::WithParamInterface, + public LayerTestsUtils::LayerTestsCommon{ +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); +protected: + void SetUp() override; +}; +} // namespace SubgraphTestsDefinitions diff --git a/inference-engine/tests/functional/shared_test_classes/src/subgraph/mvn_multiply_add.cpp b/inference-engine/tests/functional/shared_test_classes/src/subgraph/mvn_multiply_add.cpp new file mode 100644 index 00000000000000..2ab87dee11e056 --- /dev/null +++ b/inference-engine/tests/functional/shared_test_classes/src/subgraph/mvn_multiply_add.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "shared_test_classes/subgraph/mvn_multiply_add.hpp" + +namespace SubgraphTestsDefinitions { + +std::string MVNMultiplyAdd::getTestCaseName(const testing::TestParamInfo &obj) { + std::pair shapes; + InferenceEngine::SizeVector inputShapes, constantShapes; + InferenceEngine::Precision dataPrecision, axesPrecision; + std::vector axes; + bool normalizeVariance; + float eps; + std::string epsMode; + std::string targetDevice; + std::tie(shapes, dataPrecision, axesPrecision, axes, normalizeVariance, eps, epsMode, targetDevice) = obj.param; + std::tie(inputShapes, constantShapes) = shapes; + std::ostringstream result; + result << "IS=" << CommonTestUtils::vec2str(inputShapes) << "_"; + result << "CS=" << CommonTestUtils::vec2str(constantShapes) << "_"; + result << "DataPrc=" << dataPrecision.name() << "_"; + result << "AxPrc=" << axesPrecision.name() << "_"; + result << "Ax=" << CommonTestUtils::vec2str(axes) << "_"; + result << "NormVariance=" << (normalizeVariance ? "TRUE" : "FALSE") << "_"; + result << "Eps=" << eps << "_"; + result << "EM=" << epsMode << "_"; + result << "TargetDevice=" << targetDevice; + return result.str(); +} + +void MVNMultiplyAdd::SetUp() { + std::pair shapes; + InferenceEngine::SizeVector inputShapes, constantShapes; + InferenceEngine::Precision dataPrecision, axesPrecision; + std::vector axes; + bool normalizeVariance; + float eps; + std::string epsMode; + std::tie(shapes, dataPrecision, axesPrecision, axes, normalizeVariance, eps, epsMode, targetDevice) = this->GetParam(); + std::tie(inputShapes, constantShapes) = shapes; + + auto dataType = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(dataPrecision); + auto axesType = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(axesPrecision); + + auto param = ngraph::builder::makeParams(dataType, {inputShapes}); + auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes(param)); + auto axesNode = ngraph::builder::makeConstant(axesType, ngraph::Shape{axes.size()}, axes); + auto mvn = ngraph::builder::makeMVN6(paramOuts[0], axesNode, normalizeVariance, eps, epsMode); + auto gamma = ngraph::builder::makeConstant(dataType, constantShapes, {}, true); + auto mul = std::make_shared(mvn, gamma); + auto beta = ngraph::builder::makeConstant(dataType, constantShapes, {}, true); + auto add = std::make_shared(mul, beta); + + ngraph::ResultVector results{std::make_shared(add)}; + function = std::make_shared(results, param, "MVNMultiplyAdd"); +} +} // namespace SubgraphTestsDefinitions