Skip to content

Conversation

zrr1999
Copy link
Member

@zrr1999 zrr1999 commented Jul 16, 2025

PR Category

Operator Mechanism

PR Types

Bug fixes

Description

修复 paddle.nn.functional.adaptive_avg_pool2d 反向的精度问题。增加单测判断梯度和是否符合预期。

错误出现的原因在于 KernelPool2DGrad 中对 pool_size的计算错误,原本的 pool_size 由 pool_height(即 input_height / output_height 向上取整) 和 pool_width 乘积计算得出,但是实际上这样每个位置都会产生误差(除非 input_height 可以被 output_height整除),设Y=adaptive_avg_pool2d(X),对于这个算子我们期望 Y 反向传播回来的梯度可以均匀分配到输入X所有相关的元素上,也就是说X各元素的梯度和与Y各元素的梯度和应该相等,可以验证原本的算法是做不到这点的。

根据adaptive_avg_pool2d的定义我们可以知道,对于Y的每个元素 pool_size 是可能不同的,使用 input_height / output_height 向上取整这个定值是不对的。
正确的计算方法如下:
$\textbf{min} (\lceil \frac{(k+1) h_i}{h_o} \rceil , h_i)-\textbf{max} (\lfloor \frac{k h_i}{h_o} \rfloor, 0)$

可通过下列代码复现

import torch
import paddle
import numpy

device = torch.device("cuda:0")
torch.set_default_device(device)

def init_input(numpy_tensor):
    paddle_x = paddle.to_tensor(numpy_tensor)
    torch_x = torch.tensor(numpy_tensor, requires_grad=True)
    paddle_x.stop_gradient = False

    numpy.testing.assert_allclose(
        paddle_x.numpy(),
        torch_x.cpu().detach().numpy(),
        1e-10,
        1e-10,
        err_msg='intput diff'
    )
    return paddle_x, torch_x



# paddle.diff(Tensor([2, 760567127],"float32"), n=1, axis=0, prepend=Tensor([3, 760567127],"float32"), append=None, )
input_tensor = (numpy.ones([1, 1, 7, 7])).astype("float32") 
paddle_input, torch_input = init_input(input_tensor)
paddle_out = paddle.nn.functional.adaptive_avg_pool2d(paddle_input, output_size=(2, 5,), data_format="NCHW", name=None, )
torch_out = torch.nn.functional.adaptive_avg_pool2d(torch_input, output_size=(2, 5,))

print("input:", paddle_input[0][0])
print("torch shape:", torch_out.shape)
print("paddle shape:", paddle_out.shape)

print("paddle out:", paddle_out[0][0])
print("torch out:", torch_out[0][0])

numpy.testing.assert_allclose(
    torch_out.cpu().detach().numpy(),
    paddle_out.numpy(),
    1e-2,
    1e-2,
    err_msg='output diff'
)

numpy_tensor = (numpy.ones([1, 1, 2, 5])).astype("float32")
paddle_grad, torch_grad = init_input(numpy_tensor)
torch_x_grad = torch.autograd.grad([torch_out], [torch_input], grad_outputs=torch_grad)
paddle_x_grad = paddle.grad([paddle_out], [paddle_input], grad_outputs=paddle_grad, allow_unused=True)

print(torch_x_grad[0], torch.sum(torch_x_grad[0]))
print(paddle_x_grad[0], paddle.sum(paddle_x_grad[0]))
numpy.testing.assert_allclose(
    torch_x_grad[0].cpu().detach().numpy(),
    paddle_x_grad[0].numpy(),
    1e-2,
    1e-2,
    err_msg='output diff'
)

其他内容:
为了提升可读性,给 FastDivMod 结构体添加了 DivCeil方法,其他使用 Divmod 的代码后续也可以优化。

Pcard-67164

Copy link

paddle-bot bot commented Jul 16, 2025

你的PR提交成功,感谢你对开源项目的贡献!
请关注后续CI自动化测试结果,详情请参考Paddle-CI手册
Your PR has been submitted. Thanks for your contribution!
Please wait for the result of CI firstly. See Paddle CI Manual for details.

@zrr1999 zrr1999 changed the title [WIP] fix KernelPool2DGrad [Accuracy diff No.106] Fix accuracy diff for paddle.nn.functional.adaptive_avg_pool2d API Jul 17, 2025
@zrr1999 zrr1999 requested review from Copilot and huangjiyi and removed request for Copilot July 17, 2025 08:59
Copy link
Contributor

@wanghuancoder wanghuancoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 这个让书豪Review一下吧

@zrr1999 zrr1999 merged commit 55face6 into PaddlePaddle:develop Jul 18, 2025
75 of 76 checks passed
@zrr1999 zrr1999 deleted the acc/adaptive_avg_pool branch July 18, 2025 02:19
co63oc pushed a commit to co63oc/Paddle that referenced this pull request Jul 18, 2025
…ptive_avg_pool2d API (PaddlePaddle#74077)

* fix KernelPool2DGrad

* fix pool2d

* improve

* add test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants