Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
const kernel_impl_params* impl_params = reinterpret_cast<kernel_impl_params*>(ib.getKernelImplParams());
auto prim = impl_params->typed_desc<fully_connected>();
const auto weight_rank = get_compressed_weights_rank(impl_params->get_input_layout(1));
const bool has_batch_dim = weight_rank > 2;

auto shift_size = std::max<size_t>(prim->input_size - 2, 0);
const auto& arg = impl_params->get_program().get_node(impl_params->desc->id).as<fully_connected>();
Expand All @@ -286,7 +287,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
const auto ngroups = scale_layout.get_dim(get_ifm_dim_idx(scale_layout, transpose_b_scale, weight_rank));
if (scale_layout.count() == 1) {
_attrs->set_scales(DNNL_ARG_WEIGHTS, COMMON, dnnl::memory::dims{}, _ds_data_type);
} else if (ngroups == 1) {
} else if (ngroups == 1 && !has_batch_dim) {
_attrs->set_scales(DNNL_ARG_WEIGHTS, per_oc, dnnl::memory::dims{}, _ds_data_type);
} else {
_attrs->set_scales(DNNL_ARG_WEIGHTS, grouped, {_ds_group_size, 1}, _ds_data_type);
Expand All @@ -304,7 +305,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
_attrs->set_zero_points(DNNL_ARG_WEIGHTS, COMMON, dnnl::memory::dims{}, _dzp_data_type);
} else {
auto ngroups = dzp_layout.get_dim(get_ifm_dim_idx(dzp_layout, transpose_b_zp, weight_rank));
if (ngroups == 1) {
if (ngroups == 1 && !has_batch_dim) {
_attrs->set_zero_points(DNNL_ARG_WEIGHTS, per_oc, dnnl::memory::dims{}, _dzp_data_type);
} else {
_attrs->set_zero_points(DNNL_ARG_WEIGHTS, grouped, {_ds_group_size, 1}, _dzp_data_type);
Expand Down Expand Up @@ -374,6 +375,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
auto weights_layout = impl_params.get_input_layout(1);
const auto weight_rank = get_compressed_weights_rank(weights_layout);
OPENVINO_ASSERT(weight_rank <= 3, "Currently only weights with equal to or less than 3D is supported");
const bool has_batch_dim = weight_rank > 2;
auto shift_size = std::max<size_t>(prim->input_size - 2, 0);
int per_oc = PER_OC << shift_size;
int grouped = (1 << prim->input_size) - 1;
Expand All @@ -389,7 +391,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
"[GPU] group_size should be aligned to 16 if it is not a single scale group or the group_size is not one.");
if (scale_layout.count() == 1) {
attr->set_scales(DNNL_ARG_WEIGHTS, COMMON, dnnl::memory::dims{}, ds_data_type);
} else if (ngroups == 1 && weight_rank <= 2) {
} else if (ngroups == 1 && !has_batch_dim) {
attr->set_scales(DNNL_ARG_WEIGHTS, per_oc, dnnl::memory::dims{}, ds_data_type);
} else {
// should use {K, 1} for the group size + per tensor mask for 3d
Expand All @@ -413,7 +415,7 @@ struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
dzp_rank = std::max(static_cast<int64_t>(2), dzp_rank);

auto ngroups = dzp_layout.get_dim(get_ifm_dim_idx(dzp_layout, prim->transpose_b_zp, weight_rank));
if (ngroups == 1 && dzp_rank <= 2) {
if (ngroups == 1 && dzp_rank <= 2 && !has_batch_dim) {
attr->set_zero_points(DNNL_ARG_WEIGHTS, per_oc, dnnl::memory::dims{}, dzp_data_type);
} else {
// should use {K, 1} for the group size + per tensor mask for 3d
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5252,6 +5252,97 @@ TEST(fully_connected_3d_onednn_gpu, no_biases_int8) {
}
}

class fully_connected_onednn_expert_zero_points_test
: public testing::TestWithParam<std::tuple<int64_t, bool, bool, int64_t>> {};

TEST_P(fully_connected_onednn_expert_zero_points_test, per_expert_per_channel) {
auto& engine = get_test_engine();
if (!engine.get_device_info().supports_immad)
GTEST_SKIP() << "oneDNN compressed FC requires IMMAD support.";

const auto [experts, transpose_b_param, is_caching_test, group_per_channel] = GetParam();
constexpr int64_t tokens = 2;
constexpr int64_t ofm = 16;
constexpr int64_t ifm = 64;
const auto scale_groups = group_per_channel;
const auto scale_group_size = ifm / scale_groups;
const size_t weights_rank = experts == 1 ? 2 : 3;
const auto weights_shape = experts == 1 ? ov::PartialShape{ofm, ifm}
: ov::PartialShape{experts, ofm, ifm};
const auto zp_shape = experts == 1
? (transpose_b_param ? ov::PartialShape{ofm, scale_groups}
: ov::PartialShape{scale_groups, ofm})
: (transpose_b_param ? ov::PartialShape{experts, ofm, scale_groups}
: ov::PartialShape{experts, scale_groups, ofm});
const auto scale_shape = experts == 1
? (transpose_b_param ? ov::PartialShape{ofm, scale_groups}
: ov::PartialShape{scale_groups, ofm})
: (transpose_b_param ? ov::PartialShape{experts, ofm, scale_groups}
: ov::PartialShape{experts, scale_groups, ofm});

auto input = engine.allocate_memory({ov::PartialShape{experts, tokens, ifm}, data_types::f16, format::bfyx});
auto weights = engine.allocate_memory({weights_shape, data_types::u8, format::bfyx});
auto scale = engine.allocate_memory({scale_shape, data_types::f16, format::bfyx});
auto zero_points = engine.allocate_memory({zp_shape, data_types::u8, format::bfyx});
set_values<ov::float16>(input, std::vector<ov::float16>(experts * tokens * ifm, ov::float16(1.0f)));
set_values<uint8_t>(weights, std::vector<uint8_t>(experts * ofm * ifm, 9));
set_values<ov::float16>(scale, std::vector<ov::float16>(experts * ofm * scale_groups, ov::float16(1.0f)));
std::vector<uint8_t> zp_values(experts * ofm * scale_groups);
const bool transpose_zp_layout = transpose_b_param;
const auto zp_idx = [=](int64_t expert, int64_t group, int64_t oc) {
return transpose_zp_layout ? static_cast<size_t>(expert * ofm * scale_groups + oc * scale_groups + group)
: static_cast<size_t>(expert * scale_groups * ofm + group * ofm + oc);
};
for (int64_t expert = 0; expert < experts; ++expert) {
for (int64_t group = 0; group < scale_groups; ++group) {
for (int64_t oc = 0; oc < ofm; ++oc) {
zp_values[zp_idx(expert, group, oc)] = static_cast<uint8_t>((expert + group + oc) % 8);
}
}
}
set_values<uint8_t>(zero_points, zp_values);

topology topology(
input_layout("input", input->get_layout()),
data("weights", weights),
data("scale", scale),
data("zero_points", zero_points),
fully_connected("fc", input_info("input"), "weights", "", "scale", "zero_points",
data_types::f16, 3, weights_rank, true, transpose_b_param, transpose_b_param));
auto 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));
const ov::intel_gpu::ImplementationDesc impl = {format::bfyx, "", impl_types::onednn};
config.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{{"fc", impl}}));
auto network = get_network(engine, topology, config, get_test_stream_ptr(), is_caching_test);
ASSERT_TRUE(network->get_primitive("fc")->get_impl()->is_onednn());
network->set_input_data("input", input);
auto output = network->execute().at("fc").get_memory();
ASSERT_EQ(output->get_layout().get_partial_shape(), (ov::PartialShape{experts, tokens, ofm}));
mem_lock<ov::float16, mem_lock_type::read> result(output, get_test_stream());
ASSERT_EQ(result.size(), static_cast<size_t>(experts * tokens * ofm));
for (int64_t expert = 0; expert < experts; ++expert) {
for (int64_t token = 0; token < tokens; ++token) {
for (int64_t oc = 0; oc < ofm; ++oc) {
const auto idx = (expert * tokens + token) * ofm + oc;
float expected = 0.0f;
for (int64_t group = 0; group < scale_groups; ++group) {
expected += static_cast<float>(scale_group_size * (9 - zp_values[zp_idx(expert, group, oc)]));
}
EXPECT_FLOAT_EQ(static_cast<float>(result[idx]), expected)
<< "expert=" << expert << ", token=" << token << ", oc=" << oc;
}
}
}
}

INSTANTIATE_TEST_SUITE_P(smoke,
fully_connected_onednn_expert_zero_points_test,
testing::Combine(testing::Values(int64_t{1}, int64_t{64}),
testing::Bool(),
testing::Bool(),
testing::Values(int64_t{1}, int64_t{2})));

TEST(fully_connected_3d_onednn_gpu, compressed_int4_scale_static) {
tests::random_generator rg(GET_SUITE_NAME);

Expand Down
Loading