[CPU] DS support for Deformable Convolution (#8986)

This commit is contained in:
Yury Gaydaychuk authored and GitHub committed 2022-01-12 14:08:24 +03:00
1 parent 613facafde
commit b06c0b5c32
4 files changed
+640 -356

No files matched your search

@@ -578,10 +578,6 @@ private:
bool MKLDNNDeformableConvolutionNode::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
try {
if (isDynamicNgraphNode(op)) {
errorMessage = "Doesn't support op with dynamic shapes";
return false;
}
if (!one_of(op->get_type_info(),
ngraph::op::v1::DeformableConvolution::get_type_info_static(),
ngraph::op::v8::DeformableConvolution::get_type_info_static())) {
@@ -600,53 +596,53 @@ MKLDNNDeformableConvolutionNode::MKLDNNDeformableConvolutionNode(const std::shar
if (!isSupportedOperation(op, errorMessage)) {
IE_THROW(NotImplemented) << errorMessage;
}
errorPrefix = "Deformable convolution with name '" + op->get_friendly_name() + "'";
auto defConvNodeBase = std::dynamic_pointer_cast<ngraph::op::util::DeformableConvolutionBase>(op);
if (defConvNodeBase == nullptr)
IE_THROW() << "Operation with name '" << op->get_friendly_name() <<
"' is not an instance of DeformableConvolutionBase.";
IE_THROW() << errorPrefix << " is not an instance of DeformableConvolutionBase.";
group = defConvNodeBase->get_group();
deformable_group = defConvNodeBase->get_deformable_group();
defConvAttr.group = defConvNodeBase->get_group();
defConvAttr.deformable_group = defConvNodeBase->get_deformable_group();
auto& strides = defConvNodeBase->get_strides();
for (int i = 0; i < strides.size(); i++) {
stride.push_back(strides[i]);
defConvAttr.stride.push_back(strides[i]);
}
auto& dilations = defConvNodeBase->get_dilations();
for (int i = 1; i <= dilations.size(); i++) {
dilation.push_back(dilations[dilations.size() - i] - 1);
defConvAttr.dilation.push_back(dilations[dilations.size() - i] - 1);
}
paddingL = defConvNodeBase->get_pads_begin();
defConvAttr.padL = defConvNodeBase->get_pads_begin();
autoPadding = one_of(defConvNodeBase->get_auto_pad(), ov::op::PadType::SAME_UPPER, ov::op::PadType::SAME_LOWER);
if (op->get_type_info() == ngraph::op::v8::DeformableConvolution::get_type_info_static()) {
auto defConvNode = std::dynamic_pointer_cast<ngraph::op::v8::DeformableConvolution>(op);
if (defConvNode == nullptr)
IE_THROW() << "Operation with name '" << op->get_friendly_name() <<
"' is not an instance of DeformableConvolution from opset8.";
with_bilinear_pad = defConvNode->get_bilinear_interpolation_pad();
IE_THROW() << errorPrefix << " is not an instance of DeformableConvolution from opset8.";
defConvAttr.with_bilinear_pad = defConvNode->get_bilinear_interpolation_pad();
} else {
with_bilinear_pad = false;
defConvAttr.with_bilinear_pad = false;
}
}
void MKLDNNDeformableConvolutionNode::getSupportedDescriptors() {
std::string errorPrefix = "DeformableConvolution layer with name '" + getName() + "' ";
if (getParentEdges().size() != 3 && getParentEdges().size() != 4)
IE_THROW() << errorPrefix << "has incorrect number of input edges";
IE_THROW() << errorPrefix << " has incorrect number of input edges";
if (getChildEdges().empty())
IE_THROW() << errorPrefix << "has incorrect number of output edges";
if (getInputShapeAtPort(0).getRank() != 4) {
IE_THROW() << "Deformable convolution layer. Unsupported mode. Only 4D blobs are supported as input.";
IE_THROW() << errorPrefix << " has incorrect number of output edges";
if (getInputShapeAtPort(DATA_ID).getRank() != 4) {
IE_THROW() << errorPrefix << " has unsupported mode. Only 4D blobs are supported as input.";
}
if (getInputShapeAtPort(1).getRank() != 4) {
IE_THROW() << errorPrefix << "doesn't support 1st input with rank: " << getInputShapeAtPort(1).getRank();
if (getInputShapeAtPort(OFF_ID).getRank() != 4) {
IE_THROW() << errorPrefix << " doesn't support 1st input with rank: " << getInputShapeAtPort(OFF_ID).getRank();
}
if (getInputShapeAtPort(2).getRank() != 4) {
IE_THROW() << errorPrefix << "doesn't support 2nd input with rank: " << getInputShapeAtPort(2).getRank();
if (getInputShapeAtPort(WEI_ID).getRank() != 4) {
IE_THROW() << errorPrefix << " doesn't support 2nd input with rank: " << getInputShapeAtPort(WEI_ID).getRank();
}
if (getOutputShapeAtPort(0).getRank() != 4) {
IE_THROW() << errorPrefix << "doesn't support output with rank: " << getOutputShapeAtPort(0).getRank();
if (getOutputShapeAtPort(DATA_ID).getRank() != 4) {
IE_THROW() << errorPrefix << " doesn't support output with rank: " << getOutputShapeAtPort(DATA_ID).getRank();
}
}
@@ -675,9 +671,15 @@ void MKLDNNDeformableConvolutionNode::initSupportedPrimitiveDescriptors() {
impl_desc_type impl_type;
const int simd_w = mayiuse(cpu::x64::avx512_common) ? 16 : 8;
if (group != 1 || (((getInputShapeAtPort(0).getStaticDims()[1] / group) % simd_w != 0)
|| ((getOutputShapeAtPort(0).getStaticDims()[1] / group) % simd_w != 0))) {
auto &weiDims = getInputShapeAtPort(WEI_ID).getDims();
if (weiDims[1] == Shape::UNDEFINED_DIM || weiDims[0] == Shape::UNDEFINED_DIM ||
defConvAttr.group != 1 || // temporary workaround until jit impl. will correctly handle multigroup cases
(weiDims[1] % simd_w != 0) // in_channels_per_gr !% simd_w
|| ((weiDims[0] / defConvAttr.group) % simd_w != 0)) { // out_channels_per_gr !% simd_w
enforceRef = true;
} else {
enforceRef = false;
}
if (enforceRef) {
@@ -697,51 +699,41 @@ void MKLDNNDeformableConvolutionNode::initSupportedPrimitiveDescriptors() {
auto dataFormat = memory::format_tag::nhwc;
auto offFormat = memory::format_tag::nchw;
auto weiFormat = mayiuse(avx512_common) ? memory::format_tag::OIhw16i16o : memory::format_tag::OIhw8i8o;
config.inConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(0),
config.inConfs[DATA_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(DATA_ID),
memory::data_type::f32, dataFormat);
config.inConfs[1].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(1),
config.inConfs[OFF_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(OFF_ID),
memory::data_type::f32, offFormat);
auto& wDims = getInputShapeAtPort(2).getStaticDims();
if (group > 1 && wDims.size() != 5) {
auto new_dims = InferenceEngine::SizeVector({group, div_up(wDims[0], group)});
for (int i = 1; i < wDims.size(); i++) {
new_dims.push_back(wDims[i]);
}
config.inConfs[2].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(2),
memory::data_type::f32, weiFormat);
} else {
config.inConfs[2].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(2),
memory::data_type::f32, weiFormat);
}
config.inConfs[WEI_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(WEI_ID),
memory::data_type::f32, weiFormat);
if (inputsNumber > 3) {
config.inConfs[3].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(3),
config.inConfs[MOD_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(MOD_ID),
memory::data_type::f32, memory::format_tag::nchw);
}
config.outConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getOutputShapeAtPort(0),
config.outConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getOutputShapeAtPort(DATA_ID),
memory::data_type::f32, dataFormat);
supportedPrimitiveDescriptors.push_back({config, impl_type});
} else {
// reference implementation
config.inConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(0), memory::data_type::f32,
config.inConfs[DATA_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(DATA_ID), memory::data_type::f32,
memory::format_tag::nchw);
config.inConfs[1].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(1), memory::data_type::f32,
config.inConfs[OFF_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(OFF_ID), memory::data_type::f32,
memory::format_tag::nchw);
config.inConfs[2].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(2), memory::data_type::f32,
config.inConfs[WEI_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(WEI_ID), memory::data_type::f32,
memory::format_tag::oihw);
if (inputsNumber > 3) {
config.inConfs[3].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(3), memory::data_type::f32,
config.inConfs[MOD_ID].desc = std::make_shared<DnnlBlockedMemoryDesc>(getInputShapeAtPort(MOD_ID), memory::data_type::f32,
memory::format_tag::nchw);
}
config.outConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getOutputShapeAtPort(0), memory::data_type::f32,
config.outConfs[0].desc = std::make_shared<DnnlBlockedMemoryDesc>(getOutputShapeAtPort(DATA_ID), memory::data_type::f32,
memory::format_tag::nchw);
supportedPrimitiveDescriptors.push_back({config, impl_type});
}
}
void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
const std::vector<size_t>& src_strides, const float* offsets, const std::vector<size_t>& off_strides,
const float* modulation, const std::vector<size_t>& modulation_strides) {
void MKLDNNDeformableConvolutionNode::DefConvExecutor::prepareSamplingWeights(
const float* offsets, const float* modulation, bool enforceRef) {
const int MB = jcp.mb;
const int OH = jcp.oh;
const int OW = jcp.ow;
@@ -766,9 +758,6 @@ void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
const bool with_bi_pad = jcp.with_bi_pad;
// prepare weights and indices
sampledCoordsVector.resize(MB * DG * KH * KW * OH * OW * sampledPointsPerPixel);
interpWeightsVector.resize(MB * DG * KH * KW * OH * OW * sampledPointsPerPixel);
auto precompKer = [&](int mb, int dg, int oh, int ow) {
int sampledCoordIndex = (mb * DG * OH * OW + dg * OH * OW + oh * OW + ow) * KH * KW * sampledPointsPerPixel;
const int h_in = oh * KSH - padT;
@@ -777,22 +766,22 @@ void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
const int waOffsetH = (enforceRef ? 0 : h_in);
const int waOffsetW = (enforceRef ? 0 : w_in);
const float *data_offset_ptr = offsets + mb * off_strides[0] + (dg * 2 * KH * KW) * off_strides[1];
const float *data_offset_ptr = offsets + mb * offStrides[0] + (dg * 2 * KH * KW) * offStrides[1];
const float *modulation_offset_ptr = nullptr;
if (modulation != nullptr) {
modulation_offset_ptr = modulation + mb * modulation_strides[0] + (dg * ker_size) * modulation_strides[1];
modulation_offset_ptr = modulation + mb * modStrides[0] + (dg * ker_size) * modStrides[1];
}
for (int kh = 0; kh < KH; kh++) {
for (int kw = 0; kw < KW; kw++) {
const size_t data_offset_h_index = 2 * ((size_t) kh * KW + kw) * off_strides[1] + oh * off_strides[2] + ow * off_strides[3];
const size_t data_offset_w_index = (2 * ((size_t) kh * KW + kw) + 1) * off_strides[1] + oh * off_strides[2] + ow * off_strides[3];
const size_t data_offset_h_index = 2 * ((size_t) kh * KW + kw) * offStrides[1] + oh * offStrides[2] + ow * offStrides[3];
const size_t data_offset_w_index = (2 * ((size_t) kh * KW + kw) + 1) * offStrides[1] + oh * offStrides[2] + ow * offStrides[3];
const float offset_h = data_offset_ptr[data_offset_h_index];
const float offset_w = data_offset_ptr[data_offset_w_index];
float map_h = h_in + kh * (KDH + 1) + offset_h;
float map_w = w_in + kw * (KDW + 1) + offset_w;
bool skip_compute;
if (with_bilinear_pad) {
if (with_bi_pad) {
skip_compute = !(static_cast<int>(map_w) > -1 &&
static_cast<int>(map_w) < IW &&
static_cast<int>(map_h) > -1 &&
@@ -806,7 +795,7 @@ void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
float modulation_scalar = 1.0f;
if (modulation_offset_ptr != nullptr) {
size_t modulation_index = (kh * KW + kw) * modulation_strides[1] + oh * modulation_strides[2] + ow * modulation_strides[3];
size_t modulation_index = (kh * KW + kw) * modStrides[1] + oh * modStrides[2] + ow * modStrides[3];
modulation_scalar = modulation_offset_ptr[modulation_index];
}
// interpolation precomp.
@@ -833,28 +822,28 @@ void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
lh = (h_high < cur_h_end ? lh : 0);
lw = (w_high < cur_w_end ? lw : 0);
const int h_off_low = h_ind_low * src_strides[2] / src_strides[3];
const int h_off_high = h_ind_high * src_strides[2] / src_strides[3];
const int h_off_low = h_ind_low * srcStrides[2] / srcStrides[3];
const int h_off_high = h_ind_high * srcStrides[2] / srcStrides[3];
const int w_off_low = w_ind_low;
const int w_off_high = w_ind_high;
sampledCoordsVector[sampledCoordIndex] = h_off_high + w_off_high;
sampledCoordsVector[sampledCoordIndex + 1] = h_off_high + w_off_low;
sampledCoordsVector[sampledCoordIndex + 2] = h_off_low + w_off_high;
sampledCoordsVector[sampledCoordIndex + 3] = h_off_low + w_off_low;
pSampledCoordsVector[sampledCoordIndex] = h_off_high + w_off_high;
pSampledCoordsVector[sampledCoordIndex + 1] = h_off_high + w_off_low;
pSampledCoordsVector[sampledCoordIndex + 2] = h_off_low + w_off_high;
pSampledCoordsVector[sampledCoordIndex + 3] = h_off_low + w_off_low;
float w22 = hh * hw * modulation_scalar, w21 = hh * lw * modulation_scalar,
w12 = lh * hw * modulation_scalar, w11 = lh * lw * modulation_scalar;
interpWeightsVector[sampledCoordIndex] = w11;
interpWeightsVector[sampledCoordIndex + 1] = w12;
interpWeightsVector[sampledCoordIndex + 2] = w21;
interpWeightsVector[sampledCoordIndex + 3] = w22;
pInterpWeightsVector[sampledCoordIndex] = w11;
pInterpWeightsVector[sampledCoordIndex + 1] = w12;
pInterpWeightsVector[sampledCoordIndex + 2] = w21;
pInterpWeightsVector[sampledCoordIndex + 3] = w22;
} else {
sampledCoordsVector[sampledCoordIndex] = 0;
interpWeightsVector[sampledCoordIndex] = 0;
interpWeightsVector[sampledCoordIndex + 1] = 0;
interpWeightsVector[sampledCoordIndex + 2] = 0;
interpWeightsVector[sampledCoordIndex + 3] = 0;
pSampledCoordsVector[sampledCoordIndex] = 0;
pInterpWeightsVector[sampledCoordIndex] = 0;
pInterpWeightsVector[sampledCoordIndex + 1] = 0;
pInterpWeightsVector[sampledCoordIndex + 2] = 0;
pInterpWeightsVector[sampledCoordIndex + 3] = 0;
}
sampledCoordIndex += sampledPointsPerPixel;
}
@@ -866,19 +855,36 @@ void MKLDNNDeformableConvolutionNode::prepareSamplingWeights(
});
}
void MKLDNNDeformableConvolutionNode::createPrimitive() {
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU deformable convolution with name '" << getName() << "' doesn't have primitive descriptors.";
auto config = selectedPrimitiveDescriptor->getConfig();
MKLDNNDeformableConvolutionNode::DefConvExecutor::DefConvExecutor(const DefConvAttr &defConvAttr,
const std::vector<std::shared_ptr<BlockedMemoryDesc>> &descVector) {
if (descVector.size() != 4 && descVector.size() != 5) {
IE_THROW() << "Deformable Convolution executor got incorrect desc's count (" << descVector.size() << ")";
}
bool withModulation = descVector.size() == 5;
auto srcDims = getParentEdgeAt(0)->getMemory().getStaticDims();
auto weiDims = getParentEdgeAt(2)->getMemory().getStaticDims();
auto dstDims = getChildEdgesAtPort(0)[0]->getMemory().getStaticDims();
auto &srcDesc = descVector[DATA_ID];
auto &dstDesc = descVector[descVector.size() - 1];
srcStrides = std::vector<size_t>(srcDesc->getStrides().size());
offStrides = descVector[OFF_ID]->getStrides();
weiStrides = descVector[WEI_ID]->getStrides();
dstStrides = std::vector<size_t>(dstDesc->getStrides().size());
for (int i = 0; i < srcDesc->getStrides().size(); i++) {
srcStrides[srcDesc->getOrder()[i]] = srcDesc->getStrides()[i];
}
for (int i = 0; i < dstDesc->getStrides().size(); i++) {
dstStrides[dstDesc->getOrder()[i]] = dstDesc->getStrides()[i];
}
jcp.dg = deformable_group;
if (withModulation) {
modStrides = descVector[MOD_ID]->getStrides();
}
jcp.ngroups = group;
const VectorDims srcDims = descVector[DATA_ID]->getShape().getStaticDims();
const VectorDims weiDims = descVector[WEI_ID]->getShape().getStaticDims();
const VectorDims dstDims = descVector[descVector.size() - 1]->getShape().getStaticDims();
jcp.dg = defConvAttr.deformable_group;
jcp.ngroups = defConvAttr.group;
jcp.mb = srcDims[0];
@@ -893,19 +899,18 @@ void MKLDNNDeformableConvolutionNode::createPrimitive() {
jcp.kh = weiDims[2];
jcp.kw = weiDims[3];
jcp.t_pad = paddingL[0];
jcp.l_pad = paddingL[1];
jcp.t_pad = defConvAttr.padL[0];
jcp.l_pad = defConvAttr.padL[1];
jcp.stride_h = stride[0];
jcp.stride_w = stride[1];
jcp.stride_h = defConvAttr.stride[0];
jcp.stride_w = defConvAttr.stride[1];
jcp.dilate_h = dilation[0];
jcp.dilate_w = dilation[1];
jcp.dilate_h = defConvAttr.dilation[0];
jcp.dilate_w = defConvAttr.dilation[1];
jcp.with_bias = false;
jcp.with_bi_pad = with_bilinear_pad;
jcp.with_modulation = getParentEdges().size() > 3;
jcp.with_bi_pad = defConvAttr.with_bilinear_pad;
jcp.with_modulation = withModulation;
const int simd_w = mayiuse(cpu::x64::avx512_common) ? 16 : 8;
jcp.ic_block = simd_w;
jcp.nb_ic = div_up(jcp.ic, jcp.ic_block);
@@ -924,23 +929,33 @@ void MKLDNNDeformableConvolutionNode::createPrimitive() {
jcp.nb_oc_blocking = !mayiuse(cpu::x64::avx2) ? 2 : 4;
jcp.nthr = dnnl_get_max_threads();
}
if (enforceRef) {
return;
} else if (mayiuse(cpu::x64::avx512_common)) {
MKLDNNDeformableConvolutionNode::DefConvJitExecutor::DefConvJitExecutor(const DefConvAttr &defConvAttr,
const std::vector<std::shared_ptr<BlockedMemoryDesc>> &descVector) :
DefConvExecutor(defConvAttr, descVector) {
if (mayiuse(cpu::x64::avx512_common)) {
def_conv_kernel.reset(new jit_uni_def_conv_kernel_f32<cpu::x64::avx512_common>(jcp));
} else if (mayiuse(cpu::x64::avx2)) {
def_conv_kernel.reset(new jit_uni_def_conv_kernel_f32<cpu::x64::avx2>(jcp));
} else if (mayiuse(cpu::x64::sse41)) {
def_conv_kernel.reset(new jit_uni_def_conv_kernel_f32<cpu::x64::sse41>(jcp));
} else {
IE_THROW() << "Can't create DefConvJitExecutor";
}
if (def_conv_kernel)
if (def_conv_kernel) {
def_conv_kernel->create_ker();
} else {
IE_THROW() << "Can't compile DefConvJitExecutor";
}
}
void MKLDNNDeformableConvolutionNode::executeReference(const float* src, const float* weights, float* dst, const std::vector<size_t>& src_strides,
const std::vector<size_t>& wei_strides, const std::vector<size_t>& dst_strides) {
void MKLDNNDeformableConvolutionNode::DefConvRefExecutor::exec(const float* src, const float* offsets,
const float* weights, const float* modulation, float* dst,
int *pSampledCoordsVector, float *pInterpWeightsVector) {
this->pSampledCoordsVector = pSampledCoordsVector;
this->pInterpWeightsVector = pInterpWeightsVector;
prepareSamplingWeights(offsets, modulation, true);
const int G = jcp.ngroups;
const int MB = jcp.mb;
const int OH = jcp.oh;
@@ -958,26 +973,26 @@ void MKLDNNDeformableConvolutionNode::executeReference(const float* src, const f
const int HW = OH * OW;
const int channel_per_deformable_group = (IC * G) / DG;
const size_t group_wei_stride = wei_strides[0] * OC;
const size_t group_wei_stride = weiStrides[0] * OC;
auto compKer = [=](int g, int mb, int oc, int oh, int ow) {
float d = 0;
for (int ic = 0; ic < IC; ic++) {
const float *data_im_ptr = src + mb * src_strides[0] + (g * IC + ic) * src_strides[1];
const float *data_im_ptr = src + mb * srcStrides[0] + (g * IC + ic) * srcStrides[1];
const int deformable_group_index = (IC * g + ic) / channel_per_deformable_group;
int sampledCoordIndex = (mb * DGHW + deformable_group_index * HW + oh * OW + ow) * ker_size * sampledPointsPerPixel;
size_t weiIndex = (size_t) g * group_wei_stride + oc * wei_strides[0] + ic * wei_strides[1];
for (int kh_off = 0; kh_off < KH * wei_strides[2]; kh_off += wei_strides[2]) {
for (int kw_off = 0; kw_off < KW * wei_strides[3]; kw_off += wei_strides[3]) {
size_t weiIndex = (size_t) g * group_wei_stride + oc * weiStrides[0] + ic * weiStrides[1];
for (int kh_off = 0; kh_off < KH * weiStrides[2]; kh_off += weiStrides[2]) {
for (int kw_off = 0; kw_off < KW * weiStrides[3]; kw_off += weiStrides[3]) {
// check if current addendum marked as equal zero
if (sampledCoordsVector[sampledCoordIndex] != -1) {
const int v11 = sampledCoordsVector[sampledCoordIndex];
const int v12 = sampledCoordsVector[sampledCoordIndex + 1];
const int v21 = sampledCoordsVector[sampledCoordIndex + 2];
const int v22 = sampledCoordsVector[sampledCoordIndex + 3];
float val = interpWeightsVector[sampledCoordIndex++] * data_im_ptr[v11]; // v11
val += interpWeightsVector[sampledCoordIndex++] * data_im_ptr[v12]; // v12
val += interpWeightsVector[sampledCoordIndex++] * data_im_ptr[v21]; // v21
val += interpWeightsVector[sampledCoordIndex++] * data_im_ptr[v22]; // v22
if (pSampledCoordsVector[sampledCoordIndex] != -1) {
const int v11 = pSampledCoordsVector[sampledCoordIndex];
const int v12 = pSampledCoordsVector[sampledCoordIndex + 1];
const int v21 = pSampledCoordsVector[sampledCoordIndex + 2];
const int v22 = pSampledCoordsVector[sampledCoordIndex + 3];
float val = pInterpWeightsVector[sampledCoordIndex++] * data_im_ptr[v11]; // v11
val += pInterpWeightsVector[sampledCoordIndex++] * data_im_ptr[v12]; // v12
val += pInterpWeightsVector[sampledCoordIndex++] * data_im_ptr[v21]; // v21
val += pInterpWeightsVector[sampledCoordIndex++] * data_im_ptr[v22]; // v22
d += val * weights[weiIndex + kh_off + kw_off];
} else {
sampledCoordIndex += sampledPointsPerPixel;
@@ -990,14 +1005,81 @@ void MKLDNNDeformableConvolutionNode::executeReference(const float* src, const f
parallel_nd(G, MB, OC, OH, OW,
[&](int g, int mb, int oc, int oh, int ow) {
dst[mb * dst_strides[0] + (g * OC + oc) * dst_strides[1] + oh * dst_strides[2] + ow * dst_strides[3]] = compKer(g, mb, oc, oh, ow);
dst[mb * dstStrides[0] + (g * OC + oc) * dstStrides[1] + oh * dstStrides[2] + ow * dstStrides[3]] = compKer(g, mb, oc, oh, ow);
});
}
void MKLDNNDeformableConvolutionNode::prepareParams() {
auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
auto& srcMemPtr = getParentEdgeAt(DATA_ID)->getMemoryPtr();
auto& offMemPtr = getParentEdgeAt(OFF_ID)->getMemoryPtr();
auto& weiMemPtr = getParentEdgeAt(WEI_ID)->getMemoryPtr();
void MKLDNNDeformableConvolutionNode::executeOptimized(const float* src, const float* weights, float* dst,
const std::vector<size_t>& src_strides,
const std::vector<size_t>& dst_strides) {
if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr())
IE_THROW() << errorPrefix << " did not allocate destination memory";
if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr())
IE_THROW() << errorPrefix << " did not allocate input memory";
if (!offMemPtr || !offMemPtr->GetPrimitivePtr())
IE_THROW() << errorPrefix << " did not allocate offsets shape memory";
if (!weiMemPtr || !weiMemPtr->GetPrimitivePtr())
IE_THROW() << errorPrefix << " did not allocate weights memory";
if (getOriginalInputsNumber() > 3) {
auto& modMemPtr = getParentEdgeAt(MOD_ID)->getMemoryPtr();
if (!modMemPtr || !modMemPtr->GetPrimitivePtr())
IE_THROW() << errorPrefix << " did not allocate modulations memory";
}
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << errorPrefix << "' doesn't have primitive descriptors.";
auto config = selectedPrimitiveDescriptor->getConfig();
bool withModulation = getParentEdges().size() > 3;
updatePadding();
std::vector<std::shared_ptr<BlockedMemoryDesc>> descVector {
getParentEdgeAt(DATA_ID)->getMemory().GetDescWithType<BlockedMemoryDesc>(),
getParentEdgeAt(OFF_ID)->getMemory().GetDescWithType<BlockedMemoryDesc>(),
getParentEdgeAt(WEI_ID)->getMemory().GetDescWithType<BlockedMemoryDesc>()
};
if (withModulation) {
descVector.push_back(getParentEdgeAt(MOD_ID)->getMemory().GetDescWithType<BlockedMemoryDesc>());
}
descVector.push_back(getChildEdgesAtPort(0)[0]->getMemory().GetDescWithType<BlockedMemoryDesc>());
const int MB = getParentEdgeAt(DATA_ID)->getMemory().getStaticDims()[0];
const int OH = getChildEdgesAtPort(0)[0]->getMemory().getStaticDims()[2];
const int OW = getChildEdgesAtPort(0)[0]->getMemory().getStaticDims()[3];
const int KH = getParentEdgeAt(WEI_ID)->getMemory().getStaticDims()[2];
const int KW = getParentEdgeAt(WEI_ID)->getMemory().getStaticDims()[3];
const int DG = defConvAttr.deformable_group;
// allocate sampling weights and indices
sampledCoordsVector.resize(MB * DG * KH * KW * OH * OW * sampledPointsPerPixel);
interpWeightsVector.resize(MB * DG * KH * KW * OH * OW * sampledPointsPerPixel);
if (enforceRef) {
execPtr = std::make_shared<DefConvRefExecutor>(defConvAttr, descVector);
} else {
execPtr = std::make_shared<DefConvJitExecutor>(defConvAttr, descVector);
}
}
void MKLDNNDeformableConvolutionNode::executeDynamicImpl(dnnl::stream strm) {
execute(strm);
}
void MKLDNNDeformableConvolutionNode::DefConvJitExecutor::exec(const float* src, const float* offsets,
const float* weights, const float* modulation, float* dst,
int *pSampledCoordsVector, float *pInterpWeightsVector) {
this->pSampledCoordsVector = pSampledCoordsVector;
this->pInterpWeightsVector = pInterpWeightsVector;
prepareSamplingWeights(offsets, modulation, false);
size_t buffer_size = (size_t)jcp.nthr * jcp.ur_w * jcp.kh * jcp.kw * jcp.ic * jcp.typesize_in;
std::vector<float> input_buffer(buffer_size, 0);
float* input_buffer_ptr = input_buffer.data();
@@ -1010,12 +1092,12 @@ void MKLDNNDeformableConvolutionNode::executeOptimized(const float* src, const f
const size_t _oc = g * jcp.nb_oc;
const size_t _ic = g * jcp.nb_ic;
par_conv.src = &src[n * src_strides[0] + _ic*jcp.ic_block * src_strides[1] +
(oh * jcp.stride_h - jcp.t_pad) * src_strides[2] - jcp.l_pad * src_strides[3]];
par_conv.sampledWei = &interpWeightsVector[(n * jcp.dg * jcp.oh + oh) * jcp.kh * jcp.kw * jcp.ow * sampledPointsPerPixel];
par_conv.sampledCoords = &sampledCoordsVector[(n * jcp.dg * jcp.oh + oh) * jcp.kh * jcp.kw * jcp.ow * sampledPointsPerPixel];
par_conv.src = &src[n * srcStrides[0] + _ic*jcp.ic_block * srcStrides[1] +
(oh * jcp.stride_h - jcp.t_pad) * srcStrides[2] - jcp.l_pad * srcStrides[3]];
par_conv.sampledWei = &(pInterpWeightsVector[(n * jcp.dg * jcp.oh + oh) * jcp.kh * jcp.kw * jcp.ow * sampledPointsPerPixel]);
par_conv.sampledCoords = &(pSampledCoordsVector[(n * jcp.dg * jcp.oh + oh) * jcp.kh * jcp.kw * jcp.ow * sampledPointsPerPixel]);
par_conv.filt = &weights[g * jcp.nb_oc * jcp.nb_ic * jcp.kh * jcp.kw * jcp.ic_block * jcp.oc_block];
par_conv.dst = &dst[n * dst_strides[0] + _oc * jcp.oc_block * dst_strides[1] + oh * dst_strides[2]];
par_conv.dst = &dst[n * dstStrides[0] + _oc * jcp.oc_block * dstStrides[1] + oh * dstStrides[2]];
par_conv.buf = input_buffer_ptr + ithr * jcp.ur_w * jcp.kh * jcp.kw * jcp.ic;
par_conv.oh_pos = oh;
@@ -1044,34 +1126,21 @@ void MKLDNNDeformableConvolutionNode::execute(mkldnn::stream strm) {
auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor();
if (!selectedPrimitiveDescriptor)
IE_THROW() << "CPU deformable convolution with name '" << getName() << "' doesn't have primitive descriptors.";
IE_THROW() << "Deformable convolution with name '" << getName() << "' doesn't have primitive descriptors.";
auto config = selectedPrimitiveDescriptor->getConfig();
auto src_block_desc = getParentEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
std::vector<size_t> src_strides(src_block_desc->getStrides().size());
for (int i = 0; i < src_strides.size(); i++) {
src_strides[src_block_desc->getOrder()[i]] = src_block_desc->getStrides()[i];
}
auto dst_block_desc = getChildEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
std::vector<size_t> dst_strides(dst_block_desc->getStrides().size());
for (int i = 0; i < dst_strides.size(); i++) {
dst_strides[dst_block_desc->getOrder()[i]] = dst_block_desc->getStrides()[i];
}
auto off_strides = getParentEdgeAt(1)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
auto wei_strides = getParentEdgeAt(2)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
InferenceEngine::SizeVector modulation_strides;
if (inputsNumber > 3) {
modulation_strides = getParentEdgeAt(3)->getMemory().GetDescWithType<BlockedMemoryDesc>()->getStrides();
}
prepareSamplingWeights(src_strides, offsets, off_strides, modulation, modulation_strides);
if (def_conv_kernel) {
executeOptimized(src, weights, dst, src_strides, dst_strides);
if (execPtr) {
execPtr->exec(src, offsets, weights, modulation, dst, sampledCoordsVector.data(), interpWeightsVector.data());
} else {
executeReference(src, weights, dst, src_strides, wei_strides, dst_strides);
IE_THROW() << "Deformable Convolution executor doesn't exist";
}
}
void MKLDNNDeformableConvolutionNode::updatePadding() {
//update padding. TODO [DS] : rewrite when the final shape inference interface is available
if (isDynamicNode() && autoPadding) {
auto defConvNodeBase = std::dynamic_pointer_cast<ngraph::op::util::DeformableConvolutionBase>(opToShapeInfer);
defConvAttr.padL = defConvNodeBase->get_pads_begin();
}
}
@@ -73,7 +73,6 @@ public:
static bool isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept;
void getSupportedDescriptors() override;
void createPrimitive() override;
void initSupportedPrimitiveDescriptors() override;
void execute(mkldnn::stream strm) override;
bool created() const override;
@@ -86,29 +85,73 @@ public:
InferenceEngine::Precision getRuntimePrecision() const override;
private:
size_t group = 1;
bool with_bilinear_pad = false;
std::vector<ptrdiff_t> stride = {};
std::vector<ptrdiff_t> dilation = {};
std::vector<ptrdiff_t> paddingL = {};
int deformable_group = 1;
jit_def_conv_params jcp = {};
struct DefConvAttr {
size_t group = 1;
int deformable_group = 1;
bool with_bilinear_pad = false;
std::vector<ptrdiff_t> stride = {};
std::vector<ptrdiff_t> dilation = {};
std::vector<ptrdiff_t> padL;
} defConvAttr;
std::vector<int> sampledCoordsVector;
std::vector<float> interpWeightsVector;
std::shared_ptr<jit_uni_def_conv_kernel> def_conv_kernel = nullptr;
void prepareParams() override;
void updatePadding();
void prepareSamplingWeights(const std::vector<size_t>& src_strides, const float* offsets, const std::vector<size_t>& off_strides,
const float* modulation = nullptr, const std::vector<size_t>& modulation_strides = {});
void executeDynamicImpl(mkldnn::stream strm) override;
static constexpr size_t DATA_ID = 0;
static constexpr size_t OFF_ID = 1;
static constexpr size_t WEI_ID = 2;
static constexpr size_t MOD_ID = 3;
std::string errorPrefix;
class DefConvExecutor {
public:
DefConvExecutor(const DefConvAttr &defConvAttr,
const std::vector<std::shared_ptr<BlockedMemoryDesc>> &descVector);
void executeReference(const float* src, const float* weights, float* dst, const std::vector<size_t>& src_strides,
const std::vector<size_t>& wei_strides, const std::vector<size_t>& dst_strides);
void executeOptimized(const float* src, const float* weights, float* dst,
const std::vector<size_t>& src_strides, const std::vector<size_t>& dst_strides);
virtual void exec(const float* src, const float* offsets,
const float* weights, const float* modulation, float* dst,
int *pSampledCoordsVector, float *pInterpWeightsVector) = 0;
virtual ~DefConvExecutor() = default;
protected:
void prepareSamplingWeights(const float* offsets, const float* modulation = nullptr, bool enforceRef = false);
jit_def_conv_params jcp = {};
VectorDims srcStrides;
VectorDims offStrides;
VectorDims weiStrides;
VectorDims modStrides;
VectorDims dstStrides;
int *pSampledCoordsVector;
float *pInterpWeightsVector;
};
class DefConvRefExecutor : public DefConvExecutor {
public:
DefConvRefExecutor(const DefConvAttr &defConvAttr,
const std::vector<std::shared_ptr<BlockedMemoryDesc>> &descVector) :
DefConvExecutor(defConvAttr, descVector) {}
void exec(const float* src, const float* offsets,
const float* weights, const float* modulation, float* dst,
int *pSampledCoordsVector, float *pInterpWeightsVector) override;
};
class DefConvJitExecutor : public DefConvExecutor {
std::shared_ptr<jit_uni_def_conv_kernel> def_conv_kernel = nullptr;
public:
DefConvJitExecutor(const DefConvAttr &defConvAttr,
const std::vector<std::shared_ptr<BlockedMemoryDesc>> &descVector);
void exec(const float* src, const float* offsets,
const float* weights, const float* modulation, float* dst,
int *pSampledCoordsVector, float *pInterpWeightsVector) override;
};
std::shared_ptr<DefConvExecutor> execPtr = nullptr;
bool autoPadding = false;
};
} // namespace MKLDNNPlugin