Skip to content

Commit 0e4eed0

Browse files
committed
Merge pull request opencv#10867 from dkurt:dnn_fix_ave_pooling_area
2 parents 8ffcc76 + f8d0d63 commit 0e4eed0

File tree

5 files changed

+44
-8
lines changed

5 files changed

+44
-8
lines changed

modules/dnn/include/opencv2/dnn/all_layers.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
239239
bool computeMaxIdx;
240240
String padMode;
241241
bool ceilMode;
242+
// If true for average pooling with padding, divide an every output region
243+
// by a whole kernel area. Otherwise exclude zero padded values and divide
244+
// by number of real values.
245+
bool avePoolPaddedArea;
242246
// ROIPooling parameters.
243247
Size pooledSize;
244248
float spatialScale;

modules/dnn/src/layers/pooling_layer.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class PoolingLayerImpl : public PoolingLayer
106106
setParamsFrom(params);
107107
ceilMode = params.get<bool>("ceil_mode", true);
108108
spatialScale = params.get<float>("spatial_scale", 1);
109+
avePoolPaddedArea = params.get<bool>("ave_pool_padded_area", true);
109110
}
110111

111112
#ifdef HAVE_OPENCL
@@ -259,7 +260,7 @@ class PoolingLayerImpl : public PoolingLayer
259260
const Mat* src, *rois;
260261
Mat *dst, *mask;
261262
Size kernel, stride, pad;
262-
String padMode;
263+
bool avePoolPaddedArea;
263264
int nstripes;
264265
bool computeMaxIdx;
265266
std::vector<int> ofsbuf;
@@ -270,7 +271,7 @@ class PoolingLayerImpl : public PoolingLayer
270271
computeMaxIdx(0), poolingType(MAX), spatialScale(0) {}
271272

272273
static void run(const Mat& src, const Mat& rois, Mat& dst, Mat& mask, Size kernel,
273-
Size stride, Size pad, String padMode, int poolingType, float spatialScale,
274+
Size stride, Size pad, bool avePoolPaddedArea, int poolingType, float spatialScale,
274275
bool computeMaxIdx, int nstripes)
275276
{
276277
CV_Assert(src.isContinuous(), dst.isContinuous(),
@@ -289,7 +290,7 @@ class PoolingLayerImpl : public PoolingLayer
289290
p.kernel = kernel;
290291
p.stride = stride;
291292
p.pad = pad;
292-
p.padMode = padMode;
293+
p.avePoolPaddedArea = avePoolPaddedArea;
293294
p.nstripes = nstripes;
294295
p.computeMaxIdx = computeMaxIdx;
295296
p.poolingType = poolingType;
@@ -369,6 +370,7 @@ class PoolingLayerImpl : public PoolingLayer
369370
yend = min(ystart + kernel_h, inp_height + pad_h);
370371
srcData = src->ptr<float>(n, c);
371372
}
373+
int ydelta = yend - ystart;
372374
ystart = max(ystart, 0);
373375
yend = min(yend, inp_height);
374376
float *dstData = dst->ptr<float>(n, c, y0);
@@ -532,14 +534,14 @@ class PoolingLayerImpl : public PoolingLayer
532534
}
533535
else if (poolingType == AVE)
534536
{
535-
bool isSamePad = padMode == "SAME";
536537
for( ; x0 < x1; x0++ )
537538
{
538539
int xstart = x0 * stride_w - pad_w;
539540
int xend = min(xstart + kernel_w, inp_width + pad_w);
541+
int xdelta = xend - xstart;
540542
xstart = max(xstart, 0);
541543
xend = min(xend, inp_width);
542-
float inv_kernel_area = isSamePad ? (yend - ystart) * (xend - xstart) : kernel.area();
544+
float inv_kernel_area = avePoolPaddedArea ? xdelta * ydelta : ((yend - ystart) * (xend - xstart));
543545
inv_kernel_area = 1.0 / inv_kernel_area;
544546
#if CV_SIMD128
545547
if( xstart > 0 && x0 + 7 < x1 && (x0 + 7) * stride_w - pad_w + kernel_w < inp_width )
@@ -651,21 +653,21 @@ class PoolingLayerImpl : public PoolingLayer
651653
{
652654
const int nstripes = getNumThreads();
653655
Mat rois;
654-
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, padMode, type, spatialScale, computeMaxIdx, nstripes);
656+
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
655657
}
656658

657659
void avePooling(Mat &src, Mat &dst)
658660
{
659661
const int nstripes = getNumThreads();
660662
Mat rois, mask;
661-
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, padMode, type, spatialScale, computeMaxIdx, nstripes);
663+
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
662664
}
663665

664666
void roiPooling(const Mat &src, const Mat &rois, Mat &dst)
665667
{
666668
const int nstripes = getNumThreads();
667669
Mat mask;
668-
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, padMode, type, spatialScale, computeMaxIdx, nstripes);
670+
PoolingInvoker::run(src, rois, dst, mask, kernel, stride, pad, avePoolPaddedArea, type, spatialScale, computeMaxIdx, nstripes);
669671
}
670672

671673
virtual Ptr<BackendNode> initMaxPoolingHalide(const std::vector<Ptr<BackendWrapper> > &inputs)

modules/dnn/src/tensorflow/tf_importer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,7 @@ void TFImporter::populateNet(Net dstNet)
10781078
else if (type == "AvgPool")
10791079
{
10801080
layerParams.set("pool", "ave");
1081+
layerParams.set("ave_pool_padded_area", false);
10811082

10821083
setKSize(layerParams, layer);
10831084
setStrides(layerParams, layer);

modules/dnn/src/torch/torch_importer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,11 @@ struct TorchImporter
559559
layerParams.set("indices_blob_id", tensorParams["indices"].first);
560560
}
561561
if (nnName == "SpatialAveragePooling")
562+
{
562563
layerParams.set("pool", "AVE");
564+
layerParams.set("ave_pool_padded_area", scalarParams.has("count_include_pad") &&
565+
scalarParams.get<bool>("count_include_pad"));
566+
}
563567
convertTorchKernelsParams(scalarParams, layerParams);
564568

565569
CV_Assert(scalarParams.has("ceil_mode"));

modules/dnn/test/test_layers.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,4 +806,29 @@ INSTANTIATE_TEST_CASE_P(Layer_Test, Crop, Combine(
806806
/*offset value*/ Values(3, 4)
807807
));
808808

809+
// Check that by default average pooling layer should not count zero padded values
810+
// into the normalization area.
811+
TEST(Layer_Test_Average_pooling_kernel_area, Accuracy)
812+
{
813+
LayerParams lp;
814+
lp.name = "testAvePool";
815+
lp.type = "Pooling";
816+
lp.set("kernel_size", 2);
817+
lp.set("stride", 2);
818+
lp.set("pool", "AVE");
819+
820+
Net net;
821+
net.addLayerToPrev(lp.name, lp.type, lp);
822+
// 1 2 | 3
823+
// 4 5 | 6
824+
// ----+--
825+
// 7 8 | 9
826+
Mat inp = (Mat_<float>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
827+
Mat target = (Mat_<float>(2, 2) << (1 + 2 + 4 + 5) / 4.f, (3 + 6) / 2.f, (7 + 8) / 2.f, 9);
828+
Mat tmp = blobFromImage(inp);
829+
net.setInput(blobFromImage(inp));
830+
Mat out = net.forward();
831+
normAssert(out, blobFromImage(target));
832+
}
833+
809834
}} // namespace

0 commit comments

Comments
 (0)