From 3e8c0fac1b717d7719965a0d0beb77245821da03 Mon Sep 17 00:00:00 2001 From: Mateusz Tabaka Date: Wed, 30 Aug 2023 11:28:33 +0200 Subject: [PATCH] Remove useless Slices (#19451) Adjust UselessStridedSliceEraser to work with Slice nodes. Ticket: CVS-118895 --- .../optimize_strided_slice.hpp | 8 ++-- .../optimize_strided_slice.cpp | 20 +++++----- .../optimize_strided_slice_test.cpp | 37 +++++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/common/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp b/src/common/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp index 0e56210edef..e6e4edb6666 100644 --- a/src/common/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp +++ b/src/common/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp @@ -14,7 +14,7 @@ namespace ov { namespace pass { class TRANSFORMATIONS_API StridedSliceOptimization; -class TRANSFORMATIONS_API UselessStridedSliceEraser; +class TRANSFORMATIONS_API UselessSliceEraser; class TRANSFORMATIONS_API SharedStridedSliceEraser; class TRANSFORMATIONS_API GroupedStridedSliceOptimizer; class TRANSFORMATIONS_API GroupedSliceToVSplitOptimization; @@ -24,12 +24,12 @@ class TRANSFORMATIONS_API GroupedSliceToVSplitOptimization; /** * @ingroup ie_transformation_common_api - * @brief UselessStridedSliceEraser transformation removes StridedSlice operations + * @brief UselessSliceEraser transformation removes Slice/StridedSlice operations * with equal input and output shapes. */ -class ov::pass::UselessStridedSliceEraser : public ov::pass::ModelPass { +class ov::pass::UselessSliceEraser : public ov::pass::ModelPass { public: - OPENVINO_RTTI("UselessStridedSliceEraser", "0"); + OPENVINO_RTTI("UselessSliceEraser", "0"); bool run_on_model(const std::shared_ptr& m) override; }; 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 aa63ab3b6a0..d443e962f4e 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 @@ -21,8 +21,8 @@ using namespace ov; -bool ov::pass::UselessStridedSliceEraser::run_on_model(const std::shared_ptr& f) { - RUN_ON_FUNCTION_SCOPE(UselessStridedSliceEraser); +bool ov::pass::UselessSliceEraser::run_on_model(const std::shared_ptr& f) { + RUN_ON_FUNCTION_SCOPE(UselessSliceEraser); bool rewritten = false; for (auto& node : f->get_ordered_ops()) { // Recursively apply transformation for sub-graph based operations @@ -31,19 +31,21 @@ bool ov::pass::UselessStridedSliceEraser::run_on_model(const std::shared_ptr(node); - if (!ss || ss->get_output_partial_shape(0).is_dynamic() || ss->get_input_partial_shape(0).is_dynamic()) + 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()) continue; - if (ss->input(0).get_shape() != ss->output(0).get_shape()) + if (node->get_input_shape(0) != node->get_output_shape(0)) continue; - auto stridesNode = std::dynamic_pointer_cast(ss->input_value(3).get_node_shared_ptr()); + auto stridesNode = std::dynamic_pointer_cast(node->get_input_node_shared_ptr(3)); if (stridesNode) { auto strides = stridesNode->cast_vector(); if (!std::any_of(strides.begin(), strides.end(), [](int64_t strd) { return strd < 0; - })) - rewritten |= replace_output_update_name(ss->output(0), ss->input_value(0)); + })) { + rewritten |= replace_output_update_name(node->output(0), node->input_value(0)); + } } } return rewritten; @@ -404,7 +406,7 @@ bool ov::pass::StridedSliceOptimization::run_on_model(const std::shared_ptr(element::f32, Shape{5, 5, 5, 5}); + auto relu = std::make_shared(data); + auto begin = opset1::Constant::create(element::i64, Shape{2}, {0, 0}); + auto end = opset1::Constant::create(element::i64, Shape{2}, {5, 5}); + auto stride = opset1::Constant::create(element::i64, Shape{2}, {1, 1}); + auto axis = opset1::Constant::create(element::i64, Shape{2}, {1, 3}); + + auto slice = std::make_shared(relu, begin, end, stride, axis); + + model = std::make_shared(slice, ParameterVector{data}); + manager.register_pass(); + } + { + auto data = std::make_shared(element::f32, Shape{5, 5, 5, 5}); + auto relu = std::make_shared(data); + model_ref = std::make_shared(relu, ParameterVector{data}); + } +} + +TEST_F(TransformationTestsF, NegativeUselessSliceWithNegativeStrides) { + { + auto data = std::make_shared(element::f32, Shape{5, 5, 5, 5}); + auto relu = std::make_shared(data); + auto begin = opset1::Constant::create(element::i64, Shape{2}, {4, 0}); + auto end = opset1::Constant::create(element::i64, Shape{2}, {INT32_MIN, 5}); + auto stride = opset1::Constant::create(element::i64, Shape{2}, {-1, 1}); + auto axis = opset1::Constant::create(element::i64, Shape{2}, {1, 3}); + + auto slice = std::make_shared(relu, begin, end, stride, axis); + + model = std::make_shared(slice, ParameterVector{data}); + manager.register_pass(); + } +} + TEST_F(TransformationTestsF, OptimizeSS_Usefull_Test) { { auto data = std::make_shared(element::f32, Shape{5, 5, 5, 5});