558 lines
28 KiB
C++
558 lines
28 KiB
C++
// Copyright (C) 2018-2021 Intel Corporation
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <mkldnn_types.h>
|
|
#include "ie_parallel.hpp"
|
|
#include "utils/bfloat16.hpp"
|
|
#include <mkldnn_selective_build.h>
|
|
#include <ngraph/opsets/opset1.hpp>
|
|
#include "mkldnn_psroi_pooling_node.h"
|
|
#include <cpu/x64/jit_generator.hpp>
|
|
#include <nodes/common/blocked_desc_creator.h>
|
|
|
|
using namespace MKLDNNPlugin;
|
|
using namespace InferenceEngine;
|
|
using namespace mkldnn;
|
|
using namespace mkldnn::impl;
|
|
using namespace mkldnn::impl::cpu::x64;
|
|
using namespace mkldnn::impl::utils;
|
|
|
|
bool MKLDNNPSROIPoolingNode::isSupportedOperation(const std::shared_ptr<ngraph::Node>& op, std::string& errorMessage) noexcept {
|
|
try {
|
|
const auto psroi = std::dynamic_pointer_cast<const ngraph::opset1::PSROIPooling>(op);
|
|
const auto defPsroi = std::dynamic_pointer_cast<const ngraph::opset1::DeformablePSROIPooling>(op);
|
|
if (!psroi && !defPsroi) {
|
|
errorMessage = "Only opset1 PSROIPooling and DeformablePSROIPooling operations are supported";
|
|
return false;
|
|
}
|
|
|
|
std::string mode;
|
|
if (psroi) {
|
|
mode = psroi->get_mode();
|
|
if (mode != "average" && mode != "bilinear") {
|
|
errorMessage = "Doesn't support mode: " + mode;
|
|
return false;
|
|
}
|
|
} else if (defPsroi) {
|
|
mode = defPsroi->get_mode();
|
|
if (mode != "bilinear_deformable") {
|
|
errorMessage = "Doesn't support mode: " + mode;
|
|
return false;
|
|
}
|
|
}
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MKLDNNPSROIPoolingNode::MKLDNNPSROIPoolingNode(const std::shared_ptr<ngraph::Node>& op, const mkldnn::engine& eng,
|
|
MKLDNNWeightsSharing::Ptr &cache) : MKLDNNNode(op, eng, cache) {
|
|
std::string errorMessage;
|
|
if (!isSupportedOperation(op, errorMessage)) {
|
|
IE_THROW(NotImplemented) << errorMessage;
|
|
}
|
|
|
|
errorPrefix = std::string(op->get_type_name()) + " node with name '" + op->get_friendly_name() + "'";
|
|
|
|
const auto psroi = std::dynamic_pointer_cast<const ngraph::opset1::PSROIPooling>(op);
|
|
const auto defPsroi = std::dynamic_pointer_cast<const ngraph::opset1::DeformablePSROIPooling>(op);
|
|
|
|
noTrans = op->get_input_size() == 2;
|
|
if (op->get_input_shape(0).size() != 4)
|
|
IE_THROW() << errorPrefix << " has first input with incorrect rank: " + std::to_string(op->get_input_shape(0).size());
|
|
if (op->get_input_shape(1).size() != 2)
|
|
IE_THROW() << errorPrefix << " has second input with incorrect rank: " + std::to_string(op->get_input_shape(1).size());
|
|
if (!noTrans && op->get_input_shape(2).size() != 4)
|
|
IE_THROW() << errorPrefix << " has third input with incorrect rank: " + std::to_string(op->get_input_shape(2).size());
|
|
|
|
if (psroi) {
|
|
if (psroi->get_input_size() != 2)
|
|
IE_THROW() << errorPrefix << " has incorrect number of input/output edges!";
|
|
|
|
mode = psroi->get_mode();
|
|
if (mode == "average") {
|
|
algorithm = Algorithm::PSROIPoolingAverage;
|
|
} else if (mode == "bilinear") {
|
|
algorithm = Algorithm::PSROIPoolingBilinear;
|
|
}
|
|
|
|
outputDim = static_cast<size_t>(psroi->get_output_dim());
|
|
spatialScale = psroi->get_spatial_scale();
|
|
groupSize = static_cast<size_t>(psroi->get_group_size());
|
|
mode = psroi->get_mode();
|
|
spatialBinsX = static_cast<size_t>(psroi->get_spatial_bins_x());
|
|
spatialBinsY = static_cast<size_t>(psroi->get_spatial_bins_y());
|
|
pooledHeight = groupSize;
|
|
pooledWidth = groupSize;
|
|
|
|
} else if (defPsroi) {
|
|
if (defPsroi->get_input_size() != 2 && defPsroi->get_input_size() != 3)
|
|
IE_THROW() << errorPrefix << " has incorrect number of input/output edges!";
|
|
|
|
algorithm = Algorithm::PSROIPoolingBilinearDeformable;
|
|
|
|
outputDim = static_cast<size_t>(defPsroi->get_output_dim());
|
|
spatialScale = defPsroi->get_spatial_scale();
|
|
groupSize = static_cast<size_t>(defPsroi->get_group_size());
|
|
mode = defPsroi->get_mode();
|
|
spatialBinsX = static_cast<size_t>(defPsroi->get_spatial_bins_x());
|
|
spatialBinsY = static_cast<size_t>(defPsroi->get_spatial_bins_y());
|
|
transStd = defPsroi->get_trans_std();
|
|
partSize = static_cast<size_t>(defPsroi->get_part_size());
|
|
// temporary workaround due to incorrect usage of group_size in the nGraph operation for the DeformablePSROIPooling
|
|
pooledHeight = groupSize;
|
|
pooledWidth = groupSize;
|
|
}
|
|
|
|
ngraph::Shape inDims = op->get_input_shape(0);
|
|
channels = static_cast<int>(inDims[1]);
|
|
height = static_cast<int>(inDims[2]);
|
|
width = static_cast<int>(inDims[3]);
|
|
|
|
ngraph::Shape outDims = op->get_shape();
|
|
nn = static_cast<int>(outDims[0]);
|
|
nc = static_cast<int>(outDims[1]);
|
|
nh = static_cast<int>(outDims[2]);
|
|
nw = static_cast<int>(outDims[3]);
|
|
}
|
|
|
|
void MKLDNNPSROIPoolingNode::initSupportedPrimitiveDescriptors() {
|
|
if (!supportedPrimitiveDescriptors.empty())
|
|
return;
|
|
|
|
impl_desc_type impl_type;
|
|
if (mayiuse(cpu::x64::avx512_common)) {
|
|
impl_type = impl_desc_type::jit_avx512;
|
|
} else if (mayiuse(cpu::x64::avx2)) {
|
|
impl_type = impl_desc_type::jit_avx2;
|
|
} else if (mayiuse(cpu::x64::sse41)) {
|
|
impl_type = impl_desc_type::jit_sse42;
|
|
} else {
|
|
impl_type = impl_desc_type::ref;
|
|
}
|
|
|
|
auto dataPrecision = getOriginalInputPrecisionAtPort(0) == Precision::BF16 ? Precision::BF16 : Precision::FP32;
|
|
|
|
if (getAlgorithm() == Algorithm::PSROIPoolingAverage || getAlgorithm() == Algorithm::PSROIPoolingBilinear) {
|
|
std::vector<std::pair<LayoutType, LayoutType>> dataFomats{
|
|
{LayoutType::ncsp, LayoutType::ncsp},
|
|
{LayoutType::nspc, LayoutType::nspc},
|
|
{LayoutType::nCsp16c, LayoutType::nCsp16c},
|
|
{LayoutType::nCsp8c, LayoutType::nCsp8c}
|
|
};
|
|
|
|
for (const auto &df : dataFomats) {
|
|
addSupportedPrimDesc({{df.first, dataPrecision}, {LayoutType::ncsp, Precision::FP32}},
|
|
{{df.second, dataPrecision}},
|
|
impl_type);
|
|
}
|
|
} else if (getAlgorithm() == Algorithm::PSROIPoolingBilinearDeformable && noTrans) {
|
|
addSupportedPrimDesc({{LayoutType::ncsp, dataPrecision}, {LayoutType::ncsp, Precision::FP32}},
|
|
{{LayoutType::ncsp, dataPrecision}},
|
|
impl_type);
|
|
} else if (getAlgorithm() == Algorithm::PSROIPoolingBilinearDeformable) {
|
|
addSupportedPrimDesc({{LayoutType::ncsp, dataPrecision},
|
|
{LayoutType::ncsp, Precision::FP32},
|
|
{LayoutType::ncsp, Precision::FP32}},
|
|
{{LayoutType::ncsp, dataPrecision}},
|
|
impl_type);
|
|
}
|
|
}
|
|
|
|
template <typename inputType>
|
|
inline float bilinearInterp(const inputType* data, const float x, const float y, const int width_) {
|
|
int x1 = static_cast<int>(std::floor(x));
|
|
int x2 = static_cast<int>(std::ceil(x));
|
|
int y1 = static_cast<int>(std::floor(y));
|
|
int y2 = static_cast<int>(std::ceil(y));
|
|
float distX = x - x1;
|
|
float distY = y - y1;
|
|
|
|
float value11 = data[y1 * width_ + x1];
|
|
float value12 = data[y2 * width_ + x1];
|
|
float value21 = data[y1 * width_ + x2];
|
|
float value22 = data[y2 * width_ + x2];
|
|
float value = (1 - distX) * (1 - distY) * value11 + (1 - distX) * distY * value12
|
|
+ distX * (1 - distY) * value21 + distX * distY * value22;
|
|
return value;
|
|
}
|
|
|
|
void MKLDNNPSROIPoolingNode::unpackParams(const BlockedMemoryDesc& srcDesc, const BlockedMemoryDesc& dstDesc,
|
|
int& hInputStride, int& wInputStride,
|
|
int& hOutputStride, int& wOutputStride,
|
|
int& inBlockSize, int& outBlockSize,
|
|
int& outBlockCount,
|
|
unsigned long& inputChannelsPadding, unsigned long& outputChannelsPadding) {
|
|
const bool inpIsBlk = srcDesc.hasLayoutType(LayoutType::nCsp16c) || srcDesc.hasLayoutType(LayoutType::nCsp8c);
|
|
const bool outIsBlk = dstDesc.hasLayoutType(LayoutType::nCsp16c) || dstDesc.hasLayoutType(LayoutType::nCsp8c);
|
|
int expectedInBlockDimsSize = (inpIsBlk ? 5 : 4);
|
|
int expectedOutBlockDimsSize = (outIsBlk ? 5 : 4);
|
|
auto inBlkDims = srcDesc.getBlockDims();
|
|
auto outBlkDims = dstDesc.getBlockDims();
|
|
if (inBlkDims.size() != expectedInBlockDimsSize)
|
|
IE_THROW() << errorPrefix << " has unexpected size of blocking dims in input (given " << inBlkDims.size() << ", expected "
|
|
<< expectedInBlockDimsSize << ")";
|
|
if (outBlkDims.size() != expectedOutBlockDimsSize)
|
|
IE_THROW() << errorPrefix << " has unexpected size of blocking dims in output (given " << outBlkDims.size() << ", expected "
|
|
<< expectedOutBlockDimsSize << ")";
|
|
|
|
inBlockSize = (inpIsBlk ? srcDesc.getBlockDims()[4] : 1);
|
|
outBlockSize = (outIsBlk ? dstDesc.getBlockDims()[4] : 1);
|
|
inputChannelsPadding = srcDesc.getBlockDims()[1] * inBlockSize;
|
|
outputChannelsPadding = dstDesc.getBlockDims()[1] * outBlockSize;
|
|
outBlockCount = outputChannelsPadding / outBlockSize;
|
|
|
|
int hOutStrIndex = 0, wOutStrIndex = 0, hInStrIndex = 0, wInStrIndex = 0;
|
|
const auto& outOrder = dstDesc.getOrder();
|
|
const auto& inOrder = srcDesc.getOrder();
|
|
for (int i = 0; i < outOrder.size(); i++) {
|
|
if (outOrder[i] == 2) hOutStrIndex = i;
|
|
if (outOrder[i] == 3) wOutStrIndex = i;
|
|
}
|
|
for (int i = 0; i < inOrder.size(); i++) {
|
|
if (inOrder[i] == 2) hInStrIndex = i;
|
|
if (inOrder[i] == 3) wInStrIndex = i;
|
|
}
|
|
hInputStride = srcDesc.getStrides()[hInStrIndex];
|
|
wInputStride = srcDesc.getStrides()[wInStrIndex];
|
|
hOutputStride = dstDesc.getStrides()[hOutStrIndex];
|
|
wOutputStride = dstDesc.getStrides()[wOutStrIndex];
|
|
}
|
|
|
|
template <typename inputType, typename outputType>
|
|
void MKLDNNPSROIPoolingNode::executeAverage(const inputType *srcData, outputType *dstData, const float *bottomRois,
|
|
const int n, const int roiBatchInd,
|
|
const BlockedMemoryDesc& srcDesc, const BlockedMemoryDesc& dstDesc) {
|
|
int inBlockSize, outBlockSize, outBlockCount, hInputStride, wInputStride, hOutputStride, wOutputStride;
|
|
unsigned long inputChannelsPadding, outputChannelsPadding;
|
|
unpackParams(srcDesc, dstDesc, hInputStride, wInputStride, hOutputStride, wOutputStride,
|
|
inBlockSize, outBlockSize, outBlockCount, inputChannelsPadding, outputChannelsPadding);
|
|
const float roiStartW = static_cast<float>(round(bottomRois[1])) * spatialScale;
|
|
const float roiStartH = static_cast<float>(round(bottomRois[2])) * spatialScale;
|
|
const float roiEndW = static_cast<float>(round(bottomRois[3] + 1.0f)) * spatialScale;
|
|
const float roiEndH = static_cast<float>(round(bottomRois[4] + 1.0f)) * spatialScale;
|
|
// Force too small ROIs to be 1x1
|
|
const float roiWidth = std::max<float>(roiEndW - roiStartW, 0.1f); // avoid 0
|
|
const float roiHeight = std::max<float>(roiEndH - roiStartH, 0.1f);
|
|
|
|
auto avgPsroi = [&] (int c, int h, int w, int binOffIn, int binOffOut, int inBlkRes, int outBlkRes) {
|
|
float binSizeH = roiHeight / static_cast<float>(pooledHeight);
|
|
float binSizeW = roiWidth / static_cast<float>(pooledWidth);
|
|
|
|
int hStart = static_cast<int>(floor(static_cast<float>(h + 0) * binSizeH + roiStartH));
|
|
int hEnd = static_cast<int>(ceil(static_cast<float>(h + 1) * binSizeH + roiStartH));
|
|
|
|
hStart = std::min<int>(std::max<int>(hStart, 0), height);
|
|
hEnd = std::min<int>(std::max<int>(hEnd, 0), height);
|
|
int wStart = static_cast<int>(floor(static_cast<float>(w + 0) * binSizeW + roiStartW));
|
|
int wEnd = static_cast<int>(ceil(static_cast<float>(w + 1) * binSizeW + roiStartW));
|
|
|
|
wStart = std::min<int>(std::max<int>(wStart, 0), width);
|
|
wEnd = std::min<int>(std::max<int>(wEnd, 0), width);
|
|
|
|
const float binArea = static_cast<float>((hEnd - hStart) * (wEnd - wStart));
|
|
|
|
size_t dstIndex = binOffOut + h * hOutputStride + w * wOutputStride + outBlkRes;
|
|
dstData[dstIndex] = 0;
|
|
if (binArea) {
|
|
float outSum = 0.0f;
|
|
const int heightIndexBound = hEnd * hInputStride;
|
|
const int widthIndexBound = wEnd * wInputStride;
|
|
for (int hh = hStart * hInputStride; hh < heightIndexBound; hh += hInputStride) {
|
|
for (int ww = wStart * wInputStride; ww < widthIndexBound; ww += wInputStride) {
|
|
outSum += srcData[binOffIn + hh + ww + inBlkRes];
|
|
}
|
|
}
|
|
dstData[dstIndex] = outSum / binArea;
|
|
}
|
|
};
|
|
if (srcDesc.hasLayoutType(LayoutType::nspc)) {
|
|
parallel_for2d(nh, nw, [&](int h, int w) {
|
|
const int binOffsetOutput = n * nc * nh * nw;
|
|
const int binOffsetInput = roiBatchInd * channels * height * width;
|
|
for (int c = 0; c < nc; c++) {
|
|
const int gc = (c * groupSize + h) * groupSize + w;
|
|
avgPsroi(c, h, w, 0, 0, binOffsetInput + gc, binOffsetOutput + c);
|
|
}
|
|
});
|
|
} else if (srcDesc.hasLayoutType(LayoutType::ncsp)) {
|
|
parallel_for3d(nc, nh, nw, [&](int c, int h, int w) {
|
|
const int gc = (c * groupSize + h) * groupSize + w;
|
|
const int outputBlockResidual = (dstDesc.hasLayoutType(LayoutType::ncsp) ? 0 : c % inBlockSize);
|
|
const int outputBlockIdx = (c / outBlockSize) * outBlockSize;
|
|
const int binOffsetInput = (roiBatchInd * inputChannelsPadding + gc) * height * width;
|
|
const int binOffsetOutput = (n * outputChannelsPadding + outputBlockIdx) * nh * nw;
|
|
avgPsroi(c, h, w, 0, outputBlockResidual, binOffsetInput, binOffsetOutput);
|
|
});
|
|
} else { // nChw16c, nChw8c
|
|
parallel_for3d(outBlockCount, nh, nw, [&](int blkIdx, int h, int w) {
|
|
int cStart = blkIdx * outBlockSize;
|
|
int cEnd = (blkIdx == outBlockCount - 1 ? nc : cStart + outBlockSize);
|
|
for (int c = cStart; c < cEnd; c++) {
|
|
const int gc = (c * groupSize + h) * groupSize + w;
|
|
const int inputBlockResidual = (srcDesc.hasLayoutType(LayoutType::ncsp) ? 0 : gc % inBlockSize);
|
|
const int outputBlockResidual = (dstDesc.hasLayoutType(LayoutType::ncsp) ? 0 : c % inBlockSize);
|
|
const int inputBlockIdx = (gc / inBlockSize) * inBlockSize;
|
|
const int outputBlockIdx = (c / outBlockSize) * outBlockSize;
|
|
const int binOffsetInput = (roiBatchInd * inputChannelsPadding + inputBlockIdx) * height * width;
|
|
const int binOffsetOutput = (n * outputChannelsPadding + outputBlockIdx) * nh * nw;
|
|
avgPsroi(c, h, w, inputBlockResidual, outputBlockResidual, binOffsetInput, binOffsetOutput);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
template <typename inputType, typename outputType>
|
|
void MKLDNNPSROIPoolingNode::executeBilinear(const inputType *srcData, outputType *dstData, const float *bottomRois,
|
|
const int currentRoi, const int roiBatchInd,
|
|
const BlockedMemoryDesc& srcDesc, const BlockedMemoryDesc& dstDesc) {
|
|
int inBlockSize, outBlockSize, outBlockCount, hInputStride, wInputStride, hOutputStride, wOutputStride;
|
|
unsigned long inputChannelsPadding, outputChannelsPadding;
|
|
unpackParams(srcDesc, dstDesc, hInputStride, wInputStride, hOutputStride, wOutputStride,
|
|
inBlockSize, outBlockSize, outBlockCount, inputChannelsPadding, outputChannelsPadding);
|
|
const float roiStartW = bottomRois[1] * spatialScale;
|
|
const float roiStartH = bottomRois[2] * spatialScale;
|
|
const float roiEndW = bottomRois[3] * spatialScale;
|
|
const float roiEndH = bottomRois[4] * spatialScale;
|
|
const float roiWidth = roiEndW - roiStartW;
|
|
const float roiHeight = roiEndH - roiStartH;
|
|
size_t numBins = spatialBinsX * spatialBinsY;
|
|
const int binCount = nh * nw;
|
|
|
|
auto bilinearPsroi = [&] (int c, int h, int w, int binOffOut, int outBlkRes) {
|
|
float accum = 0.0f;
|
|
int binOffIn, inBlkRes;
|
|
size_t dstIndex = binOffOut + h * hOutputStride + w * wOutputStride + outBlkRes;
|
|
dstData[dstIndex] = 0;
|
|
|
|
for (size_t binY = 0; binY < spatialBinsY; binY++) {
|
|
const float boxYmin = roiStartH + (binY + 0) * (roiHeight / spatialBinsY);
|
|
const float boxYmax = roiStartH + (binY + 1) * (roiHeight / spatialBinsY);
|
|
const float heightScale = nh > 1 ? (boxYmax - boxYmin) * (height - 1) / (pooledHeight - 1) : 0.0f;
|
|
const float inY = nh > 1 ? (h * heightScale + boxYmin * (height - 1)) : 0.5f * (boxYmin + boxYmax) * (height - 1);
|
|
for (size_t binX = 0; binX < spatialBinsX; binX++) {
|
|
size_t gc = c + (binY * spatialBinsX + binX) * nc;
|
|
if (srcDesc.hasLayoutType(LayoutType::nspc)) {
|
|
binOffIn = roiBatchInd * channels * height * width + gc;
|
|
inBlkRes = 0;
|
|
} else { // nchw, nChw16c, nChw8c
|
|
const int inputBlockIdx = (gc / inBlockSize) * inBlockSize;
|
|
binOffIn = (roiBatchInd * inputChannelsPadding + inputBlockIdx) * height * width;
|
|
inBlkRes = ((srcDesc.hasLayoutType(LayoutType::nCsp16c) || srcDesc.hasLayoutType(LayoutType::nCsp8c))
|
|
? gc % inBlockSize : 0);
|
|
}
|
|
const auto *bottomData = srcData + binOffIn;
|
|
|
|
const float boxXmin = roiStartW + (binX + 0) * (roiWidth / spatialBinsX);
|
|
const float boxXmax = roiStartW + (binX + 1) * (roiWidth / spatialBinsX);
|
|
|
|
const float widthScale = nw > 1 ? (boxXmax - boxXmin) * (width - 1) / (pooledWidth - 1) : 0.0f;
|
|
const float inX = nw > 1 ? (w * widthScale + boxXmin * (width - 1)) : 0.5f * (boxXmin + boxXmax) * (width - 1);
|
|
|
|
if (!(inY < 0 || inY > height - 1 || inX < 0 || inX > width - 1)) {
|
|
const int topYIndex = static_cast<int>(floorf(inY));
|
|
int bottomYIndex = static_cast<int>(ceilf(inY));
|
|
const int leftXIndex = static_cast<int>(floorf(inX));
|
|
int rightXIndex = static_cast<int>(ceilf(inX));
|
|
|
|
if (rightXIndex > width - 1) rightXIndex = width - 1;
|
|
if (bottomYIndex > height - 1) bottomYIndex = height - 1;
|
|
|
|
auto topLeftIndex = topYIndex * hInputStride + leftXIndex * wInputStride + inBlkRes;
|
|
auto topRightIndex = topYIndex * hInputStride + rightXIndex * wInputStride + inBlkRes;
|
|
auto bottomLeftIndex = bottomYIndex * hInputStride + leftXIndex * wInputStride + inBlkRes;
|
|
auto bottomRightIndex = bottomYIndex * hInputStride + rightXIndex * wInputStride + inBlkRes;
|
|
|
|
const float topLeft = bottomData[topLeftIndex];
|
|
const float topRight = bottomData[topRightIndex];
|
|
const float bottomLeft = bottomData[bottomLeftIndex];
|
|
const float bottomRight = bottomData[bottomRightIndex];
|
|
|
|
const float top = topLeft + (topRight - topLeft) * (inX - leftXIndex);
|
|
const float bottom = bottomLeft + (bottomRight - bottomLeft) * (inX - leftXIndex);
|
|
|
|
accum += top + (bottom - top) * (inY - topYIndex);
|
|
}
|
|
}
|
|
}
|
|
accum /= numBins;
|
|
dstData[dstIndex] = accum;
|
|
};
|
|
|
|
if (srcDesc.hasLayoutType(LayoutType::nspc)) {
|
|
const int binOffsetOutput = currentRoi * nc * nh * nw;
|
|
parallel_for2d(nh, nw, [&](int h, int w) {
|
|
for (int c = 0; c < nc; c++) {
|
|
bilinearPsroi(c, h, w, 0, binOffsetOutput + c);
|
|
}
|
|
});
|
|
} else if (srcDesc.hasLayoutType(LayoutType::ncsp)) {
|
|
parallel_for3d(nc, nh, nw, [&](int c, int h, int w) {
|
|
bilinearPsroi(c, h, w, 0, (currentRoi * outputChannelsPadding + c) * binCount);
|
|
});
|
|
} else { // nChw16c, nChw8c
|
|
parallel_for3d(outBlockCount, nh, nw, [&](int blkIdx, int h, int w) {
|
|
int cStart = blkIdx * outBlockSize;
|
|
int cEnd = (blkIdx == outBlockCount - 1 ? nc : cStart + outBlockSize);
|
|
for (int c = cStart; c < cEnd; c++) {
|
|
const int outputBlockIdx = (c / inBlockSize) * inBlockSize;
|
|
const int binOffsetOutput = (currentRoi * outputChannelsPadding + outputBlockIdx) * binCount;
|
|
const int outputBlockResidual = ((srcDesc.hasLayoutType(LayoutType::nCsp16c) || srcDesc.hasLayoutType(LayoutType::nCsp8c))
|
|
? c % inBlockSize : 0);
|
|
bilinearPsroi(c, h, w, outputBlockResidual, binOffsetOutput);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
template <typename inputType, typename outputType>
|
|
void MKLDNNPSROIPoolingNode::executeBilinearDeformable(const inputType *srcData, outputType *dstData, const float *bottomRois,
|
|
const float *bottomTrans, const int numClasses, const int channelsEachClass,
|
|
const int currentRoi, const int roiBatchInd) {
|
|
const float roiStartW = static_cast<float>(round(bottomRois[1])) * spatialScale - 0.5f;
|
|
const float roiStartH = static_cast<float>(round(bottomRois[2])) * spatialScale - 0.5f;
|
|
const float roiEndW = static_cast<float>(round(bottomRois[3]) + 1.0f) * spatialScale - 0.5f;
|
|
const float roiEndH = static_cast<float>(round(bottomRois[4]) + 1.0f) * spatialScale - 0.5f;
|
|
// Force too small ROIs to be 1x1
|
|
const float roiWidth = std::max<float>(roiEndW - roiStartW, 0.1f); // avoid 0
|
|
const float roiHeight = std::max<float>(roiEndH - roiStartH, 0.1f);
|
|
parallel_for3d(nc, nh, nw, [&](int c, int h, int w) {
|
|
size_t dstIndex = ((currentRoi * nc + c) * nh + h) * nw + w;
|
|
dstData[dstIndex] = 0;
|
|
// Compute w and h at bottom
|
|
float binSizeH = roiHeight / static_cast<float>(pooledHeight);
|
|
float binSizeW = roiWidth / static_cast<float>(pooledWidth);
|
|
|
|
float subBinSizeH = binSizeH / static_cast<float>(spatialBinsY);
|
|
float subBinSizeW = binSizeW / static_cast<float>(spatialBinsX);
|
|
|
|
int partH = h * partSize / pooledHeight;
|
|
int partW = w * partSize / pooledWidth;
|
|
int classId = c / channelsEachClass;
|
|
float transX = noTrans ? 0 :
|
|
bottomTrans[(((currentRoi * numClasses + classId) * 2) * partSize + partH)
|
|
* partSize + partW] * transStd;
|
|
float transY = noTrans ? 0 :
|
|
bottomTrans[(((currentRoi * numClasses + classId) * 2 + 1) * partSize + partH)
|
|
* partSize + partW] * transStd;
|
|
|
|
float wStart = w * binSizeW + roiStartW + transX * roiWidth;
|
|
float hStart = h * binSizeH + roiStartH + transY * roiHeight;
|
|
|
|
float sum = 0;
|
|
int count = 0;
|
|
int gw = w * groupSize / pooledWidth;
|
|
int gh = h * groupSize / pooledHeight;
|
|
gw = (std::min)((std::max)(gw, 0), static_cast<int>(groupSize - 1));
|
|
gh = (std::min)((std::max)(gh, 0), static_cast<int>(groupSize - 1));
|
|
|
|
const inputType* offsetBottomData = srcData + (roiBatchInd * channels) * height * width;
|
|
for (size_t ih = 0; ih < spatialBinsY; ih++) {
|
|
for (size_t iw = 0; iw < spatialBinsX; iw++) {
|
|
float w1 = wStart + iw * subBinSizeW;
|
|
float h1 = hStart + ih * subBinSizeH;
|
|
// bilinear interpolation
|
|
if (w1 < -0.5 || w1 > width - 0.5 || h1 < -0.5 || h1 > height - 0.5)
|
|
continue;
|
|
w1 = static_cast<float>((std::min)((std::max)(static_cast<double>(w1), 0.0), width - 1.0));
|
|
h1 = static_cast<float>((std::min)((std::max)(static_cast<double>(h1), 0.0), height - 1.0));
|
|
int c1 = static_cast<int>((c * groupSize + gh) * groupSize + gw);
|
|
float val = bilinearInterp<inputType>(offsetBottomData +
|
|
c1 * height * width, w1, h1, width);
|
|
|
|
sum += val;
|
|
count++;
|
|
}
|
|
}
|
|
dstData[dstIndex] = count == 0 ? 0 : sum / count;
|
|
});
|
|
}
|
|
|
|
template <typename inputType, typename outputType>
|
|
void MKLDNNPSROIPoolingNode::executeSpecified() {
|
|
const auto *srcData = reinterpret_cast<const inputType *>(getParentEdgeAt(0)->getMemoryPtr()->GetPtr());
|
|
const auto *bottomRoisBeginning = reinterpret_cast<const float *>(getParentEdgeAt(1)->getMemoryPtr()->GetPtr());
|
|
auto *dstData = reinterpret_cast<outputType *>(getChildEdgeAt(0)->getMemoryPtr()->GetPtr());
|
|
|
|
auto srcDesc = getParentEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
|
|
auto dstDesc = getChildEdgeAt(0)->getMemory().GetDescWithType<BlockedMemoryDesc>();
|
|
|
|
int realRois = 0;
|
|
for (; realRois < nn; realRois++) {
|
|
int roiBatchInd = static_cast<int>(bottomRoisBeginning[realRois * 5]);
|
|
if (roiBatchInd == -1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// for Deformable PSROIPooling
|
|
const float *bottomTrans = nullptr;
|
|
int numClasses = 1;
|
|
int channelsEachClass = outputDim;
|
|
if (!noTrans) {
|
|
bottomTrans = reinterpret_cast<const float *>(getParentEdgeAt(2)->getMemoryPtr()->GetPtr());
|
|
numClasses = static_cast<int>(getParentEdgeAt(2)->getShape().getStaticDims()[1]) / 2;
|
|
channelsEachClass /= numClasses;
|
|
}
|
|
|
|
parallel_for(realRois, [&](int currentRoi) {
|
|
const float *bottomRois = bottomRoisBeginning + currentRoi * 5;
|
|
int roiBatchInd = static_cast<int>(bottomRois[0]);
|
|
if (getAlgorithm() == Algorithm::PSROIPoolingAverage) {
|
|
executeAverage(srcData, dstData, bottomRois, currentRoi, roiBatchInd, srcDesc, dstDesc);
|
|
} else if (getAlgorithm() == Algorithm::PSROIPoolingBilinear) {
|
|
executeBilinear(srcData, dstData, bottomRois, currentRoi, roiBatchInd, srcDesc, dstDesc);
|
|
} else if (getAlgorithm() == Algorithm::PSROIPoolingBilinearDeformable) {
|
|
executeBilinearDeformable(srcData, dstData, bottomRois, bottomTrans,
|
|
numClasses, channelsEachClass, currentRoi, roiBatchInd);
|
|
}
|
|
});
|
|
|
|
memset(dstData + realRois * nc * nh * nw, 0, (nn - realRois) * nc * nh * nw * sizeof(outputType));
|
|
}
|
|
|
|
namespace {
|
|
struct PSROIPoolingContext {
|
|
MKLDNNPSROIPoolingNode &node;
|
|
};
|
|
}
|
|
|
|
template<typename T>
|
|
struct MKLDNNPSROIPoolingNode::PSROIPoolingExecute {
|
|
using srcT = typename std::tuple_element<0, T>::type;
|
|
using dstT = typename std::tuple_element<1, T>::type;
|
|
|
|
void operator()(PSROIPoolingContext & ctx) {
|
|
ctx.node.executeSpecified<srcT, dstT>();
|
|
}
|
|
};
|
|
|
|
void MKLDNNPSROIPoolingNode::execute(mkldnn::stream strm) {
|
|
auto inputPrec = getParentEdgesAtPort(0)[0]->getMemory().GetDesc().getPrecision();
|
|
auto outputPrec = getChildEdgesAtPort(0)[0]->getMemory().GetDesc().getPrecision();
|
|
|
|
if (!((inputPrec == Precision::BF16 && outputPrec == Precision::BF16) ||
|
|
(inputPrec == Precision::FP32 && outputPrec == Precision::FP32))) {
|
|
IE_THROW() << errorPrefix + " has different precisions on input: " + inputPrec.name() + " and output: " + outputPrec.name();
|
|
}
|
|
|
|
PSROIPoolingContext ctx = {
|
|
*this,
|
|
};
|
|
|
|
OV_SWITCH(MKLDNNPlugin, PSROIPoolingExecute, ctx, std::tie(inputPrec, outputPrec),
|
|
OV_CASE2(Precision::FP32, Precision::FP32, float, float),
|
|
OV_CASE2(Precision::BF16, Precision::BF16, bfloat16_t, bfloat16_t))
|
|
}
|
|
|
|
bool MKLDNNPSROIPoolingNode::created() const {
|
|
return getType() == PSROIPooling;
|
|
}
|
|
|
|
REG_MKLDNN_PRIM_FOR(MKLDNNPSROIPoolingNode, PSROIPooling)
|