diff --git a/src/plugins/intel_gpu/src/graph/include/reshape_inst.h b/src/plugins/intel_gpu/src/graph/include/reshape_inst.h index a1f7b0fedb62..3747e2d73d4b 100644 --- a/src/plugins/intel_gpu/src/graph/include/reshape_inst.h +++ b/src/plugins/intel_gpu/src/graph/include/reshape_inst.h @@ -79,6 +79,7 @@ struct typed_program_node : public typed_program_node_base { axis == 1 && !input_pshape[1].is_dynamic() && input_pshape[1].get_length() == 1 && + prim->output_partial_shape.size() >= 2 && prim->output_partial_shape.size() + 1 == input_pshape.size(); if (!is_axis1_size1_squeeze) return false; @@ -134,8 +135,15 @@ struct typed_program_node : public typed_program_node_base { // shape tensor (not a compile-time constant) for the Reshape second input, // leaving output_pattern empty — requiring it would incorrectly block this // case even though conditions 1–3 are fully sufficient. + // Only the TransposeSplitMatcher pattern is safe: crop [batch, 1, H, S] → reshape + // drops the size-1 dim → [batch, H, S]. The output must stay ≥ 2D so that the + // downstream CM/OCL kernel still has at least one inner stride to carry the offset. + // A 2D → 1D squeeze (e.g. NMS bbox-coord split [-1, 4] → [-1, 1] → [-1]) does NOT + // meet this condition and must not be optimized — its downstream arithmetic kernels + // are compiled without dynamic-padding support. if (axis == 1 && !input_pshape[1].is_dynamic() && input_pshape[1].get_length() == 1) { - if (prim->output_partial_shape.size() + 1 == input_pshape.size()) { + if (prim->output_partial_shape.size() >= 2 && + prim->output_partial_shape.size() + 1 == input_pshape.size()) { return true; } } diff --git a/src/plugins/intel_gpu/src/plugin/transformations/transpose_fusion.cpp b/src/plugins/intel_gpu/src/plugin/transformations/transpose_fusion.cpp index 29f7dd436f30..7dd6774b0edc 100644 --- a/src/plugins/intel_gpu/src/plugin/transformations/transpose_fusion.cpp +++ b/src/plugins/intel_gpu/src/plugin/transformations/transpose_fusion.cpp @@ -586,8 +586,8 @@ TransposeSplitMatcher::TransposeSplitMatcher() { // This produces 3 outputs of shape [-1, 1, H, S] instead of [1, -1, H, S] auto new_split_axis = ov::op::v0::Constant::create(ov::element::i64, ov::Shape{}, {1}); auto new_split = std::make_shared(input_node, new_split_axis, split->get_num_splits()); - ov::copy_runtime_info(m.get_matched_nodes(), new_split); - ov::replace_node(split, new_split); + ov::copy_runtime_info(m.get_matched_nodes(), new_split); + ov::replace_node(split, new_split); return true; }; diff --git a/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp b/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp index 8961df18480f..65cb7481ebe4 100644 --- a/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp +++ b/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp @@ -1014,6 +1014,52 @@ TEST(prepare_buffer_fusing, do_runtime_in_place_crop_skips_non_propagatable_resh ASSERT_FALSE(crop_inst->can_be_optimized()); } +TEST(prepare_buffer_fusing, in_place_crop_axis1_rank_reducing_to_1d_not_optimized) { + auto& engine = get_test_engine(); + + constexpr int64_t rows = 8; + const auto input_layout_dynamic = layout{ov::PartialShape{-1, 4}, data_types::f32, format::bfyx}; + auto input_memory = engine.allocate_memory({{rows, 4}, data_types::f32, format::bfyx}); + auto axis_memory = engine.allocate_memory({{}, data_types::i64, format::bfyx}); + auto split_lengths_memory = engine.allocate_memory({{4}, data_types::i64, format::bfyx}); + auto scale_memory = engine.allocate_memory({{1}, data_types::f32, format::bfyx}); + + set_values(input_memory, std::vector(rows * 4, 1.0f)); + set_values(axis_memory, {1}); + set_values(split_lengths_memory, {1, 1, 1, 1}); + set_values(scale_memory, {1.0f}); + + topology topology( + input_layout("input", input_layout_dynamic), + data("axis", axis_memory), + data("split_lengths", split_lengths_memory), + data("scale", scale_memory), + crop("bbox_coordinate", {input_info("input"), input_info("axis"), input_info("split_lengths")}, + tensor(1), + tensor(0), + crop_ngraph_op_mode::variadic_split, + 0, + 1), + reshape("bbox_coordinate_1d", + input_info("bbox_coordinate"), + false, + {-1}, + ov::PartialShape{-1}, + reshape::reshape_mode::base), + eltwise("bbox_coordinate_scale", {input_info("bbox_coordinate_1d"), input_info("scale")}, eltwise_mode::prod), + reorder("output", input_info("bbox_coordinate_scale"), format::bfyx, data_types::f32)); + + ExecutionConfig config = get_test_default_config(engine); + config.set_property(ov::intel_gpu::allow_new_shape_infer(true)); + config.set_property(ov::intel_gpu::optimize_data(true)); + + network network(engine, topology, config); + network.set_input_data("input", input_memory); + network.execute(); + + ASSERT_FALSE(network.get_primitive("bbox_coordinate")->can_be_optimized()); +} + TEST(prepare_buffer_fusing, in_place_crop_dynamic_reshape_unsqueeze) { auto& engine = get_test_engine();