From 3e48008c3f51151c64bb5c33cf20b9f4b904a8bd Mon Sep 17 00:00:00 2001 From: Eugeny Volosenkov Date: Fri, 15 Oct 2021 12:37:43 +0300 Subject: [PATCH] Unroll If in ngraph (#7403) * added unroll_if * Fix interface function * Fix code style * add false test for unroll if * add if transformation in subgraphs * fix code style * fix transformations * delete internal transformations * Fix comments * fix to replace_node * fix description fo transformation * fix CompileNetwork * fix comments * fix comments * add function get_ie_output_name(input); * fix code style * disable cpu test --- .../src/template_executable_network.cpp | 5 +- .../src/convert_function_to_cnn_network.cpp | 17 +-- .../src/mkldnn_plugin/mkldnn_graph.cpp | 7 +- .../control_flow/unroll_if.hpp | 29 +++++ .../include/transformations/utils/utils.hpp | 10 +- .../common_optimizations.cpp | 3 + .../control_flow/unroll_if.cpp | 61 ++++++++++ .../transformations/unroll_if_test.cpp | 115 ++++++++++++++++++ .../skip_tests_config.cpp | 2 + 9 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 inference-engine/src/transformations/include/transformations/control_flow/unroll_if.hpp create mode 100644 inference-engine/src/transformations/src/transformations/control_flow/unroll_if.cpp create mode 100644 inference-engine/tests/functional/inference_engine/transformations/unroll_if_test.cpp diff --git a/docs/template_plugin/src/template_executable_network.cpp b/docs/template_plugin/src/template_executable_network.cpp index 9819d76ba7c..237cbeaa712 100644 --- a/docs/template_plugin/src/template_executable_network.cpp +++ b/docs/template_plugin/src/template_executable_network.cpp @@ -113,8 +113,9 @@ void TemplatePlugin::ExecutableNetwork::CompileNetwork(const std::shared_ptrget_results()) { - auto outputName = ngraph::op::util::create_ie_output_name(result->input_value(0)); - _outputIndex.emplace(outputName, _function->get_result_index(result)); + const auto& input = result->input_value(0); + auto name = ngraph::op::util::get_ie_output_name(input); + _outputIndex.emplace(name, _function->get_result_index(result)); } for (auto&& parameter : _function->get_parameters()) { _inputIndex.emplace(parameter->get_friendly_name(), _function->get_parameter_index(parameter)); diff --git a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp index 86860efef82..1639873a595 100644 --- a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp +++ b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp @@ -2037,12 +2037,9 @@ void convertFunctionToICNNNetwork(const std::shared_ptroutData.clear(); continue; } - NGRAPH_SUPPRESS_DEPRECATED_START - auto outName = layer->output(i).get_tensor().get_name(); - NGRAPH_SUPPRESS_DEPRECATED_END - if (outName.empty()) { - outName = ngraph::op::util::create_ie_output_name(layer->output(i)); - } + + auto outName = ngraph::op::util::get_ie_output_name(layer->output(i)); + DataPtr &ptr = cnnNetworkImpl->getData(outName.c_str()); IE_ASSERT(layer->get_output_partial_shape(i).is_static()) << " nGraph " @@ -2093,13 +2090,7 @@ void convertFunctionToICNNNetwork(const std::shared_ptr(layer)) { IE_ASSERT(layer->get_input_size() == 1); const auto &input = layer->input_value(0); - NGRAPH_SUPPRESS_DEPRECATED_START - auto name = input.get_tensor().get_name(); - NGRAPH_SUPPRESS_DEPRECATED_END - if (!name.empty()) - cnnNetworkImpl->addOutput(name); - else - cnnNetworkImpl->addOutput(ngraph::op::util::create_ie_output_name(input)); + cnnNetworkImpl->addOutput(ngraph::op::util::get_ie_output_name(input)); continue; } diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_graph.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_graph.cpp index fac6830cd73..43b8c7c765c 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_graph.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_graph.cpp @@ -228,12 +228,7 @@ void MKLDNNGraph::Replicate(const CNNNetwork &network, const MKLDNNExtensionMana if (op->get_type_info() == ngraph::op::v0::Result::type_info) { const auto &input = op->input_value(0); - NGRAPH_SUPPRESS_DEPRECATED_START - auto name = input.get_tensor().get_name(); - NGRAPH_SUPPRESS_DEPRECATED_END - if (name.empty()) { - name = ngraph::op::util::create_ie_output_name(input); - } + auto name = ngraph::op::util::get_ie_output_name(input); if (outputsInfo.count(name) != 0) { outputNodesMap[name] = node; diff --git a/inference-engine/src/transformations/include/transformations/control_flow/unroll_if.hpp b/inference-engine/src/transformations/include/transformations/control_flow/unroll_if.hpp new file mode 100644 index 00000000000..5a8efa7df63 --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/control_flow/unroll_if.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ngraph { +namespace pass { + +class TRANSFORMATIONS_API UnrollIf; + +} // namespace pass +} // namespace ngraph + +/** + * @ingroup ie_transformation_common_api + * @brief The transformation replaces 'If' operations with one of the internal functions (bodies) if the provided condition is constant. + * The condition is true: 'If' op is replaced with then_body + * The condition is false 'If' op is replaced with else_body + */ + +class ngraph::pass::UnrollIf : public ngraph::pass::FunctionPass { +public: + NGRAPH_RTTI_DECLARATION; + bool run_on_function(std::shared_ptr f) override; +}; diff --git a/inference-engine/src/transformations/include/transformations/utils/utils.hpp b/inference-engine/src/transformations/include/transformations/utils/utils.hpp index 001d2f4ecaf..0ac77626253 100644 --- a/inference-engine/src/transformations/include/transformations/utils/utils.hpp +++ b/inference-engine/src/transformations/include/transformations/utils/utils.hpp @@ -49,7 +49,6 @@ bool has_op_with_type(const std::shared_ptr &function) { } return false; } - inline std::string create_ie_output_name(const ngraph::Output& output) { const auto& prev_layer = output.get_node_shared_ptr(); std::string out_name = prev_layer->get_friendly_name(); @@ -57,6 +56,15 @@ inline std::string create_ie_output_name(const ngraph::Output& out out_name += "." + std::to_string(output.get_index()); return out_name; } +inline std::string get_ie_output_name(const ngraph::Output& output) { + NGRAPH_SUPPRESS_DEPRECATED_START + auto name = output.get_tensor().get_name(); + NGRAPH_SUPPRESS_DEPRECATED_END + if (name.empty()) { + name = create_ie_output_name(output); + } + return name; +} template bool has_constant_value(const std::shared_ptr& constant, 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 4f60d75b7f0..e77735b25ce 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 @@ -82,6 +82,8 @@ #include #include #include + +#include #include #include #include @@ -143,6 +145,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr(); + manager.register_pass(); auto conv_fusions = manager.register_pass(); conv_fusions->add_matcher(); diff --git a/inference-engine/src/transformations/src/transformations/control_flow/unroll_if.cpp b/inference-engine/src/transformations/src/transformations/control_flow/unroll_if.cpp new file mode 100644 index 00000000000..6dad373ac07 --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/control_flow/unroll_if.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/control_flow/unroll_if.hpp" + +#include +#include +#include +#include +#include +#include + +#include "itt.hpp" +#include "transformations/utils/utils.hpp" + +NGRAPH_RTTI_DEFINITION(ngraph::pass::UnrollIf, "UnrollIf", 0); + +bool ngraph::pass::UnrollIf::run_on_function(std::shared_ptr f) { + RUN_ON_FUNCTION_SCOPE(UnrollIf); + bool is_applicable = false; + for (const auto& op : f->get_ordered_ops()) { + auto if_node = std::dynamic_pointer_cast(op); + if (!if_node || transformation_callback(if_node)) { + continue; + } + Output cond = if_node->input_value(0); + const auto cond_is_const = ngraph::get_constant_from_source(cond); + if (!cond_is_const) { + continue; + } + + auto cond_value = cond_is_const->cast_vector(); + auto body = (cond_value[0]) ? if_node->get_then_body() : if_node->get_else_body(); + auto input_descriptions = if_node->get_input_descriptions(static_cast(!cond_value[0])); + auto output_descriptions = if_node->get_output_descriptions(static_cast(!cond_value[0])); + + // connect inputs instead of body parameters + for (const auto& input_descr : input_descriptions) { + auto in_data = if_node->input_value(input_descr->m_input_index); + auto& param = body->get_parameters()[input_descr->m_body_parameter_index]; + ngraph::replace_node(param, in_data.get_node_shared_ptr()); + } + for (const auto& output_desc : output_descriptions) { + std::shared_ptr result = body->get_results()[output_desc->m_body_value_index]; + const auto& in_value = result->input_value(0); + + // set output name to Tensor to store it for ngraph to cnn conversion + NGRAPH_SUPPRESS_DEPRECATED_START + in_value.get_tensor().set_name(op::util::create_ie_output_name(if_node->output(output_desc->m_output_index))); + NGRAPH_SUPPRESS_DEPRECATED_END + for (const auto& input : if_node->output(output_desc->m_output_index).get_target_inputs()) { + input.replace_source_output(result->get_input_source_output(0)); + } + } + is_applicable = true; + f->add_sinks(body->get_sinks()); + copy_runtime_info(if_node, body->get_ops()); + } + return is_applicable; +} diff --git a/inference-engine/tests/functional/inference_engine/transformations/unroll_if_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/unroll_if_test.cpp new file mode 100644 index 00000000000..2e0040c8924 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/unroll_if_test.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +using namespace testing; + +TEST(TransformationTests, UnrollIfCondIsTrue) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto X = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Y = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto cond = std::make_shared(ngraph::element::boolean, ngraph::Shape{ 1 }, true); + auto if_op = std::make_shared(cond); + auto Xt = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Yt = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto add_op = std::make_shared(Xt, Yt); + auto then_op_result = std::make_shared(add_op); + auto then_body = std::make_shared(ngraph::OutputVector{ then_op_result }, ngraph::ParameterVector{ Xt, Yt }); + + auto Xe = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Ye = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto mul_op = std::make_shared(Xe, Ye); + auto else_op_result = std::make_shared(mul_op); + auto else_body = std::make_shared(ngraph::OutputVector{ else_op_result }, ngraph::ParameterVector{ Xe, Ye }); + + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + if_op->set_output(then_op_result, else_op_result); + auto if_result = std::make_shared(if_op); + + f = std::make_shared(ngraph::NodeVector{ if_result }, ngraph::ParameterVector{ X, Y }); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto X = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Y = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto add_op = std::make_shared(X, Y); + auto if_result = std::make_shared(add_op); + f_ref = std::make_shared(ngraph::NodeVector{ if_result }, ngraph::ParameterVector{ X, Y }); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, UnrollIfCondIsFalse) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto X = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Y = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto cond = std::make_shared(ngraph::element::boolean, ngraph::Shape{ 1 }, false); + auto if_op = std::make_shared(cond); + auto Xt = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Yt = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto add_op = std::make_shared(Xt, Yt); + auto then_op_result = std::make_shared(add_op); + auto then_body = std::make_shared(ngraph::OutputVector{ then_op_result }, ngraph::ParameterVector{ Xt, Yt }); + + auto Xe = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Ye = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto mul_op = std::make_shared(Xe, Ye); + auto else_op_result = std::make_shared(mul_op); + auto else_body = std::make_shared(ngraph::OutputVector{ else_op_result }, ngraph::ParameterVector{ Xe, Ye }); + + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + if_op->set_output(then_op_result, else_op_result); + auto if_result = std::make_shared(if_op); + + f = std::make_shared(ngraph::NodeVector{ if_result }, ngraph::ParameterVector{ X, Y }); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto X = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto Y = std::make_shared(ngraph::element::f32, ngraph::Shape{ 3 }); + auto mul_op = std::make_shared(X, Y); + auto if_result = std::make_shared(mul_op); + f_ref = std::make_shared(ngraph::NodeVector{ if_result }, ngraph::ParameterVector{ X, Y }); + } + + 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/skip_tests_config.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp index db4ff23dfe0..d15a1407a9a 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp @@ -131,6 +131,8 @@ std::vector disabledTestPatterns() { R"(smoke_PrePostProcess.*resize_and_convert_layout_i8.*)", // Issue 67910 R"(.*smoke_PrePostProcess.*two_inputs_trivial.*)", + // TODO: CVS-67255 + R"(smoke_If.*SimpleIf2OutTest.*)" }; #define FIX_62820 0