[GPU] Fix stable diffusion failure (#16052)

* [dGPU] Enable stable diffusion

+ Prevent to fuse swish into oneDNN reorder.
+ Makes concat explicitly if batch size is greater than 1 and the siblings are oneDNN impl.
This commit is contained in:
Jade Cho authored and GitHub committed 2023-03-09 14:35:31 +09:00
1 parent b7ff3a1d64
commit aaeace9740
3 files changed
+169

No files matched your search

@@ -198,6 +198,16 @@ bool concat_in_place_optimization::match(concatenation_node& node) {
if (input.first->get_users().size() > 2)
return false;
// If sibling is using onednn impl and batch > 1, the onednn impl cannot process the implicit concat'ed buffer.
// Onednn impls can process implicit concat'ed buffer only through buffer pointer manipulation.
if (node.get_output_layout().batch() > 1) {
for (auto& sib : input.first->get_users()) {
if (sib->get_preferred_impl_type() == impl_types::onednn) {
return false;
}
}
}
// Check that input isn't optimized out concatenation along different axis.
if (input.first->is_type<concatenation>() && input.first->can_be_optimized() &&
input.first->as<concatenation>().get_primitive()->axis != concat_axis)
@@ -791,6 +791,11 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
if (!should_fuse)
return;
// Onednn reorder does not support eltwise nor binary post operation
if (_lo.get_optimization_attributes().use_onednn_impls && input.is_type<reorder>()) {
return;
}
p.fuse_nodes(input, activation_node, &fusing_history);
};
@@ -1285,4 +1285,158 @@ INSTANTIATE_TEST_SUITE_P(smoke,
TestParamType_concat(1, { 8, 32 }, 2, 2, false)
),
concat_gpu::PrintToStringParamName);
template <typename Type>
struct concat_gpu_4d_explict : public concat_gpu {
public:
cldnn::memory::ptr run_concat_network(std::vector<std::vector<std::vector<std::vector<std::vector<Type>>>>> input, format::type fmt, ExecutionConfig config) {
auto data_type = type_to_data_type<Type>::value;
auto& engine = get_test_engine();
const size_t batch_num = testing::get<0>(GetParam());
const std::vector<size_t> in_features = testing::get<1>(GetParam()); // only use first element.
const size_t input_y = testing::get<2>(GetParam());
const size_t input_x = testing::get<3>(GetParam());
size_t output_f = in_features[0];
topology topology;
std::vector<memory::ptr> in_memory;
std::vector<primitive_id> input_ids;
// input0 --- eltwise1 --- concat --- reorder
// / /
// input1 -- /
// /
// input2 --- eltwise2 -------------- conv
// /
// input3 --
for (size_t i = 0; i < 4; i++) {
auto size = tensor(static_cast<int32_t>(batch_num),
static_cast<int32_t>(output_f),
static_cast<int32_t>(input_x),
static_cast<int32_t>(input_y));
auto data = input[i];
auto in_lay = layout(data_type, format::bfyx, size);
auto data_flat = std::vector<Type>(in_lay.get_linear_size(), 0);
for (size_t bi = 0; bi < batch_num; ++bi) {
for (size_t fi = 0; fi < output_f; ++fi) {
for (size_t yi = 0; yi < input_y; ++yi) {
for (size_t xi = 0; xi < input_x; ++xi) {
auto coords = tensor(batch(bi), feature(fi), spatial(xi, yi, 0, 0));
auto in_offset = in_lay.get_linear_offset(coords);
data_flat[in_offset] = data[bi][fi][yi][xi];
}
}
}
}
auto in_mem = engine.allocate_memory(in_lay);
set_values(in_mem, data_flat);
in_memory.push_back(in_mem);
topology.add(input_layout("input" + std::to_string(i), in_lay));
input_ids.push_back("input" + std::to_string(i));
}
topology.add(eltwise("eltwise1", {input_info(input_ids[0]), input_info(input_ids[1])}, eltwise_mode::sum));
topology.add(eltwise("eltwise2", {input_info(input_ids[2]), input_info(input_ids[3])}, eltwise_mode::sum));
auto weights_lay = cldnn::layout(data_type, cldnn::format::bfyx, tensor(batch(output_f), feature(output_f)));
auto weights_mem = engine.allocate_memory(weights_lay);
auto& stream = get_test_stream();
weights_mem->fill(stream);
stream.finish();
{
cldnn::mem_lock<Type> weights_ptr(weights_mem, stream);
for (size_t fi = 0; fi < output_f; ++fi) {
auto coords = tensor(batch(fi), feature(fi), spatial(0, 0, 0, 0));
auto offset = weights_lay.get_linear_offset(coords);
weights_ptr[offset] = static_cast<Type>(1.f);
}
}
topology.add(data("weights" , weights_mem));
topology.add(convolution("conv", input_info("eltwise2"), { "weights" }));
topology.add(concatenation("concat", {input_info("eltwise1"), input_info("eltwise2")}, 1));
topology.add(reorder("reorder", input_info("concat"), layout(data_types::f32, format::bfyx, {(int32_t)batch_num, (int32_t)(output_f * 2), (int32_t)input_y, (int32_t)input_x})));
network concat_network(engine, topology, config);
for (size_t i = 0; i < 4; i++) {
concat_network.set_input_data(input_ids[i], in_memory[i]);
}
concat_network.execute();
bool concat_opt_enabled = config.get_property(ov::intel_gpu::optimize_data);
bool concat_opt_result = std::static_pointer_cast<concatenation_inst>(concat_network.get_primitive("concat"))->node->can_be_optimized();
// If sibling is using onednn impl and batch > 1, the onednn impl cannot process the implicit concat'ed buffer.
// Onednn impls can process implicit concat'ed buffer only through buffer pointer manipulation.
if (concat_opt_enabled && batch_num > 1) concat_opt_result = !concat_opt_result;
EXPECT_EQ(concat_opt_enabled, concat_opt_result);
return concat_network.get_output("reorder").get_memory();
}
std::vector<std::vector<std::vector<std::vector<std::vector<Type>>>>> generate_input() {
const size_t batch_num = testing::get<0>(GetParam());
const std::vector<size_t> in_features = testing::get<1>(GetParam());
const size_t input_y = testing::get<2>(GetParam());
const size_t input_x = testing::get<3>(GetParam());
std::vector<std::vector<std::vector<std::vector<std::vector<Type>>>>> inputs(4);
for (size_t i = 0; i < 4; ++i) {
inputs[i] = generate_random_4d<Type>(batch_num, in_features[0], input_y, input_x, -1, 1);
}
return inputs;
}
void test(format::type fmt) {
auto& engine = get_test_engine();
auto& stream = get_test_stream();
if (!engine.get_device_info().supports_immad) {
// This case is only for device that uses onednn.
return;
}
auto input = generate_input();
// implicit concat when batch size is 1.
ExecutionConfig config1;
config1.set_property(ov::intel_gpu::optimize_data(true));
ov::intel_gpu::ImplementationDesc impl = { fmt, std::string(""), impl_types::onednn };
config1.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{{"conv", impl}}));
config1.set_property(ov::intel_gpu::queue_type(QueueTypes::in_order));
auto out_mem1 = run_concat_network(input, fmt, config1);
cldnn::mem_lock<Type> out_ptr1(out_mem1, stream);
// explicit concat
ExecutionConfig config2;
config2.set_property(ov::intel_gpu::optimize_data(false));
config2.set_property(ov::intel_gpu::queue_type(QueueTypes::in_order));
auto out_mem2 = run_concat_network(input, fmt, config2);
cldnn::mem_lock<Type> out_ptr2(out_mem2, stream);
ASSERT_EQ(out_ptr1.size(), out_ptr2.size());
size_t diff_count = 0;
for (size_t i = 0; i < out_ptr1.size(); ++i) {
if (out_ptr1[i] != out_ptr2[i]) diff_count++;
}
ASSERT_EQ(diff_count, 0);
}
};
using concat_no_implicit_gpu_onednn_4d_f16 = concat_gpu_4d_explict<FLOAT16>;
TEST_P(concat_no_implicit_gpu_onednn_4d_f16, input_order_opt_b_fs_yx_fsv16) {
ASSERT_NO_FATAL_FAILURE(test(format::b_fs_yx_fsv16));
}
INSTANTIATE_TEST_SUITE_P(smoke,
concat_no_implicit_gpu_onednn_4d_f16,
::testing::Values(
TestParamType_concat(1, { 16 }, 2, 2, false),
TestParamType_concat(2, { 16 }, 2, 2, false)
),
concat_gpu::PrintToStringParamName);
#endif