[GPU] Support implicit crop in simple format. (#24280)

_For Stable Diffusion Unet performance improvement,_
- _Support implicit crop for all axis in simple format_
- _Enable Eltwise fusion in fs_byx_fsv32 format for special
pattern.(Actually Eltwise run simple format)_

### Tickets:
 - *137950*

---------

Signed-off-by: hyunback <hyunback.kim@intel.com>
This commit is contained in:
hyunback kim 2024-05-10 09:01:26 +09:00 committed by GitHub
parent 0897bec40d
commit 6eac9dca0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 111 additions and 41 deletions

View File

@ -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<int32_t> 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<int32_t> 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;
}

View File

@ -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<reshape>()) {
auto& reshape_node = node.get_dependency(0);
if (reshape_node.get_dependencies().size() > 0 && reshape_node.get_dependency(0).is_type<reorder>()) {
auto& reorder_node = reshape_node.get_dependency(0);
if (reorder_node.get_dependencies().size() > 0 && reorder_node.get_dependency(0).is_type<mvn>()) {
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;
}

View File

@ -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<int> output_ptr(output, get_test_stream());
std::vector<int> 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<float> 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<int> output_ptr(output, get_test_stream());
std::vector<int> 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;