[GPU] Added paddings processing for dynamic convolutions primitives; enabled convolution osv16 optimized shape agnostic kernel (#19001)

This commit is contained in:
Sergey Shlyapnikov authored and GitHub committed 2023-08-08 14:57:54 +02:00
1 parent 5ae9d80113
commit e7565eda3e
24 files changed
+297 -91

No files matched your search

@@ -155,7 +155,10 @@ void prepare_padding::run(program& p) {
continue;
auto conv = node.get_primitive();
if (node.is_dynamic()) continue;
if (node.is_dynamic() && !node.use_explicit_padding())
continue;
auto& conv_input_node = node.get_dependency(0);
auto conv_layout = node.get_output_layout();
@@ -197,7 +200,8 @@ void prepare_padding::run(program& p) {
layout filter_layout = filter_node.get_output_layout().convert_to_weights_layout(conv->grouped_weights_shape);
// Compute initial required paddings for primitive used as input for convolution.
auto pad = conv->padding_begin;
auto padding_begin = conv->padding_begin;
auto padding_end = conv->padding_end;
auto stride = conv->stride;
auto dilation = conv->dilation;
uint32_t stride_z = stride.size() >= 3 ? static_cast<uint32_t>(stride[stride.size() - 3]) : 1;
@@ -208,23 +212,40 @@ void prepare_padding::run(program& p) {
uint32_t dilation_y = dilation.size() >= 2 ? static_cast<uint32_t>(dilation[dilation.size() - 2]) : 1;
uint32_t dilation_x = dilation.size() >= 1 ? static_cast<uint32_t>(dilation[dilation.size() - 1]) : 1;
tensor::value_type pad_z = pad.size() >= 3 ? pad[pad.size() - 3] : 0;
tensor::value_type pad_y = pad.size() >= 2 ? pad[pad.size() - 2] : 0;
tensor::value_type pad_x = pad.size() >= 1 ? pad[pad.size() - 1] : 0;
tensor::value_type pad_z = padding_begin.size() >= 3 ? padding_begin[padding_begin.size() - 3] : 0;
tensor::value_type pad_y = padding_begin.size() >= 2 ? padding_begin[padding_begin.size() - 2] : 0;
tensor::value_type pad_x = padding_begin.size() >= 1 ? padding_begin[padding_begin.size() - 1] : 0;
auto input_limit_x = -pad_x + (conv_layout.spatial(0) - 1) * stride_x +
(filter_layout.spatial(0) - 1) * dilation_x + 1;
auto input_limit_y = -pad_y + (conv_layout.spatial(1) - 1) * stride_y +
(filter_layout.spatial(1) - 1) * dilation_y + 1;
auto input_limit_z = -pad_z + (conv_layout.spatial(2) - 1) * stride_z +
(filter_layout.spatial(2) - 1) * dilation_z + 1;
tensor::value_type padding_begin_x, padding_begin_y, padding_begin_z;
tensor::value_type padding_end_x, padding_end_y, padding_end_z;
auto padding_begin_x = std::max(pad_x, 0);
auto padding_begin_y = std::max(pad_y, 0);
auto padding_begin_z = std::max(pad_z, 0);
auto padding_end_x = std::max<tensor::value_type>(input_limit_x - prev_prim_output_layout.spatial(0), 0);
auto padding_end_y = std::max<tensor::value_type>(input_limit_y - prev_prim_output_layout.spatial(1), 0);
auto padding_end_z = std::max<tensor::value_type>(input_limit_z - prev_prim_output_layout.spatial(2), 0);
if (node.is_dynamic() && node.use_explicit_padding()) {
padding_begin_x = std::max(pad_x, 0);
padding_begin_y = std::max(pad_y, 0);
padding_begin_z = std::max(pad_z, 0);
pad_z = padding_end.size() >= 3 ? padding_end[padding_end.size() - 3] : 0;
pad_y = padding_end.size() >= 2 ? padding_end[padding_end.size() - 2] : 0;
pad_x = padding_end.size() >= 1 ? padding_end[padding_end.size() - 1] : 0;
padding_end_x = std::max(pad_x, 0);
padding_end_y = std::max(pad_y, 0);
padding_end_z = std::max(pad_z, 0);
} else {
auto input_limit_x = -pad_x + (conv_layout.spatial(0) - 1) * stride_x +
(filter_layout.spatial(0) - 1) * dilation_x + 1;
auto input_limit_y = -pad_y + (conv_layout.spatial(1) - 1) * stride_y +
(filter_layout.spatial(1) - 1) * dilation_y + 1;
auto input_limit_z = -pad_z + (conv_layout.spatial(2) - 1) * stride_z +
(filter_layout.spatial(2) - 1) * dilation_z + 1;
padding_begin_x = std::max(pad_x, 0);
padding_begin_y = std::max(pad_y, 0);
padding_begin_z = std::max(pad_z, 0);
padding_end_x = std::max<tensor::value_type>(input_limit_x - prev_prim_output_layout.spatial(0), 0);
padding_end_y = std::max<tensor::value_type>(input_limit_y - prev_prim_output_layout.spatial(1), 0);
padding_end_z = std::max<tensor::value_type>(input_limit_z - prev_prim_output_layout.spatial(2), 0);
}
// Adjust right padding, so entire buffer size in X dimension is properly aligned.
// TODO: NOTE: Will be reenabled with next check-in once heuristic for line-aligned algorithm will be added.
@@ -85,6 +85,7 @@ public:
ov::CoordinateDiff pads_begin(primitive->padding_begin.begin(), primitive->padding_begin.end());
ov::CoordinateDiff pads_end(primitive->padding_end.begin(), primitive->padding_end.end());
const auto auto_pad = primitive->auto_pad;
conv_params.has_explicit_paddings = primitive->auto_pad == ov::op::PadType::EXPLICIT;
if (auto_pad == ov::op::PadType::SAME_UPPER || auto_pad == ov::op::PadType::SAME_LOWER) {
pads_begin.clear();
pads_end.clear();
@@ -110,10 +111,15 @@ public:
uint32_t kz = weights_layout.spatial(2);
conv_params.filterSize = { kx, ky, kz };
uint32_t pad_z = std::max<std::ptrdiff_t>(pads_begin.size() >= 3 ? pads_begin[pads_begin.size() - 3] : 0, 0);
uint32_t pad_y = std::max<std::ptrdiff_t>(pads_begin.size() >= 2 ? pads_begin[pads_begin.size() - 2] : 0, 0);
uint32_t pad_x = std::max<std::ptrdiff_t>(pads_begin.size() >= 1 ? pads_begin[pads_begin.size() - 1] : 0, 0);
conv_params.padding = {pad_x, pad_y, pad_z};
uint32_t pad_begin_z = std::max<std::ptrdiff_t>(pads_begin.size() >= 3 ? pads_begin[pads_begin.size() - 3] : 0, 0);
uint32_t pad_begin_y = std::max<std::ptrdiff_t>(pads_begin.size() >= 2 ? pads_begin[pads_begin.size() - 2] : 0, 0);
uint32_t pad_begin_x = std::max<std::ptrdiff_t>(pads_begin.size() >= 1 ? pads_begin[pads_begin.size() - 1] : 0, 0);
conv_params.padding_begin = {pad_begin_x, pad_begin_y, pad_begin_z};
uint32_t pad_end_z = std::max<std::ptrdiff_t>(pads_end.size() >= 3 ? pads_end[pads_end.size() - 3] : 0, 0);
uint32_t pad_end_y = std::max<std::ptrdiff_t>(pads_end.size() >= 2 ? pads_end[pads_end.size() - 2] : 0, 0);
uint32_t pad_end_x = std::max<std::ptrdiff_t>(pads_end.size() >= 1 ? pads_end[pads_end.size() - 1] : 0, 0);
conv_params.padding_end = {pad_end_x, pad_end_y, pad_end_z};
uint32_t stride_z = stride.size() >= 3 ? static_cast<uint32_t>(stride[stride.size() - 3]) : 1;
uint32_t stride_y = stride.size() >= 2 ? static_cast<uint32_t>(stride[stride.size() - 2]) : 1;
@@ -183,7 +189,7 @@ public:
}
}
conv_params.filterSize = { ky, kx, kz };
conv_params.padding = {pad_y, pad_x, pad_z};
conv_params.padding_begin = {pad_begin_y, pad_begin_x, pad_begin_z};
conv_params.stride = {stride_y, stride_x, stride_z};
conv_params.dilation = {dilation_y, dilation_x, dilation_z};
}
@@ -100,7 +100,7 @@ public:
uint32_t pad_y = std::max<std::ptrdiff_t>(pad.size() >= 2 ? pad[pad.size() - 2] : 0, 0);
uint32_t pad_x = std::max<std::ptrdiff_t>(pad.size() >= 1 ? pad[pad.size() - 1] : 0, 0);
params.padding = {pad_x, pad_y, pad_z};
params.padding_begin = {pad_x, pad_y, pad_z};
uint32_t stride_z = stride.size() >= 3 ? static_cast<uint32_t>(stride[stride.size() - 3]) : 1;
uint32_t stride_y = stride.size() >= 2 ? static_cast<uint32_t>(stride[stride.size() - 2]) : 1;
@@ -42,12 +42,12 @@ public:
static std::string to_string(binary_convolution_node const& node);
typed_primitive_inst(network& network, binary_convolution_node const& node);
bool need_reset_input_memory() const override {
bool need_reset_input_memory(size_t idx = 0) const override {
if (idx != 0)
return false;
auto input_layout = _deps[0].first->_impl_params->get_output_layout(0);
if (input_layout.data_padding) {
return true;
}
return false;
return input_layout.data_padding ? true : false;
}
bool need_reset_output_memory() const override {
@@ -128,12 +128,12 @@ public:
static layout calc_output_layout(convolution_node const& node, kernel_impl_params const& impl_param);
static std::string to_string(convolution_node const& node);
bool need_reset_input_memory() const override {
bool need_reset_input_memory(size_t idx = 0) const override {
if (idx != 0)
return false;
auto input_layout = _deps[0].first->_impl_params->get_output_layout(0);
if (input_layout.data_padding) {
return true;
}
return false;
return input_layout.data_padding ? true : false;
}
bool need_reset_output_memory() const override {
@@ -60,12 +60,12 @@ public:
static layout calc_output_layout(deconvolution_node const& node, kernel_impl_params const& impl_param);
static std::string to_string(deconvolution_node const& node);
bool need_reset_input_memory() const override {
bool need_reset_input_memory(size_t idx = 0) const override {
if (idx != 0)
return false;
auto input_layout = _deps[0].first->_impl_params->get_output_layout(0);
if (input_layout.data_padding) {
return true;
}
return false;
return input_layout.data_padding ? true : false;
}
bool need_reset_output_memory() const override {
@@ -388,17 +388,26 @@ protected:
return { layout(in_layout.get<ShapeType>(), output_type, in_layout.format) };
}
virtual bool need_reset_input_memory() const {
virtual bool need_reset_input_memory(size_t) const {
return false;
}
virtual bool need_reset_output_memory() const {
std::vector<primitive_id> users;
std::vector<std::pair<primitive_id, size_t>> users;
for (auto u : _node->get_users())
users.push_back(u->id());
users.emplace_back(u->id(), u->get_dependency_index(*_node));
for (const auto& u : _network.get_primitives(users)) {
if (u->need_reset_input_memory())
for (const auto& u : users) {
auto user_inst = _network.get_primitive(u.first);
// Check users of optimized_out inst, as the optimized out inst will not be able to
// reset it's memory
if (user_inst->can_be_optimized()) {
if (user_inst->need_reset_output_memory())
return true;
continue;
}
if (user_inst->need_reset_input_memory(u.second))
return true;
}
return false;
@@ -33,7 +33,10 @@ public:
static layout calc_output_layout(reduce_node const& node, kernel_impl_params const& impl_param);
static std::string to_string(reduce_node const& node);
bool need_reset_input_memory() const override {
bool need_reset_input_memory(size_t idx = 0) const override {
if (idx != 0)
return false;
auto input_layout = _deps[0].first->_impl_params->get_output_layout(_deps[0].second);
if (!format::format::is_simple_data_format(input_layout.format) && input_layout.feature() % 16 != 0) {
return true;
@@ -1035,11 +1035,16 @@ format layout_optimizer::get_expected_format(convolution_node const& node) {
auto output_layout = node.get_output_layout(0);
auto weights_layout = node.weights().get_output_layout().convert_to_weights_layout(prim->grouped_weights_shape);
auto expected_format = output_layout.format;
bool i8_u8_input = input_layout.data_type == data_types::u8 || input_layout.data_type == data_types::i8;
if (prim->deformable_mode) {
return format::adjust_to_rank(format::bfyx, output_layout.get_partial_shape().size());
}
// Use planar bfyx format for dynamic convolutions with explicit padding
if (node.is_dynamic() && output_layout.get_partial_shape().size() == 4 && node.use_explicit_padding() && !i8_u8_input)
return format::bfyx;
if (input_layout.is_dynamic() || output_layout.is_dynamic()) {
if (input_layout.get_partial_shape().size() <= 4)
expected_format = format::b_fs_yx_fsv16;
@@ -1052,7 +1057,6 @@ format layout_optimizer::get_expected_format(convolution_node const& node) {
bool onednn_valid_post_ops = get_post_ops_count(node) <= 32;
bool use_onednn_impls = _optimization_attributes.use_onednn_impls && input_layout.data_type != data_types::f32;
bool i8_u8_input = input_layout.data_type == data_types::u8 || input_layout.data_type == data_types::i8;
if (use_onednn_impls && onednn_valid_post_ops) {
expected_format = node.get_preferred_output_fmt();
@@ -350,7 +350,8 @@ void primitive_inst::update_shape() {
_impl_params->memory_deps = memory_deps;
auto update_output_layout = [&](layout& layout, size_t idx) {
layout.data_padding = padding::max(_node->get_primitive()->output_paddings[idx], layout.data_padding);
auto data_padding = padding::max(_impl_params->get_output_layout(idx).data_padding, layout.data_padding);
layout.data_padding = padding::max(_node->get_primitive()->output_paddings[idx], data_padding);
if (_impl_params->get_output_layout(idx) != layout) {
GPU_DEBUG_TRACE_DETAIL << id() << ": update shape: was: " << _impl_params->get_output_layout(idx).to_short_string()
<< " now: " << layout.to_short_string() << std::endl;
@@ -437,7 +438,7 @@ event::ptr primitive_inst::realloc_if_needed() {
_outputs[0]->set_reused(true);
_outputs[0] = _network.get_engine().reinterpret_buffer(*_outputs[0], actual_layout);
}
if (need_reset_output_memory()) {
if (need_reset_output_memory() && !can_be_optimized()) {
ev = _outputs[0]->fill(_network.get_stream());
}
} else {
@@ -995,6 +996,7 @@ primitive_inst::primitive_inst(network& network, program_node const& node, bool
if (_impl) {
_impl->set_node_params(node);
if (_impl->is_dynamic() && !_impl->is_cpu()) {
GPU_DEBUG_TRACE_DETAIL << id() << ": initialize impl with dynamic impl " << _impl->get_kernel_name() << std::endl;
_dynamic_impl = _impl->clone();
// Actual shape info layout is the following:
// input_0 -> input_1, ..., fused_dep_0, fused_dep1, ..., output_0, output_1, ...
@@ -56,6 +56,7 @@ if (_kernel_data.leftovers)
REQD_SUB_GROUP_SIZE(SUB_GROUP_SIZE)
__attribute__((reqd_work_group_size(1, 1, SUB_GROUP_SIZE)))
KERNEL(convolution_gpu_bfyx_os_iyx_osv16)(
OPTIONAL_SHAPE_INFO_ARG
const __global UNIT_TYPE* input,
__global UNIT_TYPE* output,
const __global UNIT_TYPE* weights
@@ -237,7 +238,14 @@ KERNEL(convolution_gpu_bfyx_os_iyx_osv16)(
for(uint r = 0; r < OUTPUT_BLOCK_HEIGHT; r++) {
if(!(or + r >= OUTPUT_SIZE_Y))
{
#if (OUTPUT_SIZE_X % OUTPUT_BLOCK_WIDTH) == 0 // in this case we don't need to check if we're outside of X boundaries
#if !IS_DYNAMIC
#if (OUTPUT_SIZE_X % OUTPUT_BLOCK_WIDTH) == 0
#define CAN_SKIP_CHECK
#endif
#endif
#ifdef CAN_SKIP_CHECK // in this case we don't need to check if we're outside of X boundaries
uint out_vstore_offset = 0;
#if (OUT_BLOCK_WIDTH % 8) > 3
MAKE_VECTOR_TYPE(UNIT_TYPE, 4) tmp = MAKE_VECTOR_TYPE(UNIT_TYPE, 4)(
@@ -281,12 +281,12 @@ bool ConvolutionKernel_b_fs_yx_fsv_16_32_imad_dw::HasPaddedInput(const convoluti
+ (params.filterSize.z - 1) * params.dilation.z + 1;
bool has_pad = true;
has_pad &= params.padding.x <= params.inputs[0].X().pad.before;
has_pad &= params.padding.y <= params.inputs[0].Y().pad.before;
has_pad &= params.padding.z <= params.inputs[0].Z().pad.before;
has_pad &= inputLimitX <= params.padding.x + params.inputs[0].X().v + params.inputs[0].X().pad.after;
has_pad &= inputLimitY <= params.padding.y + params.inputs[0].Y().v + params.inputs[0].Y().pad.after;
has_pad &= inputLimitZ <= params.padding.z + params.inputs[0].Z().v + params.inputs[0].Z().pad.after;
has_pad &= params.padding_begin.x <= params.inputs[0].X().pad.before;
has_pad &= params.padding_begin.y <= params.inputs[0].Y().pad.before;
has_pad &= params.padding_begin.z <= params.inputs[0].Z().pad.before;
has_pad &= inputLimitX <= params.padding_begin.x + params.inputs[0].X().v + params.inputs[0].X().pad.after;
has_pad &= inputLimitY <= params.padding_begin.y + params.inputs[0].Y().v + params.inputs[0].Y().pad.after;
has_pad &= inputLimitZ <= params.padding_begin.z + params.inputs[0].Z().v + params.inputs[0].Z().pad.after;
return has_pad;
}
@@ -300,9 +300,9 @@ bool ConvolutionKernel_b_fs_yx_fsv_16_32_imad_dw::ParamsHavePadding(const convol
+ (params.filterSize.z - 1) * params.dilation.z + 1;
bool needs_pad = false;
needs_pad |= params.padding.x != 0;
needs_pad |= params.padding.y != 0;
needs_pad |= params.padding.z != 0;
needs_pad |= params.padding_begin.x != 0;
needs_pad |= params.padding_begin.y != 0;
needs_pad |= params.padding_begin.z != 0;
needs_pad |= inputLimitX > params.inputs[0].X().v;
needs_pad |= inputLimitY > params.inputs[0].Y().v;
needs_pad |= inputLimitZ > params.inputs[0].Z().v;
@@ -28,7 +28,7 @@ bool ConvolutionKernelBase::Validate(const Params& p, const optional_params& o)
JitConstants ConvolutionKernelBase::GetJitConstants(const convolution_params& params, const DispatchData& dispatchData) const {
JitConstants mem_consts = WeightBiasKernelBase::GetJitConstants(params);
mem_consts.Merge(GetFusedPrimitivesJitConstants(params, dispatchData));
const auto& padding = params.padding;
const auto& padding = params.padding_begin;
const auto& input = params.inputs[0];
int64_t input_offset_with_padding =
@@ -37,7 +37,7 @@ JitConstants ConvolutionKernelBase::GetJitConstants(const convolution_params& pa
mem_consts.AddConstants({
MakeJitConstant("STRIDE", params.stride),
MakeJitConstant("PADDING", params.padding),
MakeJitConstant("PADDING", padding),
MakeJitConstant("DILATION", params.dilation),
MakeJitConstant("FILTER_ARRAY_NUM", params.groups),
MakeJitConstant("INPUT0_OFFSET_WITH_PADDING", input_offset_with_padding),
@@ -183,11 +183,17 @@ KernelsData ConvolutionKernelBase::GetCommonKernelsData(const Params& params,
}
if (NeedPaddedInput()) {
kd.reorderInput = ConvolutionUpdateInputParams(newParams);
if (newParams.has_dynamic_inputs()) {
if (!CheckConvolutionExplicitPaddings(newParams))
return {};
} else {
kd.reorderInput = ConvolutionUpdateInputParams(newParams);
if (kd.reorderInput && !options.allowInputReordering)
return {};
if (kd.reorderInput && !options.allowInputReordering)
return {};
}
}
DispatchData dispatchData = SetDefault(newParams, autoTuneIndex);
if (!params.is_shape_agnostic && !CheckWorkGroups(dispatchData)) {
@@ -264,7 +270,7 @@ bool CheckConvolutionPaddedInputDesc(const convolution_params& params, const Dat
reqDesc.Feature().pad.after <= params.inputs[0].Feature().pad.after &&
reqDesc.Batch().pad.after <= params.inputs[0].Batch().pad.after;
properPadding &= ((params.padding.x == 0 && params.padding.y == 0) || params.inputs[0].GetPaddedVal() == 0.f);
properPadding &= ((params.padding_begin.x == 0 && params.padding_begin.y == 0) || params.inputs[0].GetPaddedVal() == 0.f);
return properPadding;
}
@@ -276,16 +282,14 @@ static DataTensor GetConvolutionBFYXPaddedTensor(const convolution_params& cp) {
DataTensor t = cp.inputs[0];
std::vector<Tensor::Pad> pad{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
pad[0].before = cp.padding.x;
pad[1].before = cp.padding.y;
pad[2].before = cp.padding.z;
pad[0].before = cp.padding_begin.x;
pad[1].before = cp.padding_begin.y;
pad[2].before = cp.padding_begin.z;
const auto inputLimitX = (cp.outputs[0].X().v - 1) * cp.stride.x + (cp.filterSize.x - 1) * cp.dilation.x + 1;
const auto inputLimitY = (cp.outputs[0].Y().v - 1) * cp.stride.y + (cp.filterSize.y - 1) * cp.dilation.y + 1;
const auto inputLimitZ = (cp.outputs[0].Z().v - 1) * cp.stride.z + (cp.filterSize.z - 1) * cp.dilation.z + 1;
pad[0].after = (size_t)std::max(static_cast<int>(inputLimitX) - static_cast<int>(t.X().v) - static_cast<int>(pad[0].before), static_cast<int>(0));
pad[1].after = (size_t)std::max(static_cast<int>(inputLimitY) - static_cast<int>(t.Y().v) - static_cast<int>(pad[1].before), static_cast<int>(0));
pad[2].after = (size_t)std::max(static_cast<int>(inputLimitZ) - static_cast<int>(t.Z().v) - static_cast<int>(pad[2].before), static_cast<int>(0));
@@ -303,10 +307,29 @@ static DataTensor GetConvolutionBFYXPaddedTensor(const convolution_params& cp) {
return {dims, t.GetDType(), t.GetLayout()};
}
bool CheckConvolutionExplicitPaddings(const convolution_params& conv_params) {
if (!conv_params.has_explicit_paddings)
return false;
bool proper_padding = true;
proper_padding &= conv_params.padding_begin.x == conv_params.inputs[0].X().pad.before &&
conv_params.padding_begin.y == conv_params.inputs[0].Y().pad.before &&
conv_params.padding_begin.z == conv_params.inputs[0].Z().pad.before;
proper_padding &= conv_params.padding_end.x == conv_params.inputs[0].X().pad.after &&
conv_params.padding_end.y == conv_params.inputs[0].Y().pad.after &&
conv_params.padding_end.z == conv_params.inputs[0].Z().pad.after;
return proper_padding;
}
bool ConvolutionCheckInput(const Params& p, const optional_params& o) {
const convolution_params& params = static_cast<const convolution_params&>(p);
const convolution_optional_params& optParams = static_cast<const convolution_optional_params&>(o);
if (params.has_dynamic_inputs())
return CheckConvolutionExplicitPaddings(params);
const auto req_input = GetConvolutionBFYXPaddedTensor(params);
const bool bProperInputDesc = CheckConvolutionPaddedInputDesc(params, req_input);
const bool bInputPadded = optParams.allowInputReordering || bProperInputDesc;
@@ -73,6 +73,7 @@ protected:
bool ConvolutionCheckInput(const Params& p, const optional_params& o);
bool CheckConvolutionPaddedInputDesc(const convolution_params& params, const DataTensor& reqDesc);
bool CheckConvolutionExplicitPaddings(const convolution_params& conv_params);
bool ConvolutionUpdateInputParams(convolution_params& params);
} // namespace kernel_selector
@@ -111,7 +111,7 @@ bool convolution_kernel_bfyx_1x1_opt::Validate(const Params& p, const optional_p
if (cp.outputs[0].Feature().v % 64 != 0)
return false;
if (cp.padding.x != 0 || cp.padding.y != 0)
if (cp.padding_begin.x != 0 || cp.padding_begin.y != 0)
return false;
if (cp.inputs[0].Feature().v % 2 != 0) {
@@ -67,7 +67,7 @@ JitConstants ConvolutionKernel_bfyx_depthwise_weights_lwg::GetJitConstants(const
const DispatchData& dispatchData) const {
auto mem_consts = ConvolutionKernelBase::GetJitConstants(params, dispatchData);
if (params.padding.x != 0 || params.padding.y != 0)
if (params.padding_begin.x != 0 || params.padding_begin.y != 0)
mem_consts.AddConstant(MakeJitConstant("BOUNDARY_CHECK", 1));
return mem_consts;
@@ -50,6 +50,7 @@ ParamsKey ConvolutionKernel_bfyx_os_iyx_osv16::GetSupportedKey() const {
k.EnableBatching();
k.EnableDilation();
k.EnableGroupedConvolution();
k.EnableDynamicShapesSupport();
return k;
}
@@ -128,7 +129,7 @@ ConvolutionKernel_bfyx_os_iyx_osv16::AutoTuneOption ConvolutionKernel_bfyx_os_iy
// if less than 16 values is required to compute one single row of output
// then each WI shall compute one single row to maximize reuse within SIMD subgroup (this gives very nice
// performance results)
} else if (cp.outputs[0].X().v + (cp.filterSize.x - 1) * cp.dilation.x < sub_group_size) {
} else if (!p.is_shape_agnostic && cp.outputs[0].X().v + (cp.filterSize.x - 1) * cp.dilation.x < sub_group_size) {
option.blockWidth = cp.outputs[0].X().v;
option.blockHeight = 1;
option.prefetch = 4;
@@ -153,7 +154,7 @@ ConvolutionKernel_bfyx_os_iyx_osv16::AutoTuneOption ConvolutionKernel_bfyx_os_iy
// if this is not 1x1 batch1 case then shrink filters, other way we're memory bound and it's best to use 16x1 block
// sizes
if (cp.filterSize.x != 1 || cp.filterSize.y != 1 || cp.outputs[0].Batch().v != 1) {
if (!p.is_shape_agnostic && (cp.filterSize.x != 1 || cp.filterSize.y != 1 || cp.outputs[0].Batch().v != 1)) {
shrink_blocks_to_output_size(cp.outputs[0].X().v, cp.outputs[0].Y().v, option.blockWidth, option.blockHeight, sub_group_size);
}
return option;
@@ -51,8 +51,8 @@ JitConstants ConvolutionKernel_Winograd_2x3_s1_fused::GetJitConstants(const conv
auto C4_up16 = ((uint32_t)((idepth + 15) / 16) * 16) / 4;
// if there's input padding then input offset should be ignored
const auto inoffset_x = (input_pad_x) ? 0 : params.padding.x;
const auto inoffset_y = (input_pad_y) ? 0 : params.padding.y;
const auto inoffset_x = (input_pad_x) ? 0 : params.padding_begin.x;
const auto inoffset_y = (input_pad_y) ? 0 : params.padding_begin.y;
jit.AddConstants({
MakeJitConstant("H", rows),
@@ -89,8 +89,8 @@ ConvolutionKernel_Winograd_2x3_s1_fused::Parent::DispatchData ConvolutionKernel_
const auto cols = arg.inputs[0].X().v + input_pad_x;
// if there's input padding then input offset should be ignored
const auto inoffset_x = (input_pad_x) ? 0 : arg.padding.x;
const auto inoffset_y = (input_pad_y) ? 0 : arg.padding.y;
const auto inoffset_x = (input_pad_x) ? 0 : arg.padding_begin.x;
const auto inoffset_y = (input_pad_y) ? 0 : arg.padding_begin.y;
auto P = rows - 2 + 2 * inoffset_y;
auto Q = cols - 2 + 2 * inoffset_x;
@@ -52,8 +52,8 @@ JitConstants ConvolutionKernel_Winograd_6x3_s1_fused::GetJitConstants(const conv
auto C4_up16 = ((uint32_t)((idepth + 15) / 16) * 16) / 4;
// if there's input padding then input offset should be ignored
const auto inoffset_x = (input_pad_x) ? 0 : params.padding.x;
const auto inoffset_y = (input_pad_y) ? 0 : params.padding.y;
const auto inoffset_x = (input_pad_x) ? 0 : params.padding_begin.x;
const auto inoffset_y = (input_pad_y) ? 0 : params.padding_begin.y;
jit.AddConstants({
MakeJitConstant("H", rows),
@@ -101,8 +101,8 @@ ConvolutionKernel_Winograd_6x3_s1_fused::Parent::DispatchData ConvolutionKernel_
const auto cols = arg.inputs[0].X().v + input_pad_x;
// if there's input padding then input offset should be ignored
const auto inoffset_x = (input_pad_x) ? 0 : arg.padding.x;
const auto inoffset_y = (input_pad_y) ? 0 : arg.padding.y;
const auto inoffset_x = (input_pad_x) ? 0 : arg.padding_begin.x;
const auto inoffset_y = (input_pad_y) ? 0 : arg.padding_begin.y;
auto P = rows - 2 + 2 * inoffset_y;
auto Q = cols - 2 + 2 * inoffset_x;
@@ -20,7 +20,7 @@ std::string convolution_params::to_string() const {
s << filterSize.x << "_" << filterSize.y << "_";
s << stride.x << "_" << stride.y << "_";
s << dilation.x << "_" << dilation.y << "_";
s << padding.x << "_" << padding.y << "_";
s << padding_begin.x << "_" << padding_begin.y << "_";
s << 1;
return s.str();
@@ -33,7 +33,7 @@ std::string convolution_params::to_cache_string_v2() const {
s << filterSize.x << "_" << filterSize.y << "_" << filterSize.z << ";";
s << stride.x << "_" << stride.y << "_" << stride.z << ";";
s << dilation.x << "_" << dilation.y << "_" << dilation.z << ";";
s << padding.x << "_" << padding.y << "_" << padding.z << ";";
s << padding_begin.x << "_" << padding_begin.y << "_" << padding_begin.z << ";";
s << 1 << ";";
s << groups;
@@ -20,7 +20,8 @@ struct convolution_params : public weight_bias_zero_point_params {
uSize filterSize;
uSize stride;
uSize dilation;
uSize padding;
uSize padding_begin;
uSize padding_end;
bool transposed = false;
QuantizationType quantization = QuantizationType::NONE;
bool deformable_mode = false;
@@ -29,6 +30,7 @@ struct convolution_params : public weight_bias_zero_point_params {
uint32_t deformable_groups = 1;
bool bilinear_interpolation_pad {false};
bool deformable_mask_enabled {false};
bool has_explicit_paddings {false};
std::string to_string() const override;
std::string to_cache_string_v2() const override;
@@ -68,7 +68,7 @@ JitConstants DeformableConvolutionKernel_bfyx_interp::GetJitConstants(const conv
jit.AddConstant(MakeJitConstant("FILTER_SIZE_X", params.kernelSize.x));
jit.AddConstant(MakeJitConstant("FILTER_SIZE_Y", params.kernelSize.y));
jit.AddConstants({MakeJitConstant("STRIDE", params.stride),
MakeJitConstant("PADDING", params.padding),
MakeJitConstant("PADDING", params.padding_begin),
MakeJitConstant("DILATION", params.dilation)
});
jit.AddConstants({MakeJitConstant("DEFORMABLE_GROUPS", params.deformable_groups)});
@@ -21,7 +21,7 @@ TEST(eltwise_activation_fusing_test, basic_dynamic_rank4) {
// is_valid_fusion() should work properly when conv->add->prelu case
auto& engine = get_test_engine();
layout weight_layout = layout{ov::PartialShape{1, 3, 3, 3}, data_types::f32, format::bfyx};
layout weight_layout = layout{ov::PartialShape{1, 3, 3, 3}, data_types::f16, format::bfyx};
auto weights = engine.allocate_memory(weight_layout);
set_values<FLOAT16>(weights, {
1.0f, 1.0f, 1.0f,
@@ -42,11 +42,11 @@ TEST(eltwise_activation_fusing_test, basic_dynamic_rank4) {
set_values(input_mem, {11.0f, 11.0f, 11.0f, 11.0f,
11.0f, 11.0f, 11.0f, 11.0f,
11.0f, 11.0f, 11.0f, 11.0f});
std::vector<float> ref = { 33.0625f, 55.09375f, 55.09375f, 33.0625f,
55.09375f, 99.1875f, 429.75f, 385.75f,
385.75f, 760.5f, 1091.0f, 716.5f,
363.75f, 716.5f, 716.5f, 363.75f};
std::vector<float> ref = { 77.0f, 143.0f, 143.0f, 77.0f,
143.0f, 275.0f, 275.0f, 143.0f,
143.0f, 275.0f, 275.0f, 143.0f,
77.0f, 143.0f, 143.0f, 77.0f };
auto const1 = engine.allocate_memory(layout{ov::PartialShape({1, 1, 1, 1}), data_types::f32, format::bfyx});
set_values(const1, {11.0f});
auto const2 = engine.allocate_memory(layout{ov::PartialShape({1, 1, 1, 1}), data_types::f32, format::bfyx});
@@ -8866,7 +8866,7 @@ public:
void SetUp() override {
rg.set_seed(GET_SUITE_NAME);
}
static void TearDownTestCase() {
all_generic_params.clear();
all_layer_params.clear();
@@ -9954,3 +9954,129 @@ TEST(convolution_f32_fw_gpu, basic_convolution_no_bias_swap_xy) {
}
EXPECT_TRUE(found_define);
}
struct conv_dyn_test_params {
ov::Shape in_shape;
ov::Shape wei_shape;
ov::Strides stride;
ov::Strides dilation;
ov::CoordinateDiff pad_begin;
ov::CoordinateDiff pad_end;
};
class conv_dyn_test : public testing::TestWithParam<conv_dyn_test_params> {};
TEST_P(conv_dyn_test, convolution_gpu_bfyx_os_iyx_osv16_no_bias) {
auto& engine = get_test_engine();
auto p = GetParam();
auto is_grouped = p.wei_shape.size() == 5;
auto groups_num = is_grouped ? static_cast<uint32_t>(p.wei_shape[0]) : 1;
auto calculate_ref = [&](memory::ptr input, memory::ptr weights, ExecutionConfig config) {
auto in_layout = input->get_layout();
topology topology_ref(
input_layout("input", in_layout),
data("weights", weights),
convolution("conv", input_info("input"), "weights", no_bias, groups_num, p.stride, p.dilation, p.pad_begin, p.pad_end, is_grouped));
network network_ref(engine, topology_ref, config);
network_ref.set_input_data("input", input);
auto outputs_ref = network_ref.execute();
return outputs_ref.at("conv").get_memory();
};
auto in_layout = layout{ov::PartialShape{ov::Dimension(), ov::Dimension(p.in_shape[1]), ov::Dimension(), ov::Dimension()}, data_types::f32, format::bfyx};
auto input = engine.allocate_memory({ p.in_shape, data_types::f32, format::bfyx });
auto weights = engine.allocate_memory({p.wei_shape, data_types::f32, is_grouped ? format::bfzyx : format::bfyx});
tests::random_generator rg(GET_SUITE_NAME);
VF<float> input_rnd = rg.generate_random_1d<float>(ov::shape_size(p.in_shape), -10, 10);
VF<float> weights_rnd = rg.generate_random_1d<float>(ov::shape_size(p.wei_shape), -10, 10);
set_values(input, input_rnd);
set_values(weights, weights_rnd);
topology topology(
input_layout("input", in_layout),
data("weights", weights),
convolution("conv", input_info("input"), "weights", no_bias, groups_num, p.stride, p.dilation, p.pad_begin, p.pad_end, is_grouped));
ExecutionConfig config = get_test_default_config(engine);
ov::intel_gpu::ImplementationDesc conv_impl = { format::bfyx, "convolution_gpu_bfyx_os_iyx_osv16", impl_types::ocl };
config.set_property(ov::intel_gpu::force_implementations(ov::intel_gpu::ImplForcingMap{ { "conv", conv_impl } }));
config.set_property(ov::intel_gpu::allow_new_shape_infer(true));
config.set_property(ov::enable_profiling(true));
network network(engine, topology, config);
network.set_input_data("input", input);
auto inst = network.get_primitive("conv");
auto impl = inst->get_impl();
ASSERT_TRUE(impl != nullptr);
ASSERT_TRUE(impl->is_dynamic());
auto outputs = network.execute();
auto output_memory = outputs.at("conv").get_memory();
auto output_memory_ref = calculate_ref(input, weights, config);
cldnn::mem_lock<float> output_ptr(output_memory, get_test_stream());
cldnn::mem_lock<float> output_ptr_ref(output_memory_ref, get_test_stream());
ASSERT_EQ(outputs.at("conv").get_layout(), output_memory_ref->get_layout());
for (size_t i = 0; i < output_ptr.size(); i++) {
ASSERT_EQ(output_ptr[i], output_ptr_ref[i]);
}
{
// Change original shape for the second run
auto new_shape = p.in_shape;
new_shape[2] += 4;
new_shape[3] += 8;
auto input = engine.allocate_memory({ new_shape, data_types::f32, format::bfyx });
VF<float> input_rnd = rg.generate_random_1d<float>(ov::shape_size(p.in_shape), -10, 10);
set_values(input, input_rnd);
network.set_input_data("input", input);
auto outputs = network.execute();
auto output_memory = outputs.at("conv").get_memory();
auto output_memory_ref = calculate_ref(input, weights, config);
cldnn::mem_lock<float> output_ptr(output_memory, get_test_stream());
cldnn::mem_lock<float> output_ptr_ref(output_memory_ref, get_test_stream());
ASSERT_EQ(outputs.at("conv").get_layout(), output_memory_ref->get_layout());
for (size_t i = 0; i < output_ptr.size(); i++) {
ASSERT_EQ(output_ptr[i], output_ptr_ref[i]);
}
}
}
INSTANTIATE_TEST_SUITE_P(smoke, conv_dyn_test,
testing::ValuesIn(std::vector<conv_dyn_test_params>{
{ ov::Shape{1, 8, 14, 14}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 8, 32, 32}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 8, 60, 60}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 8, 64, 64}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 8, 110, 111}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 8, 110, 111}, ov::Shape{16, 8, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 8, 110, 111}, ov::Shape{16, 8, 5, 5}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{2, 640, 32, 32}, ov::Shape{640, 640, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 32, 16, 16}, ov::Shape{32, 32, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{2, 32, 16, 16}, ov::Shape{32, 32, 3, 3}, ov::Strides{2, 2}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 32, 32, 32}, ov::Shape{64, 32, 1, 1}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 4, 32, 32}, ov::Shape{32, 4, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 4, 64, 64}, ov::Shape{4, 4, 1, 1}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 32, 28, 28}, ov::Shape{32, 1, 1, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 48, 16, 16}, ov::Shape{48, 48, 4, 4}, ov::Strides{4, 4}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 16, 28, 28}, ov::Shape{32, 16, 2, 2}, ov::Strides{2, 2}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 3, 32, 32}, ov::Shape{96, 3, 4, 4}, ov::Strides{4, 4}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
{ ov::Shape{1, 768, 7, 7}, ov::Shape{768, 1, 1, 3, 3}, ov::Strides{1, 1}, ov::Strides{1, 1}, ov::CoordinateDiff{1, 1}, ov::CoordinateDiff{1, 1} },
{ ov::Shape{1, 48, 56, 56}, ov::Shape{48, 48, 8, 8}, ov::Strides{8, 8}, ov::Strides{1, 1}, ov::CoordinateDiff{0, 0}, ov::CoordinateDiff{0, 0} },
}));