[GPU] integration oneDNN3.0 (#14647)

* Support oneDNN3.0 API
* Use binary_mul post_opt instead of oscale channel-wise mask(2)
* Disable some post-opt fusing because of no eltwise scale API
    eltw(non_linear)+eltw(linear), eltw+sum+eltw(linear)
* Fix hardwish issue in 3.0
   hard coded hardswish parameter(2.7) is changed alpha and beta from user's required input.

Signed-off-by: hyunback <hyunback.kim@intel.com>
This commit is contained in:
hyunback kim authored and GitHub committed 2023-01-16 17:11:17 +09:00
1 parent 0c9abf43a9
commit e75fa049ac
18 files changed
+446 -480

No files matched your search

@@ -34,16 +34,17 @@ void select_preferred_formats::run(program& p) {
for (auto n : p.get_processing_order()) {
// Onednn primitive descriptor creation may fail, for example, due to asymmetric weight.
try {
dnnl::primitive_desc prim_desc;
if (n->is_type<convolution>()) {
auto desc = onednn::get_convolution_descriptor(*n->get_kernel_impl_params(), dnnl::memory::format_tag::any);
prim_desc = dnnl::primitive_desc(&desc->data, nullptr, engine.get_onednn_engine(), nullptr);
auto prim_desc = onednn::get_convolution_primitive_descriptor(*n->get_kernel_impl_params(),
dnnl::primitive_attr(),
dnnl::memory::format_tag::any);
_lo.select_preferred_formats_for_onednn(*n, *prim_desc);
} else if (n->is_type<deconvolution>()) {
auto desc = onednn::get_deconvolution_descriptor(*n->get_kernel_impl_params(), dnnl::memory::format_tag::any);
prim_desc = dnnl::primitive_desc(&desc->data, nullptr, engine.get_onednn_engine(), nullptr);
auto prim_desc = onednn::get_deconvolution_primitive_descriptor(*n->get_kernel_impl_params(),
dnnl::primitive_attr(),
dnnl::memory::format_tag::any);
_lo.select_preferred_formats_for_onednn(*n, *prim_desc);
}
_lo.select_preferred_formats_for_onednn(*n, prim_desc);
} catch(std::exception &exception) {
GPU_DEBUG_INFO << "WARNING(select_preferred_formats): " << exception.what() << std::endl;
}
@@ -17,8 +17,8 @@
namespace cldnn {
namespace onednn {
struct concatenation_onednn : typed_primitive_onednn_impl<concatenation, void, dnnl::concat::primitive_desc, dnnl::concat> {
using parent = typed_primitive_onednn_impl<concatenation, void, dnnl::concat::primitive_desc, dnnl::concat>;
struct concatenation_onednn : typed_primitive_onednn_impl<concatenation, dnnl::concat::primitive_desc, dnnl::concat> {
using parent = typed_primitive_onednn_impl<concatenation, dnnl::concat::primitive_desc, dnnl::concat>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -49,23 +49,26 @@ protected:
return args;
}
static std::shared_ptr<dnnl::concat::primitive_desc> get_concatenation_descriptor(const kernel_impl_params& impl_params,
const int64_t axis,
const cldnn::engine& engine) {
static std::shared_ptr<dnnl::concat::primitive_desc> get_concatenation_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr,
const int64_t axis) {
auto& engine = impl_params.prog->get_engine();
std::vector<dnnl::memory::desc> input_mds;
for (size_t i = 0; i < impl_params.input_layouts.size(); i++) {
input_mds.push_back(onednn::layout_to_memory_desc(impl_params.get_input_layout(i)));
}
auto output_md = onednn::layout_to_memory_desc(impl_params.get_output_layout());
return std::make_shared<dnnl::concat::primitive_desc>(
engine.get_onednn_engine(),
output_md,
axis,
input_mds,
engine.get_onednn_engine());
attr);
}
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
if (_prim.get(true) == nullptr) {
ob << false;
return;
@@ -82,9 +85,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
bool has_prim;
ib >> has_prim;
@@ -104,6 +109,7 @@ public:
ib >> prim_cache;
_prim = dnnl::concat(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const concatenation_node& arg, const kernel_impl_params& impl_params) {
@@ -112,12 +118,10 @@ public:
if (arg.can_be_optimized())
return make_unique<concatenation_onednn>(engine);
auto prim = impl_params.typed_desc<concatenation>();
auto desc = get_concatenation_descriptor(impl_params, prim->axis, impl_params.prog->get_engine());
auto attr = arg.get_onednn_primitive_attributes();
auto prim_desc = get_concatenation_primitive_descriptor(impl_params, *attr, prim->axis);
std::shared_ptr<void> dummy = nullptr;
return cldnn::make_unique<concatenation_onednn>(engine, config, dummy, attr, *desc);
return cldnn::make_unique<concatenation_onednn>(engine, config, attr, *prim_desc);
}
};
@@ -22,8 +22,8 @@
namespace cldnn {
namespace onednn {
struct convolution_onednn : typed_primitive_onednn_impl<convolution, dnnl::convolution_forward::desc> {
using parent = typed_primitive_onednn_impl<convolution, dnnl::convolution_forward::desc>;
struct convolution_onednn : typed_primitive_onednn_impl<convolution> {
using parent = typed_primitive_onednn_impl<convolution>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -46,7 +46,7 @@ protected:
args.insert({DNNL_ARG_BIAS, bias->get_onednn_memory(_pd.weights_desc(1))});
}
if (has_zero_points(DNNL_ARG_SRC, _attrs)) {
if (instance.activations_zero_points_term()) {
auto a_zp = instance.activations_zero_points_memory();
dnnl::memory::desc desc = onednn::layout_to_memory_desc(a_zp->get_layout(), dnnl::memory::format_tag::a, true);
args.insert({DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_SRC, a_zp->get_onednn_memory(desc)});
@@ -63,7 +63,7 @@ protected:
}
}
if (has_zero_points(DNNL_ARG_WEIGHTS, _attrs)) {
if (instance.weights_zero_points_term()) {
auto w_zp = instance.weights_zero_points_memory();
dnnl::memory::desc desc = onednn::layout_to_memory_desc(w_zp->get_layout(), dnnl::memory::format_tag::a, true);
args.insert({DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_WEIGHTS, w_zp->get_onednn_memory(desc)});
@@ -87,13 +87,9 @@ protected:
static void set_activation_zero_points_attr(const std::shared_ptr<dnnl::primitive_attr>& attrs, cldnn::data_node& node) {
int32_t zp_val = DNNL_RUNTIME_S32_VAL;
bool is_per_tensor = onednn::is_per_tensor<T>(node, zp_val);
if (is_per_tensor) {
attrs->set_zero_points(DNNL_ARG_SRC, 0, {zp_val});
} else {
memory::ptr s32_mem = onednn::convert_zp_data_to_s32<T>(node.get_attached_memory_ptr());
node.attach_memory(s32_mem, false);
attrs->set_zero_points(DNNL_ARG_SRC, 2, {DNNL_RUNTIME_S32_VAL});
}
memory::ptr s32_mem = onednn::convert_zp_data_to_s32<T>(node.get_attached_memory_ptr());
node.attach_memory(s32_mem, false);
attrs->set_zero_points_mask(DNNL_ARG_SRC, is_per_tensor ? 0 : 2);
}
static std::shared_ptr<dnnl::primitive_attr> get_primitive_attributes(const typed_program_node<convolution>& arg) {
@@ -163,6 +159,7 @@ protected:
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_convolution_desc_t));
@@ -170,9 +167,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const char dummy_mem[sizeof(dnnl::convolution_forward::desc)] = {};
@@ -186,16 +185,17 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const convolution_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_convolution_descriptor(impl_params);
auto attr = get_primitive_attributes(arg);
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
return cldnn::make_unique<convolution_onednn>(engine, config, desc, attr, prim_desc, get_weights_reorder(impl_params, prim_desc, arg.get_transposed()));
auto prim_desc = get_convolution_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<convolution_onednn>(engine, config, attr, *prim_desc, get_weights_reorder(impl_params, *prim_desc, arg.get_transposed()));
}
};
@@ -6,8 +6,10 @@
namespace cldnn {
namespace onednn {
static std::shared_ptr<dnnl::convolution_forward::desc> get_convolution_descriptor(const kernel_impl_params& impl_params,
static std::shared_ptr<dnnl::convolution_forward::primitive_desc> get_convolution_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr(),
dnnl::memory::format_tag tag_in_out = dnnl::memory::format_tag::undef) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<convolution>();
auto input_layout = impl_params.get_input_layout(0);
@@ -28,16 +30,17 @@ static std::shared_ptr<dnnl::convolution_forward::desc> get_convolution_descript
for (size_t i = 0; i < dilation.size(); i++) {
dilation[i]--;
int weights_offset = (grouped_weights ? 3 : 2) + static_cast<int>(i);
auto os = output_md.dims()[2 + i];
auto is = input_md.dims()[2 + i];
auto ks = weights_md.dims()[weights_offset];
auto os = output_md.get_dims()[2 + i];
auto is = input_md.get_dims()[2 + i];
auto ks = weights_md.get_dims()[weights_offset];
auto kernel_range = 1 + (ks - 1) * (dilation[i] + 1);
pad_r[i] = (os - 1) * stride[i] - is + kernel_range - pad_l[i];
}
if (!prim->bias.empty()) {
auto bias_md = onednn::layout_to_memory_desc(impl_params.get_input_layout(2), dnnl::memory::format_tag::any, true);
return std::make_shared<dnnl::convolution_forward::desc>(
return std::make_shared<dnnl::convolution_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
dnnl::algorithm::convolution_direct,
input_md,
@@ -47,9 +50,11 @@ static std::shared_ptr<dnnl::convolution_forward::desc> get_convolution_descript
stride,
dilation,
pad_l,
pad_r);
pad_r,
attr);
} else {
return std::make_shared<dnnl::convolution_forward::desc>(
return std::make_shared<dnnl::convolution_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
dnnl::algorithm::convolution_direct,
input_md,
@@ -58,7 +63,8 @@ static std::shared_ptr<dnnl::convolution_forward::desc> get_convolution_descript
stride,
dilation,
pad_l,
pad_r);
pad_r,
attr);
}
}
} // namespace onednn
@@ -18,8 +18,8 @@
namespace cldnn {
namespace onednn {
struct deconvolution_onednn : typed_primitive_onednn_impl<deconvolution, dnnl::deconvolution_forward::desc> {
using parent = typed_primitive_onednn_impl<deconvolution, dnnl::deconvolution_forward::desc>;
struct deconvolution_onednn : typed_primitive_onednn_impl<deconvolution> {
using parent = typed_primitive_onednn_impl<deconvolution>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -48,9 +48,7 @@ protected:
}
static std::shared_ptr<dnnl::primitive_attr> get_primitive_attributes(const typed_program_node<deconvolution>& arg) {
auto attrs = arg.get_onednn_primitive_attributes();
return attrs;
return arg.get_onednn_primitive_attributes();
}
static kernel_selector::WeightsReorderParams get_weights_reorder(const kernel_impl_params& impl_params, const dnnl::primitive_desc& pd) {
@@ -88,6 +86,7 @@ protected:
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_deconvolution_desc_t));
@@ -95,9 +94,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const char dummy_mem[sizeof(dnnl::deconvolution_forward::desc)] = {};
@@ -111,16 +112,16 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const deconvolution_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_deconvolution_descriptor(impl_params);
auto attr = get_primitive_attributes(arg);
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
auto prim_desc = get_deconvolution_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<deconvolution_onednn>(engine, config, desc, attr, prim_desc, get_weights_reorder(impl_params, prim_desc));
return cldnn::make_unique<deconvolution_onednn>(engine, config, attr, *prim_desc, get_weights_reorder(impl_params, *prim_desc));
}
};
@@ -6,8 +6,10 @@
namespace cldnn {
namespace onednn {
static std::shared_ptr<dnnl::deconvolution_forward::desc> get_deconvolution_descriptor(const kernel_impl_params& impl_params,
static std::shared_ptr<dnnl::deconvolution_forward::primitive_desc> get_deconvolution_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr(),
dnnl::memory::format_tag tag_in_out = dnnl::memory::format_tag::undef) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<deconvolution>();
auto input_layout = impl_params.get_input_layout(0);
@@ -27,16 +29,17 @@ static std::shared_ptr<dnnl::deconvolution_forward::desc> get_deconvolution_desc
for (size_t i = 0; i < dilation.size(); i++) {
dilation[i]--;
int weights_offset = (grouped_weights ? 3 : 2) + static_cast<int>(i);
auto os = output_md.dims()[2 + i];
auto is = input_md.dims()[2 + i];
auto ks = weights_md.dims()[weights_offset];
auto os = output_md.get_dims()[2 + i];
auto is = input_md.get_dims()[2 + i];
auto ks = weights_md.get_dims()[weights_offset];
auto kernel_range = 1 + (ks - 1) * (dilation[i] + 1);
pad_r[i] = (is - 1) * stride[i] - os + kernel_range - pad_l[i];
}
if (!prim->bias.empty()) {
auto bias_md = onednn::layout_to_memory_desc(impl_params.get_input_layout(2), dnnl::memory::format_tag::any, true);
return std::make_shared<dnnl::deconvolution_forward::desc>(
return std::make_shared<dnnl::deconvolution_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
dnnl::algorithm::deconvolution_direct,
input_md,
@@ -46,9 +49,11 @@ static std::shared_ptr<dnnl::deconvolution_forward::desc> get_deconvolution_desc
stride,
dilation,
pad_l,
pad_r);
pad_r,
attr);
} else {
return std::make_shared<dnnl::deconvolution_forward::desc>(
return std::make_shared<dnnl::deconvolution_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
dnnl::algorithm::deconvolution_direct,
input_md,
@@ -57,7 +62,8 @@ static std::shared_ptr<dnnl::deconvolution_forward::desc> get_deconvolution_desc
stride,
dilation,
pad_l,
pad_r);
pad_r,
attr);
}
}
} // namespace onednn
@@ -15,8 +15,8 @@
namespace cldnn {
namespace onednn {
struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected, dnnl::inner_product_forward::desc> {
using parent = typed_primitive_onednn_impl<fully_connected, dnnl::inner_product_forward::desc>;
struct fully_connected_onednn : typed_primitive_onednn_impl<fully_connected> {
using parent = typed_primitive_onednn_impl<fully_connected>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -95,7 +95,9 @@ protected:
return weights_reorder_params;
}
static std::shared_ptr<dnnl::inner_product_forward::desc> get_fully_connected_descriptor(const kernel_impl_params& impl_params) {
static std::shared_ptr<dnnl::inner_product_forward::primitive_desc> get_fully_connected_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr()) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<fully_connected>();
auto input_layout = impl_params.get_input_layout(0);
@@ -133,23 +135,28 @@ protected:
if (!prim->bias.empty()) {
auto bias_md = onednn::layout_to_memory_desc(impl_params.get_input_layout(2), dnnl::memory::format_tag::any, true);
return std::make_shared<dnnl::inner_product_forward::desc>(
return std::make_shared<dnnl::inner_product_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
input_md,
weights_md,
bias_md,
output_md);
output_md,
attr);
} else {
return std::make_shared<dnnl::inner_product_forward::desc>(
return std::make_shared<dnnl::inner_product_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
input_md,
weights_md,
output_md);
output_md,
attr);
}
}
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_inner_product_desc_t));
@@ -157,9 +164,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const char dummy_mem[sizeof(dnnl::inner_product_forward::desc)] = {};
@@ -173,16 +182,16 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const fully_connected_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_fully_connected_descriptor(impl_params);
auto attr = arg.get_onednn_primitive_attributes();
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
auto prim_desc = get_fully_connected_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<fully_connected_onednn>(engine, config, desc, attr, prim_desc, get_weights_reorder(impl_params, prim_desc));
return cldnn::make_unique<fully_connected_onednn>(engine, config, attr, *prim_desc, get_weights_reorder(impl_params, *prim_desc));
}
};
@@ -15,8 +15,8 @@
namespace cldnn {
namespace onednn {
struct gemm_onednn : typed_primitive_onednn_impl<gemm, dnnl::matmul::desc> {
using parent = typed_primitive_onednn_impl<gemm, dnnl::matmul::desc>;
struct gemm_onednn : typed_primitive_onednn_impl<gemm> {
using parent = typed_primitive_onednn_impl<gemm>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -53,7 +53,9 @@ protected:
}
}
static std::shared_ptr<dnnl::matmul::desc> get_gemm_descriptor(const kernel_impl_params& impl_params) {
static std::shared_ptr<dnnl::matmul::primitive_desc> get_gemm_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr()) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<gemm>();
auto gemm_with_bias = prim->dependencies().size() == 3;
auto out_l = impl_params.get_output_layout();
@@ -116,21 +118,26 @@ protected:
dnnl::memory::format_tag bias_fmt = onednn::convert_gemm_data_format(bias_dims);
dnnl::memory::desc bias_md(bias_dims, bias_dt, bias_fmt);
return std::make_shared<dnnl::matmul::desc>(
return std::make_shared<dnnl::matmul::primitive_desc>(
engine.get_onednn_engine(),
in0_md,
in1_md,
bias_md,
out_md);
out_md,
attr);
} else {
return std::make_shared<dnnl::matmul::desc>(
return std::make_shared<dnnl::matmul::primitive_desc>(
engine.get_onednn_engine(),
in0_md,
in1_md,
out_md);
out_md,
attr);
}
}
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_matmul_desc_t));
@@ -138,9 +145,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const char dummy_mem[sizeof(dnnl::matmul::desc)] = {};
@@ -154,16 +163,16 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const gemm_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_gemm_descriptor(impl_params);
auto attr = arg.get_onednn_primitive_attributes();
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
auto prim_desc = get_gemm_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<gemm_onednn>(engine, config, desc, attr, prim_desc);
return cldnn::make_unique<gemm_onednn>(engine, config, attr, *prim_desc);
}
};
@@ -15,8 +15,8 @@
namespace cldnn {
namespace onednn {
struct pooling_onednn : typed_primitive_onednn_impl<pooling, dnnl::pooling_forward::desc> {
using parent = typed_primitive_onednn_impl<pooling, dnnl::pooling_forward::desc>;
struct pooling_onednn : typed_primitive_onednn_impl<pooling> {
using parent = typed_primitive_onednn_impl<pooling>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -26,7 +26,9 @@ protected:
return make_unique<pooling_onednn>(*this);
}
static std::shared_ptr<dnnl::pooling_forward::desc> get_pooling_descriptor(const kernel_impl_params& impl_params) {
static std::shared_ptr<dnnl::pooling_forward::primitive_desc> get_pooling_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr()) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<pooling>();
auto input_layout = impl_params.get_input_layout(0);
@@ -36,45 +38,53 @@ protected:
auto stride_shape = prim->stride;
auto pads_begin_shape = prim->pads_begin;
auto pads_end_shape = prim->pads_end;
auto dilation_shape = prim->dilation;
if (dilation_shape.empty()) dilation_shape.resize(stride_shape.size(), 0);
kernel_shape.resize(std::max<size_t>(2, prim->size.size()), 1);
stride_shape.resize(std::max<size_t>(2, prim->stride.size()), 1);
pads_begin_shape.resize(std::max<size_t>(2, prim->pads_begin.size()), 0);
pads_end_shape.resize(std::max<size_t>(2, prim->pads_end.size()), 0);
dilation_shape.resize(std::max<size_t>(2, dilation_shape.size()), 0);
dnnl::memory::dims stride(stride_shape.begin(), stride_shape.end());
dnnl::memory::dims kernel(kernel_shape.begin(), kernel_shape.end());
dnnl::memory::dims pad_l(pads_begin_shape.begin(), pads_begin_shape.end());
dnnl::memory::dims pad_r(pads_end_shape.begin(), pads_end_shape.end());
dnnl::memory::dims dilation(dilation_shape.begin(), dilation_shape.end());
auto input_md = onednn::layout_to_memory_desc(input_layout);
auto output_md = onednn::layout_to_memory_desc(output_layout);
for (size_t i = 0; i < kernel.size(); i++) {
pad_r[i] = (output_md.dims()[2 + i] - 1) * stride[i] - input_md.dims()[2 + i] + kernel[i] - pad_l[i];
pad_r[i] = (output_md.get_dims()[2 + i] - 1) * stride[i] - input_md.get_dims()[2 + i] + kernel[i] - pad_l[i];
}
dnnl::algorithm alg;
switch (prim->mode) {
case pooling_mode::average: alg = dnnl::algorithm::pooling_avg; break;
case pooling_mode::average: alg = dnnl::algorithm::pooling_avg_include_padding; break;
case pooling_mode::max: alg = dnnl::algorithm::pooling_max; break;
case pooling_mode::average_no_padding: alg = dnnl::algorithm::pooling_avg_exclude_padding; break;
default: throw std::runtime_error("unsupported pool mode");
}
return std::make_shared<dnnl::pooling_forward::desc>(
return std::make_shared<dnnl::pooling_forward::primitive_desc>(
engine.get_onednn_engine(),
dnnl::prop_kind::forward_inference,
alg,
input_md,
output_md,
stride,
kernel,
dilation,
pad_l,
pad_r);
pad_r,
attr);
}
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_pooling_desc_t));
@@ -82,9 +92,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const char dummy_mem[sizeof(dnnl::pooling_forward::desc)] = {};
@@ -98,16 +110,16 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const pooling_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_pooling_descriptor(impl_params);
auto attr = arg.get_onednn_primitive_attributes();
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
auto prim_desc = get_pooling_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<pooling_onednn>(engine, config, desc, attr, prim_desc);
return cldnn::make_unique<pooling_onednn>(engine, config, attr, *prim_desc);
}
};
@@ -30,10 +30,9 @@ namespace onednn {
static std::mutex cacheAccessMutex;
template <class PType, class DescType, class PrimDescType = dnnl::primitive_desc, class PrimType = dnnl::primitive>
template <class PType, class PrimDescType = dnnl::primitive_desc, class PrimType = dnnl::primitive>
struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
const engine* _engine;
std::shared_ptr<DescType> _desc;
std::shared_ptr<dnnl::primitive_attr> _attrs;
PrimDescType _pd;
PrimType _prim;
@@ -41,13 +40,11 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
typed_primitive_onednn_impl(const engine& engine,
const ExecutionConfig& config,
std::shared_ptr<DescType> desc,
std::shared_ptr<dnnl::primitive_attr> attrs,
const PrimDescType& pd,
kernel_selector::WeightsReorderParams weights_reorder = {})
: typed_primitive_impl<PType>(weights_reorder, pd.impl_info_str()),
_engine(&engine),
_desc(desc),
_attrs(attrs),
_pd(pd) {
build_primitive(config);
@@ -62,7 +59,7 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
typed_primitive_onednn_impl()
: typed_primitive_impl<PType>({}, "undef"),
_desc(nullptr), _pd(), _prim() {
_pd(), _prim() {
_attrs = std::make_shared<dnnl::primitive_attr>();
}
@@ -73,6 +70,7 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
// [ dnnl::primitive_desc ]
// [ dnnl::cache_blob ]
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
if (_attrs.get() == nullptr) {
ob << false;
} else {
@@ -205,9 +203,11 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
ob << scales;
}
}
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
bool has_attrs;
ib >> has_attrs;
@@ -360,6 +360,7 @@ struct typed_primitive_onednn_impl : public typed_primitive_impl<PType> {
_engine = &ib.get_engine();
}
#endif
}
private:
@@ -424,22 +425,6 @@ private:
protected:
virtual bool optimized_out(typed_primitive_inst<PType>&) const { return false; }
static bool has_output_scales(const std::shared_ptr<dnnl::primitive_attr>& attr) {
int mask;
std::vector<float> scales;
attr->get_output_scales(mask, scales);
const auto drfv = reinterpret_cast<const int32_t&>(DNNL_RUNTIME_F32_VAL);
return !scales.empty() && (reinterpret_cast<const int32_t&>(scales[0]) == drfv);
}
static bool has_zero_points(int arg, const std::shared_ptr<dnnl::primitive_attr>& attr) {
int mask;
std::vector<int32_t> zp;
attr->get_zero_points(arg, mask, zp);
const auto drsv = reinterpret_cast<const int32_t&>(DNNL_RUNTIME_S32_VAL);
return !zp.empty() && (reinterpret_cast<const int32_t&>(zp[0]) == drsv);
}
void configure_post_ops_arguments(typed_primitive_inst<PType>& instance, std::unordered_map<int, dnnl::memory>& args) const {
auto& engine = instance.get_network().get_engine();
auto dnnl_engine = engine.get_onednn_engine();
@@ -453,7 +438,7 @@ protected:
for (size_t post_op_idx = 0, num_of_optimized_post_ops = 0; post_op_idx < post_ops_size; post_op_idx++) {
auto post_op_type = cur_post_ops[post_op_idx].op_type;
auto memory_offset = cur_post_ops[post_op_idx].mem_offset;
auto onednn_post_op_idx = has_output_scales(_attrs) && post_op_idx > 0 ? post_op_idx - 1 : post_op_idx;
auto onednn_post_op_idx = post_op_idx;
onednn_post_op_idx -= num_of_optimized_post_ops;
switch (post_op_type) {
@@ -489,14 +474,6 @@ protected:
break;
}
case onednn_post_op_type::scale:
{
auto scale_op_mem = instance.fused_memory(memory_offset);
dnnl::memory::desc desc = onednn::layout_to_memory_desc(scale_op_mem->get_layout(), dnnl::memory::format_tag::a, true);
args.insert({DNNL_ARG_ATTR_OUTPUT_SCALES, scale_op_mem->get_onednn_memory(desc)});
break;
}
case onednn_post_op_type::sum:
case onednn_post_op_type::optimized_sum:
case onednn_post_op_type::optimized_eltwise_linear:
@@ -37,8 +37,8 @@ static void reorder_unreduced_axis_no_fusion(const cldnn::layout& input_layout,
output_layout.set_tensor(output_tensor);
}
struct reduction_onednn : typed_primitive_onednn_impl<reduce, dnnl::reduction::desc> {
using parent = typed_primitive_onednn_impl<reduce, dnnl::reduction::desc>;
struct reduction_onednn : typed_primitive_onednn_impl<reduce> {
using parent = typed_primitive_onednn_impl<reduce>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -48,7 +48,9 @@ protected:
return make_unique<reduction_onednn>(*this);
}
static std::shared_ptr<dnnl::reduction::desc> get_reduction_descriptor(const kernel_impl_params& impl_params) {
static std::shared_ptr<dnnl::reduction::primitive_desc> get_reduction_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr = dnnl::primitive_attr()) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<reduce>();
auto input_layout = impl_params.get_input_layout(0);
auto output_layout = impl_params.get_output_layout();
@@ -84,16 +86,19 @@ protected:
default: throw std::runtime_error("unsupported reduce mode");
}
return std::make_shared<dnnl::reduction::desc>(
return std::make_shared<dnnl::reduction::primitive_desc>(
engine.get_onednn_engine(),
alg,
input_md,
output_md,
p,
eps);
eps,
attr);
}
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
ob << make_data(&_desc->data, sizeof(dnnl_reduction_desc_t));
@@ -101,9 +106,11 @@ public:
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
_desc = std::make_shared<dnnl::reduction::desc>();
@@ -114,16 +121,16 @@ public:
_pd = dnnl::primitive_desc(&_desc->data, _attrs.get(), ib.get_engine().get_onednn_engine(), nullptr);
_prim = dnnl::primitive(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const reduce_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto desc = get_reduction_descriptor(impl_params);
auto attr = arg.get_onednn_primitive_attributes();
dnnl::primitive_desc prim_desc{&desc->data, attr.get(), engine.get_onednn_engine(), nullptr};
auto prim_desc = get_reduction_primitive_descriptor(impl_params, *attr);
return cldnn::make_unique<reduction_onednn>(engine, config, desc, attr, prim_desc);
return cldnn::make_unique<reduction_onednn>(engine, config, attr, *prim_desc);
}
};
@@ -15,8 +15,8 @@
namespace cldnn {
namespace onednn {
struct reorder_onednn : typed_primitive_onednn_impl<reorder, void, dnnl::reorder::primitive_desc, dnnl::reorder> {
using parent = typed_primitive_onednn_impl<reorder, void, dnnl::reorder::primitive_desc, dnnl::reorder>;
struct reorder_onednn : typed_primitive_onednn_impl<reorder, dnnl::reorder::primitive_desc, dnnl::reorder> {
using parent = typed_primitive_onednn_impl<reorder, dnnl::reorder::primitive_desc, dnnl::reorder>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
@@ -43,9 +43,9 @@ protected:
return args;
}
static std::shared_ptr<dnnl::reorder::primitive_desc> get_reorder_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr,
const cldnn::engine& engine) {
static std::shared_ptr<dnnl::reorder::primitive_desc> get_reorder_primitive_descriptor(const kernel_impl_params& impl_params,
const dnnl::primitive_attr& attr) {
auto& engine = impl_params.prog->get_engine();
auto prim = impl_params.typed_desc<reorder>();
auto input_layout = impl_params.get_input_layout(0);
@@ -64,14 +64,17 @@ protected:
public:
void save(BinaryOutputBuffer& ob) const override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::save(ob);
std::vector<uint8_t> prim_cache;
prim_cache = _prim.get_cache_blob();
ob << prim_cache;
#endif
}
void load(BinaryInputBuffer& ib) override {
#ifdef ONEDNN_PRIMITIVE_SERIALIZATION
parent::load(ib);
const kernel_impl_params* impl_params = reinterpret_cast<kernel_impl_params*>(ib.getKernlImplParams());
@@ -82,17 +85,18 @@ public:
ib >> prim_cache;
_prim = dnnl::reorder(_pd, prim_cache);
#endif
}
static std::unique_ptr<primitive_impl> create(const reorder_node& arg, const kernel_impl_params& impl_params) {
auto& engine = impl_params.prog->get_engine();
auto& config = impl_params.prog->get_config();
auto attr = arg.get_onednn_primitive_attributes();
auto desc = get_reorder_descriptor(impl_params, *attr, impl_params.prog->get_engine());
auto prim_desc = get_reorder_primitive_descriptor(impl_params, *attr);
std::shared_ptr<void> dummy = nullptr;
return cldnn::make_unique<reorder_onednn>(engine, config, dummy, attr, *desc);
return cldnn::make_unique<reorder_onednn>(engine, config, attr, *prim_desc);
}
};
@@ -14,14 +14,6 @@ namespace cldnn {
namespace onednn {
namespace {
void pad_dims(dnnl::memory::dims& padded_dims, cldnn::format format) {
auto block_sizes = format.block_sizes();
for (auto& block : block_sizes) {
auto rounded_dim = round_up_to(padded_dims[block.first], block.second);
padded_dims[block.first] = rounded_dim;
}
}
std::string convert_data_format_string(cldnn::format fmt) {
switch (fmt) {
case cldnn::format::b_fs_yx_fsv2: return "aBcd2b";
@@ -36,78 +28,6 @@ std::string convert_data_format_string(cldnn::format fmt) {
}
}
dnnl::memory::desc create_memory_desc_from_format_string(dnnl::memory::dims dims, dnnl::memory::data_type dt, std::string tag) {
dnnl::memory::desc desc;
dnnl_memory_desc_t* md = &desc.data;
int ndims = static_cast<int>(dims.size());
md->ndims = ndims;
if (ndims > DNNL_MAX_NDIMS) throw std::invalid_argument("[clDNN] Unsupported ndims " + std::to_string(ndims));
std::copy(&dims[0], &dims[0] + ndims, md->dims);
md->data_type = static_cast<dnnl_data_type_t>(dt);
md->format_kind = dnnl_blocked;
// Parse dimensions and their block sizes starting from the innermost one.
std::vector<std::pair<int, int>> dim_blocks;
int pos = static_cast<int>(tag.size()) - 1;
int ndims_from_tag = -1;
while (pos >= 0) {
int pos0 = pos;
--pos;
while (pos >= 0 && std::isdigit(tag[pos]))
pos--;
int dim_idx = std::tolower(tag[pos0]) - 'a';
if (dim_idx >= ndims) throw std::invalid_argument("[clDNN] Unsupported tag for oneDNN " + tag);
ndims_from_tag = std::max(dim_idx + 1, ndims_from_tag);
int block_str_len = pos0 - pos - 1;
int block = (block_str_len == 0)
? 1
: std::stoi(tag.substr(pos + 1, block_str_len));
dim_blocks.emplace_back(dim_idx, block);
}
if (ndims_from_tag != ndims) throw std::invalid_argument("[clDNN] Unsupported tag for oneDNN " + tag);
auto &blk = md->format_desc.blocking;
// Compute strides and fill inner block sizes/indices.
dnnl_dim_t stride = 1;
dnnl_dims_t full_inner_blks;
std::fill(full_inner_blks, full_inner_blks + md->ndims, 1);
for (auto &p : dim_blocks) {
int dim_idx = p.first;
int block = p.second;
if (block == 1) {
assert(blk.strides[dim_idx] == 0);
blk.strides[dim_idx] = stride;
dnnl_dim_t fib = full_inner_blks[dim_idx];
dnnl_dim_t padded_dim = md->dims[dim_idx] == DNNL_RUNTIME_DIM_VAL
? DNNL_RUNTIME_DIM_VAL
: (md->dims[dim_idx] + fib - 1) / fib * fib;
md->padded_dims[dim_idx] = padded_dim;
if (padded_dim == DNNL_RUNTIME_DIM_VAL)
stride = DNNL_RUNTIME_DIM_VAL;
else
stride *= (padded_dim / fib);
} else {
full_inner_blks[dim_idx] *= block;
blk.inner_blks[blk.inner_nblks] = block;
blk.inner_idxs[blk.inner_nblks] = dim_idx;
blk.inner_nblks++;
stride *= block;
}
}
// Inner block sizes/indices are stored from the outermost to the innermost
// so need to reverse them.
std::reverse(blk.inner_blks, blk.inner_blks + blk.inner_nblks);
std::reverse(blk.inner_idxs, blk.inner_idxs + blk.inner_nblks);
return desc;
}
} // namespace
template <typename T>
@@ -204,6 +124,7 @@ std::vector<std::pair<cldnn::format, dnnl::memory::format_tag>> format_map = {
{ cldnn::format::b_fs_zyx_fsv16, dnnl::memory::format_tag::nCdhw16c },
{ cldnn::format::b_fs_zyx_fsv32, dnnl::memory::format_tag::aBcde32b },
{ cldnn::format::bs_fs_yx_bsv16_fsv16, dnnl::memory::format_tag::NChw16n16c },
{ cldnn::format::bs_fs_yx_bsv16_fsv32, dnnl::memory::format_tag::NChw16n32c },
{ cldnn::format::bs_fs_yx_bsv32_fsv32, dnnl::memory::format_tag::NChw32n32c },
{ cldnn::format::bs_fs_yx_bsv4_fsv4, dnnl::memory::format_tag::ABcd4a4b },
{ cldnn::format::bs_fs_yx_bsv8_fsv4, dnnl::memory::format_tag::ABcd8a4b },
@@ -213,6 +134,7 @@ std::vector<std::pair<cldnn::format, dnnl::memory::format_tag>> format_map = {
{ cldnn::format::bs_fs_zyx_bsv32_fsv16, dnnl::memory::format_tag::NCdhw32n16c },
{ cldnn::format::bs_fs_zyx_bsv32_fsv32, dnnl::memory::format_tag::NCdhw32n32c },
{ cldnn::format::bs_fs_zyx_bsv16_fsv16, dnnl::memory::format_tag::NCdhw16n16c },
// { cldnn::format::bs_fs_zyx_bsv16_fsv32, dnnl::memory::format_tag::NCdhw16n32c }, // TODO onednn3.0: Request NCdhw16n32c format
{ cldnn::format::bs_fs_zyx_bsv8_fsv4, dnnl::memory::format_tag::ABcde8a4b },
{ cldnn::format::bs_fs_zyx_bsv8_fsv2, dnnl::memory::format_tag::ABcde8a2b },
};
@@ -260,55 +182,48 @@ int64_t get_f_offset(cldnn::layout&& l, dnnl::memory::desc&& desc) {
}
}
switch (desc.data.data_type) {
case dnnl_data_type_t::dnnl_s8:
case dnnl_data_type_t::dnnl_u8:
switch (desc.get_data_type()) {
case dnnl::memory::data_type::s8:
case dnnl::memory::data_type::u8:
return offset;
case dnnl_data_type_t::dnnl_f16:
case dnnl_data_type_t::dnnl_bf16:
case dnnl::memory::data_type::f16:
case dnnl::memory::data_type::bf16:
return (offset * 2);
case dnnl_data_type_t::dnnl_f32:
case dnnl_data_type_t::dnnl_s32:
case dnnl::memory::data_type::f32:
case dnnl::memory::data_type::s32:
return (offset * 4);
default: throw std::runtime_error(std::string("Unsupported offset for dnnl_data_type_t ") + dnnl_dt2str(desc.data.data_type));
default:
throw std::runtime_error(std::string("Unsupported offset for dnnl_data_type_t ")
+ dnnl_dt2str(static_cast<dnnl_data_type_t>(desc.get_data_type())));
}
}
dnnl::memory::desc layout_to_memory_desc(cldnn::layout l, dnnl::memory::format_tag target_fmt, bool flatten) {
dnnl::memory::dims dims;
dnnl::memory::dims padded_dims;
dnnl::memory::dims padded_offset;
if (target_fmt == dnnl::memory::format_tag::ab && flatten) {
dims = flatten_tensor(l.get_tensor());
dims.insert(dims.begin(), 1);
} else if (target_fmt == dnnl::memory::format_tag::ab) {
dims.push_back(l.batch());
dims.push_back(l.get_tensor().count() / l.batch());
padded_dims = dims;
} else if (flatten) {
dims = flatten_tensor(l.get_tensor());
} else {
auto rank = cldnn::format::dimension(l.format);
dims = convert_tensor(l.get_tensor(), rank, cldnn::format::is_grouped(l.format));
}
padded_dims = dims;
pad_dims(padded_dims, l.format);
dnnl::memory::data_type dt = convert_data_type(l.data_type);
dnnl::memory::format_tag fmt = target_fmt == dnnl::memory::format_tag::undef ? convert_data_format(l.format) : target_fmt;
if (fmt == dnnl::memory::format_tag::undef) {
return create_memory_desc_from_format_string(dims, dt, convert_data_format_string(l.format));
throw ov::Exception("[GPU] Unexpected fmt: " + convert_data_format_string(l.format));
} else {
dnnl::memory::desc res(dims, dt, fmt);
std::copy(padded_dims.begin(), padded_dims.end(), res.data.padded_dims);
std::copy(padded_offset.begin(), padded_offset.end(), res.data.padded_offsets);
return res;
}
}
static void get_identical_order(std::vector<std::vector<size_t>>& orders, std::vector<size_t> order,
size_t first, size_t depth) {
if (depth == 0)
@@ -323,12 +238,11 @@ static void get_identical_order(std::vector<std::vector<size_t>>& orders, std::v
std::swap(order[first], order[idx]);
}
}
// Get candidate orders calculated by stride value of dnnl::memory::descriptor could be multiple
std::vector<std::vector<size_t>> get_candidate_orders(dnnl::memory::desc desc) {
std::vector<std::vector<size_t>> orders;
auto strides = desc.data.format_desc.blocking.strides;
std::vector<size_t> order(desc.data.ndims);
auto strides = desc.get_strides();
std::vector<size_t> order(desc.get_ndims());
std::iota(order.begin(), order.end(), 0);
std::sort(order.begin(), order.end(),
[&strides] (size_t ind_l, size_t ind_r) {
@@ -367,18 +281,17 @@ static bool compare_orders(std::vector<std::vector<size_t>> a, std::vector<size_
}
cldnn::format find_data_format(dnnl::memory::desc desc) {
auto blk = desc.data.format_desc.blocking;
auto order = get_candidate_orders(desc);
for (int32_t fmt_idx = format::bfyx ; fmt_idx < format::oiyx ; fmt_idx++) {
auto candidate_trait = format::traits(static_cast<format::type>(fmt_idx));
if (desc.data.ndims == static_cast<int>(candidate_trait._order.size())
&& blk.inner_nblks == static_cast<int>(candidate_trait.block_sizes.size())
if (desc.get_ndims() == static_cast<int>(candidate_trait._order.size())
&& desc.get_inner_nblks() == static_cast<int>(candidate_trait.block_sizes.size())
&& compare_orders(order, candidate_trait._order)) {
bool is_match = true;
for (size_t idx = 0 ; idx < candidate_trait.block_sizes.size() ; idx++) {
if (blk.inner_blks[idx] != static_cast<int>(candidate_trait.block_sizes[idx].second)
|| blk.inner_idxs[idx] != static_cast<int>(candidate_trait.block_sizes[idx].first)) {
if (desc.get_inner_blks()[idx] != static_cast<int>(candidate_trait.block_sizes[idx].second)
|| desc.get_inner_idxs()[idx] != static_cast<int>(candidate_trait.block_sizes[idx].first)) {
is_match = false;
break;
}
@@ -390,17 +303,16 @@ cldnn::format find_data_format(dnnl::memory::desc desc) {
std::stringstream msg;
msg << "Unsupported onednn dnnl::memory::desc find_data_format. "
<< "ndims: " << desc.data.ndims
<< ", inner_nblks: " << blk.inner_nblks
<< "ndims: " << desc.get_ndims()
<< ", inner_nblks: " << desc.get_inner_nblks()
<< ", inner_blks: ";
for (int i = 0; i < blk.inner_nblks; i++)
msg << "(blk " << blk.inner_blks[i] << ", idx " << blk.inner_idxs[i] << ") ";
for (int i = 0; i < desc.get_inner_nblks(); i++)
msg << "(blk " << desc.get_inner_blks()[i] << ", idx " << desc.get_inner_idxs()[i] << ") ";
throw std::runtime_error(msg.str());
}
cldnn::format find_format(dnnl::memory::desc desc, bool is_grouped) {
auto blk = desc.data.format_desc.blocking;
auto orders = get_candidate_orders(desc);
format start_format = format::oiyx;
@@ -409,8 +321,8 @@ cldnn::format find_format(dnnl::memory::desc desc, bool is_grouped) {
for (int32_t fmt_idx = start_format ; fmt_idx < format::format_num ; fmt_idx++) {
auto candidate_trait = format::traits(static_cast<format::type>(fmt_idx));
if (static_cast<size_t>(desc.data.ndims) == candidate_trait._order.size()
&& static_cast<size_t>(blk.inner_nblks) == candidate_trait.block_sizes.size()
if (static_cast<size_t>(desc.get_ndims()) == candidate_trait._order.size()
&& static_cast<size_t>(desc.get_inner_nblks()) == candidate_trait.block_sizes.size()
&& compare_orders(orders, candidate_trait._order)) {
// Compare all pairs of dimension number and block size to format_traits_map of all formats
bool is_match = true;
@@ -420,21 +332,21 @@ cldnn::format find_format(dnnl::memory::desc desc, bool is_grouped) {
if (is_grouped && candidate_trait.is_group_char(candidate_trait.internal_order[block_idx])) {
// inner_idx gets the index of group dimension in mem::desc when blocked axis is group
auto inner_idx = candidate_trait.order.find_first_of(candidate_trait.internal_order[block_idx]);
if (blk.inner_blks[idx] != block_size ||
blk.inner_idxs[idx] != static_cast<dnnl_dim_t>(inner_idx)) {
if (desc.get_inner_blks()[idx] != block_size ||
desc.get_inner_idxs()[idx] != static_cast<dnnl_dim_t>(inner_idx)) {
is_match = false;
break;
}
} else if (is_grouped) {
// g,o,i from cldnn formats are matching to a,b,c of dnnl. But g is at the end of internal order.
if (blk.inner_blks[idx] != block_size ||
(blk.inner_idxs[idx] - static_cast<dnnl_dim_t>(candidate_trait.group_num)) != block_idx) {
if (desc.get_inner_blks()[idx] != block_size ||
(desc.get_inner_idxs()[idx] - static_cast<dnnl_dim_t>(candidate_trait.group_num)) != block_idx) {
is_match = false;
break;
}
} else {
if (blk.inner_blks[idx] != block_size ||
blk.inner_idxs[idx] != block_idx) {
if (desc.get_inner_blks()[idx] != block_size ||
desc.get_inner_idxs()[idx] != block_idx) {
is_match = false;
break;
}
@@ -448,18 +360,19 @@ cldnn::format find_format(dnnl::memory::desc desc, bool is_grouped) {
std::stringstream msg;
msg << "Unsupported " << (is_grouped ? "grouped" : "") << "onednn dnnl::memory::desc find_format. "
<< "ndims: " << desc.data.ndims
<< ", inner_nblks: " << blk.inner_nblks
<< "ndims: " << desc.get_ndims()
<< ", inner_nblks: " << desc.get_inner_nblks()
<< ", inner_blks: ";
for (int i = 0; i < blk.inner_nblks; i++)
msg << "(blk " << blk.inner_blks[i] << ", idx " << blk.inner_idxs[i] << ") ";
for (int i = 0; i < desc.get_inner_nblks(); i++)
msg << "(blk " << desc.get_inner_blks()[i] << ", idx " << desc.get_inner_idxs()[i] << ") ";
for (auto order : orders) {
msg << ", strides_order : ";
for (const auto& value : order)
msg << value << " ";
}
msg << ", stride_value : ";
auto strides = desc.data.format_desc.blocking.strides;
auto strides = desc.get_strides();
for (size_t idx = 0; idx < orders[0].size() ; idx++) {
msg << strides[idx] << " ";
}
@@ -472,7 +385,7 @@ dnnl::algorithm convert_activation_func(cldnn::activation_func func) {
switch (func) {
case cldnn::activation_func::relu: return dnnl::algorithm::eltwise_relu;
case cldnn::activation_func::relu_negative_slope: return dnnl::algorithm::eltwise_relu;
case cldnn::activation_func::gelu: return dnnl::algorithm::eltwise_gelu;
case cldnn::activation_func::gelu: return dnnl::algorithm::eltwise_gelu_erf;
case cldnn::activation_func::elu: return dnnl::algorithm::eltwise_elu;
case cldnn::activation_func::mish: return dnnl::algorithm::eltwise_mish;
case cldnn::activation_func::swish: return dnnl::algorithm::eltwise_swish;
@@ -510,5 +423,6 @@ bool is_per_tensor(cldnn::data_node& node, int32_t& zp_val) {
template bool is_per_tensor<int8_t>(cldnn::data_node& node, int32_t& zp_val);
template bool is_per_tensor<uint8_t>(cldnn::data_node& node, int32_t& zp_val);
} // namespace onednn
} // namespace cldnn
@@ -465,8 +465,8 @@ private:
onednn_attrs = attrs;
}
bool has_out_scales(const std::shared_ptr<dnnl::primitive_attr>& attr);
dnnl::post_ops try_optimize_post_ops(dnnl::post_ops& p_ops, const std::shared_ptr<dnnl::primitive_attr>& attr, bool& optimization_is_completed);
#endif // ENABLE_ONEDNN_FOR_GPU
size_t num_outputs = 1;
};
+71 -180
View File
@@ -490,14 +490,6 @@ void program_node::set_preferred_output_fmt(size_t idx, format::type type) {
#ifdef ENABLE_ONEDNN_FOR_GPU
bool program_node::has_out_scales(const std::shared_ptr<dnnl::primitive_attr>& attr) {
int mask;
std::vector<float> scales;
attr->get_output_scales(mask, scales);
const auto drfv = reinterpret_cast<const int32_t&>(DNNL_RUNTIME_F32_VAL);
return !scales.empty() && (reinterpret_cast<const int32_t&>(scales[0]) == drfv);
}
dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const std::shared_ptr<dnnl::primitive_attr>& attr,
bool& optimization_is_completed) {
// Create new dnnl::post_ops object which will be filled inside the optimization process
@@ -512,9 +504,9 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
case onednn_post_op_type::eltwise_round:
{
dnnl::algorithm alg;
float scale, alpha, beta;
cur_p_ops.get_params_eltwise(idx, scale, alg, alpha, beta);
new_p_ops.append_eltwise(scale, alg, alpha, beta);
float alpha, beta;
cur_p_ops.get_params_eltwise(idx, alg, alpha, beta);
new_p_ops.append_eltwise(alg, alpha, beta);
break;
}
@@ -551,7 +543,7 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
cur_p_ops.get_params_sum(idx, scale, data_type);
// Only conv supports data type specification in append_sum. Other primitives(deconv, fc) do not support it.
if (is_type<convolution>()) {
new_p_ops.append_sum(scale, data_type);
new_p_ops.append_sum(scale, 0/*zero_point*/, data_type);
} else {
new_p_ops.append_sum(scale);
}
@@ -604,7 +596,6 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
};
auto type_is_binary_add = [](onednn_post_op_type type) -> bool { return type == onednn_post_op_type::binary_add; };
auto type_is_binary_mul = [](onednn_post_op_type type) -> bool { return type == onednn_post_op_type::binary_mul; };
auto type_is_sum = [](onednn_post_op_type type) -> bool { return type == onednn_post_op_type::sum; };
auto type_is_optimized_sum = [](onednn_post_op_type type) -> bool { return type == onednn_post_op_type::optimized_sum; };
auto type_is_scale = [](onednn_post_op_type type) -> bool { return type == onednn_post_op_type::scale; };
@@ -696,22 +687,19 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
GPU_DEBUG_TRACE << "after prev_post_op_idx: " << prev_post_op_idx << ", cur_post_op_idx: " << cur_post_op_idx << std::endl;
auto cur_idx = static_cast<int>(has_out_scales(attr) ? (cur_post_op_idx >= 1 ? cur_post_op_idx - 1 : 0) : cur_post_op_idx);
auto prev_idx = static_cast<int>(has_out_scales(attr) ? (prev_post_op_idx >= 1 ? prev_post_op_idx - 1 : 0) : prev_post_op_idx);
// If prev_idx and cur_idx are same, add the last post-op to dnnl::post_ops
if (prev_post_op_idx == post_ops_size - 1 && prev_idx == cur_idx && !type_is_any_optimized(prev_type)) {
add_post_op(prev_type, p_ops, optimized_p_ops, prev_idx);
// If prev_post_op_idx and cur_idx are same, add the last post-op to dnnl::post_ops
if (prev_post_op_idx == post_ops_size - 1 && prev_post_op_idx == cur_post_op_idx && !type_is_any_optimized(prev_type)) {
add_post_op(prev_type, p_ops, optimized_p_ops, prev_post_op_idx);
break;
}
// If this is the last pair and it's optimized - add the last post-op and go out from the cycle
if (cur_post_op_idx == post_ops_size - 1 && (type_is_any_optimized(cur_type) || type_is_any_optimized(prev_type))) {
if (!type_is_any_optimized(prev_type)) {
add_post_op(prev_type, p_ops, optimized_p_ops, prev_idx);
add_post_op(prev_type, p_ops, optimized_p_ops, prev_post_op_idx);
}
if (!type_is_any_optimized(cur_type)) {
add_post_op(cur_type, p_ops, optimized_p_ops, cur_idx);
add_post_op(cur_type, p_ops, optimized_p_ops, cur_post_op_idx);
}
break;
}
@@ -720,50 +708,35 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
auto eltw_and_eltw = type_is_eltwise(cur_type) && type_is_eltwise(prev_type);
auto bin_and_eltw = type_is_binary_add_or_mul(cur_type) && type_is_eltwise_linear(prev_type);
auto eltw_and_bin = type_is_eltwise_linear(cur_type) && type_is_binary_add_or_mul(prev_type);
auto sum_and_eltw = type_is_sum(cur_type) && type_is_eltwise(prev_type);
auto eltw_and_scale = type_is_eltwise_linear(cur_type) && type_is_scale(prev_type);
auto can_try_optimize = eltw_and_eltw ||
bin_and_eltw ||
eltw_and_bin ||
sum_and_eltw ||
eltw_and_scale;
bool cur_ops_pair_is_optimized = false;
GPU_DEBUG_TRACE << "prev_idx: " << prev_idx << " " << prev_type
<< ", cur_idx: " << cur_idx << " " << cur_type << std::endl;
if (can_try_optimize) {
if (eltw_and_eltw) {
dnnl::algorithm cur_alg, prev_alg;
float cur_scale, prev_scale, cur_alpha, prev_alpha, cur_beta, prev_beta;
float cur_alpha, prev_alpha, cur_beta, prev_beta;
p_ops.get_params_eltwise(prev_idx, prev_scale, prev_alg, prev_alpha, prev_beta);
p_ops.get_params_eltwise(cur_idx, cur_scale, cur_alg, cur_alpha, cur_beta);
p_ops.get_params_eltwise(prev_post_op_idx, prev_alg, prev_alpha, prev_beta);
p_ops.get_params_eltwise(cur_post_op_idx, cur_alg, cur_alpha, cur_beta);
auto eltw_linear_and_eltw_linear = type_is_eltwise_linear(cur_type) && type_is_eltwise_linear(prev_type);
auto eltw_linear_and_eltw_non_linear = type_is_eltwise_linear(cur_type) && !type_is_eltwise_linear(prev_type) && cur_beta == 0;
// eltwise_linear + eltwise_linear combination can be optimized always
if (eltw_linear_and_eltw_linear) {
dnnl::post_ops eltw_p_op;
float optimized_alpha = cur_alpha * prev_alpha * prev_scale;
float optimized_beta = cur_alpha * prev_beta * prev_scale + cur_beta;
float optimized_scale = cur_scale;
eltw_p_op.append_eltwise(optimized_scale, cur_alg, optimized_alpha, optimized_beta);
float optimized_alpha = cur_alpha * prev_alpha;
float optimized_beta = cur_alpha * prev_beta + cur_beta;
eltw_p_op.append_eltwise(cur_alg, optimized_alpha, optimized_beta);
// Combine 2 eltwises into one
add_post_op(cur_type, eltw_p_op, optimized_p_ops, 0);
} else if (eltw_linear_and_eltw_non_linear) {
dnnl::post_ops eltw_p_op;
eltw_p_op.append_eltwise(cur_scale * prev_scale * cur_alpha, prev_alg, prev_alpha, prev_beta);
// Combine 2 eltwises into one
add_post_op(prev_type, eltw_p_op, optimized_p_ops, 0);
}
if (eltw_linear_and_eltw_linear || eltw_linear_and_eltw_non_linear) {
// Marked current and previous eltwise operations as 'optimized' (they will be ignored on the next iteration of cycle)
cur_post_ops[cur_post_op_idx].op_type = onednn_post_op_type::optimized;
cur_post_ops[prev_post_op_idx].op_type = get_optimized_eltwise_type(prev_type);
@@ -782,18 +755,18 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
} else if (bin_and_eltw) {
dnnl::algorithm alg;
dnnl::memory::desc desc;
float scale, alpha, beta;
float alpha, beta;
cldnn::program_node& cur_node = get_dependency(cur_post_ops[cur_post_op_idx].mem_dep);
p_ops.get_params_binary(cur_idx, alg, desc);
p_ops.get_params_eltwise(prev_idx, scale, alg, alpha, beta);
p_ops.get_params_binary(cur_post_op_idx, alg, desc);
p_ops.get_params_eltwise(prev_post_op_idx, alg, alpha, beta);
// Eltwise operations can use runtime non-constant data buffers, so check that memory buffers consist of constant data only
auto bin_ops_can_be_optimized = cur_node.is_type<data>() && cur_node.is_constant() &&
cur_node.get_users().size() == 1 && desc.data_type() == dnnl_f32;
cur_node.get_users().size() == 1 && desc.get_data_type() == dnnl_f32;
auto bin_add_and_eltw = alpha == 1.0f && scale == 1.0f && type_is_binary_add(cur_type) && bin_ops_can_be_optimized;
auto bin_add_and_eltw = alpha == 1.0f && type_is_binary_add(cur_type) && bin_ops_can_be_optimized;
auto bin_mul_and_eltw = beta == 0.f && type_is_binary_mul(cur_type) && bin_ops_can_be_optimized;
if (bin_add_and_eltw || bin_mul_and_eltw) {
@@ -812,7 +785,7 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
}
} else {
for (size_t data_idx = 0; data_idx < cur_bin_mem_size; data_idx++) {
bin_and_eltw_lock[data_idx] *= alpha * scale;
bin_and_eltw_lock[data_idx] *= alpha;
}
}
@@ -824,18 +797,18 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
} else if (eltw_and_bin) {
dnnl::algorithm alg;
dnnl::memory::desc desc;
float scale, alpha, beta;
float alpha, beta;
cldnn::program_node& prev_node = get_dependency(cur_post_ops[prev_post_op_idx].mem_dep);
p_ops.get_params_eltwise(cur_idx, scale, alg, alpha, beta);
p_ops.get_params_binary(prev_idx, alg, desc);
p_ops.get_params_eltwise(cur_post_op_idx, alg, alpha, beta);
p_ops.get_params_binary(prev_post_op_idx, alg, desc);
// Eltwise operations can use runtime non-constant data buffers, so check that memory buffers consist of constant data only
auto bin_ops_can_be_optimized = prev_node.is_type<data>() && prev_node.is_constant() &&
prev_node.get_users().size() == 1 && desc.data_type() == dnnl_f32;
prev_node.get_users().size() == 1 && desc.get_data_type() == dnnl_f32;
auto eltw_and_bin_add = alpha == 1.0f && scale == 1.0f && type_is_binary_add(prev_type) && bin_ops_can_be_optimized;
auto eltw_and_bin_add = alpha == 1.0f && type_is_binary_add(prev_type) && bin_ops_can_be_optimized;
auto eltw_and_bin_mul = beta == 0.f && type_is_binary_mul(prev_type) && bin_ops_can_be_optimized;
if (eltw_and_bin_add || eltw_and_bin_mul) {
@@ -854,76 +827,22 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
}
} else {
for (size_t data_idx = 0; data_idx < prev_bin_mem_size; data_idx++) {
eltw_and_bin_lock[data_idx] *= alpha * scale;
eltw_and_bin_lock[data_idx] *= alpha;
}
}
// Marked current eltwise operation as 'optimized' (it will be ignored on the next iteration of cycle)
cur_post_ops[cur_post_op_idx].op_type = onednn_post_op_type::optimized;
cur_ops_pair_is_optimized = true;
}
} else if (sum_and_eltw) {
dnnl::algorithm alg;
float sum_scale, eltw_scale, alpha, beta;
dnnl::algorithm next_alg;
float next_scale, next_alpha, next_beta;
int64_t next_idx = cur_idx + 1;
int64_t next_post_op_idx = cur_post_op_idx + 1;
bool can_optimize_eltw_and_sum = false;
if (cur_post_op_idx < post_ops_size - 1) {
auto next_type = cur_post_ops[next_post_op_idx].op_type;
if (type_is_eltwise_linear(next_type)) {
p_ops.get_params_eltwise(next_idx, next_scale, next_alg, next_alpha, next_beta);
if (next_beta == 0)
can_optimize_eltw_and_sum = true;
}
}
// Try to optimize eltwise (any) + sum + eltwise_linear (with beta = 0) chain of operations
if (can_optimize_eltw_and_sum) {
dnnl::memory::data_type data_type;
p_ops.get_params_sum(cur_idx, sum_scale, data_type);
p_ops.get_params_eltwise(prev_idx, eltw_scale, alg, alpha, beta);
dnnl::post_ops eltw_p_op_prev, sum_p_op;
eltw_p_op_prev.append_eltwise(eltw_scale * next_alpha * next_scale, alg, alpha, beta);
// Only conv supports data type specification in append_sum. Other primitives(deconv, fc) do not support it.
if (is_type<convolution>()) {
sum_p_op.append_sum(sum_scale * next_alpha, data_type);
} else {
sum_p_op.append_sum(sum_scale * next_alpha);
}
add_post_op(prev_type, eltw_p_op_prev, optimized_p_ops, 0);
add_post_op(cur_type, sum_p_op, optimized_p_ops, 0);
// Marked current, previous and next operations as 'optimized' (they will be ignored on the next iteration of cycle)
cur_post_ops[prev_post_op_idx].op_type = get_optimized_eltwise_type(prev_type);
cur_post_ops[cur_post_op_idx].op_type = onednn_post_op_type::optimized_sum;
cur_post_ops[next_post_op_idx].op_type = onednn_post_op_type::optimized;
// Set the flag if extra optimizations checking is needed
if (next_post_op_idx < post_ops_size - 1) {
if (type_is_eltwise_linear(cur_post_ops[next_post_op_idx + 1].op_type) ||
type_is_optimized_eltwise(cur_post_ops[next_post_op_idx + 1].op_type)) {
optimization_is_completed = true;
}
}
cur_ops_pair_is_optimized = true;
}
} else if (eltw_and_scale) {
dnnl::algorithm alg;
float eltw_scale, alpha, beta;
float alpha, beta;
cldnn::program_node& prev_node = get_dependency(cur_post_ops[prev_post_op_idx].mem_dep);
p_ops.get_params_eltwise(cur_idx, eltw_scale, alg, alpha, beta);
p_ops.get_params_eltwise(cur_post_op_idx, alg, alpha, beta);
// Eltwise can be inserted into the output_scale if cur_beta is equal to 0.f
if (beta == 0.f && prev_node.get_output_layout().data_type == data_types::f32) {
@@ -937,7 +856,7 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
// Update all scale coefficients
for (size_t data_idx = 0; data_idx < prev_scale_mem_size; data_idx++) {
eltw_and_scale_lock[data_idx] *= alpha * eltw_scale;
eltw_and_scale_lock[data_idx] *= alpha;
}
// Marked current eltwise operation as 'optimized' (it will be ignored on the next iteration of cycle)
@@ -949,14 +868,14 @@ dnnl::post_ops program_node::try_optimize_post_ops(dnnl::post_ops& p_ops, const
}
// If no optimizations have been applied then copy post-op info into the new optimized_p_ops structure
if (!(has_out_scales(attr) && prev_post_op_idx == 0) && !cur_ops_pair_is_optimized) {
add_post_op(prev_type, p_ops, optimized_p_ops, prev_idx);
if (!cur_ops_pair_is_optimized) {
add_post_op(prev_type, p_ops, optimized_p_ops, prev_post_op_idx);
}
if (cur_post_op_idx == post_ops_size - 1 && !cur_ops_pair_is_optimized) {
add_post_op(cur_type, p_ops, optimized_p_ops, cur_idx);
add_post_op(cur_type, p_ops, optimized_p_ops, cur_post_op_idx);
optimization_done = true;
} else if (cur_post_ops[cur_post_op_idx].op_type != onednn_post_op_type::optimized) {
} else if (cur_post_ops[cur_post_op_idx].op_type != onednn_post_op_type::optimized && cur_post_op_idx < post_ops_size - 1) {
cur_post_op_idx++;
prev_post_op_idx++;
}
@@ -1004,6 +923,7 @@ void program_node::init_onednn_primitive_attributes() {
type == onednn_post_op_type::binary_relu ||
type == onednn_post_op_type::scale ||
type == onednn_post_op_type::sum;
if (has_memory_buffers)
memory_offset++;
};
@@ -1012,7 +932,7 @@ void program_node::init_onednn_primitive_attributes() {
for (size_t idx = 0; idx < cldnn_post_ops.size(); idx++) {
auto& desc = cldnn_post_ops[idx];
if (desc.is_type<activation>()) {
auto fused_desc = desc.typed_desc<activation>();;
auto fused_desc = desc.typed_desc<activation>();
if (fused_desc->activation_function == cldnn::activation_func::relu_negative_slope
&& !fused_desc->additional_params_input.empty()) {
auto dep_idx = cldnn_post_ops[idx].dep_start_idx;
@@ -1021,18 +941,20 @@ void program_node::init_onednn_primitive_attributes() {
update_onednn_post_op_list(onednn_post_op_type::binary_relu, dep_idx);
} else if (fused_desc->activation_function == cldnn::activation_func::hard_sigmoid) {
// Splits hard_sigmoid activation into eltwise_linear, min and max.
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear,
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear,
fused_desc->additional_params.a, fused_desc->additional_params.b);
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_clip, 0.0f, 1.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_clip, 0.0f, 1.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
update_onednn_post_op_list(onednn_post_op_type::eltwise_clip, empty_mem);
} else {
dnnl::algorithm alg = onednn::convert_activation_func(fused_desc->activation_function);
// Usage of alpha and beta between cldnn::pow and dnnl::eltwise::pow is different : d = pow(src, a) / d = a * pow(src, b)
if (alg == dnnl::algorithm::eltwise_pow)
post_ops.append_eltwise(1.0f, alg, 1.0f, fused_desc->additional_params.a);
post_ops.append_eltwise(alg, 1.0f, fused_desc->additional_params.a);
else if (alg == dnnl::algorithm::eltwise_hardswish) // mapping val * min(max(0, val + 3), 6) / 6 to val * max(min(1, alpha * val + beta), 0)
post_ops.append_eltwise(alg, 1/6.f, 0.5f);
else
post_ops.append_eltwise(1.0f, alg, fused_desc->additional_params.a, fused_desc->additional_params.b);
post_ops.append_eltwise(alg, fused_desc->additional_params.a, fused_desc->additional_params.b);
update_onednn_post_op_list(onednn_post_op_type::eltwise_act, empty_mem);
}
@@ -1044,7 +966,7 @@ void program_node::init_onednn_primitive_attributes() {
auto fusing_type = onednn_add_fusing_helpers::get_add_fusing_type(*this, cldnn_post_ops[idx]);
if (fusing_type == add_fusing_type::sum && num_sum_post_ops == 0) {
if (is_type<convolution>()) {
post_ops.append_sum(1.0f, onednn::convert_data_type(in.data_type));
post_ops.append_sum(1.0f, 0/*zero-point*/, onednn::convert_data_type(in.data_type));
} else {
post_ops.append_sum(1.0f);
}
@@ -1060,24 +982,9 @@ void program_node::init_onednn_primitive_attributes() {
post_ops.append_binary(dnnl::algorithm::binary_sub, in_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_sub, dep_idx);
} else if (desc.typed_desc<eltwise>()->mode == eltwise_mode::prod) {
auto input_datatype = get_dependency(0).get_output_layout().data_type;
// convolution using post-op output scales can only be used when i8/u8 input (which use integer accumulator)
bool cant_use_output_scales =
idx != 0 ||
has_out_scales(attrs) ||
is_type<pooling>() ||
is_type<reduce>() ||
(is_type<convolution>() && data_type_traits::is_floating_point(input_datatype)) ||
(is_type<deconvolution>() && data_type_traits::is_floating_point(input_datatype));
if (cant_use_output_scales) {
dnnl::memory::desc in_desc = onednn::layout_to_memory_desc(in, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx);
} else {
int mask = in.count() > 1 ? 2 : 0;
attrs->set_output_scales(mask, {DNNL_RUNTIME_F32_VAL});
update_onednn_post_op_list(onednn_post_op_type::scale, dep_idx);
}
dnnl::memory::desc in_desc = onednn::layout_to_memory_desc(in, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx);
} else {
std::stringstream error_msg;
error_msg << "Unsupported eltwise mode: " << static_cast<int>(desc.typed_desc<eltwise>()->mode) << ". ";
@@ -1093,30 +1000,22 @@ void program_node::init_onednn_primitive_attributes() {
// 1. pre-scale & pre-shift
{
if (q_param->per_tensor_input_scale && q_param->per_tensor_input_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->in_scale, q_param->in_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->in_scale, q_param->in_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
if (q_param->per_tensor_input_scale) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->in_scale, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->in_scale, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto in_scale = get_dependency(dep_idx++).get_output_layout();
if (idx == 0 && !has_out_scales(attrs) && in_scale.data_type == data_types::f32 &&
is_type<convolution>() &&
!data_type_traits::is_floating_point(get_dependency(0).get_output_layout().data_type)) {
int mask = in_scale.count() > 1 ? 2 : 0;
attrs->set_output_scales(mask, {DNNL_RUNTIME_F32_VAL});
update_onednn_post_op_list(onednn_post_op_type::scale, dep_idx - 1);
} else {
dnnl::memory::desc in_scale_desc = onednn::layout_to_memory_desc(in_scale, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_scale_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx - 1);
}
dnnl::memory::desc in_scale_desc = onednn::layout_to_memory_desc(in_scale, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_scale_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx - 1);
}
if (q_param->has_pre_shift) {
if (q_param->per_tensor_input_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1.0f, q_param->in_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1.0f, q_param->in_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto in_shift = get_dependency(dep_idx++).get_output_layout();
@@ -1133,7 +1032,7 @@ void program_node::init_onednn_primitive_attributes() {
{
bool output_type_is_int8 = out_dt == data_types::u8 || out_dt == data_types::i8;
if (!output_type_is_int8) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_round, 0.0f, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_round, 0.0f, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_round, empty_mem);
}
}
@@ -1142,12 +1041,12 @@ void program_node::init_onednn_primitive_attributes() {
{
if (q_param->has_post_scale && q_param->has_post_shift &&
q_param->per_tensor_output_scale && q_param->per_tensor_output_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->out_scale, q_param->out_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->out_scale, q_param->out_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
if (q_param->has_post_scale) {
if (q_param->per_tensor_output_scale) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->out_scale, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->out_scale, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto out_scale = get_dependency(dep_idx++).get_output_layout();
@@ -1159,7 +1058,7 @@ void program_node::init_onednn_primitive_attributes() {
if (q_param->has_post_shift) {
if (q_param->per_tensor_output_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1.0f, q_param->out_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1.0f, q_param->out_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto out_shift = get_dependency(dep_idx++).get_output_layout();
@@ -1176,7 +1075,7 @@ void program_node::init_onednn_primitive_attributes() {
if (q_param->has_clamp || idx < cldnn_post_ops.size() - 1) {
float out_lo = q_param->has_min_clamp ? q_param->out_lo : data_type_traits::min<float>(out_dt);
float out_hi = q_param->has_max_clamp ? q_param->out_hi : data_type_traits::max<float>(out_dt);
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_clip, out_lo, out_hi);
post_ops.append_eltwise(dnnl::algorithm::eltwise_clip, out_lo, out_hi);
update_onednn_post_op_list(onednn_post_op_type::eltwise_clip, empty_mem);
}
}
@@ -1202,30 +1101,22 @@ void program_node::init_onednn_primitive_attributes() {
// 2. pre-scale & pre-shift
{
if (q_param->per_tensor_input_scale && q_param->per_tensor_input_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->in_scale, q_param->in_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->in_scale, q_param->in_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
if (q_param->per_tensor_input_scale) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->in_scale, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->in_scale, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto in_scale = get_dependency(dep_idx++).get_output_layout();
if (idx == 0 && !q_param->has_clamp && !has_out_scales(attrs) && in_scale.data_type == data_types::f32 &&
is_type<convolution>() &&
!data_type_traits::is_floating_point(get_dependency(0).get_output_layout().data_type)) {
int mask = in_scale.count() > 1 ? 2 : 0;
attrs->set_output_scales(mask, {DNNL_RUNTIME_F32_VAL});
update_onednn_post_op_list(onednn_post_op_type::scale, dep_idx - 1);
} else {
dnnl::memory::desc in_scale_desc = onednn::layout_to_memory_desc(in_scale, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_scale_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx - 1);
}
dnnl::memory::desc in_scale_desc = onednn::layout_to_memory_desc(in_scale, dnnl::memory::format_tag::ab, true);
post_ops.append_binary(dnnl::algorithm::binary_mul, in_scale_desc);
update_onednn_post_op_list(onednn_post_op_type::binary_mul, dep_idx - 1);
}
if (q_param->has_pre_shift) {
if (q_param->per_tensor_input_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1.0f, q_param->in_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1.0f, q_param->in_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto in_shift = get_dependency(dep_idx++).get_output_layout();
@@ -1239,7 +1130,7 @@ void program_node::init_onednn_primitive_attributes() {
// 3. round
{
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_round, 0.0f, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_round, 0.0f, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_round, empty_mem);
}
@@ -1247,12 +1138,12 @@ void program_node::init_onednn_primitive_attributes() {
{
if (q_param->has_post_scale && q_param->has_post_shift &&
q_param->per_tensor_output_scale && q_param->per_tensor_output_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->out_scale, q_param->out_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->out_scale, q_param->out_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
if (q_param->has_post_scale) {
if (q_param->per_tensor_output_scale) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, q_param->out_scale, 0.0f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, q_param->out_scale, 0.0f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto out_scale = get_dependency(dep_idx++).get_output_layout();
@@ -1264,7 +1155,7 @@ void program_node::init_onednn_primitive_attributes() {
if (q_param->has_post_shift) {
if (q_param->per_tensor_output_shift) {
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1.0f, q_param->out_shift);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1.0f, q_param->out_shift);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto out_shift = get_dependency(dep_idx++).get_output_layout();
@@ -1290,16 +1181,16 @@ void program_node::init_onednn_primitive_attributes() {
auto activation_type = get_fused_activations_funcs()[i];
if (activation_type == cldnn::activation_func::hsigmoid) {
// Unsupported hsigmoid oneDNN gpu, splits hsigmoid activation min(max(val + 3, 0), 6) / 6
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1.f, 3.f);
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_clip, 0.f, 6.f);
post_ops.append_eltwise(1.0f, dnnl::algorithm::eltwise_linear, 1/6.f, 0.f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1.f, 3.f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_clip, 0.f, 6.f);
post_ops.append_eltwise(dnnl::algorithm::eltwise_linear, 1/6.f, 0.f);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
update_onednn_post_op_list(onednn_post_op_type::eltwise_clip, empty_mem);
update_onednn_post_op_list(onednn_post_op_type::eltwise_linear, empty_mem);
} else {
auto params = get_fused_activations_params()[i];
dnnl::algorithm alg = onednn::convert_activation_func(activation_type);
post_ops.append_eltwise(1.0f, alg, params.a, params.b);
post_ops.append_eltwise(alg, params.a, params.b);
update_onednn_post_op_list(onednn_post_op_type::eltwise_act, empty_mem);
}
}
@@ -165,46 +165,3 @@ INSTANTIATE_TEST_SUITE_P(smoke, weight_format_test_match_dnnl,
{{32, 32, 8, 8}, dnnl::memory::data_type::u8, dnnl::memory::format_tag::BAcd4b8a8b4a, cldnn::format::is_os_yx_isa4_osa8_isv8_osv4},
}),
weight_format_test_match_dnnl::PrintToString);
struct stride_matching_test_params {
dnnl_desc_params test_desc;
int inner_nblks; // The number of innermost blocks
dnnl_dims_t inner_idxs; // The size of the blocks, e.g. `{4, 16, 4}` in case of `OIhw_4i16o4i`
dnnl_dims_t inner_blks; // The logical indices of the blocks, e.g. `{1, 0, 1}` in case of 4i16o4i
cldnn::format cldnn_format;
};
class weight_format_test_with_stride : public testing::TestWithParam<stride_matching_test_params> {
public:
static std::string PrintToString(testing::TestParamInfo<stride_matching_test_params> param_info) {
auto strides = param_info.param.test_desc.strides;
std::string res = " stride : {";
for (auto stride : strides) {
res += std::to_string(stride) + " ";
}
res += "} > " + format::traits(param_info.param.cldnn_format).str;
return res;
}
};
TEST_P(weight_format_test_with_stride, test_match_data_format) {
auto param = GetParam();
dnnl::memory::desc test_desc(param.test_desc.dims, param.test_desc.data_type, param.test_desc.strides);
test_desc.data.format_desc.blocking.inner_nblks = param.inner_nblks;
for (auto idx = 0; idx < param.inner_nblks; idx++) {
test_desc.data.format_desc.blocking.inner_idxs[idx] = param.inner_idxs[idx];
test_desc.data.format_desc.blocking.inner_blks[idx] = param.inner_blks[idx];
}
auto result = onednn::find_format(test_desc, false);
ASSERT_TRUE(result == param.cldnn_format);
}
INSTANTIATE_TEST_SUITE_P(smoke, weight_format_test_with_stride,
testing::ValuesIn(std::vector<stride_matching_test_params>{
{{{16, 16, 1, 1}, dnnl::memory::data_type::f16, {16, 256, 1, 1}}, 2, {1, 0}, {16, 16}, cldnn::format::is_os_yx_isv16_osv16},
{{{16, 16, 1, 1}, dnnl::memory::data_type::f16, {256, 16, 1, 1}}, 2, {1, 0}, {16, 16}, cldnn::format::os_is_yx_isv16_osv16},
}),
weight_format_test_with_stride::PrintToString);
@@ -9194,6 +9194,174 @@ TEST(convolution_gpu_onednn, padding_for_cldnn_kernel_after_onednn) {
}
}
TEST(convolution_gpu_onednn, quantized_onednn_convolution_u8s8f32_asymmetric_activations_per_tensor) {
auto& engine = get_test_engine();
if (!engine.get_device_info().supports_immad)
return;
auto input = engine.allocate_memory({ data_types::u8, format::bfyx, { 1, 1, 5, 4 } });
auto weights = engine.allocate_memory({ data_types::i8, format::bfyx, { 2, 1, 3, 3 } });
auto biases = engine.allocate_memory({ data_types::f32, format::bfyx, { 1, 2, 1, 1 } });
auto a_zp = engine.allocate_memory({ data_types::u8, format::bfyx, { 1, 1, 1, 1 } });
set_values<uint8_t>(input, { 1, 2, 3, 4, 5,
2, 2, 3, 4, 6,
3, 3, 3, 5, 1,
1, 1, 1, 1, 1 });
set_values<int8_t>(weights, { 1, 2, -1,
-2, 1, 2,
9, 7, -1,
9, 0, -4,
-1, 3, 2,
0, 2, 5 });
set_values<uint8_t>(a_zp, { 2 });
set_values(biases, { 1.0f, -8.0f });
VVVF<float> output_vec = {
{
{ 16.0f, 42.0f, -13.0f },
{ 2.0f, 8.0f, 2.0f }
},
{
{ -12.0f, 3.0f, 15.0f },
{ -7.0f, 1.0f, -16.0f }
} };
topology topology(
input_layout("input", input->get_layout()),
data("weights", weights),
data("biases", biases),
data("a_zp", a_zp),
convolution("conv", input_info("input"), { "weights" }, { "biases" }, { }, { "a_zp" }, 1, data_types::f32,
{ 2, 2 }, { 0, 0 }, { 1, 1 }, tensor{ 1, 2, 3, 2 }, false),
reorder("out", input_info("conv"), format::bfyx, data_types::f32));
ExecutionConfig config;
ov::intel_gpu::ImplementationDesc conv_impl = { format::byxf, "", impl_types::onednn };
config.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{ { "conv", conv_impl }}));
config.set_property(ov::intel_gpu::optimize_data(true));
config.set_property(ov::intel_gpu::queue_type(QueueTypes::in_order));
network network(engine, topology, config);
network.set_input_data("input", input);
auto outputs = network.execute();
ASSERT_EQ(outputs.begin()->first, "out");
auto output_memory = outputs.at("out").get_memory();
cldnn::mem_lock<float> output_ptr(output_memory, get_test_stream());
auto output_layout = output_memory->get_layout();
int y_size = output_layout.spatial(1);
int x_size = output_layout.spatial(0);
int f_size = output_layout.feature();
int b_size = output_layout.batch();
ASSERT_EQ(output_layout.format, format::bfyx);
ASSERT_EQ(y_size, 2);
ASSERT_EQ(x_size, 3);
ASSERT_EQ(f_size, 2);
ASSERT_EQ(b_size, 1);
for (int f = 0; f < f_size; f++)
for (int y = 0; y < y_size; ++y) {
for (int x = 0; x < x_size; ++x) {
ASSERT_NEAR(output_vec[f][y][x], ((float)output_ptr[f * y_size * x_size + y * x_size + x]), 1e-5f) <<
" x="<< x << " y=" << y << " f=" << f;
}
}
}
TEST(convolution_gpu_onednn, quantized_onednn_convolution_u8s8f32_asymmetric_activations_per_channel) {
auto& engine = get_test_engine();
if (!engine.get_device_info().supports_immad)
return;
auto input = engine.allocate_memory({ data_types::u8, format::bfyx, { 1, 2, 5, 4 } });
auto weights = engine.allocate_memory({ data_types::i8, format::bfyx, { 2, 2, 3, 3 } });
auto biases = engine.allocate_memory({ data_types::f32, format::bfyx, { 1, 2, 1, 1 } });
auto a_zp = engine.allocate_memory({ data_types::u8, format::bfyx, { 1, 2, 1, 1 } });
set_values<uint8_t>(input, { 1, 2, 3, 4, 5,
2, 2, 3, 4, 6,
3, 3, 3, 5, 1,
1, 1, 1, 1, 1,
1, 2, 3, 4, 5,
2, 2, 3, 4, 6,
3, 3, 3, 5, 1,
1, 1, 1, 1, 1 });
set_values<int8_t>(weights, { 1, 2, -1,
-2, 1, 2,
9, 7, -1,
9, 0, -4,
-1, 3, 2,
0, 2, 5,
1, 2, -1,
-2, 1, 2,
9, 7, -1,
9, 0, -4,
-1, 3, 2,
0, 2, 5 });
set_values<uint8_t>(a_zp, { 2, 5 });
set_values(biases, { 1.0f, -8.0f });
VVVF<float> output_vec = {
{
{ -36.0f, 5.0f, -14.0f },
{ -24.0f, -10.0f, -30.0f }
},
{
{ -45.0f, -4.0f, -23.0f },
{ -33.0f, -19.0f, -39.0f }
} };
topology topology(
input_layout("input", input->get_layout()),
data("weights", weights),
data("biases", biases),
data("a_zp", a_zp),
convolution("conv", input_info("input"), { "weights" }, { "biases" }, { }, { "a_zp" }, 1, data_types::f32,
{ 2, 2 }, { 0, 0 }, { 1, 1 }, tensor{ 1, 2, 3, 2 }, false),
reorder("out", input_info("conv"), format::bfyx, data_types::f32));
ExecutionConfig config;
ov::intel_gpu::ImplementationDesc conv_impl = { format::byxf, "", impl_types::onednn };
config.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{ { "conv", conv_impl }}));
config.set_property(ov::intel_gpu::optimize_data(true));
config.set_property(ov::intel_gpu::queue_type(QueueTypes::in_order));
network network(engine, topology, config);
network.set_input_data("input", input);
auto outputs = network.execute();
ASSERT_EQ(outputs.begin()->first, "out");
auto output_memory = outputs.at("out").get_memory();
cldnn::mem_lock<float> output_ptr(output_memory, get_test_stream());
auto output_layout = output_memory->get_layout();
int y_size = output_layout.spatial(1);
int x_size = output_layout.spatial(0);
int f_size = output_layout.feature();
int b_size = output_layout.batch();
ASSERT_EQ(output_layout.format, format::bfyx);
ASSERT_EQ(y_size, 2);
ASSERT_EQ(x_size, 3);
ASSERT_EQ(f_size, 2);
ASSERT_EQ(b_size, 1);
for (int f = 0; f < f_size; f++)
for (int y = 0; y < y_size; ++y) {
for (int x = 0; x < x_size; ++x) {
ASSERT_NEAR(output_vec[f][y][x], ((float)output_ptr[f * y_size * x_size + y * x_size + x]), 1e-5f) <<
" x="<< x << " y=" << y << " f=" << f;
}
}
}
#endif // ENABLE_ONEDNN_FOR_GPU
template <typename T>