Skip to content

Commit 14a64df

Browse files
committed
code style, test refator, comments
1 parent adc5479 commit 14a64df

6 files changed

Lines changed: 145 additions & 104 deletions

File tree

src/common/transformations/include/transformations/common_optimizations/strided_slice_reshape_concat_fusion.hpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,39 @@ class TRANSFORMATIONS_API StridedSliceReshapeConcatFusion;
1717

1818
/**
1919
* @ingroup ov_transformation_common_api
20-
* @brief StridedSliceReshapeConcatFusion matches framing-like pattern built from
21-
* Slice/StridedSlice + Reshape + Concat and replaces it with a single Gather.
20+
* @brief Detects and fuses framing-like subgraphs made of Slice/StridedSlice + Reshape + Concat.
21+
*
22+
* This matcher pass identifies branches that extract windows from the same 2D input tensor,
23+
* reshapes each window from [B, W] to [B, 1, W], and concatenates them along axis=1.
24+
* The pass replaces the whole pattern with a single Gather.
25+
*
26+
* ## Before (for illustration purpose)
27+
*
28+
* Input [B, N]
29+
* |
30+
* +---------------+---------------+
31+
* | | |
32+
* StridedSlice/Slice StridedSlice/Slice ...
33+
* [B, W] [B, W]
34+
* | |
35+
* Reshape [B,1,W] Reshape [B,1,W]
36+
* | |
37+
* +------- Concat(axis=1) -------+
38+
* |
39+
* Output [B, K, W]
40+
*
41+
* ## After
42+
*
43+
* Input [B, N]
44+
* |
45+
* Gather(axis=1, indices[K,W])
46+
* |
47+
* Output [B, K, W]
48+
*
49+
* ## Notes
50+
* - All branches must read from the same source tensor.
51+
* - Branch window sizes must be equal (same W).
52+
* - This pass covers both Slice and StridedSlice forms under supported constraints.
2253
*/
2354
class ov::pass::StridedSliceReshapeConcatFusion : public ov::pass::MatcherPass {
2455
public:

src/common/transformations/src/transformations/common_optimizations/strided_slice_reshape_concat_fusion.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,16 @@ bool parse_slice_window(const std::shared_ptr<ov::Node>& node, int64_t& start, i
5858
if (const auto strided_slice = ov::as_type_ptr<op::v1::StridedSlice>(node)) {
5959
data = strided_slice->input_value(0);
6060
const auto pshape = data.get_partial_shape();
61-
if (pshape.rank().is_dynamic() || pshape.rank().get_length() != 2 || pshape[0].is_dynamic() || pshape[1].is_dynamic()) {
61+
if (pshape.rank().is_dynamic() || pshape.rank().get_length() != 2 || pshape[0].is_dynamic() ||
62+
pshape[1].is_dynamic()) {
6263
return false;
6364
}
6465

6566
std::vector<int64_t> begin;
6667
std::vector<int64_t> end;
6768
std::vector<int64_t> strides;
68-
if (!get_vector_i64(strided_slice->input_value(1), begin) || !get_vector_i64(strided_slice->input_value(2), end) ||
69+
if (!get_vector_i64(strided_slice->input_value(1), begin) ||
70+
!get_vector_i64(strided_slice->input_value(2), end) ||
6971
!get_vector_i64(strided_slice->input_value(3), strides)) {
7072
return false;
7173
}

src/common/transformations/tests/common_optimizations/strided_slice_reshape_concat_fusion_test.cpp

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
#include <gtest/gtest.h>
88

9-
#include "common_test_utils/ov_test_utils.hpp"
109
#include "common_test_utils/ov_tensor_utils.hpp"
10+
#include "common_test_utils/ov_test_utils.hpp"
1111
#include "openvino/op/concat.hpp"
1212
#include "openvino/op/gather.hpp"
1313
#include "openvino/op/reshape.hpp"
@@ -27,13 +27,12 @@ TEST_F(StridedSliceReshapeConcatFusionTest, Positive) {
2727
auto begin = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {0, start});
2828
auto end = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, start + 4});
2929
auto strides = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{2}, {1, 1});
30-
auto strided_slice =
31-
std::make_shared<ov::op::v1::StridedSlice>(input,
32-
begin,
33-
end,
34-
strides,
35-
std::vector<int64_t>{0, 0},
36-
std::vector<int64_t>{0, 0});
30+
auto strided_slice = std::make_shared<ov::op::v1::StridedSlice>(input,
31+
begin,
32+
end,
33+
strides,
34+
std::vector<int64_t>{0, 0},
35+
std::vector<int64_t>{0, 0});
3736
auto shape = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{3}, {1, 1, 4});
3837
auto reshape = std::make_shared<ov::op::v1::Reshape>(strided_slice, shape, false);
3938
concat_inputs.push_back(reshape);
@@ -47,8 +46,8 @@ TEST_F(StridedSliceReshapeConcatFusionTest, Positive) {
4746
{
4847
auto input = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::Shape{1, 16});
4948
auto indices = ov::op::v0::Constant::create<int64_t>(ov::element::i64,
50-
ov::Shape{3, 4},
51-
{0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7});
49+
ov::Shape{3, 4},
50+
{0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7});
5251
auto axis = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{}, {1});
5352
auto gather = std::make_shared<ov::op::v8::Gather>(input, indices, axis, 0);
5453
model_ref = std::make_shared<ov::Model>(ov::OutputVector{gather}, ov::ParameterVector{input});
@@ -66,11 +65,11 @@ TEST_F(StridedSliceReshapeConcatFusionTest, NegativeUnequalSliceLength) {
6665
auto end = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, stop});
6766
auto strides = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{2}, {1, 1});
6867
auto strided_slice = std::make_shared<ov::op::v1::StridedSlice>(input,
69-
begin,
70-
end,
71-
strides,
72-
std::vector<int64_t>{0, 0},
73-
std::vector<int64_t>{0, 0});
68+
begin,
69+
end,
70+
strides,
71+
std::vector<int64_t>{0, 0},
72+
std::vector<int64_t>{0, 0});
7473
auto shape = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{3}, {1, 1, stop - start});
7574
auto reshape = std::make_shared<ov::op::v1::Reshape>(strided_slice, shape, false);
7675
concat_inputs.push_back(reshape);
@@ -93,13 +92,12 @@ TEST(StridedSliceReshapeConcatFusionInferTest, NumericalEquivalence) {
9392
auto begin = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {0, start});
9493
auto end = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, start + 4});
9594
auto strides = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, 1});
96-
auto strided_slice =
97-
std::make_shared<ov::op::v1::StridedSlice>(input,
98-
begin,
99-
end,
100-
strides,
101-
std::vector<int64_t>{0, 0},
102-
std::vector<int64_t>{0, 0});
95+
auto strided_slice = std::make_shared<ov::op::v1::StridedSlice>(input,
96+
begin,
97+
end,
98+
strides,
99+
std::vector<int64_t>{0, 0},
100+
std::vector<int64_t>{0, 0});
103101
auto shape = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{3}, {1, 1, 4});
104102
auto reshape = std::make_shared<ov::op::v1::Reshape>(strided_slice, shape, false);
105103
concat_inputs.push_back(reshape);
@@ -129,4 +127,3 @@ TEST(StridedSliceReshapeConcatFusionInferTest, NumericalEquivalence) {
129127
ASSERT_EQ(outputs_before.size(), 1);
130128
ov::test::utils::compare(outputs_before[0], outputs_after[0], 0.0, 0.0);
131129
}
132-

src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
#include "transformations/common_optimizations/reshape_prelu.hpp"
7676
#include "transformations/common_optimizations/sdpa_fusion.hpp"
7777
#include "transformations/common_optimizations/shared_ops_optimization.hpp"
78-
#include "transformations/common_optimizations/strided_slice_reshape_concat_fusion.hpp"
7978
#include "transformations/common_optimizations/transpose_sinking.hpp"
8079
#include "transformations/common_optimizations/weights_dequantize_to_fake_quantize.hpp"
8180
#include "transformations/common_optimizations/wrap_interpolate_into_transposes.hpp"
@@ -205,6 +204,7 @@
205204
# include "snippets/lowered/pass/mha_parallel_wa_optimizer.hpp"
206205
# include "snippets/pass/common_optimizations.hpp"
207206
# include "transformations/common_optimizations/rms_fusion.hpp"
207+
# include "transformations/common_optimizations/strided_slice_reshape_concat_fusion.hpp"
208208
# include "transformations/cpu_opset/common/op/sdpa.hpp"
209209
# include "transformations/cpu_opset/common/pass/causal_mask_preprocess_fusion.hpp"
210210
# include "transformations/cpu_opset/common/pass/convert_fq_rnn_to_quantized_rnn.hpp"

src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/strided_slice_reshape_concat_fusion.cpp

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (C) 2018-2026 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "functional_test_utils/skip_tests_config.hpp"
6+
#include "openvino/op/concat.hpp"
7+
#include "openvino/op/reshape.hpp"
8+
#include "openvino/op/strided_slice.hpp"
9+
#include "shared_test_classes/base/ov_subgraph.hpp"
10+
#include "utils/cpu_test_utils.hpp"
11+
12+
using namespace CPUTestUtils;
13+
14+
namespace ov {
15+
namespace test {
16+
17+
using StridedSliceReshapeConcatFusionParams = std::tuple<InputShape>;
18+
19+
class StridedSliceReshapeConcatFusionCPUTest
20+
: public testing::WithParamInterface<StridedSliceReshapeConcatFusionParams>,
21+
virtual public SubgraphBaseTest,
22+
public CPUTestsBase {
23+
public:
24+
static std::string getTestCaseName(const testing::TestParamInfo<StridedSliceReshapeConcatFusionParams>& obj) {
25+
const auto& [inputShape] = obj.param;
26+
std::ostringstream result;
27+
result << "IS=" << ov::test::utils::partialShape2str({inputShape.first}) << "_TS=";
28+
for (const auto& shape : inputShape.second) {
29+
result << ov::test::utils::vec2str(shape);
30+
}
31+
return result.str();
32+
}
33+
34+
void SetUp() override {
35+
targetDevice = ov::test::utils::DEVICE_CPU;
36+
37+
const auto& [inputShape] = GetParam();
38+
init_input_shapes({inputShape});
39+
40+
auto input = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, inputDynamicShapes[0]);
41+
ov::OutputVector concat_inputs;
42+
43+
for (const int64_t start : {0, 2, 4}) {
44+
auto begin = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {0, start});
45+
auto end = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, start + 4});
46+
auto strides = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{2}, {1, 1});
47+
auto strided_slice = std::make_shared<ov::op::v1::StridedSlice>(input,
48+
begin,
49+
end,
50+
strides,
51+
std::vector<int64_t>{0, 0},
52+
std::vector<int64_t>{0, 0});
53+
auto shape = ov::op::v0::Constant::create<int64_t>(ov::element::i64, ov::Shape{3}, {1, 1, 4});
54+
auto reshape = std::make_shared<ov::op::v1::Reshape>(strided_slice, shape, false);
55+
concat_inputs.push_back(reshape);
56+
}
57+
58+
auto concat = std::make_shared<ov::op::v0::Concat>(concat_inputs, 1);
59+
function = std::make_shared<ov::Model>(ov::OutputVector{concat}, ov::ParameterVector{input});
60+
}
61+
62+
void check_results() {
63+
CheckNumberOfNodesWithType(compiledModel, "Gather", 1);
64+
}
65+
};
66+
67+
TEST_P(StridedSliceReshapeConcatFusionCPUTest, CompareWithRefs) {
68+
SKIP_IF_CURRENT_TEST_IS_DISABLED();
69+
run();
70+
check_results();
71+
}
72+
73+
namespace {
74+
75+
const std::vector<InputShape> input_shapes = {
76+
{{1, 16}, {{1, 16}}},
77+
};
78+
79+
INSTANTIATE_TEST_SUITE_P(smoke_StridedSliceReshapeConcatFusion,
80+
StridedSliceReshapeConcatFusionCPUTest,
81+
::testing::Combine(::testing::ValuesIn(input_shapes)),
82+
StridedSliceReshapeConcatFusionCPUTest::getTestCaseName);
83+
84+
} // namespace
85+
86+
} // namespace test
87+
} // namespace ov

0 commit comments

Comments
 (0)