diff --git a/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_buffer_fusing.cpp b/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_buffer_fusing.cpp index ae6531a93d8..8bab7e44dca 100644 --- a/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_buffer_fusing.cpp +++ b/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_buffer_fusing.cpp @@ -366,6 +366,12 @@ static bool can_reshape_be_optimized(const reshape_node& node) { static bool is_optimizable_padding_for_crop(const crop_node& node) { const auto& crop_layout = node.get_output_layout(); auto input_layout = node.get_dependency(0).get_output_layout(); + + if (input_layout.data_padding.lower_size().batch[0] != 0 || input_layout.data_padding.upper_size().batch[0] != 0 || + input_layout.data_padding.lower_size().spatial[0] != 0 || input_layout.data_padding.upper_size().spatial[0] != 0 || + input_layout.data_padding.lower_size().spatial[1] != 0 || input_layout.data_padding.upper_size().spatial[1] != 0) + return false; + auto crop_prim = node.get_primitive(); auto opt_lower_pad = crop_prim->offsets.feature[0]; auto opt_upper_pad = input_layout.feature() - crop_prim->offsets.feature[0] - crop_layout.get_tensor().feature[0]; @@ -377,11 +383,6 @@ static bool is_optimizable_padding_for_crop(const crop_node& node) { (opt_lower_pad % 16 != 0 || opt_upper_pad % 16 != 0)) return false; - if (input_layout.data_padding.lower_size().batch[0] != 0 || input_layout.data_padding.upper_size().batch[0] != 0 || - input_layout.data_padding.lower_size().spatial[0] != 0 || input_layout.data_padding.upper_size().spatial[0] != 0 || - input_layout.data_padding.lower_size().spatial[1] != 0 || input_layout.data_padding.upper_size().spatial[1] != 0) - return false; - // oneDNN doesn't support paddings if (usr->get_preferred_impl_type() == impl_types::onednn) return false; @@ -410,19 +411,14 @@ static bool can_crop_be_optimized_along_feature(const crop_node& node) { return false; } -static bool can_crop_be_optimized_along_batch(const crop_node& node) { +static bool can_crop_be_optimized_simple_data_format(const crop_node& node) { const auto& crop_layout = node.get_output_layout(); auto format = crop_layout.format; auto input_layout = node.get_dependency(0).get_output_layout(); - const auto crop_shape = crop_layout.get_ordered_dims(); - const auto input_shape = input_layout.get_ordered_dims(); const auto& in_padding = input_layout.data_padding; const auto& out_padding = crop_layout.data_padding; - // Check format's order is 'bxxx' and only batch size is different - if (format::is_simple_data_format(format) && format.dims_order()[0] == 0 && - std::equal(input_shape.begin()+1, input_shape.end(), crop_shape.begin()+1) && - !out_padding && !in_padding) { + if (format::is_simple_data_format(format) && !out_padding && !in_padding) { return true; } @@ -491,7 +487,6 @@ void prepare_buffer_fusing::run(program& p) { auto& node = (*node_itr++); if (!node->is_valid_output_layout()) continue; - if (!can_optimize(node)) continue; @@ -581,37 +576,23 @@ void prepare_buffer_fusing::run(program& p) { opt_upper_pad, out_pad.upper_size().spatial[0], out_pad.upper_size().spatial[1]})); - } else if (can_crop_be_optimized_along_batch(node)) { + } else if (can_crop_be_optimized_simple_data_format(node)) { auto crop_prim = node.get_primitive(); - auto opt_lower_pad = crop_prim->offsets.batch[0]; - auto opt_upper_pad = input_layout.batch() - crop_prim->offsets.batch[0] - crop_size.batch[0]; - padding new_padding; - if (crop_layout.get_rank() == 4) { - new_padding = padding({opt_lower_pad, - out_pad.lower_size().feature[0], - out_pad.lower_size().spatial[0], - out_pad.lower_size().spatial[1]}, - {opt_upper_pad, - out_pad.upper_size().feature[0], - out_pad.upper_size().spatial[0], - out_pad.upper_size().spatial[1]}); - } else if (crop_layout.get_rank() == 5) { - new_padding = padding({opt_lower_pad, - out_pad.lower_size().feature[0], - out_pad.lower_size().spatial[0], - out_pad.lower_size().spatial[1], - out_pad.lower_size().spatial[2]}, - {opt_upper_pad, - out_pad.upper_size().feature[0], - out_pad.upper_size().spatial[0], - out_pad.upper_size().spatial[1], - out_pad.upper_size().spatial[2]}); - } else { - return; + std::vector lower_sizes; + lower_sizes.push_back(crop_prim->offsets.batch[0]); + lower_sizes.push_back(crop_prim->offsets.feature[0]); + for (size_t i = 0; i < input_layout.get_spatial_rank(); i++) { + lower_sizes.push_back(crop_prim->offsets.spatial[i]); + } + std::vector upper_sizes; + upper_sizes.push_back(input_layout.batch() - crop_prim->offsets.batch[0] - crop_size.batch[0]); + upper_sizes.push_back(input_layout.feature() - crop_prim->offsets.feature[0] - crop_size.feature[0]); + for (size_t i = 0; i < input_layout.get_spatial_rank(); i++) { + upper_sizes.push_back(input_layout.spatial(i) - crop_prim->offsets.spatial[i] - crop_size.spatial[i]); } - node.set_output_padding(new_padding); + node.set_output_padding(padding(lower_sizes, upper_sizes)); } else { return; } diff --git a/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_primitive_fusing.cpp b/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_primitive_fusing.cpp index 77139ab73f5..47c8ec2cc82 100644 --- a/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_primitive_fusing.cpp +++ b/src/plugins/intel_gpu/src/graph/graph_optimizer/prepare_primitive_fusing.cpp @@ -563,11 +563,25 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) { }; auto eltwise_supports_fusings = [&](eltwise_node& node) -> bool { + auto has_reorder_behind_mvn = [&]() -> bool { + // MVN with rank size 3 always requires Reorder and Reshape. This pattern always run simple formats(bfyx..). + if (node.get_dependencies().size() > 0 && node.get_dependency(0).is_type()) { + auto& reshape_node = node.get_dependency(0); + if (reshape_node.get_dependencies().size() > 0 && reshape_node.get_dependency(0).is_type()) { + auto& reorder_node = reshape_node.get_dependency(0); + if (reorder_node.get_dependencies().size() > 0 && reorder_node.get_dependency(0).is_type()) { + return true; + } + } + } + return false; + }; + auto out_layout = node.get_output_layout(); // Do not fuse if the estimated format is fs_b_yx_fsv32 because the optimized kernel does not support fusion if (out_layout.data_type == data_types::f16 && out_layout.is_static() && out_layout.batch() > 1 && ((_lo.get_optimization_attributes().fs_b_yx_fsv32_network && - !_lo.get_optimization_attributes().use_onednn_impls) || + !_lo.get_optimization_attributes().use_onednn_impls && !has_reorder_behind_mvn()) || out_layout.format == format::fs_b_yx_fsv32)) { return false; } diff --git a/src/plugins/intel_gpu/tests/unit/test_cases/crop_gpu_test.cpp b/src/plugins/intel_gpu/tests/unit/test_cases/crop_gpu_test.cpp index c6bb3543a9a..849a4ec7796 100644 --- a/src/plugins/intel_gpu/tests/unit/test_cases/crop_gpu_test.cpp +++ b/src/plugins/intel_gpu/tests/unit/test_cases/crop_gpu_test.cpp @@ -1623,6 +1623,81 @@ TEST(crop_single_axis, simple_Baxis) { ASSERT_EQ(crop_prim->can_be_optimized(), true); } +TEST(crop_single_axis, simple_Xaxis) { + auto& engine = get_test_engine(); + + auto input0 = engine.allocate_memory({ data_types::f32, format::bfyx, tensor{ 3, 2, 3, 1 } }); + + set_values(input0, { + 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, + 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, + 13.f, 14.f, 15.f, 16.f, 17.f, 18.f, + }); + + topology topology; + topology.add(input_layout("Input", input0->get_layout())); + topology.add(crop("crop", input_info("Input"), tensor{3, 2, 1, 1}, tensor(0, 0, 1, 0))); + topology.add(reorder("reorder", input_info("crop"), format::bfyx, data_types::i32)); + + ExecutionConfig config = get_test_default_config(engine); + config.set_property(ov::intel_gpu::optimize_data(true)); + network network(engine, topology, config); + + network.set_input_data("Input", input0); + + auto outputs = network.execute(); + auto output = outputs.at("reorder").get_memory(); + cldnn::mem_lock output_ptr(output, get_test_stream()); + + std::vector expected_results = { + 2, 5, 8, 11, 14, 17, + }; + + for (size_t i = 0; i < expected_results.size(); i++) { + ASSERT_EQ(output_ptr[i], expected_results[i]); + } + + auto crop_prim = network.get_primitive("crop"); + ASSERT_EQ(crop_prim->can_be_optimized(), true); +} + +TEST(crop_single_axis, simple_all_axis) { + auto& engine = get_test_engine(); + + auto input0 = engine.allocate_memory({ data_types::f32, format::bfyx, tensor{ 3, 3, 3, 3 } }); + + std::vector input0_vals; + for (uint32_t i = 0; i < 81; ++i) + input0_vals.push_back(i); + + set_values(input0, input0_vals); + + topology topology; + topology.add(input_layout("Input", input0->get_layout())); + topology.add(crop("crop", input_info("Input"), tensor{1, 1, 1, 1}, tensor(1, 1, 1, 1))); + topology.add(reorder("reorder", input_info("crop"), format::bfyx, data_types::i32)); + + ExecutionConfig config = get_test_default_config(engine); + config.set_property(ov::intel_gpu::optimize_data(true)); + network network(engine, topology, config); + + network.set_input_data("Input", input0); + + auto outputs = network.execute(); + auto output = outputs.at("reorder").get_memory(); + cldnn::mem_lock output_ptr(output, get_test_stream()); + + std::vector expected_results = { + 40, + }; + + for (size_t i = 0; i < expected_results.size(); i++) { + ASSERT_EQ(output_ptr[i], expected_results[i]); + } + + auto crop_prim = network.get_primitive("crop"); + ASSERT_EQ(crop_prim->can_be_optimized(), true); +} struct crop_input_test_params { data_types input_type;