Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix max_pool2d with ceil_mode bug #46558

Closed
5 changes: 3 additions & 2 deletions aten/src/ATen/native/Pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ static inline T pooling_output_shape_pad_lr(
T outputSize = div_rtn<T>(
inputSize + pad_l + pad_r - dilation * (kernelSize - 1) - 1 +
(ceil_mode ? stride - 1 : 0), stride) + 1;
if (pad_l) {
if (ceil_mode) {
// ensure that the last pooling starts inside the image
// needed to avoid problems in ceil mode
if ((outputSize - 1) * stride >= inputSize + pad_l)
if ((outputSize - 1) * stride >= inputSize + pad_l) {
--outputSize;
}
}
return outputSize;
}
Expand Down
4 changes: 2 additions & 2 deletions test/quantization/test_quantized_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ def pool_output_shape(input_size, kernel_size, padding, stride,
output_size = (
(input_size + 2 * padding - dilation * (kernel_size - 1) - 1
+ (stride - 1 if ceiling_mode else 0)) // stride + 1)
if (padding > 0 and
if (ceiling_mode and
((output_size - 1) * stride >= input_size + padding)):
output_size += 1
output_size -= 1
return output_size

"""
Expand Down
16 changes: 16 additions & 0 deletions test/test_nn.py
Original file line number Diff line number Diff line change
Expand Up @@ -10515,6 +10515,22 @@ def test(nonlinearity, *args, **kwargs):
test('threshold', 3, 2)
test('threshold', 3, 2, inplace=True)

def test_pooling_shape(self, device):
heitorschueroff marked this conversation as resolved.
Show resolved Hide resolved
''' Test the output shape calculation for pooling functions '''

# Checks output shape against expected for 1D, 2D and 3D
def check(expected_out_shape, sizes, *args, **kwargs):
for kernel in ['max', 'avg']:
for i in [1, 2, 3]:
if hasattr(torch.nn.functional, f'{kernel}_pool{i}d'):
op = getattr(torch.nn.functional, f'{kernel}_pool{i}d')
t = torch.randn(sizes[:i + 2], device=device)
self.assertEqual(op(t, *args, **kwargs).shape, expected_out_shape[:i + 2])

check((1, 1, 3, 3, 4), (1, 1, 5, 6, 7), kernel_size=1, stride=2, padding=0, ceil_mode=True)
heitorschueroff marked this conversation as resolved.
Show resolved Hide resolved
heitorschueroff marked this conversation as resolved.
Show resolved Hide resolved
check((1, 1, 2, 3, 3), (1, 1, 3, 4, 5), kernel_size=2, stride=2, padding=1, ceil_mode=False)
check((1, 1, 2, 3, 3), (1, 1, 3, 4, 5), kernel_size=2, stride=2, padding=1, ceil_mode=True)

@onlyOnCPUAndCUDA # TODO: fix on XLA
def test_adaptive_avg_pool2d_output_size_one(self, device):
def helper(size, memory_format):
Expand Down
24 changes: 24 additions & 0 deletions torch/nn/modules/pooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class MaxPool1d(_MaxPoolNd):
for :attr:`padding` number of points. :attr:`dilation` is the stride between the elements within the
sliding window. This `link`_ has a nice visualization of the pooling parameters.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
heitorschueroff marked this conversation as resolved.
Show resolved Hide resolved
input + left padding (starting in the right padded region is now allowed).

Args:
kernel_size: The size of the sliding window, must be > 0.
stride: The stride of the sliding window, must be > 0. Default value is :attr:`kernel_size`.
Expand Down Expand Up @@ -104,6 +108,10 @@ class MaxPool2d(_MaxPoolNd):
for :attr:`padding` number of points. :attr:`dilation` controls the spacing between the kernel points.
It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
input + left padding (starting in the right padded region is now allowed).

The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding`, :attr:`dilation` can either be:

- a single ``int`` -- in which case the same value is used for the height and width dimension
Expand Down Expand Up @@ -174,6 +182,10 @@ class MaxPool3d(_MaxPoolNd):
for :attr:`padding` number of points. :attr:`dilation` controls the spacing between the kernel points.
It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
input + left padding (starting in the right padded region is now allowed).

The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding`, :attr:`dilation` can either be:

- a single ``int`` -- in which case the same value is used for the depth, height and width dimension
Expand Down Expand Up @@ -474,6 +486,10 @@ class AvgPool1d(_AvgPoolNd):
If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides
for :attr:`padding` number of points.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
input + left padding (starting in the right padded region is now allowed).

The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding` can each be
an ``int`` or a one-element tuple.

Expand Down Expand Up @@ -537,6 +553,10 @@ class AvgPool2d(_AvgPoolNd):
If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides
for :attr:`padding` number of points.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
input + left padding (starting in the right padded region is now allowed).

The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding` can either be:

- a single ``int`` -- in which case the same value is used for the height and width dimension
Expand Down Expand Up @@ -614,6 +634,10 @@ class AvgPool3d(_AvgPoolNd):
If :attr:`padding` is non-zero, then the input is implicitly zero-padded on all three sides
for :attr:`padding` number of points.

Note:
When ceil_mode=True, sliding windows are allowed to go off-bounds as long as it starts within the
input + left padding (starting in the right padded region is now allowed).

The parameters :attr:`kernel_size`, :attr:`stride` can either be:

- a single ``int`` -- in which case the same value is used for the depth, height and width dimension
Expand Down