[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:
parent
0897bec40d
commit
6eac9dca0e
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue