Skip to content

Conversation

@zrr1999
Copy link
Member

@zrr1999 zrr1999 commented Aug 15, 2025

PR Category

Operator Mechanism

PR Types

Performance

Description

修改内容

  • 原本的 Paddle GPU PowKernel 仅针对 factor为0和 1 进行了特化,本PR 额外添加了对 0.5 2 3 -0.5 -1 -2 的特化(对齐PyTorch),其中 -0.5 -1 -2 不对整数类型进行特化。
  • 原本的 Paddle GPU PowGradKernel 仅针对 factor 为0 进行了特化,本PR 额外添加了对 1 1.5 2 3 4 0.5 -1 的特化(对齐PyTorch),其中 0.5 -1 不对整数类型进行特化。
  • PowGradKernel 的 1 特化使用copy。2 特化复用现有functor。-1 0.5特化使用新的CudaReciprocalGradDepXFunctor 和 CudaSqrtGradDepXFunctor,依赖于X而不是out。1.5 3 4 使用新的 CudaPow1p5GradFunctor,CudaCubeGradFunctor, CudaPow4GradFunctor。
  • PowKernel 的 0.5 2 -0.5 -1 特化复用现有functor。3 -2 使用新的CudaCubeFunctor 和 CudaRsquareFunctor。
  • PowKernel 和 PowGradKernel 的非特化部分通过修改计算顺序可以对齐PyTorch的精度 image
  • MPTypeTrait 添加 complex 到 complex 的提升,与pytorch对齐。
  • exponent 当前使用 float 保存,存在精度损失,本PR修改为double 本PR修改为T,与PyTorch对齐
  • ElementwisePowGradKernel 的 compute_pow_grad_dx 和 compute_pow_grad_dy 通过修改计算顺序和精度对齐PyTorch的精度。
  • test_pow_op单测中,numpy 会将 float(np.random.uniform(1, 2, [])) 视为float32,但实际上这个值是float64,Paddle与PyTorch对齐后,这部分输入将视为float64,因此添加 .astype(np.float32)保证float64和float32在这个值上是一致的,从而与numpy的输入保持一致。
  • ElementwiseInversePowFunctor<ComplexType> 的实现中,gpu的逻辑把 pow(a,b)修正为pow(b, a)。

特化实现思路

PyTorch 的反向实现如下:

Tensor pow_backward_self(
    const Tensor& grad,
    const Tensor& self,
    const Tensor& exponent) {
  auto out = at::where(
      exponent == 0.0,
      at::scalar_tensor(0.0, grad.options()),
      grad * (exponent * self.pow(exponent - 1)).conj());
  return handle_r_to_c(self, std::move(out));
}

PyTorch 与 Paddle,PyTorch的反向和正向使用了相同的算子库,因此对pow特化的时候,反向不需要额外的特化,但是Paddle实现要注意以下几点:

  • PyTorch 许多算子实数和复数使用了同一套实现,因此一些计算并不是最优路径,
  • PyTorch 采用了统一的实现(包括实数和复数),所以在计算顺序上并不是通常的顺序计算,例如 1/x的反向,最优应该是-dout/(x*x),但PyTorch是dout*(-1/(x*x))。x^3的反向 dout * three * x * x 要改成 dout * (three * (x * x)) 。
  • PyTorch 的正向对 0 0.5 1 2 3 -0.5 -1 -2 进行了特化,根据上述实现可知反向对 1 1.5 2 3 4 0.5 0 -1 实现了特化。

剩余问题

本PR合入后剩余不对齐 case如下:

paddle.pow(Tensor([2, 3, 4],"float32"), Tensor([],"float32"), )
paddle.pow(Tensor([20, 1],"float32"), Tensor([],"float32"), )
paddle.pow(Tensor([20000, 1],"float32"), Tensor([],"float32"), )
paddle.pow(Tensor([20600, 1],"float32"), Tensor([],"float32"), )
paddle.pow(Tensor([4, 3, 2],"float32"), Tensor([4, 3, 2],"float16"), )
paddle.pow(Tensor([4, 3, 2],"float64"), Tensor([4, 3, 2],"float16"), )
paddle.pow(Tensor([4, 3, 2],"float64"), Tensor([4, 3, 2],"float32"), )
paddle.pow(Tensor([5, 9, 7],"float64"), Tensor([7],"float64"), )
paddle.pow(Tensor([],"float32"), Tensor([209],"float32"), )
paddle.pow(Tensor([4, 3, 2],"float64"), Tensor([4, 3, 2],"float32"), )
paddle.pow(Tensor([4, 3, 2],"float64"), Tensor([4, 3, 2],"float16"), )

其余问题目前汇总如下:

  • 目前特化只针对pow(tensor, scalar),需要补充pow(tensor, tensor)
  • 第一个输入是常数或0d的情况 PyTorch 也单独写了一个kernel,Paddle目前无法对齐,需要新增kernel。
  • a b 的shape不一致时,广播可能产生随机性。
  • a b 的dtype不一致时且a的精度高于b的精度,根据分析 PyTorch 的实现(grad * (exponent * self.pow(exponent - 1)).conj())可以发现,PyTorch的反向是复用的前向算子,并未有类型提升机制,exponent - 1 的会产生精度误差,虽然进行self.pow(exponent - 1)计算的时候会进行类型提升,但是精度损失已经产生,而 paddle 则提前进行了类型提升,所以进行类似的 exponent - 1 时精度本身就是更高的,后续的计算与PyTorch可以对齐。

其他不能与PyTorch 对齐的情况:

  • tensor^scalar当,tensor为int,scalar为float的时候,torch会返回f32,paddle返回与tensor一致。

其他问题:

下列内容与本PR的具体修改内容无关:

Pcard-67164

@paddle-bot
Copy link

paddle-bot bot commented Aug 15, 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 Acc/pow Improve PowKernel and PowGradKernel for GPU Aug 15, 2025
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

@wanghuancoder wanghuancoder merged commit 5cb6b67 into PaddlePaddle:develop Aug 25, 2025
177 of 190 checks passed
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.

2 participants