diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9cb779b257d57b..afa794920c85f1 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,7 +25,7 @@ jobs: - name: Setup ccache - uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13 + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 with: max-size: 50G diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 3880f8333f18c5..e20fc6081969fe 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -131,7 +131,7 @@ jobs: # - name: Setup ccache - uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13 + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 with: max-size: "2000M" # Should save cache only if run in the master branch of the base repo diff --git a/.github/workflows/mac_arm64.yml b/.github/workflows/mac_arm64.yml index 8386f54719b02c..f14c897af2c661 100644 --- a/.github/workflows/mac_arm64.yml +++ b/.github/workflows/mac_arm64.yml @@ -131,7 +131,7 @@ jobs: # - name: Setup ccache - uses: hendrikmuhs/ccache-action@c92f40bee50034e84c763e33b317c77adaa81c92 # v1.2.13 + uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14 with: max-size: "2000M" # Should save cache only if run in the master branch of the base repo diff --git a/docs/articles_en/get-started/configurations.rst b/docs/articles_en/get-started/configurations.rst index d977c98293e908..3e471c33445292 100644 --- a/docs/articles_en/get-started/configurations.rst +++ b/docs/articles_en/get-started/configurations.rst @@ -1,6 +1,4 @@ -.. {#openvino_docs_install_guides_configurations_header} - -Additional Configurations For Hardware +Additional Configurations ====================================== @@ -16,10 +14,10 @@ Additional Configurations For Hardware For GPU For NPU + GenAI Dependencies -For certain use cases, you may need to install additional software, to use the full -potential of OpenVINO™. Check the following list for components for elements used in -your workflow: +For certain use cases, you may need to install additional software, to benefit from the full +potential of OpenVINO™. Check the following list for components used in your workflow: | **GPU drivers** | If you want to run inference on a GPU, make sure your GPU's drivers are properly installed. @@ -33,6 +31,11 @@ your workflow: See the :doc:`guide on NPU configuration ` for details. +| **OpenVINO GenAI Dependencies** +| OpenVINO GenAI is a flavor of OpenVINO, aiming to simplify running generative + AI models. For information on the dependencies required to use OpenVINO GenAI, see the + :doc:`guide on OpenVINO GenAI Dependencies `. + | **Open Computer Vision Library** | OpenCV is used to extend the capabilities of some models, for example enhance some of OpenVINO samples, when used as a dependency in compilation. To install OpenCV for OpenVINO, see the diff --git a/docs/articles_en/get-started/configurations/genai-dependencies.rst b/docs/articles_en/get-started/configurations/genai-dependencies.rst new file mode 100644 index 00000000000000..cfa35dee5de34d --- /dev/null +++ b/docs/articles_en/get-started/configurations/genai-dependencies.rst @@ -0,0 +1,31 @@ +OpenVINO™ GenAI Dependencies +================================= + +OpenVINO™ GenAI depends on both `OpenVINO `__ and +`OpenVINO Tokenizers `__. During OpenVINO™ +GenAI installation from PyPi, the same versions of OpenVINO and OpenVINO Tokenizers +are used (e.g. ``openvino==2024.3.0`` and ``openvino-tokenizers==2024.3.0.0`` are installed for +``openvino-genai==2024.3.0``). + +Trying to update any of the dependency packages might result in a version incompatiblibty +due to different Application Binary Interfaces (ABIs), which will result in errors while running +OpenVINO GenAI. Having package version in the ``...`` format, allows +changing the ```` portion of the full version to ensure ABI compatibility. Changing +````, ```` or ```` part of the version may break ABI. + +GenAI, Tokenizers, and OpenVINO wheels for Linux on PyPI are compiled with ``_GLIBCXX_USE_CXX11_ABI=0`` +to cover a wider range of platforms. In the C++ archive distributions for Ubuntu, ``_GLIBCXX_USE_CXX11_ABI=1`` +is used instead. Mixing different ABIs is not possible as doing so will result in a link error. + +To try OpenVINO GenAI with different dependencies versions (which are **not** prebuilt packages +as archives or python wheels), build OpenVINO GenAI library from +`Source `__. + +Additional Resources +####################### + +* :doc:`OpenVINO GenAI Installation Guide <../install-openvino/install-openvino-genai>` +* `OpenVINO GenAI repository `__ +* :doc:`OpenVINO Installation Guide <../install-openvino>` +* :doc:`OpenVINO Tokenizers <../../learn-openvino/llm_inference_guide/ov-tokenizers>` + diff --git a/docs/articles_en/get-started/install-openvino/install-openvino-genai.rst b/docs/articles_en/get-started/install-openvino/install-openvino-genai.rst index 6368ef95bd887e..4eb8e8df3a3f00 100644 --- a/docs/articles_en/get-started/install-openvino/install-openvino-genai.rst +++ b/docs/articles_en/get-started/install-openvino/install-openvino-genai.rst @@ -11,7 +11,9 @@ To see GenAI in action, check the Jupyter notebooks: `LLM-powered Chatbot `__ and `LLM Instruction-following pipeline `__. -The OpenVINO GenAI flavor is available for installation via PyPI and Archive distributions: +The OpenVINO GenAI flavor is available for installation via PyPI and Archive distributions. +A `detailed guide `__ +on how to build OpenVINO GenAI is available in the OpenVINO GenAI repository. PyPI Installation ############################### diff --git a/docs/dev/build_linux.md b/docs/dev/build_linux.md index d3e1319f9d2c1a..38c217bb2a5e79 100644 --- a/docs/dev/build_linux.md +++ b/docs/dev/build_linux.md @@ -74,7 +74,7 @@ You can use the following additional build options: ``` 3. After the build process finishes, export the newly built Python libraries to the user environment variables: ``` - export PYTHONPATH=/bin/intel64/Release/python:$PYTHONPATH + export PYTHONPATH=/bin/intel64/Release/python:/tools/ovc:$PYTHONPATH export LD_LIBRARY_PATH=/bin/intel64/Release:$LD_LIBRARY_PATH ``` or install the wheel with pip: diff --git a/docs/dev/build_windows.md b/docs/dev/build_windows.md index 2515000e5ec4f0..a7fdc9d409c527 100644 --- a/docs/dev/build_windows.md +++ b/docs/dev/build_windows.md @@ -61,7 +61,7 @@ Supported configurations: ``` 3. After the build process finishes, export the newly built Python libraries to the user environment variables: ``` - set PYTHONPATH=/bin//Release/python;%PYTHONPATH% + set PYTHONPATH=/bin//Release/python;/tools/ovc;%PYTHONPATH% set OPENVINO_LIB_PATHS=/bin//Release;/temp/tbb/bin ``` or install the wheel with pip: diff --git a/src/common/transformations/include/transformations/common_optimizations/move_eltwise_up_data_movement.hpp b/src/common/transformations/include/transformations/common_optimizations/move_eltwise_up_data_movement.hpp index 7f41c1694b32bc..4f704b089190a4 100644 --- a/src/common/transformations/include/transformations/common_optimizations/move_eltwise_up_data_movement.hpp +++ b/src/common/transformations/include/transformations/common_optimizations/move_eltwise_up_data_movement.hpp @@ -11,10 +11,56 @@ namespace ov { namespace pass { -class TRANSFORMATIONS_API MoveEltwiseUpThroughDataMov : public ov::pass::MatcherPass { +/// This transformation tries to put element-wise operations (Unary or Binary with scalar second input) before a set of +/// data movement ops in order to allow further element-wise op fusion to previous op and zero-copy optimizations for +/// data movement op itself. +/// ┌───────────┐ ┌───────────┐ +/// │ AnyOp │ │ AnyOp │ +/// └─────┬─────┘ └─────┬─────┘ +/// │ │ +/// │ │ +/// ┌───────┴────────┐ ┌───────┴────────┐ +/// | DataMovementOp | => | Element-Wise | +/// └───────┬────────┘ └───────┬────────┘ +/// │ │ +/// │ │ +/// ┌───────┴────────┐ ┌───────┴────────┐ +/// │ Element-Wise | │ DataMovementOp | +/// └────────────────┘ └────────────────┘ +class TRANSFORMATIONS_API MoveEltwiseUpThroughDataMovScalar : public ov::pass::MatcherPass { +public: + OPENVINO_RTTI("MoveEltwiseUpThroughDataMovScalar", "0"); + MoveEltwiseUpThroughDataMovScalar(std::vector allowed_data_movement_ops); +}; + +/// This transformation tries to put element-wise operations before Reshape/Squeeze/Unsqueeze ops +/// when second input to eltwise is per-channel Constant op +/// ┌───────────┐ ┌────────────────┐ ┌───────────┐ ┌────────────────────┐ +/// │ AnyOp │ │ TargetShape │ │ AnyOp │ │ Per-Channel Const │ +/// └─────┬─────┘ └────────┬───────┘ └─────┬─────┘ └─────────┬──────────┘ +/// │ │ │ │ +/// │ | │ | +/// │ ┌─────────┐ │ │ ┌──────────────┐ │ +/// └───┤ Reshape ├────────┘ => └───┤ Element-Wise ├─────────┘ +/// └────┬────┘ └───────┬──────┘ +/// │ │ +/// │ │ +/// ┌───────┴────────┐ ┌────────────────────┐ ┌─────┴─────┐ ┌─────────────┐ +/// │ Element-Wise ├────┤ Per-Channel Const │ │ Reshape ├────┤ TargetShape │ +/// └────────────────┘ └────────────────────┘ └───────────┘ └─────────────┘ +class TRANSFORMATIONS_API MoveEltwiseUpThroughDataMovPerChannel : public ov::pass::MatcherPass { +public: + OPENVINO_RTTI("MoveEltwiseUpThroughDataMovPerChannel", "0"); + MoveEltwiseUpThroughDataMovPerChannel(); +}; + +class TRANSFORMATIONS_API MoveEltwiseUpThroughDataMov : public ov::pass::GraphRewrite { public: OPENVINO_RTTI("MoveEltwiseUpThroughDataMov", "0"); - MoveEltwiseUpThroughDataMov(std::vector allowed_data_movement_ops = get_default_allowed_ops()); + MoveEltwiseUpThroughDataMov(std::vector allowed_data_movement_ops = get_default_allowed_ops()) { + this->add_matcher(allowed_data_movement_ops); + this->add_matcher(); + } private: static std::vector get_default_allowed_ops(); diff --git a/src/common/transformations/src/transformations/common_optimizations/move_eltwise_up_data_movement.cpp b/src/common/transformations/src/transformations/common_optimizations/move_eltwise_up_data_movement.cpp index 9218c93bac269f..fd9e7417261b81 100644 --- a/src/common/transformations/src/transformations/common_optimizations/move_eltwise_up_data_movement.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/move_eltwise_up_data_movement.cpp @@ -4,13 +4,17 @@ #include "transformations/common_optimizations/move_eltwise_up_data_movement.hpp" +#include #include -#include #include #include "itt.hpp" #include "openvino/core/rt_info.hpp" #include "openvino/core/type.hpp" +#include "openvino/op/constant.hpp" +#include "openvino/op/reshape.hpp" +#include "openvino/op/squeeze.hpp" +#include "openvino/op/unsqueeze.hpp" #include "openvino/pass/pattern/op/wrap_type.hpp" #include "transformations/utils/utils.hpp" @@ -50,9 +54,9 @@ std::vector ov::pass::MoveEltwiseUpThroughDataMov::get_def }; } -ov::pass::MoveEltwiseUpThroughDataMov::MoveEltwiseUpThroughDataMov( +ov::pass::MoveEltwiseUpThroughDataMovScalar::MoveEltwiseUpThroughDataMovScalar( std::vector allowed_data_movement_ops) { - MATCHER_SCOPE(MoveEltwiseUpThroughDataMov); + MATCHER_SCOPE(MoveEltwiseUpThroughDataMovScalar); auto eltwise_pattern = ov::pass::pattern::wrap_type(ov::pass::pattern::has_static_rank()); @@ -126,3 +130,102 @@ ov::pass::MoveEltwiseUpThroughDataMov::MoveEltwiseUpThroughDataMov( auto m = std::make_shared(eltwise_pattern, matcher_name); register_matcher(m, callback); } + +ov::pass::MoveEltwiseUpThroughDataMovPerChannel::MoveEltwiseUpThroughDataMovPerChannel() { + MATCHER_SCOPE(MoveEltwiseUpThroughDataMovPerChannel); + + auto const_predicate = [](const ov::Output& output) { + auto constant_op = std::dynamic_pointer_cast(output.get_node_shared_ptr()); + if (!constant_op) + return false; + + if (output.get_target_inputs().size() != 1) + return false; + + const auto& shape = constant_op->get_shape(); + return std::count_if(shape.begin(), shape.end(), [](size_t v) { + return v > 1; + }) == 1; + }; + + auto eltw_predicate = [](const ov::Output& output) { + if (output.get_target_inputs().size() != 1) + return false; + + auto node = output.get_node(); + + if (node->get_output_partial_shape(0).rank().is_dynamic()) + return false; + + const size_t const_idx = ov::is_type(node->get_input_node_ptr(0)) ? 0 : 1; + const size_t data_flow_idx = (const_idx + 1) % 2; + + if (node->get_input_partial_shape(data_flow_idx).size() < node->get_input_partial_shape(const_idx).size()) + return false; + + return true; + }; + + auto eltw_data_flow_in = + ov::pass::pattern::wrap_type(); + auto eltw_const_in = ov::pass::pattern::wrap_type(const_predicate); + auto eltwise_pattern = + ov::pass::pattern::wrap_type({eltw_data_flow_in, eltw_const_in}, + eltw_predicate); + + ov::matcher_pass_callback callback = [OV_CAPTURE_CPY_AND_THIS](ov::pass::pattern::Matcher& m) { + const auto& pattern_map = m.get_pattern_value_map(); + + auto eltwise = pattern_map.at(eltwise_pattern).get_node_shared_ptr(); + if (transformation_callback(eltwise)) { + return false; + } + + const size_t const_idx = ov::is_type(eltwise->get_input_node_ptr(0)) ? 0 : 1; + const size_t data_flow_idx = (const_idx + 1) % 2; + + auto const_shape = eltwise->get_input_shape(const_idx); + size_t channel_idx = 0; + size_t channel_val = 0; + for (size_t i = 0; i < const_shape.size(); i++) { + if (const_shape[i] > 1) { + channel_idx = i; + channel_val = const_shape[i]; + } + } + + auto parent = eltwise->get_input_node_shared_ptr(data_flow_idx); + const auto& parent_in_pshape = parent->get_input_partial_shape(0); + auto parent_in_channel_dim = + parent_in_pshape.size() <= channel_idx ? ov::Dimension(1) : parent_in_pshape[channel_idx]; + auto parent_out_channel_dim = parent->get_output_partial_shape(0)[channel_idx]; + if (parent_in_channel_dim.is_dynamic() || parent_in_channel_dim != channel_val || + parent_out_channel_dim.is_dynamic() || parent_out_channel_dim != channel_val) + return false; + + auto new_shape = ov::Shape(parent->get_input_partial_shape(0).size(), 1); + + new_shape[channel_idx] = const_shape[channel_idx]; + auto old_const = std::dynamic_pointer_cast(eltwise->get_input_node_shared_ptr(const_idx)); + auto new_const = std::make_shared(*old_const, new_shape); + ov::replace_node_update_name(old_const, new_const); + ov::replace_output_update_name(eltwise->output(0), eltwise->input_value(data_flow_idx)); + + ov::OutputVector eltwise_inputs = eltwise->input_values(); + eltwise_inputs[data_flow_idx] = parent->input_value(0); + auto new_eltwise = eltwise->clone_with_new_inputs(eltwise_inputs); + ov::copy_runtime_info(eltwise, new_eltwise); + + ov::OutputVector parent_inputs = parent->input_values(); + parent_inputs[0] = new_eltwise; + auto new_parent = parent->clone_with_new_inputs(parent_inputs); + ov::copy_runtime_info(parent, new_parent); + new_parent->set_friendly_name(parent->get_friendly_name()); + + ov::replace_node(parent, new_parent); + return true; + }; + + auto m = std::make_shared(eltwise_pattern, matcher_name); + register_matcher(m, callback); +} diff --git a/src/common/transformations/src/transformations/op_conversions/convert_maxpool_downgrade.cpp b/src/common/transformations/src/transformations/op_conversions/convert_maxpool_downgrade.cpp index f74584a3fa8b7f..55ae717dbf58f4 100644 --- a/src/common/transformations/src/transformations/op_conversions/convert_maxpool_downgrade.cpp +++ b/src/common/transformations/src/transformations/op_conversions/convert_maxpool_downgrade.cpp @@ -98,23 +98,23 @@ ov::pass::ConvertMaxPool14ToMaxPool8::ConvertMaxPool14ToMaxPool8() { const auto strides = max_pool_v14->get_strides(); const auto padding_begin = max_pool_v14->get_pads_begin(); const auto padding_begin_node = - node_registry.make(element::i64, Shape{padding_begin.size()}, padding_begin); + node_registry.make(element::i32, Shape{padding_begin.size()}, padding_begin); const auto padding_end = max_pool_v14->get_pads_end(); const auto padding_end_node = - node_registry.make(element::i64, Shape{padding_end.size()}, padding_end); - const auto zero = node_registry.make(element::i64, Shape{}, 0); - const auto one = node_registry.make(element::i64, Shape{}, 1); - const auto two = node_registry.make(element::i64, Shape{}, 2); + node_registry.make(element::i32, Shape{padding_end.size()}, padding_end); + const auto zero = node_registry.make(element::i32, Shape{}, 0); + const auto one = node_registry.make(element::i32, Shape{}, 1); + const auto two = node_registry.make(element::i32, Shape{}, 2); const auto pads_size = max_pool_v14->get_pads_begin().size(); - const auto pads_len = node_registry.make(element::i64, Shape{}, pads_size); + const auto pads_len = node_registry.make(element::i32, Shape{}, pads_size); const auto pads_remaining = - node_registry.make(element::i64, Shape{2}, std::vector{0, 0}); + node_registry.make(element::i32, Shape{2}, std::vector{0, 0}); // gather input spatial dims and prepare for compare as values (in_dim + pad) - const auto end = node_registry.make(element::i64, Shape{}, pads_size + 2); - const auto dim_idxs = node_registry.make(two, end, one, element::i64); - const auto shape = node_registry.make(input, element::i64); + const auto end = node_registry.make(element::i32, Shape{}, pads_size + 2); + const auto dim_idxs = node_registry.make(two, end, one, element::i32); + const auto shape = node_registry.make(input, element::i32); const auto gth_in_dims = node_registry.make(shape, dim_idxs, zero); const auto in_left_padded = node_registry.make(gth_in_dims, padding_begin_node); @@ -126,10 +126,10 @@ ov::pass::ConvertMaxPool14ToMaxPool8::ConvertMaxPool14ToMaxPool8() { max_pool_v14->get_pads_end(), max_pool_v14->get_kernel(), ov::op::RoundingType::CEIL); - const auto shape_of_mp = node_registry.make(mp, element::i64); + const auto shape_of_mp = node_registry.make(mp, element::i32); const auto gth_out_dims = node_registry.make(shape_of_mp, dim_idxs, zero); const auto out_sub_one = node_registry.make(gth_out_dims, one); - const auto stride_node = node_registry.make(element::i64, Shape{strides.size()}, strides); + const auto stride_node = node_registry.make(element::i32, Shape{strides.size()}, strides); const auto out_mul_stride = node_registry.make(out_sub_one, stride_node); // if (in_dim + pad) > ((out_dim - 1) * stride) sliding window in bound use end padding. diff --git a/src/common/transformations/tests/common_optimizations/move_eltwise_up_data_movement_test.cpp b/src/common/transformations/tests/common_optimizations/move_eltwise_up_data_movement_test.cpp index b2561d5f1fc150..cba3ae82d90fe3 100644 --- a/src/common/transformations/tests/common_optimizations/move_eltwise_up_data_movement_test.cpp +++ b/src/common/transformations/tests/common_optimizations/move_eltwise_up_data_movement_test.cpp @@ -349,3 +349,99 @@ TEST_F(MoveEltwiseUpThroughDataMovTest, TransposeFakeQuantizePerChannel) { manager.register_pass(); } } + +TEST_F(MoveEltwiseUpThroughDataMovTest, PerChannelEltwiseUnsqueeze) { + const ov::Shape shape{10, 20}; + { + auto input = std::make_shared(ov::element::f32, shape); + + auto unsqueeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{2}, {2, 3}); // {10, 20, 1, 1} + auto unsqueeze = std::make_shared(input, unsqueeze_const); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {1, 20, 1, 1}, {0.5}); + auto add = std::make_shared(unsqueeze, per_channel_const); + + model = std::make_shared(ov::NodeVector{add}, ov::ParameterVector{input}); + manager.register_pass(); + } + { + auto input = std::make_shared(ov::element::f32, shape); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {1, 20}, {0.5}); + auto add = std::make_shared(input, per_channel_const); + + auto unsqueeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{2}, {2, 3}); // {10, 20, 1, 1} + auto unsqueeze = std::make_shared(add, unsqueeze_const); + + model_ref = std::make_shared(ov::NodeVector{unsqueeze}, ov::ParameterVector{input}); + } +} + +TEST_F(MoveEltwiseUpThroughDataMovTest, PerChannelEltwiseUnsqueezeReverseInOrder) { + const ov::Shape shape{10, 20}; + { + auto input = std::make_shared(ov::element::f32, shape); + + auto unsqueeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{2}, {2, 3}); // {10, 20, 1, 1} + auto unsqueeze = std::make_shared(input, unsqueeze_const); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {1, 20, 1, 1}, {0.5}); + auto add = std::make_shared(per_channel_const, unsqueeze); + + model = std::make_shared(ov::NodeVector{add}, ov::ParameterVector{input}); + manager.register_pass(); + } + { + auto input = std::make_shared(ov::element::f32, shape); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {1, 20}, {0.5}); + auto add = std::make_shared(per_channel_const, input); + + auto unsqueeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{2}, {2, 3}); // {10, 20, 1, 1} + auto unsqueeze = std::make_shared(add, unsqueeze_const); + + model_ref = std::make_shared(ov::NodeVector{unsqueeze}, ov::ParameterVector{input}); + } +} + +TEST_F(MoveEltwiseUpThroughDataMovTest, PerChannelEltwiseSqueeze) { + const ov::Shape shape{10, 20, 1, 1}; + { + auto input = std::make_shared(ov::element::f32, shape); + + auto squeeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{}, {2}); // {10, 20, 1} + auto squeeze = std::make_shared(input, squeeze_const); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {10, 1, 1}, {0.5}); + auto add = std::make_shared(squeeze, per_channel_const); + + model = std::make_shared(ov::NodeVector{add}, ov::ParameterVector{input}); + manager.register_pass(); + } + { + auto input = std::make_shared(ov::element::f32, shape); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {10, 1, 1, 1}, {0.5}); + auto add = std::make_shared(input, per_channel_const); + + auto squeeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{}, {2}); // {10, 20, 1} + auto squeeze = std::make_shared(add, squeeze_const); + + model_ref = std::make_shared(ov::NodeVector{squeeze}, ov::ParameterVector{input}); + } +} + +TEST_F(MoveEltwiseUpThroughDataMovTest, PerChannelEltwiseSqueezeIllegal_1) { + // Only last dimensions can be updated by squeeze/unsqueeze op, while this subgraph removes dimension in the middle + const ov::Shape shape{10, 1, 20}; + auto input = std::make_shared(ov::element::f32, shape); + + auto squeeze_const = ov::opset8::Constant::create(ov::element::i64, ov::Shape{}, {1}); // {10, 20} + auto squeeze = std::make_shared(input, squeeze_const); + + auto per_channel_const = ov::opset8::Constant::create(ov::element::f32, {1, 1, 20}, {0.5}); + auto add = std::make_shared(squeeze, per_channel_const); + + model = std::make_shared(ov::NodeVector{add}, ov::ParameterVector{input}); + manager.register_pass(); +} diff --git a/src/common/transformations/tests/op_conversions/convert_maxpool_downgrade_test.cpp b/src/common/transformations/tests/op_conversions/convert_maxpool_downgrade_test.cpp index 42366f6ac2c669..2105dec9fe91dd 100644 --- a/src/common/transformations/tests/op_conversions/convert_maxpool_downgrade_test.cpp +++ b/src/common/transformations/tests/op_conversions/convert_maxpool_downgrade_test.cpp @@ -91,20 +91,20 @@ std::shared_ptr create_ceil_torch_workaround_model(const ov::op::Roun const ov::Strides strides{2, 2}, dilations{1, 1}; ov::Shape pads_begin{1, 1}, pads_end{1, 1}, kernel{2, 2}; - const auto padding_begin_node = Constant::create(ov::element::i64, ov::Shape{pads_begin.size()}, pads_begin); - const auto padding_end_node = Constant::create(ov::element::i64, ov::Shape{pads_end.size()}, pads_end); - const auto zero = Constant::create(ov::element::i64, ov::Shape{}, {0}); - const auto one = Constant::create(ov::element::i64, ov::Shape{}, {1}); - const auto two = Constant::create(ov::element::i64, ov::Shape{}, {2}); + const auto padding_begin_node = Constant::create(ov::element::i32, ov::Shape{pads_begin.size()}, pads_begin); + const auto padding_end_node = Constant::create(ov::element::i32, ov::Shape{pads_end.size()}, pads_end); + const auto zero = Constant::create(ov::element::i32, ov::Shape{}, {0}); + const auto one = Constant::create(ov::element::i32, ov::Shape{}, {1}); + const auto two = Constant::create(ov::element::i32, ov::Shape{}, {2}); const auto pads_size = pads_begin.size(); - const auto pads_len = Constant::create(ov::element::i64, ov::Shape{}, {pads_size}); - const auto pads_remaining = Constant::create(ov::element::i64, ov::Shape{2}, {0, 0}); + const auto pads_len = Constant::create(ov::element::i32, ov::Shape{}, {pads_size}); + const auto pads_remaining = Constant::create(ov::element::i32, ov::Shape{2}, {0, 0}); // gather input spatial dims and prepare for compare as values (in_dim + pad) - const auto end = Constant::create(ov::element::i64, ov::Shape{}, {pads_size + 2}); - const auto dim_idxs = std::make_shared(two, end, one, ov::element::i64); - const auto shape = std::make_shared(input, ov::element::i64); + const auto end = Constant::create(ov::element::i32, ov::Shape{}, {pads_size + 2}); + const auto dim_idxs = std::make_shared(two, end, one, ov::element::i32); + const auto shape = std::make_shared(input, ov::element::i32); const auto gth_in_dims = std::make_shared(shape, dim_idxs, zero); const auto in_left_padded = std::make_shared(gth_in_dims, padding_begin_node); @@ -116,10 +116,10 @@ std::shared_ptr create_ceil_torch_workaround_model(const ov::op::Roun pads_end, kernel, ov::op::RoundingType::CEIL); - const auto shape_of_mp = std::make_shared(mp, ov::element::i64); + const auto shape_of_mp = std::make_shared(mp, ov::element::i32); const auto gth_out_dims = std::make_shared(shape_of_mp, dim_idxs, zero); const auto out_sub_one = std::make_shared(gth_out_dims, one); - const auto stride_node = Constant::create(ov::element::i64, ov::Shape{strides.size()}, strides); + const auto stride_node = Constant::create(ov::element::i32, ov::Shape{strides.size()}, strides); const auto out_mul_stride = std::make_shared(out_sub_one, stride_node); // if (in_dim + pad) > ((out_dim - 1) * stride) sliding window in bound use end padding. diff --git a/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp b/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp index 531203790330ec..4504ff85de6bc2 100644 --- a/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp +++ b/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp @@ -798,6 +798,7 @@ void Transformations::PostLpt() { }, ov::pass::UnrollTensorIterator); CPU_REGISTER_PASS_COMMON(postLPTPassManager, ov::pass::MoveEltwiseUpThroughDataMov); + CPU_DISABLE_PASS_COMMON(postLPTPassManager, ov::pass::MoveEltwiseUpThroughDataMovPerChannel); CPU_SET_CALLBACK_COMMON(postLPTPassManager, [](const std::shared_ptr& node) -> bool { if (!ov::is_type(node) && node->get_output_element_type(0) != node->get_input_element_type(0)) @@ -809,7 +810,7 @@ void Transformations::PostLpt() { } return false; }, - ov::pass::MoveEltwiseUpThroughDataMov); + ov::pass::MoveEltwiseUpThroughDataMovScalar); CPU_REGISTER_PASS_COMMON(postLPTPassManager, ov::pass::Validate); CPU_REGISTER_PASS_COMMON(postLPTPassManager, ov::pass::ConstantFolding);