1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Merge pull request #12519 from l-bat:l-bat/onnx_parser

Support asymmetric padding in pooling layer (#12519)

* Add Inception_V1 support in ONNX

* Add asymmetric padding in OpenCL and Inference engine

* Refactoring
This commit is contained in:
Lubov Batanina
2018-09-17 20:26:17 +03:00
committed by Alexander Alekhin
parent 76d4aa0c06
commit 43f889ae1f
11 changed files with 142 additions and 85 deletions
+29 -4
View File
@@ -64,10 +64,17 @@ public:
BaseConvolutionLayerImpl(const LayerParams &params)
{
setParamsFrom(params);
getConvolutionKernelParams(params, kernel.height, kernel.width, pad.height,
pad.width, stride.height, stride.width, dilation.height,
int pad_t = 0, pad_l = 0, pad_r = 0, pad_b = 0;
getConvolutionKernelParams(params, kernel.height, kernel.width, pad_t,
pad_l, pad_b, pad_r, stride.height, stride.width, dilation.height,
dilation.width, padMode);
if (pad_t != pad_b || pad_l != pad_r)
CV_Error(Error::StsNotImplemented, "Unsupported asymmetric padding in convolution layer");
pad.width = pad_l;
pad.height = pad_t;
numOutput = params.get<int>("num_output");
int ngroups = params.get<int>("group", 1);
@@ -100,8 +107,18 @@ public:
}
Size outSize = Size(outputs[0].size[3], outputs[0].size[2]);
int pad_t = pad.height, pad_l = pad.width, pad_b = pad.height, pad_r = pad.width;
getConvPoolPaddings(Size(input.size[3], input.size[2]), outSize,
kernel, stride, padMode, dilation, pad);
kernel, stride, padMode, dilation, pad_t, pad_l, pad_b, pad_r);
if (pad_t != pad_b || pad_l != pad_r)
CV_Error(Error::StsNotImplemented, "Unsupported asymmetric padding in convolution layer");
pad.width = pad_l;
pad.height = pad_t;
}
bool hasBias() const
@@ -1156,9 +1173,17 @@ public:
std::vector<Mat> inputs, outputs;
inputs_arr.getMatVector(inputs);
outputs_arr.getMatVector(outputs);
int pad_t = pad.height, pad_l = pad.width, pad_b = pad.height, pad_r = pad.width;
getConvPoolPaddings(Size(outputs[0].size[3], outputs[0].size[2]),
Size(inputs[0].size[3], inputs[0].size[2]),
kernel, stride, padMode, dilation, pad);
kernel, stride, padMode, dilation, pad_t, pad_l, pad_b, pad_r);
if (pad_t != pad_b || pad_l != pad_r)
CV_Error(Error::StsNotImplemented, "Unsupported asymmetric padding in convolution layer");
pad.width = pad_l;
pad.height = pad_t;
}
class MatMulInvoker : public ParallelLoopBody
+23 -13
View File
@@ -118,9 +118,19 @@ void getKernelSize(const LayerParams &params, int &kernelH, int &kernelW)
CV_Assert(kernelH > 0 && kernelW > 0);
}
void getStrideAndPadding(const LayerParams &params, int &padH, int &padW, int &strideH, int &strideW, cv::String& padMode)
void getStrideAndPadding(const LayerParams &params, int &padT, int &padL, int &padB, int &padR, int &strideH, int &strideW, cv::String& padMode)
{
util::getParameter(params, "pad", "pad", padH, padW, true, 0);
if (params.has("pad_l") && params.has("pad_t") && params.has("pad_r") && params.has("pad_b")) {
padT = params.get<int>("pad_t");
padL = params.get<int>("pad_l");
padB = params.get<int>("pad_b");
padR = params.get<int>("pad_r");
}
else {
util::getParameter(params, "pad", "pad", padT, padL, true, 0);
padB = padT;
padR = padL;
}
util::getParameter(params, "stride", "stride", strideH, strideW, true, 1);
padMode = "";
@@ -129,15 +139,15 @@ void getStrideAndPadding(const LayerParams &params, int &padH, int &padW, int &s
padMode = params.get<String>("pad_mode");
}
CV_Assert(padH >= 0 && padW >= 0 && strideH > 0 && strideW > 0);
CV_Assert(padT >= 0 && padL >= 0 && padB >= 0 && padR >= 0 && strideH > 0 && strideW > 0);
}
}
void getPoolingKernelParams(const LayerParams &params, int &kernelH, int &kernelW, bool &globalPooling,
int &padH, int &padW, int &strideH, int &strideW, cv::String &padMode)
int &padT, int &padL, int &padB, int &padR, int &strideH, int &strideW, cv::String &padMode)
{
util::getStrideAndPadding(params, padH, padW, strideH, strideW, padMode);
util::getStrideAndPadding(params, padT, padL, padB, padR, strideH, strideW, padMode);
globalPooling = params.has("global_pooling") &&
params.get<bool>("global_pooling");
@@ -148,9 +158,9 @@ void getPoolingKernelParams(const LayerParams &params, int &kernelH, int &kernel
{
CV_Error(cv::Error::StsBadArg, "In global_pooling mode, kernel_size (or kernel_h and kernel_w) cannot be specified");
}
if(padH != 0 || padW != 0 || strideH != 1 || strideW != 1)
if(padT != 0 || padL != 0 || padB != 0 || padR != 0 || strideH != 1 || strideW != 1)
{
CV_Error(cv::Error::StsBadArg, "In global_pooling mode, pad_h and pad_w must be = 0, and stride_h and stride_w must be = 1");
CV_Error(cv::Error::StsBadArg, "In global_pooling mode, pads must be = 0, and stride_h and stride_w must be = 1");
}
}
else
@@ -159,12 +169,11 @@ void getPoolingKernelParams(const LayerParams &params, int &kernelH, int &kernel
}
}
void getConvolutionKernelParams(const LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW,
void getConvolutionKernelParams(const LayerParams &params, int &kernelH, int &kernelW, int &padT, int &padL, int &padB, int &padR,
int &strideH, int &strideW, int &dilationH, int &dilationW, cv::String &padMode)
{
util::getKernelSize(params, kernelH, kernelW);
util::getStrideAndPadding(params, padH, padW, strideH, strideW, padMode);
util::getStrideAndPadding(params, padT, padL, padB, padR, strideH, strideW, padMode);
util::getParameter(params, "dilation", "dilation", dilationH, dilationW, true, 1);
CV_Assert(dilationH > 0 && dilationW > 0);
@@ -201,11 +210,11 @@ void getConvPoolOutParams(const Size& inp, const Size &kernel,
void getConvPoolPaddings(const Size& inp, const Size& out,
const Size &kernel, const Size &stride,
const String &padMode, const Size &dilation, Size &pad)
const String &padMode, const Size &dilation, int &padT, int &padL, int &padB, int &padR)
{
if (padMode == "VALID")
{
pad = cv::Size(0,0);
padT = padL = padB = padR = 0;
}
else if (padMode == "SAME")
{
@@ -213,7 +222,8 @@ void getConvPoolPaddings(const Size& inp, const Size& out,
int Pw = std::max(0, (out.width - 1) * stride.width + (dilation.width * (kernel.width - 1) + 1) - inp.width);
// For odd values of total padding, add more padding at the 'right'
// side of the given dimension.
pad = cv::Size(Pw / 2, Ph / 2);
padT= padB = Ph / 2;
padL = padR = Pw / 2;
}
}
+4 -3
View File
@@ -60,19 +60,20 @@ namespace cv
namespace dnn
{
void getConvolutionKernelParams(const LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW,
void getConvolutionKernelParams(const LayerParams &params, int &kernelH, int &kernelW, int &padT, int &padL, int &padB, int &padR,
int &strideH, int &strideW, int &dilationH, int &dilationW, cv::String& padMode);
void getPoolingKernelParams(const LayerParams &params, int &kernelH, int &kernelW, bool &globalPooling,
int &padH, int &padW, int &strideH, int &strideW, cv::String& padMode);
int &padT, int &padL, int &padB, int &padR, int &strideH, int &strideW, cv::String& padMode);
void getConvPoolOutParams(const Size& inp, const Size &kernel,
const Size &stride, const String &padMode,
const Size &dilation, Size& out);
void getConvPoolPaddings(const Size& inp, const Size& out,
const Size &kernel, const Size &stride,
const String &padMode, const Size &dilation, Size &pad);
const String &padMode, const Size &dilation, int &padT, int &padL, int &padB, int &padR);
}
}
+49 -34
View File
@@ -85,8 +85,12 @@ public:
type = STOCHASTIC;
else
CV_Error(Error::StsBadArg, "Unknown pooling type \"" + pool + "\"");
getPoolingKernelParams(params, kernel.height, kernel.width, globalPooling,
pad.height, pad.width, stride.height, stride.width, padMode);
pad_t, pad_l, pad_b, pad_r, stride.height, stride.width, padMode);
pad.width = pad_l;
pad.height = pad_t;
}
else if (params.has("pooled_w") || params.has("pooled_h"))
{
@@ -130,7 +134,9 @@ public:
kernel = inp;
}
getConvPoolPaddings(inp, out, kernel, stride, padMode, Size(1, 1), pad);
getConvPoolPaddings(inp, out, kernel, stride, padMode, Size(1, 1), pad_t, pad_l, pad_b, pad_r);
pad.width = pad_l;
pad.height = pad_t;
#ifdef HAVE_OPENCL
poolOp.release();
@@ -149,7 +155,7 @@ public:
else
return backendId == DNN_BACKEND_OPENCV ||
backendId == DNN_BACKEND_HALIDE && haveHalide() &&
(type == MAX || type == AVE && !pad.width && !pad.height);
(type == MAX || type == AVE && !pad_t && !pad_l && !pad_b && !pad_r);
}
#ifdef HAVE_OPENCL
@@ -169,7 +175,10 @@ public:
config.in_shape = shape(inputs[0]);
config.out_shape = shape(outputs[0]);
config.kernel = kernel;
config.pad = pad;
config.pad_l = pad_l;
config.pad_t = pad_t;
config.pad_r = pad_r;
config.pad_b = pad_b;
config.stride = stride;
config.channels = inputs[0].size[1];
config.pool_method = type == MAX ? LIBDNN_POOLING_METHOD_MAX :
@@ -193,7 +202,6 @@ public:
if (!poolOp->Forward(inpMat, outMat, maskMat))
return false;
}
return true;
}
#endif
@@ -264,8 +272,10 @@ public:
poolLayer->_kernel_y = kernel.height;
poolLayer->_stride_x = stride.width;
poolLayer->_stride_y = stride.height;
poolLayer->_padding_x = pad.width;
poolLayer->_padding_y = pad.height;
poolLayer->_padding_x = pad_l;
poolLayer->_padding_y = pad_t;
poolLayer->params["pad-r"] = format("%d", pad_r);
poolLayer->params["pad-b"] = format("%d", pad_b);
poolLayer->_exclude_pad = type == AVE && padMode == "SAME";
poolLayer->params["rounding-type"] = ceilMode ? "ceil" : "floor";
poolLayer->_type = type == MAX ? InferenceEngine::PoolingLayer::PoolType::MAX :
@@ -296,12 +306,14 @@ public:
return Ptr<BackendNode>();
}
class PoolingInvoker : public ParallelLoopBody
{
public:
const Mat* src, *rois;
Mat *dst, *mask;
Size kernel, stride, pad;
Size kernel, stride;
int pad_l, pad_t, pad_r, pad_b;
bool avePoolPaddedArea;
int nstripes;
bool computeMaxIdx;
@@ -313,7 +325,7 @@ public:
computeMaxIdx(0), poolingType(MAX), spatialScale(0) {}
static void run(const Mat& src, const Mat& rois, Mat& dst, Mat& mask, Size kernel,
Size stride, Size pad, bool avePoolPaddedArea, int poolingType, float spatialScale,
Size stride, int pad_l, int pad_t, int pad_r, int pad_b, bool avePoolPaddedArea, int poolingType, float spatialScale,
bool computeMaxIdx, int nstripes)
{
CV_Assert_N(
@@ -332,7 +344,10 @@ public:
p.mask = &mask;
p.kernel = kernel;
p.stride = stride;
p.pad = pad;
p.pad_l = pad_l;
p.pad_t = pad_t;
p.pad_r = pad_r;
p.pad_b = pad_b;
p.avePoolPaddedArea = avePoolPaddedArea;
p.nstripes = nstripes;
p.computeMaxIdx = computeMaxIdx;
@@ -359,7 +374,6 @@ public:
size_t stripeStart = r.start*stripeSize;
size_t stripeEnd = std::min(r.end*stripeSize, total);
int kernel_w = kernel.width, kernel_h = kernel.height;
int pad_w = pad.width, pad_h = pad.height;
int stride_w = stride.width, stride_h = stride.height;
bool compMaxIdx = computeMaxIdx;
@@ -411,8 +425,8 @@ public:
}
else
{
ystart = y0 * stride_h - pad_h;
yend = min(ystart + kernel_h, inp_height + pad_h);
ystart = y0 * stride_h - pad_t;
yend = min(ystart + kernel_h, inp_height + pad_b);
srcData = src->ptr<float>(n, c);
}
int ydelta = yend - ystart;
@@ -428,7 +442,7 @@ public:
if( poolingType == MAX)
for( ; x0 < x1; x0++ )
{
int xstart = x0 * stride_w - pad_w;
int xstart = x0 * stride_w - pad_l;
int xend = min(xstart + kernel_w, inp_width);
xstart = max(xstart, 0);
if (xstart >= xend || ystart >= yend)
@@ -439,7 +453,7 @@ public:
continue;
}
#if CV_SIMD128
if( xstart > 0 && x0 + 7 < x1 && (x0 + 7) * stride_w - pad_w + kernel_w < inp_width )
if( xstart > 0 && x0 + 7 < x1 && (x0 + 7) * stride_w - pad_l + kernel_w < inp_width )
{
if( compMaxIdx )
{
@@ -578,15 +592,15 @@ public:
{
for( ; x0 < x1; x0++ )
{
int xstart = x0 * stride_w - pad_w;
int xend = min(xstart + kernel_w, inp_width + pad_w);
int xstart = x0 * stride_w - pad_l;
int xend = min(xstart + kernel_w, inp_width + pad_r);
int xdelta = xend - xstart;
xstart = max(xstart, 0);
xend = min(xend, inp_width);
float inv_kernel_area = avePoolPaddedArea ? xdelta * ydelta : ((yend - ystart) * (xend - xstart));
inv_kernel_area = 1.0 / inv_kernel_area;
#if CV_SIMD128
if( xstart > 0 && x0 + 7 < x1 && (x0 + 7) * stride_w - pad_w + kernel_w < inp_width )
if( xstart > 0 && x0 + 7 < x1 && (x0 + 7) * stride_w - pad_l + kernel_w < inp_width )
{
v_float32x4 sum_val0 = v_setzero_f32(), sum_val1 = v_setzero_f32();
v_float32x4 ikarea = v_setall_f32(inv_kernel_area);
@@ -695,21 +709,21 @@ public:
{
const int nstripes = getNumThreads();
Mat rois;
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad_l, pad_t, pad_r, pad_b, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
}
void avePooling(Mat &src, Mat &dst)
{
const int nstripes = getNumThreads();
Mat rois, mask;
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad_l, pad_t, pad_r, pad_b, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
}
void roiPooling(const Mat &src, const Mat &rois, Mat &dst)
{
const int nstripes = getNumThreads();
Mat mask;
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad_l, pad_t, pad_r, pad_b, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
}
virtual Ptr<BackendNode> initMaxPoolingHalide(const std::vector<Ptr<BackendWrapper> > &inputs)
@@ -723,10 +737,10 @@ public:
Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name));
Halide::RDom r(0, kernel.width, 0, kernel.height);
Halide::Expr kx, ky;
if (pad.width || pad.height)
if(pad_l || pad_t)
{
kx = clamp(x * stride.width + r.x - pad.width, 0, inWidth - 1);
ky = clamp(y * stride.height + r.y - pad.height, 0, inHeight - 1);
kx = clamp(x * stride.width + r.x - pad_l, 0, inWidth - 1);
ky = clamp(y * stride.height + r.y - pad_t, 0, inHeight - 1);
}
else
{
@@ -739,11 +753,11 @@ public:
// Compute offset from argmax in range [0, kernel_size).
Halide::Expr max_index;
if (pad.width || pad.height)
if(pad_l || pad_t)
{
max_index = clamp(y * stride.height + res[1] - pad.height,
max_index = clamp(y * stride.height + res[1] - pad_t,
0, inHeight - 1) * inWidth +
clamp(x * stride.width + res[0] - pad.width,
clamp(x * stride.width + res[0] - pad_l,
0, inWidth - 1);
}
else
@@ -852,21 +866,21 @@ public:
}
else if (padMode.empty())
{
float height = (float)(in.height + 2 * pad.height - kernel.height) / stride.height;
float width = (float)(in.width + 2 * pad.width - kernel.width) / stride.width;
float height = (float)(in.height + pad_t + pad_b - kernel.height) / stride.height;
float width = (float)(in.width + pad_l + pad_r - kernel.width) / stride.width;
out.height = 1 + (ceilMode ? ceil(height) : floor(height));
out.width = 1 + (ceilMode ? ceil(width) : floor(width));
if (pad.height || pad.width)
if (pad_r || pad_b)
{
// If we have padding, ensure that the last pooling starts strictly
// inside the image (instead of at the padding); otherwise clip the last.
if ((out.height - 1) * stride.height >= in.height + pad.height)
if ((out.height - 1) * stride.height >= in.height + pad_b)
--out.height;
if ((out.width - 1) * stride.width >= in.width + pad.width)
if ((out.width - 1) * stride.width >= in.width + pad_r)
--out.width;
CV_Assert((out.height - 1) * stride.height < in.height + pad.height);
CV_Assert((out.width - 1) * stride.width < in.width + pad.width);
CV_Assert((out.height - 1) * stride.height < in.height + pad_b);
CV_Assert((out.width - 1) * stride.width < in.width + pad_r);
}
}
else
@@ -888,6 +902,7 @@ public:
dims[1] = psRoiOutChannels;
}
outputs.assign(type == MAX ? 2 : 1, shape(dims, 4));
return false;
}