diff --git a/.github/ISSUE_TEMPLATE/good_first_issue.yml b/.github/ISSUE_TEMPLATE/good_first_issue.yml index 52f42508a621bf..ac7bb8952d6ae8 100644 --- a/.github/ISSUE_TEMPLATE/good_first_issue.yml +++ b/.github/ISSUE_TEMPLATE/good_first_issue.yml @@ -43,6 +43,7 @@ body: value: | - [Contribution guide - start here!](https://github.com/openvinotoolkit/openvino/blob/master/CONTRIBUTING.md) - [Intel DevHub Discord channel](https://discord.gg/7pVRxUwdWG) - engage in discussions, ask questions and talk to OpenVINO developers + - [How to link your Pull Request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue-using-the-pull-request-sidebar) validations: required: true diff --git a/.github/components.yml b/.github/components.yml index b5f6143e22aae5..71cb0721ac2974 100644 --- a/.github/components.yml +++ b/.github/components.yml @@ -34,6 +34,7 @@ CPU: - TF_FE - ONNX_FE build: + - AUTO - HETERO - AUTO_BATCH - TEMPLATE @@ -41,6 +42,7 @@ CPU: GPU: build: + - AUTO - HETERO - AUTO_BATCH - TEMPLATE diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e2636f9097cf8..35d232eca0422a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,7 +143,7 @@ Use the issue description and locally built OpenVINO to complete the task. Remem ### 4. Submit a PR with your changes -Follow our [Good Pull Request guidelines](https://github.com/openvinotoolkit/openvino/blob/master/CONTRIBUTING_PR.md). +Follow our [Good Pull Request guidelines](https://github.com/openvinotoolkit/openvino/blob/master/CONTRIBUTING_PR.md). Please remember about [linking your Pull Request to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue-using-the-pull-request-sidebar) it addresses. ### 5. Wait for a review diff --git a/CONTRIBUTING_PR.md b/CONTRIBUTING_PR.md index 48546e03ec7d12..a1046b455ecf7b 100644 --- a/CONTRIBUTING_PR.md +++ b/CONTRIBUTING_PR.md @@ -16,6 +16,7 @@ * Follow the [OpenVINO code style guide](https://github.com/openvinotoolkit/openvino/blob/master/docs/dev/coding_style.md). * Make your PRs small - each PR should address one issue. Remove all changes unrelated to the PR. +* [Link your Pull Request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue-using-the-pull-request-sidebar) if it addresses one. * Document your contribution! If your changes may impact how the user works with OpenVINO, provide the information in proper articles. You can do it yourself, or contact one of OpenVINO documentation contributors to work together on diff --git a/src/common/low_precision_transformations/include/low_precision/propagate_shared_value.hpp b/src/common/low_precision_transformations/include/low_precision/propagate_shared_value.hpp index 305f63e34f7b63..64c6c2473e810a 100644 --- a/src/common/low_precision_transformations/include/low_precision/propagate_shared_value.hpp +++ b/src/common/low_precision_transformations/include/low_precision/propagate_shared_value.hpp @@ -44,6 +44,9 @@ class ov::pass::low_precision::PropagateSharedValue : public ov::pass::ModelPass std::vector> nodes(f->get_ordered_ops()); for (auto it = nodes.begin(); it != nodes.end(); it++) { const std::shared_ptr node = *it; + + ov::op::util::process_subgraph(*this, node); + if (ov::is_type(node)) { assert(node->get_output_size() == 1ul); auto& outputRtInfo = node->output(0).get_rt_info(); diff --git a/src/common/snippets/src/pass/propagate_precision.cpp b/src/common/snippets/src/pass/propagate_precision.cpp index 6660b5db6eb629..73e68733d541fd 100644 --- a/src/common/snippets/src/pass/propagate_precision.cpp +++ b/src/common/snippets/src/pass/propagate_precision.cpp @@ -8,6 +8,7 @@ #include "snippets/itt.hpp" #include "snippets/utils.hpp" #include "openvino/core/rt_info.hpp" +#include "transformations/utils/utils.hpp" #include #include @@ -29,6 +30,8 @@ bool ov::snippets::pass::PropagatePrecision::run_on_model(const std::shared_ptr< bool was_updated = false; for (const auto& op : f->get_ordered_ops()) { + ov::op::util::process_subgraph(*this, op); + auto type_info = op->get_type_info(); auto exec = target_machine->get_supported_precisions(type_info); const auto& supported_precisions = exec(op); diff --git a/src/common/transformations/include/transformations/utils/utils.hpp b/src/common/transformations/include/transformations/utils/utils.hpp index f1e270823ba1f4..e60243b60e6028 100644 --- a/src/common/transformations/include/transformations/utils/utils.hpp +++ b/src/common/transformations/include/transformations/utils/utils.hpp @@ -276,6 +276,8 @@ TRANSFORMATIONS_API bool is_constant_and_all_values_equal_int(const Output TRANSFORMATIONS_API bool is_on_constant_path(const ov::Output& output); +TRANSFORMATIONS_API bool process_subgraph(ov::pass::ModelPass& model_pass, const std::shared_ptr& node); + template ov::pass::pattern::op::ValuePredicate constant_predicate(std::function&)> predicate) { return pass::pattern::op::as_value_predicate([=](std::shared_ptr n) -> bool { diff --git a/src/common/transformations/src/transformations/common_optimizations/fused_names_cleanup.cpp b/src/common/transformations/src/transformations/common_optimizations/fused_names_cleanup.cpp index c3f602ebcacd91..6dc3e68dfc3cb4 100644 --- a/src/common/transformations/src/transformations/common_optimizations/fused_names_cleanup.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/fused_names_cleanup.cpp @@ -6,11 +6,14 @@ #include "openvino/cc/pass/itt.hpp" #include "transformations/rt_info/fused_names_attribute.hpp" +#include "transformations/utils/utils.hpp" bool ov::pass::FusedNamesCleanup::run_on_model(const std::shared_ptr& f) { RUN_ON_FUNCTION_SCOPE(FusedNamesCleanup); for (auto& node : f->get_ordered_ops()) { + ov::op::util::process_subgraph(*this, node); + RTMap& rt_info = node->get_rt_info(); auto it = rt_info.find(ov::FusedNames::get_type_info_static()); if (it != rt_info.end()) { diff --git a/src/common/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp b/src/common/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp index a7599a96fd277e..253004f694113e 100644 --- a/src/common/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp @@ -19,6 +19,7 @@ #include "openvino/pass/manager.hpp" #include "transformations/common_optimizations/shared_ops_optimization.hpp" #include "transformations/op_conversions/convert_slice_to_strided_slice.hpp" +#include "transformations/utils/utils.hpp" using namespace ov; @@ -27,11 +28,8 @@ bool ov::pass::UselessSliceEraser::run_on_model(const std::shared_ptr bool rewritten = false; for (auto& node : f->get_ordered_ops()) { // Recursively apply transformation for sub-graph based operations - if (auto sub_graph_node = std::dynamic_pointer_cast(node)) { - if (auto sub_graph = sub_graph_node->get_function()) { - rewritten |= run_on_model(sub_graph); - } - } + rewritten = ov::op::util::process_subgraph(*this, node) || rewritten; + bool is_slice = ov::is_type(node) || ov::is_type(node); if (!is_slice || node->get_output_partial_shape(0).is_dynamic() || node->get_input_partial_shape(0).is_dynamic()) @@ -45,7 +43,7 @@ bool ov::pass::UselessSliceEraser::run_on_model(const std::shared_ptr if (!std::any_of(strides.begin(), strides.end(), [](int64_t strd) { return strd < 0; })) { - rewritten |= replace_output_update_name(node->output(0), node->input_value(0)); + rewritten = replace_output_update_name(node->output(0), node->input_value(0)) || rewritten; } } } @@ -102,11 +100,8 @@ bool ov::pass::GroupedStridedSliceOptimizer::run_on_model(const std::shared_ptr< std::map, std::vector> source_to_ss_with_plan; for (const auto& node : f->get_ordered_ops()) { // Recursively apply transformation for sub-graph based operations - if (auto sub_graph_node = std::dynamic_pointer_cast(node)) { - if (auto sub_graph = sub_graph_node->get_function()) { - graph_rewritten |= run_on_model(sub_graph); - } - } + graph_rewritten = ov::op::util::process_subgraph(*this, node) || graph_rewritten; + if (auto ss = std::dynamic_pointer_cast(node)) { auto slice_plan = get_slice_plan(ss); if (slice_plan == op::util::SlicePlan()) @@ -291,12 +286,8 @@ bool ov::pass::GroupedSliceToVSplitOptimization::run_on_model(const std::shared_ std::vector ordered_outputs; for (const auto& node : model->get_ordered_ops()) { // Recursively apply transformation for sub-graph based operations - if (auto multi_subgraph_op = std::dynamic_pointer_cast(node)) { - for (const auto& sub_graph : multi_subgraph_op->get_functions()) { - if (sub_graph) - graph_rewritten |= run_on_model(sub_graph); - } - } + graph_rewritten = ov::op::util::process_subgraph(*this, node) || graph_rewritten; + if (auto op = ov::as_type_ptr(node)) { SliceAttrs attributes{}; if (slice_is_suitable_for_optimization(op, attributes)) { @@ -365,8 +356,9 @@ bool ov::pass::GroupedSliceToVSplitOptimization::run_on_model(const std::shared_ auto i = 0; for (auto& slice_with_attrs : attributes) { - graph_rewritten |= - ov::replace_output_update_name(slice_with_attrs.slice->output(0), variadic_split->output(i)); + graph_rewritten = + ov::replace_output_update_name(slice_with_attrs.slice->output(0), variadic_split->output(i)) || + graph_rewritten; ov::copy_runtime_info(slice_with_attrs.slice, variadic_split); ++i; } diff --git a/src/common/transformations/src/transformations/common_optimizations/reverse_shape_and_type_infer.cpp b/src/common/transformations/src/transformations/common_optimizations/reverse_shape_and_type_infer.cpp index b8224184b28731..e277efb5fc9580 100644 --- a/src/common/transformations/src/transformations/common_optimizations/reverse_shape_and_type_infer.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/reverse_shape_and_type_infer.cpp @@ -21,6 +21,7 @@ #include "openvino/op/util/binary_elementwise_arithmetic.hpp" #include "openvino/op/util/pad_base.hpp" #include "openvino/op/util/unary_elementwise_arithmetic.hpp" +#include "transformations/utils/utils.hpp" bool ov::pass::ReverseShapeAndTypeInfer::inherit_output_shape(const std::shared_ptr& node, const std::vector& input_idxs) { @@ -70,6 +71,8 @@ bool ov::pass::ReverseShapeAndTypeInfer::run_on_model(const std::shared_ptrget_ordered_ops(); for (auto it = ops.rbegin(); it != ops.rend(); ++it) { const auto& op = *it; + is_changed = ov::op::util::process_subgraph(*this, op) || is_changed; + auto output_shape = op->get_output_partial_shape(0); auto output_type = op->get_output_element_type(0); if (const auto& param = std::dynamic_pointer_cast(op)) { diff --git a/src/common/transformations/src/transformations/common_optimizations/shared_ops_optimization.cpp b/src/common/transformations/src/transformations/common_optimizations/shared_ops_optimization.cpp index 55a61af60a4dab..320e1b49468255 100644 --- a/src/common/transformations/src/transformations/common_optimizations/shared_ops_optimization.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/shared_ops_optimization.cpp @@ -109,7 +109,7 @@ bool shared_node_optimization(const shared_ptr& model) { if (auto multi_subgraph_op = dynamic_pointer_cast(op)) { for (const auto& sub_graph : multi_subgraph_op->get_functions()) { if (sub_graph) - rewritten |= shared_node_optimization(sub_graph); + rewritten = shared_node_optimization(sub_graph) || rewritten; } } for (auto& output : op->outputs()) { @@ -136,7 +136,8 @@ bool shared_node_optimization(const shared_ptr& model) { continue; const auto& child_op = shared_nodes[j]; if (nodes_are_equal(root_op, child_op)) { - rewritten |= replace_output_update_name(child_op->output(0), root_op->output(0)); + rewritten = + replace_output_update_name(child_op->output(0), root_op->output(0)) || rewritten; visited_nodes[j] = true; } } @@ -154,7 +155,7 @@ bool shape_of_upgrade(const shared_ptr& model) { if (auto multi_subgraph_op = dynamic_pointer_cast(op)) { for (const auto& sub_graph : multi_subgraph_op->get_functions()) { if (sub_graph) - rewritten |= shape_of_upgrade(sub_graph); + rewritten = shape_of_upgrade(sub_graph) || rewritten; } } else if (auto v1_shape_of = ov::as_type_ptr(op)) { auto v3_shape_of = std::make_shared(v1_shape_of->input_value(0), element::i64); @@ -171,6 +172,6 @@ bool pass::SharedOpOptimization::run_on_model(const shared_ptr& model) { RUN_ON_FUNCTION_SCOPE(SharedOpOptimization); bool rewritten = shape_of_upgrade(model); - rewritten |= shared_node_optimization(model); + rewritten = shared_node_optimization(model) || rewritten; return rewritten; } diff --git a/src/common/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp b/src/common/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp index dbddf574292998..099623fc9894c4 100644 --- a/src/common/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp +++ b/src/common/transformations/src/transformations/control_flow/unroll_tensor_iterator.cpp @@ -23,6 +23,8 @@ bool ov::pass::UnrollTensorIterator::run_on_model(const std::shared_ptr& f) { RUN_ON_FUNCTION_SCOPE(UnrollTensorIterator); for (const auto& op : f->get_ops()) { + ov::op::util::process_subgraph(*this, op); + auto sub_graph_op = std::dynamic_pointer_cast(op); if (!sub_graph_op || transformation_callback(sub_graph_op)) { continue; diff --git a/src/common/transformations/src/transformations/convert_precision.cpp b/src/common/transformations/src/transformations/convert_precision.cpp index 8d67b73aeb9f2d..e3f149f958e6b3 100644 --- a/src/common/transformations/src/transformations/convert_precision.cpp +++ b/src/common/transformations/src/transformations/convert_precision.cpp @@ -231,18 +231,18 @@ bool convert_function_precision(const std::shared_ptr& f, for (auto& node : ops) { if (skip_precision_sensitive && fp16_compression_is_disabled(node) && has_fp16_compression) continue; - is_changed |= convert_node_input_precision(node, precisions, type_to_extend); + is_changed = convert_node_input_precision(node, precisions, type_to_extend) || is_changed; } for (const auto& param : f->get_parameters()) { if (skip_precision_sensitive && fp16_compression_is_disabled(param) && has_fp16_compression) continue; - is_changed |= fuse_type_to_parameter(param, precisions, convert_input_output_precision); + is_changed = fuse_type_to_parameter(param, precisions, convert_input_output_precision) || is_changed; } if (convert_input_output_precision || store_original_precision_as_rt_attribute) { for (const auto& variable : f->get_variables()) { - is_changed |= fuse_type_to_variable(variable, precisions); + is_changed = fuse_type_to_variable(variable, precisions) || is_changed; } } @@ -272,17 +272,18 @@ bool convert_function_precision(const std::shared_ptr& f, if (auto sub_graph_node = std::dynamic_pointer_cast(node)) { size_t sub_graphs_num = sub_graph_node->get_internal_subgraphs_size(); for (size_t sub_graph_ind = 0; sub_graph_ind < sub_graphs_num; ++sub_graph_ind) { - is_changed |= convert_function_precision(sub_graph_node->get_function(static_cast(sub_graph_ind)), - type_to_fuse, - type_to_extend, - precisions, - const_to_internal_output, - has_fp16_compression, - skip_precision_sensitive, - is_changed || is_output_precision_changed, - true, - true, - store_original_precision_as_rt_attribute); + is_changed = convert_function_precision(sub_graph_node->get_function(static_cast(sub_graph_ind)), + type_to_fuse, + type_to_extend, + precisions, + const_to_internal_output, + has_fp16_compression, + skip_precision_sensitive, + is_changed || is_output_precision_changed, + true, + true, + store_original_precision_as_rt_attribute) || + is_changed; } } // if convert_input_output_precision flag is set, we don't need to preserve the original precision @@ -293,16 +294,17 @@ bool convert_function_precision(const std::shared_ptr& f, node->revalidate_and_infer_types(); continue; } - is_output_precision_changed |= convert_node_output_precision(node, - precisions, - type_to_fuse, - const_to_internal_output, - is_changed || is_output_precision_changed); + is_output_precision_changed = convert_node_output_precision(node, + precisions, + type_to_fuse, + const_to_internal_output, + is_changed || is_output_precision_changed) || + is_output_precision_changed; } if (is_output_precision_changed) { ops = f->get_ordered_ops(); - is_changed |= is_output_precision_changed; + is_changed = is_output_precision_changed || is_changed; } if (!is_subgraph) { diff --git a/src/common/transformations/src/transformations/fp16_compression/align_mixed_fp32_fp16_types.cpp b/src/common/transformations/src/transformations/fp16_compression/align_mixed_fp32_fp16_types.cpp index 990f85fc6eea80..5281f68f39343a 100644 --- a/src/common/transformations/src/transformations/fp16_compression/align_mixed_fp32_fp16_types.cpp +++ b/src/common/transformations/src/transformations/fp16_compression/align_mixed_fp32_fp16_types.cpp @@ -88,8 +88,8 @@ bool ov::pass::AlignMixedFP32FP16Types::run_on_model(const std::shared_ptr& f) { RUN_ON_FUNCTION_SCOPE(InitNodeInfo); for (auto& node : f->get_ops()) { // Recursively apply transformation for sub-graph based operations - if (auto sub_graph_node = std::dynamic_pointer_cast(node)) { - if (auto sub_graph = sub_graph_node->get_function()) { - run_on_model(sub_graph); - } - } + ov::op::util::process_subgraph(*this, node); + auto& rtInfo = node->get_rt_info(); rtInfo.emplace(FusedNames::get_type_info_static(), FusedNames{node->get_friendly_name()}); } diff --git a/src/common/transformations/src/transformations/smart_reshape/lstm_states_broadcast.cpp b/src/common/transformations/src/transformations/smart_reshape/lstm_states_broadcast.cpp index 0a2340d4620356..28b65cf9add1a6 100644 --- a/src/common/transformations/src/transformations/smart_reshape/lstm_states_broadcast.cpp +++ b/src/common/transformations/src/transformations/smart_reshape/lstm_states_broadcast.cpp @@ -135,11 +135,11 @@ bool relax_batch_for_initial_states_of_lstm_in_ti(const shared_ptr(lstm_cell->get_input_node_shared_ptr(1))) { auto outer_init_hidden_state_input = get_outer_input_of_ti_by_parameter(init_hidden_state, ti); - rewritten |= broadcast_state_by_batch(outer_init_hidden_state_input, batch_delivering_node); + rewritten = broadcast_state_by_batch(outer_init_hidden_state_input, batch_delivering_node) || rewritten; } if (auto init_cell_state = dynamic_pointer_cast(lstm_cell->get_input_node_shared_ptr(2))) { auto outer_init_cell_state_input = get_outer_input_of_ti_by_parameter(init_cell_state, ti); - rewritten |= broadcast_state_by_batch(outer_init_cell_state_input, batch_delivering_node); + rewritten = broadcast_state_by_batch(outer_init_cell_state_input, batch_delivering_node) || rewritten; } return rewritten; } @@ -151,8 +151,8 @@ bool relax_batch_for_initial_states_of_lstm(const shared_ptr(batched_shape, ov::op::v0::Constant::create(ov::element::i64, ov::Shape{1}, {0}), ov::op::v0::Constant::create(ov::element::i64, ov::Shape{}, {0})); - rewritten |= broadcast_state_by_batch(lstm_cell->input(1), batch_delivering_node); - rewritten |= broadcast_state_by_batch(lstm_cell->input(2), batch_delivering_node); + rewritten = broadcast_state_by_batch(lstm_cell->input(1), batch_delivering_node) || rewritten; + rewritten = broadcast_state_by_batch(lstm_cell->input(2), batch_delivering_node) || rewritten; return rewritten; } @@ -163,13 +163,11 @@ bool ov::pass::LSTMStatesBroadcast::run_on_model(const shared_ptr& f) bool rewritten = false; for (auto& node : f->get_ordered_ops()) { // Recursively apply transformation for sub-graph based operations - if (const auto& sub_graph_node = dynamic_pointer_cast(node)) - if (const auto& sub_graph = sub_graph_node->get_function()) - rewritten |= run_on_model(sub_graph); + rewritten = ov::op::util::process_subgraph(*this, node) || rewritten; // Case without TI (LSTMCell and Constant are in the same ov::Model) if (const auto& lstm_cell = dynamic_pointer_cast(node)) - rewritten |= relax_batch_for_initial_states_of_lstm(lstm_cell); + rewritten = relax_batch_for_initial_states_of_lstm(lstm_cell) || rewritten; // Case with TI (LSTMCell and Constant are in different ov::Model objects) if (auto ti = dynamic_pointer_cast(node)) { @@ -178,7 +176,7 @@ bool ov::pass::LSTMStatesBroadcast::run_on_model(const shared_ptr& f) continue; for (const auto& body_node : body->get_ordered_ops()) if (const auto& lstm_cell = dynamic_pointer_cast(body_node)) - rewritten |= relax_batch_for_initial_states_of_lstm_in_ti(ti, lstm_cell); + rewritten = relax_batch_for_initial_states_of_lstm_in_ti(ti, lstm_cell) || rewritten; } } return rewritten; diff --git a/src/common/transformations/src/transformations/symbolic_transformations/label_optimization.cpp b/src/common/transformations/src/transformations/symbolic_transformations/label_optimization.cpp index 06a046c3bfa5f2..5a8cbf2cf87ae3 100644 --- a/src/common/transformations/src/transformations/symbolic_transformations/label_optimization.cpp +++ b/src/common/transformations/src/transformations/symbolic_transformations/label_optimization.cpp @@ -17,6 +17,7 @@ #include "openvino/op/squeeze.hpp" #include "openvino/op/util/multi_subgraph_base.hpp" #include "openvino/op/util/symbolic_info.hpp" +#include "transformations/utils/utils.hpp" namespace { void update_label(const ov::EqTable& table, ov::label_t& label) { @@ -250,10 +251,7 @@ bool ov::pass::OptimizeLabelsUsedAsValues::run_on_model(const std::shared_ptr(op)) - for (const auto& sub_graph : multi_subgraph_op->get_functions()) - if (sub_graph) - run_on_model(sub_graph); + ov::op::util::process_subgraph(*this, op); for (auto& output : op->outputs()) { optimize_value_usage(output, label_shape_source, label_value_source); diff --git a/src/common/transformations/src/transformations/symbolic_transformations/symbolic_optimizations.cpp b/src/common/transformations/src/transformations/symbolic_transformations/symbolic_optimizations.cpp index 1676c7206fad95..31b3ac6dedc1a9 100644 --- a/src/common/transformations/src/transformations/symbolic_transformations/symbolic_optimizations.cpp +++ b/src/common/transformations/src/transformations/symbolic_transformations/symbolic_optimizations.cpp @@ -25,6 +25,7 @@ #include "transformations/symbolic_transformations/nop_broadcast.hpp" #include "transformations/symbolic_transformations/reshape_optimizations.hpp" #include "transformations/symbolic_transformations/utils.hpp" +#include "transformations/utils/utils.hpp" using namespace ov::pass; using namespace ov::symbol::util; @@ -106,10 +107,7 @@ bool ov::pass::SymbolicPropagation::run_on_model(const std::shared_ptrrevalidate_and_infer_types(); // Recursively apply transformation for sub-graph based operations - if (auto multi_subgraph_op = std::dynamic_pointer_cast(op)) - for (const auto& sub_graph : multi_subgraph_op->get_functions()) - if (sub_graph) - run_on_model(sub_graph); + ov::op::util::process_subgraph(*this, op); // additional label propagation rules must be triggered here special_case_range_label_propagation(op); diff --git a/src/common/transformations/src/transformations/utils/utils.cpp b/src/common/transformations/src/transformations/utils/utils.cpp index 60cfdd744050d9..a5deb7daffb95f 100644 --- a/src/common/transformations/src/transformations/utils/utils.cpp +++ b/src/common/transformations/src/transformations/utils/utils.cpp @@ -14,6 +14,7 @@ #include "openvino/op/constant.hpp" #include "openvino/op/gather.hpp" #include "openvino/op/reshape.hpp" +#include "openvino/op/util/multi_subgraph_base.hpp" #include "openvino/opsets/opset1.hpp" #include "openvino/opsets/opset3.hpp" @@ -456,6 +457,20 @@ bool is_on_constant_path(const ov::Output& output) { return status; } +bool process_subgraph(ov::pass::ModelPass& model_pass, const std::shared_ptr& node) { + bool changed = false; + + if (const auto& multi_subgraph_op = std::dynamic_pointer_cast(node)) { + for (const auto& sub_graph : multi_subgraph_op->get_functions()) { + if (sub_graph) { + changed = model_pass.run_on_model(sub_graph) || changed; + } + } + } + + return changed; +} + } // namespace util } // namespace op } // namespace ov diff --git a/src/core/src/pass/constant_folding.cpp b/src/core/src/pass/constant_folding.cpp index 3e93d0da979258..291c91e11b1354 100644 --- a/src/core/src/pass/constant_folding.cpp +++ b/src/core/src/pass/constant_folding.cpp @@ -101,7 +101,7 @@ bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr& m remove_requires_precision_conversion_attribute(node); node = util::convert_to_supported_precision(node.get()); } else { - rewritten |= restore_original_input_precision(node); + rewritten = restore_original_input_precision(node) || rewritten; } if (rewritten) { @@ -139,7 +139,8 @@ bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr& m // recursively constant fold operators containing subgraphs (ie: TensorIterator, Loop) size_t sub_graphs_num = sub_graph_node->get_internal_subgraphs_size(); for (size_t sub_graph_ind = 0; sub_graph_ind < sub_graphs_num; ++sub_graph_ind) { - rewritten |= run_on_model(sub_graph_node->get_function(static_cast(sub_graph_ind))); + rewritten = + run_on_model(sub_graph_node->get_function(static_cast(sub_graph_ind))) || rewritten; } } diff --git a/src/core/src/pass/low_latency.cpp b/src/core/src/pass/low_latency.cpp index 13a793a10d4de3..f6111c2617924d 100644 --- a/src/core/src/pass/low_latency.cpp +++ b/src/core/src/pass/low_latency.cpp @@ -13,6 +13,7 @@ #include "openvino/opsets/opset9.hpp" #include "openvino/pass/graph_rewrite.hpp" #include "openvino/util/log.hpp" +#include "transformations/utils/utils.hpp" namespace { std::string generate_variable_name(const std::string& op_name, const std::string& param_name, int64_t variable_idx) { @@ -259,6 +260,8 @@ bool ov::pass::LowLatency2::run_on_model(const std::shared_ptr& f) { ov::SinkVector assigns; for (const auto& op : f->get_ordered_ops()) { + ov::op::util::process_subgraph(*this, op); + if (const auto& sub_graph_op = std::dynamic_pointer_cast(op)) { int64_t variable_id = 0; const auto& func = sub_graph_op->get_function(); diff --git a/src/frontends/tensorflow/src/op_table.cpp b/src/frontends/tensorflow/src/op_table.cpp index bdc13df7b0e08a..2ea0e696c1bba8 100644 --- a/src/frontends/tensorflow/src/op_table.cpp +++ b/src/frontends/tensorflow/src/op_table.cpp @@ -166,8 +166,8 @@ const std::map get_supported_ops() { {"Swish", CreatorFunction(translate_unary_op)}, // note: BinaryOp translator declaration for each op must to be added in binary_op.cpp file - {"Add", CreatorFunction(translate_binary_op)}, - {"AddV2", CreatorFunction(translate_binary_op)}, + {"Add", CreatorFunction(translate_addv2_op)}, + {"AddV2", CreatorFunction(translate_addv2_op)}, {"Atan2", CreatorFunction(translate_atan2_op)}, {"BitwiseAnd", CreatorFunction(translate_binary_op)}, {"BitwiseOr", CreatorFunction(translate_binary_op)}, diff --git a/src/frontends/tensorflow_common/include/common_op_table.hpp b/src/frontends/tensorflow_common/include/common_op_table.hpp index f0b564f0f07a86..41110be14288da 100644 --- a/src/frontends/tensorflow_common/include/common_op_table.hpp +++ b/src/frontends/tensorflow_common/include/common_op_table.hpp @@ -31,7 +31,7 @@ OP_T_CONVERTER(translate_unary_op); OP_CONVERTER(translate_selu_op); OP_T_CONVERTER(translate_binary_op); OP_T_CONVERTER(translate_direct_reduce_op); - +OP_CONVERTER(translate_addv2_op); OP_CONVERTER(translate_add_n_op); OP_CONVERTER(translate_adjust_contrast_op); OP_CONVERTER(translate_arg_max_op); diff --git a/src/frontends/tensorflow_common/src/op/binary_op.cpp b/src/frontends/tensorflow_common/src/op/binary_op.cpp index e992c1bfc0b760..832aff9409c288 100644 --- a/src/frontends/tensorflow_common/src/op/binary_op.cpp +++ b/src/frontends/tensorflow_common/src/op/binary_op.cpp @@ -142,6 +142,33 @@ OutputVector translate_mul_op(const NodeContext& node) { set_node_name(node.get_name(), result); return {result}; } + +OutputVector translate_addv2_op(const NodeContext& node) { + default_op_checks(node, 2, {"Add", "AddV2"}, true); + auto lhs = node.get_input(0); + auto rhs = node.get_input(1); + + auto complex_type_mark_lhs = as_type_ptr(lhs.get_node_shared_ptr()); + auto complex_type_mark_rhs = as_type_ptr(rhs.get_node_shared_ptr()); + auto complex_type_inputs = (complex_type_mark_lhs || complex_type_mark_rhs) ? true : false; + + if (complex_type_inputs) { + lhs = complex_type_mark_lhs->input_value(0); + rhs = complex_type_mark_rhs->input_value(0); + } + + auto result = make_shared(lhs, rhs); + if (complex_type_inputs) { + auto complex_result = make_shared(result, complex_type_mark_lhs->get_complex_part_type()); + set_node_name(node.get_name(), result); + + return {complex_result}; + } + + set_node_name(node.get_name(), result); + return {result}; +} + template OutputVector translate_binary_op(const NodeContext& node); template OutputVector translate_binary_op(const NodeContext& node); template OutputVector translate_binary_op(const NodeContext& node); diff --git a/src/frontends/tensorflow_common/src/op/size.cpp b/src/frontends/tensorflow_common/src/op/size.cpp index 4a56f4d5aba086..00abf883a70ce9 100644 --- a/src/frontends/tensorflow_common/src/op/size.cpp +++ b/src/frontends/tensorflow_common/src/op/size.cpp @@ -3,7 +3,9 @@ // #include "common_op_table.hpp" +#include "helper_ops/complex_type_mark.hpp" #include "openvino/op/constant.hpp" +#include "openvino/op/divide.hpp" #include "openvino/op/reduce_prod.hpp" #include "openvino/op/shape_of.hpp" #include "openvino/op/unsqueeze.hpp" @@ -19,12 +21,29 @@ namespace op { ov::OutputVector translate_size_op(const NodeContext& node) { // Size operation computes a number of elements in the input tensor - default_op_checks(node, 1, {"Size"}); + default_op_checks(node, 1, {"Size"}, true); auto input = node.get_input(0); + auto complex_type_mark = as_type_ptr(input.get_node_shared_ptr()); + // retrive attribute of the output type auto out_type = node.get_attribute("out_type", element::i32); + if (complex_type_mark) { + input = complex_type_mark->input_value(0); + + // compute the input tensor size + auto shape_of = make_shared(input, out_type); + auto axis = make_shared(element::i32, Shape{}, 0); + auto complex_size = make_shared(shape_of, axis); + + // need to divide the size by 2 because real and imaginary parts are counted separately + auto complex_size_divided_by_two = + make_shared(complex_size, make_shared(element::i32, Shape{}, 2)); + set_node_name(node.get_name(), complex_size_divided_by_two); + return {complex_size_divided_by_two->output(0)}; + } + // introduce extra dimension in order to compute size in case of a scalar input auto const_zero = make_shared(element::i32, Shape{1}, 0); input = make_shared(input, const_zero); @@ -33,6 +52,7 @@ ov::OutputVector translate_size_op(const NodeContext& node) { auto shape_of = make_shared(input, out_type); auto axis = make_shared(element::i32, Shape{}, 0); auto size = make_shared(shape_of, axis); + set_node_name(node.get_name(), size); return {size}; } diff --git a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp index 7a7a563d488801..6e5f6c43f9ff07 100644 --- a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp +++ b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp @@ -312,6 +312,53 @@ void jit_power_static_emitter::emit_isa(const std::vector &in_vec_idxs, } } +/// PRELU /// +jit_prelu_emitter::jit_prelu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const std::shared_ptr& node) + : jit_emitter(host, host_isa, node, get_arithmetic_binary_exec_precision(node)) { +} + +jit_prelu_emitter::jit_prelu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const ov::element::Type exec_prc) + : jit_emitter(host, host_isa, exec_prc) { +} + +size_t jit_prelu_emitter::get_inputs_count() const { return 2; } + +size_t jit_prelu_emitter::get_aux_vecs_count() const { return 1; } + +std::set> jit_prelu_emitter::get_supported_precisions(const std::shared_ptr& node) { + return {{element::f32}}; +} + +void jit_prelu_emitter::emit_impl(const std::vector& in_vec_idxs, const std::vector& out_vec_idxs) const { + if (host_isa_ == dnnl::impl::cpu::aarch64::asimd) { + emit_isa(in_vec_idxs, out_vec_idxs); + } else { + OPENVINO_THROW("Can't create jit eltwise kernel"); + } +} + +template +void jit_prelu_emitter::emit_isa(const std::vector &in_vec_idxs, const std::vector &out_vec_idxs) const { + if (exec_prc_ != ov::element::f32) { + OPENVINO_THROW("unsupported precision: " + exec_prc_.to_string()); + } + + using TReg = typename dnnl::impl::cpu::aarch64::cpu_isa_traits::TReg; + + TReg tmp = TReg(aux_vec_idxs[0]); + TReg src1 = TReg(in_vec_idxs[0]); + TReg src2 = TReg(in_vec_idxs[1]); + TReg dst = TReg(out_vec_idxs[0]); + + h->fcmge(dst.s, src1.s, 0.0); + h->fmul(tmp.s, src1.s, src2.s); + h->bsl(dst.b16, src1.b16, tmp.b16); +} + /// RELU /// jit_relu_emitter::jit_relu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, diff --git a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp index 1c8aa44b357f2d..7703c461f39d23 100644 --- a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp +++ b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp @@ -110,6 +110,29 @@ class jit_power_static_emitter : public jit_emitter { void emit_isa(const std::vector &in_vec_idxs, const std::vector &out_vec_idxs) const; }; +class jit_prelu_emitter : public jit_emitter { +public: + jit_prelu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const ov::element::Type exec_prc = ov::element::f32); + + jit_prelu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const std::shared_ptr& node); + + size_t get_inputs_count() const override; + + size_t get_aux_vecs_count() const override; + + static std::set> get_supported_precisions(const std::shared_ptr& node = nullptr); + +private: + void emit_impl(const std::vector &in_vec_idxs, const std::vector &out_vec_idxs) const override; + + template + void emit_isa(const std::vector &in_vec_idxs, const std::vector &out_vec_idxs) const; +}; + class jit_relu_emitter : public jit_emitter { public: jit_relu_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, diff --git a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp index 24dfeb6f845115..c9e4a3f815ef26 100644 --- a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp +++ b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp @@ -22,6 +22,7 @@ bool JitEltwiseExecutor::isSupported( Algorithm::EltwiseMultiply, Algorithm::EltwiseMulAdd, Algorithm::EltwisePowerStatic, + Algorithm::EltwisePrelu, Algorithm::EltwiseRelu, Algorithm::EltwiseSubtract); if (!is_supported) { diff --git a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp index 3050ec4785c5f3..ec503fedb3da75 100644 --- a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp +++ b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp @@ -506,6 +506,7 @@ std::shared_ptr jit_uni_eltwise_generic::create_eltwise_emitte OV_CASE(Algorithm::EltwiseMulAdd, ov::intel_cpu::aarch64::jit_mul_add_emitter), OV_CASE(Algorithm::EltwiseMultiply, ov::intel_cpu::aarch64::jit_multiply_emitter), OV_CASE(Algorithm::EltwisePowerStatic, ov::intel_cpu::aarch64::jit_power_static_emitter), + OV_CASE(Algorithm::EltwisePrelu, ov::intel_cpu::aarch64::jit_prelu_emitter), OV_CASE(Algorithm::EltwiseRelu, ov::intel_cpu::aarch64::jit_relu_emitter), OV_CASE(Algorithm::EltwiseSubtract, ov::intel_cpu::aarch64::jit_subtract_emitter)); @@ -656,6 +657,7 @@ std::set> eltwise_precision_helper::get_supported_pre OV_CASE(Algorithm::EltwiseAdd, jit_add_emitter), OV_CASE(Algorithm::EltwiseMulAdd, jit_mul_add_emitter), OV_CASE(Algorithm::EltwiseMultiply, jit_multiply_emitter), + OV_CASE(Algorithm::EltwisePrelu, jit_prelu_emitter), OV_CASE(Algorithm::EltwisePowerStatic, jit_power_static_emitter), OV_CASE(Algorithm::EltwiseSubtract, jit_subtract_emitter)); diff --git a/src/plugins/intel_cpu/src/transformations/snippets/x64/pass/enforce_precision.cpp b/src/plugins/intel_cpu/src/transformations/snippets/x64/pass/enforce_precision.cpp index 064db31ed49bef..b90b35f9359aa4 100644 --- a/src/plugins/intel_cpu/src/transformations/snippets/x64/pass/enforce_precision.cpp +++ b/src/plugins/intel_cpu/src/transformations/snippets/x64/pass/enforce_precision.cpp @@ -11,6 +11,7 @@ #include "openvino/core/rt_info.hpp" #include "snippets/pass/propagate_precision.hpp" #include "cpu/x64/cpu_isa_traits.hpp" +#include "transformations/utils/utils.hpp" using namespace ov::intel_cpu::pass; @@ -30,6 +31,8 @@ bool EnforcePrecision::run_on_model(const std::shared_ptr& f) { bool was_updated = false; for (const auto& op : f->get_ordered_ops()) { + ov::op::util::process_subgraph(*this, op); + const auto& precisions = get_supported_precisions(op); if (precisions.empty()) { diff --git a/src/plugins/intel_cpu/src/utils/print_model.hpp b/src/plugins/intel_cpu/src/utils/print_model.hpp index 4f15a136f5d54c..6f89fc197706b8 100644 --- a/src/plugins/intel_cpu/src/utils/print_model.hpp +++ b/src/plugins/intel_cpu/src/utils/print_model.hpp @@ -20,6 +20,7 @@ #include "openvino/core/node.hpp" #include "openvino/op/constant.hpp" #include "openvino/pass/pass.hpp" +#include "transformations/utils/utils.hpp" namespace ov { namespace pass { @@ -402,6 +403,10 @@ class OPENVINO_API PrintModel : public ov::pass::ModelPass { if (m_file_name.empty()) return false; + for (auto& node : model->get_ordered_ops()) { + ov::op::util::process_subgraph(*this, node); + } + std::ofstream ofs(m_file_name); if (!ofs) { // OPENVINO_WARN << "Error opening file " << m_file_name << " for output" << std::endl; @@ -416,4 +421,4 @@ class OPENVINO_API PrintModel : public ov::pass::ModelPass { std::string m_file_name; }; } // namespace pass -} // namespace ov \ No newline at end of file +} // namespace ov diff --git a/src/plugins/intel_gpu/src/graph/broadcast.cpp b/src/plugins/intel_gpu/src/graph/broadcast.cpp index 9890b8c321d3f9..0617fd8a8561c9 100644 --- a/src/plugins/intel_gpu/src/graph/broadcast.cpp +++ b/src/plugins/intel_gpu/src/graph/broadcast.cpp @@ -126,6 +126,25 @@ std::string broadcast_inst::to_string(broadcast_node const& node) { return primitive_description.str(); } +void broadcast_inst::on_execute() { + update_output_memory(); +} + +void broadcast_inst::update_output_memory() { + if (!can_be_optimized()) + return; + if (static_cast(_outputs[0]) && _network.get_engine().is_the_same_buffer(output_memory(), input_memory())) + return; + + if (_node != nullptr) + build_deps(); + + GPU_DEBUG_TRACE_DETAIL << id() << " : update_output_memory with mem of input " << get_node().get_dependency(0).id() + << " : " << input_memory_ptr()->buffer_ptr() << std::endl; + _outputs[0] = input_memory_ptr(); + _mem_allocated = false; +} + broadcast_inst::typed_primitive_inst(network& network, broadcast_node const& node) : parent(network, node) { auto input_layout = node.get_input_layout(); if (input_layout.is_dynamic()) diff --git a/src/plugins/intel_gpu/src/graph/graph_optimizer/mark_runtime_skippable_nodes.cpp b/src/plugins/intel_gpu/src/graph/graph_optimizer/mark_runtime_skippable_nodes.cpp index d50affe4056452..da847d5d2504bc 100644 --- a/src/plugins/intel_gpu/src/graph/graph_optimizer/mark_runtime_skippable_nodes.cpp +++ b/src/plugins/intel_gpu/src/graph/graph_optimizer/mark_runtime_skippable_nodes.cpp @@ -8,6 +8,7 @@ #include "strided_slice_inst.h" #include "kv_cache_inst.h" #include "gemm_inst.h" +#include "broadcast_inst.h" #include "program_helpers.h" using namespace cldnn; @@ -95,5 +96,44 @@ void mark_runtime_skippable_nodes::run(program& p) { node.can_be_optimized(true); GPU_DEBUG_TRACE_DETAIL << "[mark_runtime_skippable_nodes] : " << node.id() << " can_be_optimized" << std::endl; }); + program_helpers::do_for_types(*node, [](broadcast_node& node){ + auto impl_params = node.get_kernel_impl_params(); + if (node.is_output() + || node.has_fused_primitives() + || (impl_params->get_input_layout(0).format != impl_params->get_output_layout().format) + || (impl_params->get_input_layout(0).data_type != impl_params->get_output_layout().data_type)) + return; + + if (node.is_dynamic()) { + // If the user is reorder, it could be fused to broadcast in the remove_redundant_reorders pass. + // In this case, broadcast can not be optimized due to different input and output shapes. + if (node.have_user_with_type() && node.get_users().size() == 1) + return; + + // Check if the size of rank is different, or if one of static dimensions has different size + auto input_pshape = impl_params->get_input_layout(0).get_partial_shape(); + auto output_pshape = impl_params->get_output_layout().get_partial_shape(); + + if (input_pshape.rank().is_static() && output_pshape.rank().is_static()) { + if (input_pshape.size() != output_pshape.size()) + return; + + auto input_pdim = input_pshape.begin(); + auto output_pdim = output_pshape.begin(); + while (input_pdim != input_pshape.end()) { + if (input_pdim->is_static() && output_pdim->is_static()) { + if (input_pdim->get_max_length() != output_pdim->get_max_length()) + return; + } + + input_pdim++; + output_pdim++; + } + } + + node.can_be_optimized(true); + GPU_DEBUG_TRACE_DETAIL << "[mark_runtime_skippable_nodes] : " << node.id() << " can_be_optimized" << std::endl; + } + }); } } diff --git a/src/plugins/intel_gpu/src/graph/impls/common/loop.cpp b/src/plugins/intel_gpu/src/graph/impls/common/loop.cpp index 3ffad79067db9c..bb5650d8cc09fb 100644 --- a/src/plugins/intel_gpu/src/graph/impls/common/loop.cpp +++ b/src/plugins/intel_gpu/src/graph/impls/common/loop.cpp @@ -167,6 +167,9 @@ struct loop_impl : typed_primitive_impl { // read initial execution condition from outer network int64_t execution_condition = 1; if (!primitive->first_execution_condition_id.empty()) { + // Wait for completion of the execution_condition of outer_network + if (outer_network.has_event(primitive->first_execution_condition_id)) + outer_network.get_primitive_event(primitive->first_execution_condition_id)->wait(); memory::ptr first_execution_condition_mem = outer_network.get_primitive(primitive->first_execution_condition_id)->output_memory_ptr(); execution_condition = read_scalar_value(first_execution_condition_mem, stream); } diff --git a/src/plugins/intel_gpu/src/graph/impls/ocl/primitive_base.hpp b/src/plugins/intel_gpu/src/graph/impls/ocl/primitive_base.hpp index d1ae3e7e48b4c1..95f3be018911f4 100644 --- a/src/plugins/intel_gpu/src/graph/impls/ocl/primitive_base.hpp +++ b/src/plugins/intel_gpu/src/graph/impls/ocl/primitive_base.hpp @@ -21,6 +21,7 @@ #include "gather_inst.h" #include "permute_inst.h" #include "strided_slice_inst.h" +#include "broadcast_inst.h" #include #include @@ -88,7 +89,8 @@ struct typed_primitive_impl_ocl : public typed_primitive_impl { !((impl_param.is_type() || impl_param.is_type() || impl_param.is_type() || - impl_param.is_type()) && impl_param.is_dynamic())) { + impl_param.is_type() || + impl_param.is_type()) && impl_param.is_dynamic())) { return make_unique(kernel_selector::kernel_data{}); } auto kernel_params = ImplType::get_kernel_params(ImplType::static_canonicalize_shapes(impl_param)); diff --git a/src/plugins/intel_gpu/src/graph/include/broadcast_inst.h b/src/plugins/intel_gpu/src/graph/include/broadcast_inst.h index 9b339aadd5c221..4d6e44720e05da 100644 --- a/src/plugins/intel_gpu/src/graph/include/broadcast_inst.h +++ b/src/plugins/intel_gpu/src/graph/include/broadcast_inst.h @@ -39,6 +39,10 @@ class typed_primitive_inst : public typed_primitive_inst_base; diff --git a/src/plugins/intel_gpu/src/graph/include/primitive_inst.h b/src/plugins/intel_gpu/src/graph/include/primitive_inst.h index 6426aa16463c3b..d3e07948bdbc7b 100644 --- a/src/plugins/intel_gpu/src/graph/include/primitive_inst.h +++ b/src/plugins/intel_gpu/src/graph/include/primitive_inst.h @@ -235,6 +235,7 @@ class primitive_inst { void do_runtime_skip_gather(); void do_runtime_skip_permute(); void do_runtime_skip_strided_slice(); + void do_runtime_skip_broadcast(); void do_runtime_in_place_concat(); void do_runtime_in_place_kv_cache(); void configure_shape_of_dependencies(); diff --git a/src/plugins/intel_gpu/src/graph/primitive_inst.cpp b/src/plugins/intel_gpu/src/graph/primitive_inst.cpp index 18e5e48b416807..a2514e62eb7d28 100644 --- a/src/plugins/intel_gpu/src/graph/primitive_inst.cpp +++ b/src/plugins/intel_gpu/src/graph/primitive_inst.cpp @@ -29,6 +29,7 @@ #include "kv_cache_inst.h" #include "condition_inst.h" #include "gather_inst.h" +#include "broadcast_inst.h" #include "experimental_detectron_roi_feature_extractor_inst.hpp" #include "implementation_map.hpp" #include "graph_optimizer/prepare_buffer_fusing.h" @@ -538,7 +539,8 @@ event::ptr primitive_inst::realloc_if_needed() { } // Clear out memory if if was previously reused, but now primitive can't be optimized - if (_node->is_type() || _node->is_type() || _node->is_type() || _node->is_type() || _node->is_type()) { + if (_node->is_type() || _node->is_type() || _node->is_type() || _node->is_type() || + _node->is_type() || _node->is_type()) { if (can_be_optimized()) { _max_output_layout_count = _deps[0].first->_max_output_layout_count; GPU_DEBUG_PROFILED_STAGE_MEMALLOC_INFO("can_be_optimized"); @@ -1156,6 +1158,30 @@ void primitive_inst::do_runtime_skip_strided_slice() { set_can_be_optimized(true); } +void primitive_inst::do_runtime_skip_broadcast() { + OV_ITT_SCOPED_TASK(ov::intel_gpu::itt::domains::intel_gpu_plugin, openvino::itt::handle("do_runtime_skip_broadcast: " + id())); + // Check pattern + if (!get_node().is_type() || !get_node().can_be_optimized()) + return; + + GPU_DEBUG_TRACE_DETAIL << "[do_runtime_skip_broadcast] " << id() << " : check optimizability" << std::endl; + auto input_layout = _impl_params->get_input_layout(0); + auto output_layout = _impl_params->get_output_layout(); + + // Check runtime shape (need to reset can_be_optimized) + if (input_layout != output_layout) { + set_can_be_optimized(false); + GPU_DEBUG_TRACE_DETAIL << "--- Cannot optimize because input layout(" << input_layout.to_short_string() + << ") != output layout(" << output_layout.to_short_string() << ")" << std::endl; + return; + } + + GPU_DEBUG_TRACE_DETAIL << "[do_runtime_skip_broadcast] " << id() << " : can_be_optimized" << std::endl; + GPU_DEBUG_TRACE_DETAIL << " - Input layout : " << _impl_params->get_input_layout(0).to_short_string() << std::endl; + GPU_DEBUG_TRACE_DETAIL << " - Output layout : " << _impl_params->get_output_layout().to_short_string() << std::endl; + set_can_be_optimized(true); +} + void primitive_inst::do_runtime_in_place_concat() { OV_ITT_SCOPED_TASK(ov::intel_gpu::itt::domains::intel_gpu_plugin, openvino::itt::handle("do_runtime_in_place_concat: " + id())); GPU_DEBUG_GET_INSTANCE(debug_config); @@ -1280,6 +1306,7 @@ event::ptr primitive_inst::execute(const std::vector& events) { do_runtime_in_place_kv_cache(); do_runtime_skip_permute(); do_runtime_skip_strided_slice(); + do_runtime_skip_broadcast(); if (!is_valid_fusion()) { OV_ITT_SCOPED_TASK(ov::intel_gpu::itt::domains::intel_gpu_plugin, openvino::itt::handle("unfused_subgraph_exec: " + id())); diff --git a/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/reorder_data.cl b/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/reorder_data.cl index da52d5af2da5b5..2e76331812b3a3 100644 --- a/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/reorder_data.cl +++ b/src/plugins/intel_gpu/src/kernel_selector/cl_kernels/reorder_data.cl @@ -137,42 +137,81 @@ KERNEL (reorder_data)( #endif #if defined INPUT0_LAYOUT_NV12 && !SURFACE_INPUT - uint8 ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 0, v, u, w, z, y, x); - uint output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(R), NL_M, NL_N); - ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 1, v, u, w, z, y, x); - output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(G), NL_M, NL_N); - ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 2, v, u, w, z, y, x); - output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(B), NL_M, NL_N); + uint8 ov0 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 0, v, u, w, z, y, x); + uint8 ov1 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 1, v, u, w, z, y, x); + uint8 ov2 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 2, v, u, w, z, y, x); + uint output_idx_R = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov0.s0, ov0.s1, ov0.s2, ov0.s3, ov0.s4, ov0.s5, ov0.s6, ov0.s7); + uint output_idx_G = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov1.s0, ov1.s1, ov1.s2, ov1.s3, ov1.s4, ov1.s5, ov1.s6, ov1.s7); + uint output_idx_B = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov2.s0, ov2.s1, ov2.s2, ov2.s3, ov2.s4, ov2.s5, ov2.s6, ov2.s7); + #if HAS_FUSED_OPS + res = TO_OUTPUT_REORDER_TYPE(R); + FUSED_OPS; + output[output_idx_R] = FUSED_OPS_RESULT; + res = TO_OUTPUT_REORDER_TYPE(G); + FUSED_OPS; + output[output_idx_G] = FUSED_OPS_RESULT; + res = TO_OUTPUT_REORDER_TYPE(B); + FUSED_OPS; + output[output_idx_B] = FUSED_OPS_RESULT; + #else + output[output_idx_R] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(R), NL_M, NL_N); + output[output_idx_G] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(G), NL_M, NL_N); + output[output_idx_B] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(B), NL_M, NL_N); + #endif #elif INPUT0_LAYOUT_IMAGE_2D_RGBA - uint8 ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 0, v, u, w, z, y, x); - uint output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s0), NL_M, NL_N); - ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 1, v, u, w, z, y, x); - output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s1), NL_M, NL_N); - ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 2, v, u, w, z, y, x); - output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s2), NL_M, NL_N); -#if INPUT0_FEATURE_NUM == 4 - ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 3, v, u, w, z, y, x); - output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); - output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s3), NL_M, NL_N); -#endif + uint8 ov0 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 0, v, u, w, z, y, x); + uint8 ov1 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 1, v, u, w, z, y, x); + uint8 ov2 = RESHAPE_DIMS(INPUT0, OUTPUT, b, 2, v, u, w, z, y, x); + uint output_idx_0 = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov0.s0, ov0.s1, ov0.s2, ov0.s3, ov0.s4, ov0.s5, ov0.s6, ov0.s7); + uint output_idx_1 = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov1.s0, ov1.s1, ov1.s2, ov1.s3, ov1.s4, ov1.s5, ov1.s6, ov1.s7); + uint output_idx_2 = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov2.s0, ov2.s1, ov2.s2, ov2.s3, ov2.s4, ov2.s5, ov2.s6, ov2.s7); + #if HAS_FUSED_OPS + res = TO_OUTPUT_REORDER_TYPE(colorRGBA.s0); + FUSED_OPS; + output[output_idx_0] = FUSED_OPS_RESULT; + res = TO_OUTPUT_REORDER_TYPE(colorRGBA.s1); + FUSED_OPS; + output[output_idx_1] = FUSED_OPS_RESULT; + res = TO_OUTPUT_REORDER_TYPE(colorRGBA.s2); + FUSED_OPS; + output[output_idx_2] = FUSED_OPS_RESULT; + #else + output[output_idx_0] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s0), NL_M, NL_N); + output[output_idx_1] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s1), NL_M, NL_N); + output[output_idx_2] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s2), NL_M, NL_N); + #endif + #if INPUT0_FEATURE_NUM == 4 + uint8 ov = RESHAPE_DIMS(INPUT0, OUTPUT, b, 3, v, u, w, z, y, x); + uint output_idx = FUNC_CALL(get_output_index)(OPTIONAL_SHAPE_INFO_TENSOR ov.s0, ov.s1, ov.s2, ov.s3, ov.s4, ov.s5, ov.s6, ov.s7); + #if HAS_FUSED_OPS + res = TO_OUTPUT_REORDER_TYPE(colorRGBA.s3); + FUSED_OPS; + output[output_idx] = FUSED_OPS_RESULT; + #else + output[output_idx] = ACTIVATION_FUNC_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(colorRGBA.s3), NL_M, NL_N); + #endif + #endif #elif OUTPUT_LAYOUT_IMAGE_2D_RGBA IMAGE_WRITE(output, (int2)(x, y), colorRGBA); #else -#if INPUT0_IS_FP && !OUTPUT_IS_FP -#if CONVERT_TRUNCATE - output[output_idx] = ACTIVATION_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(convert_long(res)), ACTIVATION_PARAMS_TYPED); -#else - output[output_idx] = ACTIVATION_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE_SAT(res), ACTIVATION_PARAMS_TYPED); -#endif -#else - output[output_idx] = ACTIVATION_TYPED(OUTPUT_REORDER, TO_OUTPUT_REORDER_TYPE(res), ACTIVATION_PARAMS_TYPED); -#endif + #if INPUT0_IS_FP && !OUTPUT_IS_FP + #if CONVERT_TRUNCATE + #define __TO_OUTPUT_REORDER_TYPE(res) TO_OUTPUT_REORDER_TYPE(convert_long(res)) + #else + #define __TO_OUTPUT_REORDER_TYPE(res) TO_OUTPUT_REORDER_TYPE_SAT(res) + #endif + #else + #define __TO_OUTPUT_REORDER_TYPE(res) TO_OUTPUT_REORDER_TYPE(res) + #endif + + #if HAS_FUSED_OPS + res = __TO_OUTPUT_REORDER_TYPE(res); + FUSED_OPS; + output[output_idx] = FUSED_OPS_RESULT; + #else + output[output_idx] = ACTIVATION_TYPED(OUTPUT_REORDER, __TO_OUTPUT_REORDER_TYPE(res), ACTIVATION_PARAMS_TYPED); + #endif +#undef __TO_OUTPUT_REORDER_TYPE #endif } diff --git a/src/plugins/intel_gpu/src/kernel_selector/kernels/reorder/reorder_kernel.cpp b/src/plugins/intel_gpu/src/kernel_selector/kernels/reorder/reorder_kernel.cpp index df5e7b48162b3b..d4c8303d712c35 100644 --- a/src/plugins/intel_gpu/src/kernel_selector/kernels/reorder/reorder_kernel.cpp +++ b/src/plugins/intel_gpu/src/kernel_selector/kernels/reorder/reorder_kernel.cpp @@ -41,6 +41,17 @@ JitConstants ReorderKernelRef::GetJitConstants(const reorder_params& params) con if (params.surface_input) jit.AddConstant(MakeJitConstant("SURFACE_INPUT", true)); + if (!params.fused_ops.empty()) { + std::vector idx_order; + if (DataTensor::ChannelsCount(params.outputs[0].GetLayout()) == 4) { + idx_order = {"b", "f", "y", "x"}; + } else if (DataTensor::ChannelsCount(params.outputs[0].GetLayout()) == 5) { + idx_order = {"b", "f", "z", "y", "x"}; + } + FusedOpsConfiguration conf = {"", idx_order, "res", GetUnitType(params), 1}; + jit.Merge(MakeFusedOpsJitConstants(params, {conf})); + } + return jit; } diff --git a/src/plugins/intel_gpu/tests/unit/test_cases/reorder_gpu_test.cpp b/src/plugins/intel_gpu/tests/unit/test_cases/reorder_gpu_test.cpp index e4085c4ffe14f9..561ef4374d1520 100644 --- a/src/plugins/intel_gpu/tests/unit/test_cases/reorder_gpu_test.cpp +++ b/src/plugins/intel_gpu/tests/unit/test_cases/reorder_gpu_test.cpp @@ -583,6 +583,55 @@ TEST(reorder_gpu_f32, basic_subtract_value) { } } +TEST(reorder_gpu_f32, fusing_double_activations) { + // reorder_data reorder_data + // | | + // sqrt | + // | fuse | + // power data ----> | data + // \ / | / + // divide divide + // | | + // result result + // + // This test case is limited to the case of reorder_data using ReorderKernelRef. + // Because other kernels for reorder_data don't support fusing double activations e.g. reorder_data_fast_b1 + // + auto& engine = get_test_engine(); + + auto input1 = engine.allocate_memory({{1}, data_types::f32, format::bfyx}); + auto input2 = engine.allocate_memory({{1, 1, 1, 2, 2}, data_types::f32, format::bfzyx}); + + topology topology { + input_layout("input1", input1->get_layout()), + reorder("reorder", input_info("input1"), format::bfyx, data_types::f32), + activation("sqrt", input_info("reorder"), activation_func::sqrt), + activation("power", input_info("sqrt"), activation_func::pow), + input_layout("input2", input2->get_layout()), + eltwise("divide", {input_info("power"), input_info("input2")}, eltwise_mode::div), + reorder("result", input_info("divide"), format::bfyx, data_types::f32) + }; + + set_values(input1, {25000}); + set_values(input2, {0.1f, 0.2f, 0.5f, 1.0f}); + + ExecutionConfig config = get_test_default_config(engine); + ov::intel_gpu::ImplementationDesc reorder_impl = {format::bfyx, "reorder_data"}; + config.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{{"reorder", reorder_impl}})); + + network network(engine, topology, config); + network.set_input_data("input1", input1); + network.set_input_data("input2", input2); + + auto output = network.execute(); + + mem_lock output_mem(output.at("result").get_memory(), network.get_stream()); + std::vector output_ref = {10, 5, 2, 1}; + for (size_t i = 0; i < output_mem.size(); ++i) { + ASSERT_EQ(output_mem[i], output_ref[i]); + } +} + TEST(reorder_gpu_f16, basic_subtract_f32_output_f32) { // Input : 2x2x2x2 (FP16) // Output : 2x2x2x2 (FP32) diff --git a/tests/layer_tests/tensorflow_tests/test_tf_Add.py b/tests/layer_tests/tensorflow_tests/test_tf_Add.py index 7fb4977b802698..fa8245bf288796 100644 --- a/tests/layer_tests/tensorflow_tests/test_tf_Add.py +++ b/tests/layer_tests/tensorflow_tests/test_tf_Add.py @@ -222,3 +222,60 @@ def test_add_placeholder_const_broadcast_5D(self, params, ie_device, precision, use_legacy_frontend=use_legacy_frontend), ie_device, precision, ir_version=ir_version, temp_dir=temp_dir, use_legacy_frontend=use_legacy_frontend) + + +class TestComplexAdd(CommonTFLayerTest): + def _prepare_input(self, inputs_info): + rng = np.random.default_rng() + assert 'param_real_1:0' in inputs_info + assert 'param_imag_1:0' in inputs_info + assert 'param_real_2:0' in inputs_info + assert 'param_imag_2:0' in inputs_info + param_real_shape_1 = inputs_info['param_real_1:0'] + param_imag_shape_1 = inputs_info['param_imag_1:0'] + param_real_shape_2 = inputs_info['param_real_2:0'] + param_imag_shape_2 = inputs_info['param_imag_2:0'] + inputs_data = {} + inputs_data['param_real_1:0'] = 4 * rng.random(param_real_shape_1).astype(np.float32) - 2 + inputs_data['param_imag_1:0'] = 4 * rng.random(param_imag_shape_1).astype(np.float32) - 2 + inputs_data['param_real_2:0'] = 4 * rng.random(param_real_shape_2).astype(np.float32) - 2 + inputs_data['param_imag_2:0'] = 4 * rng.random(param_imag_shape_2).astype(np.float32) - 2 + return inputs_data + + def create_complex_addv2_net(self, input_shape): + import tensorflow as tf + tf.compat.v1.reset_default_graph() + # Create the graph and model + with tf.compat.v1.Session() as sess: + param_real1 = tf.compat.v1.placeholder(np.float32, input_shape, 'param_real_1') + param_imag1 = tf.compat.v1.placeholder(np.float32, input_shape, 'param_imag_1') + param_real2 = tf.compat.v1.placeholder(np.float32, input_shape, 'param_real_2') + param_imag2 = tf.compat.v1.placeholder(np.float32, input_shape, 'param_imag_2') + complex1 = tf.raw_ops.Complex(real=param_real1, imag=param_imag1) + complex2 = tf.raw_ops.Complex(real=param_real2, imag=param_imag2) + add = tf.raw_ops.AddV2(x=complex1, y=complex2, name="complex_add") + real = tf.raw_ops.Real(input=add) + img = tf.raw_ops.Imag(input=add) + tf.compat.v1.global_variables_initializer() + tf_net = sess.graph_def + + return tf_net, None + + + test_data_basic = [ + dict(input_shape=[]), + dict(input_shape=[2]), + dict(input_shape=[1, 3]), + dict(input_shape=[2, 3, 4]), + dict(input_shape=[3, 4, 5, 6]), + ] + + @pytest.mark.parametrize("params", test_data_basic) + @pytest.mark.precommit_tf_fe + @pytest.mark.nightly + def test_complex_add(self, params, ie_device, precision, ir_version, temp_dir, + use_legacy_frontend): + self._test( + *self.create_complex_addv2_net(**params), + ie_device, precision, ir_version, temp_dir=temp_dir, + use_legacy_frontend=use_legacy_frontend) diff --git a/tests/layer_tests/tensorflow_tests/test_tf_Size.py b/tests/layer_tests/tensorflow_tests/test_tf_Size.py index 0622625e78a6ba..19705556f04176 100644 --- a/tests/layer_tests/tensorflow_tests/test_tf_Size.py +++ b/tests/layer_tests/tensorflow_tests/test_tf_Size.py @@ -43,3 +43,45 @@ def test_size_basic(self, params, ie_device, precision, ir_version, temp_dir, self._test(*self.create_size_net(**params), ie_device, precision, ir_version, temp_dir=temp_dir, use_legacy_frontend=use_legacy_frontend) + +class TestComplexSize(CommonTFLayerTest): + def _prepare_input(self, inputs_info): + rng = np.random.default_rng() + assert 'param_real:0' in inputs_info + assert 'param_imag:0' in inputs_info + param_real_shape_1 = inputs_info['param_real:0'] + param_imag_shape_1 = inputs_info['param_imag:0'] + inputs_data = {} + inputs_data['param_real:0'] = 4 * rng.random(param_real_shape_1).astype(np.float32) - 2 + inputs_data['param_imag:0'] = 4 * rng.random(param_imag_shape_1).astype(np.float32) - 2 + return inputs_data + + def create_complex_size_net(self, input_shape): + tf.compat.v1.reset_default_graph() + # Create the graph and model + with tf.compat.v1.Session() as sess: + param_real = tf.compat.v1.placeholder(np.float32, input_shape, 'param_real') + param_imag = tf.compat.v1.placeholder(np.float32, input_shape, 'param_imag') + complex = tf.raw_ops.Complex(real=param_real, imag=param_imag) + tf.raw_ops.Size(input=complex) + tf.compat.v1.global_variables_initializer() + tf_net = sess.graph_def + + return tf_net, None + + test_data_basic = [ + dict(input_shape=[]), + dict(input_shape=[1]), + dict(input_shape=[2, 6]), + dict(input_shape=[2, 4, 5]), + ] + + @pytest.mark.parametrize("params", test_data_basic) + @pytest.mark.precommit_tf_fe + @pytest.mark.nightly + def test_complex_size(self, params, ie_device, precision, ir_version, temp_dir, + use_legacy_frontend): + self._test( + *self.create_complex_size_net(**params), + ie_device, precision, ir_version, temp_dir=temp_dir, + use_legacy_frontend=use_legacy_frontend)