Skip to content

Commit 5adba33

Browse files
f0kfacebook-github-bot
authored andcommitted
Use integer floor division for pooling shape computation (#22304)
Summary: Fixes #21935 by using the integer floor division that was introduced for convolution shapes in #9640. Without this fix, the pooling operators can produce a 1-element output in cases they shouldn't. Disclaimer: I couldn't properly test it locally (it's not picking up the modified version for some reason). I'm marking this WIP until I checked what the CI tools say... Pull Request resolved: #22304 Differential Revision: D16181955 Pulled By: ezyang fbshipit-source-id: a2405372753572548b40616d1206848b527c8121
1 parent 3328245 commit 5adba33

File tree

7 files changed

+45
-53
lines changed

7 files changed

+45
-53
lines changed

aten/src/ATen/native/Pool.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <ATen/ATen.h>
22
#include <ATen/Parallel.h>
33
#include <ATen/NativeFunctions.h>
4+
#include <ATen/div_rtn.h>
45
#include <tuple>
56

67
#pragma once
@@ -21,18 +22,29 @@ safe_downcast(src_t v)
2122
}
2223

2324
template<typename T>
24-
static inline T pooling_output_shape(
25-
T inputSize, T kernelSize, T pad, T stride, T dilation, bool ceil_mode) {
26-
T outputSize = ((inputSize + 2 * pad - dilation * (kernelSize - 1) - 1 + (ceil_mode ? stride - 1 : 0)) / stride + 1);
27-
if (pad) {
25+
static inline T pooling_output_shape_pad_lr(
26+
T inputSize, T kernelSize, T pad_l, T pad_r, T stride, T dilation,
27+
bool ceil_mode) {
28+
T outputSize = div_rtn<T>(
29+
inputSize + pad_l + pad_r - dilation * (kernelSize - 1) - 1 +
30+
(ceil_mode ? stride - 1 : 0), stride) + 1;
31+
if (pad_l) {
2832
// ensure that the last pooling starts inside the image
2933
// needed to avoid problems in ceil mode
30-
if ((outputSize - 1) * stride >= inputSize + pad)
34+
if ((outputSize - 1) * stride >= inputSize + pad_l)
3135
--outputSize;
3236
}
3337
return outputSize;
3438
}
3539

40+
template<typename T>
41+
static inline T pooling_output_shape(
42+
T inputSize, T kernelSize, T pad, T stride, T dilation, bool ceil_mode) {
43+
return pooling_output_shape_pad_lr(
44+
inputSize, kernelSize, pad, pad, stride, dilation, ceil_mode);
45+
}
46+
47+
3648
// AveragePool2d/DilatedMaxPool2d (forward)
3749
static inline void
3850
pool2d_shape_check(

aten/src/ATen/native/mkldnn/Utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <ATen/native/mkldnn/Utils.h>
2-
#include <THNN/generic/pooling_shape.h>
2+
#include <ATen/native/Pool.h>
33

44
namespace at { namespace native {
55

aten/src/ATen/native/quantized/cpu/qpool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <ATen/native/TensorIterator.h>
55
#include <ATen/native/cpu/Loops.h>
66
#include <ATen/quantized/Quantizer.h>
7-
#include <THNN/generic/pooling_shape.h>
7+
#include <ATen/native/Pool.h>
88

99
#include <algorithm>
1010
#include <vector>

aten/src/THCUNN/generic/pooling_shape.h

Lines changed: 0 additions & 18 deletions
This file was deleted.

aten/src/THNN/generic/pooling_shape.h

Lines changed: 0 additions & 27 deletions
This file was deleted.

test/test_nn.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4028,6 +4028,31 @@ def test_pool_large_size_cuda(self, dtype=torch.float):
40284028
def test_pool_large_size(self, dtype=torch.float):
40294029
self._test_pool_large_size(self, device="cpu")
40304030

4031+
@staticmethod
4032+
def _test_pool_invalid_size(self, device, dtype=torch.float):
4033+
for op in ('max', 'avg'):
4034+
for num_dim in [1, 2, 3]:
4035+
fn_name = '{}_pool{}d'.format(op, num_dim)
4036+
fn = getattr(F, fn_name)
4037+
# use a configuration that gives zero outputs only
4038+
# when doing a correct floor division by the stride
4039+
x = torch.ones([1, 1] + num_dim * [4],
4040+
device=device, dtype=dtype)
4041+
with self.assertRaisesRegex(RuntimeError, r"too small|smaller than"):
4042+
try:
4043+
res = fn(x, 3, stride=2, padding=0, dilation=2)
4044+
except TypeError:
4045+
# some implementations do not support dilation
4046+
res = fn(x, 6, stride=2, padding=0)
4047+
4048+
@unittest.skipIf(not TEST_CUDA, "CUDA unavailable")
4049+
@repeat_test_for_types(ALL_TENSORTYPES)
4050+
def test_pool_invalid_size_cuda(self, dtype=torch.float):
4051+
self._test_pool_invalid_size(self, device="cuda", dtype=dtype)
4052+
4053+
def test_pool_invalid_size(self, dtype=torch.float):
4054+
self._test_pool_invalid_size(self, device="cpu")
4055+
40314056
def _test_scatter(self, tensor):
40324057
x = tensor.detach().requires_grad_()
40334058
result = dp.scatter(x, (0, 1))

test/test_quantized.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def _pool_output_shape(self, input_size, kernel_size, padding, stride,
7272
dilation, ceiling_mode=False):
7373
output_size = (
7474
(input_size + 2 * padding - dilation * (kernel_size - 1) - 1
75-
+ (stride - 1 if ceiling_mode else 0)) / stride + 1)
75+
+ (stride - 1 if ceiling_mode else 0)) // stride + 1)
7676
if (padding > 0 and
7777
((output_size - 1) * stride >= input_size + padding)):
7878
output_size += 1

0 commit comments

Comments
 (0)