Repository navigation
Conversation
…cale Under FLAGS_use_accuracy_compatible_kernel, the CUDA bilinear compat path now also covers NHWC layout, align_corners=True, explicit scale / Scale tensor without recompute, and FP16/BF16, matching torch's deterministic _upsample_linear decomposition. Scales reuse funcs::AreaPixelComputeScale.
Under FLAGS_use_accuracy_compatible_kernel, CUDA trilinear interpolation now matches torch's deterministic _upsample_linear decomposition for FP32/FP16/BF16, NCDHW/NDHWC, align_corners and explicit scales, using the same dispatch rules as the bilinear compat kernel and reusing its coordinate, lerp and index helpers.
KeTrilinearInterpBw now computes source indices and lambdas with AreaPixelComputeSourceIndex / PreCalculatorForLinearInterpInputIndex in MT, like KeTrilinearInterpFw and torch's upsample_trilinear3d_backward, and forms each contribution in MT before casting to T for the atomic add.
Paddle-Bot Review Board (review完成)
可维护性建议(总分 88.5 / 100,只给建议,不影响评审结论)
各维度得分(仅评本 PR 改动,点击展开)
Powered by Nyanpasu claude with Opus 5.5 默认推理级别, please check the suggestions carefully. |
| if (FLAGS_use_accuracy_compatible_kernel && interp_method == "bilinear" && | ||
| data_layout == DataLayout::NCHW && !align_corners && align_mode == 0 && | ||
| scale.empty() && !scale_tensor) { | ||
| (align_corners || align_mode == 0) && !(has_scale && has_size) && |
There was a problem hiding this comment.
这里把
align_corners=True、带 scale_factor(非 recompute)以及 NHWC 都路由进了 compat kernel,但仓库现有的 test/legacy_test/test_bilinear_interp_accuracy_compatible.py 仍按旧契约断言这些场景「保持原 kernel 路径」:
test_other_modes_keep_existing_path对align_corners=True、scale_factor=0.75、data_format='NHWC'三个子用例做 flag 开/关tobytes()完全相等断言;test_nonrecomputed_scale_keeps_existing_path对scale_factor非 recompute 的前向做逐位相等断言。
compat kernel 采用 left + (right - left) * w 的逐步 FP32 舍入,原 kernel 是 h2*(w2*a+w1*b)+h1*(...) 加权和,两者结果按位不同。我用 NumPy 按两种公式模拟(7x9 输入):align_corners 3x4 有 4/24、scale=0.75 5x6 有 29/60、半像素 3x4 有 12/24 个元素不一致,因此上述子用例在 CUDA 环境下预计会失败(本地无 GPU,未实跑)。
建议同步更新该测试文件:删除/改写这些「保持原路径」的断言,改为对 NHWC、align_corners、scale 路径给出与 torch 对齐的参考值(可复用文件内 reference_forward/reference_backward 并扩展参数)。
There was a problem hiding this comment.
已修复:test_other_modes_keep_existing_path 删除了 align_corners / scale_factor / NHWC 子用例,test_nonrecomputed_scale_keeps_existing_path 改为 test_nonrecomputed_scale,并新增 test_align_corners、test_nhwc、test_low_precision、test_scale_tensor_pir,均与扩展后的 NumPy 参考逐位比较。CPU 上用参考实现回放各用例自洽通过;GPU 未实跑。
| T w2lambda = static_cast<T>(w2lambda_mt); | ||
| int64_t in_img_idt, in_img_idy, in_img_idx, d_id, h_id, w_id; | ||
| MT d1lambda, d2lambda, h1lambda, h2lambda, w1lambda, w2lambda; | ||
| MT src_d = funcs::AreaPixelComputeSourceIndex<MT>( |
There was a problem hiding this comment.
KeTrilinearInterpBw 的这处改动不在 FLAGS_use_accuracy_compatible_kernel 之后,会改变默认路径(flag 关闭)以及 flag 开启但仍回退到原 kernel(如 align_mode=1、scale 与 size 同时给出)时的反向结果。
逐项对比旧实现:坐标与 lambda 的取值在 FP32 下与旧逻辑等价,FP32 结果应不变;但 FP16/BF16 下旧代码先把 6 个 lambda 转成 T,再在 T 中做 d*h*w*grad 连乘,新代码在 MT(float) 中计算后只舍入一次,结果会变化(精度提升,与 2D KeBilinearInterpBw 一致)。
这属于默认路径的数值行为变化,建议:要么挂到兼容 flag 之后,要么在 PR 描述中明确说明该默认路径变化及影响范围(仅 FP16/BF16 trilinear 反向),并补一个 FP16/BF16 trilinear 反向与 FP32 参考对比的用例。
There was a problem hiding this comment.
新增的 TestTrilinearInterpGradHalfPrecision 在默认 flag 下覆盖了 FP16/BF16 trilinear 反向(NCDHW/NDHWC),确认这是有意的默认路径精度提升,旧实现在 T 中连乘无法通过该用例。按已处理关闭;PR 描述中的说明并入「PR 描述为空」一项跟踪。
| const bool has_scale = scale_tensor || !scale.empty(); | ||
| const bool has_size = out_size || (size_tensor && size_tensor->size() > 0); | ||
| if (FLAGS_use_accuracy_compatible_kernel && interp_method == "trilinear" && | ||
| (align_corners || align_mode == 0) && !(has_scale && has_size) && |
There was a problem hiding this comment.
新增的
trilinear_compat 前向/反向(含 NDHWC、align_corners、scale、warp 规约与单线程 32-lane 回放两条路径),以及 bilinear compat 新开放的 FP16/BF16、NHWC、align_corners、scale 路径,本 PR 都没有新增或修改任何测试;PR 描述的 Description 也为空,未说明与 torch 2.12 对齐的验证方式。
这些 kernel 的目标是与 torch 逐位一致,回归风险集中在索引/布局与求和顺序,靠现有 test_trilinear_interp_v2_op 的容差比较无法发现。建议参照 test_bilinear_interp_accuracy_compatible.py 补一组 trilinear 用例:覆盖 NCDHW/NDHWC、align_corners 真/假、scale_factor、下采样与 >2x 上采样(走 WarpReduce 分支)、FP16/BF16,并给出 torch 生成的 md5 或独立 NumPy 参考;同时在 PR 描述中补充动机与验证结果。
There was a problem hiding this comment.
测试部分已补齐:新增 test_trilinear_interp_accuracy_compatible.py 覆盖 NCDHW/NDHWC、align_corners、scale_factor(含 >2x WarpReduce 分支)、Scale Tensor + PIR、FP16/BF16,bilinear 侧同步补齐。剩余项降为 P3:PR 描述的 Description 仍为空,请补充动机、与 torch 2.12 对齐的验证方式,并注明 flag 关闭时 FP16/BF16 trilinear 反向数值也会变化。
There was a problem hiding this comment.
PR 描述已补充动机、分发与回退规则、默认路径 FP16/BF16 trilinear 反向的数值变化及验证结果,此项已解决。
Cover the bilinear compat kernel's NHWC, align_corners, scale_factor, Scale tensor and FP16/BF16 paths, add bitwise tests for the trilinear compat kernel against an independent torch-equivalent NumPy reference, and check that the native trilinear backward forms FP16/BF16 contributions in FP32 and rounds them once, as torch does.
Paddle-Review-Bot
left a comment
There was a problem hiding this comment.
测试问题已修复;剩余 P3:请补充 PR 描述(动机、验证方式及默认路径 FP16/BF16 trilinear 反向的数值变化说明)。
|
/re-run all-failed |
2 similar comments
|
/re-run all-failed |
|
/re-run all-failed |
… align-interpolate
| std::is_same<T, phi::bfloat16>::value) { | ||
| const bool has_scale = scale_tensor || !scale.empty(); | ||
| const bool has_size = out_size || (size_tensor && size_tensor->size() > 0); | ||
| if (FLAGS_use_accuracy_compatible_kernel && interp_method == "trilinear" && |
There was a problem hiding this comment.
💡 可维护性建议(设计一致性,不阻塞合入):compat kernel 的启用条件(dtype 白名单、flag、interp_method、align_corners || align_mode == 0、!(has_scale && has_size)、尺寸是否变化)在 interpolate_kernel.cu 2D/3D 前向和 interpolate_grad_kernel.cu 2D/3D 反向共复制了 4 份,3D 处只靠「Same dispatch rules as ...」注释维持同步。前向与反向一旦条件分叉,会出现前向走 compat、反向走原 kernel 的情况。建议在 compat 头文件中提供一个 host 端谓词(如 UseAccuracyCompatibleKernel(align_corners, align_mode, has_scale, has_size, size_changed)),四处统一调用。
| } | ||
|
|
||
| template <typename T> | ||
| inline void LaunchForward(const T* input, |
There was a problem hiding this comment.
💡 可维护性建议(抽象适配度,不阻塞合入):文件内已有 Geometry,但 LaunchForward/LaunchBackward 仍接收 16 个位置参数(6 个相邻的 int64_t 尺寸 + bool + 3 个 double),并各自重复一遍 10 参数的 MakeGeometry(...);调用方交换 in/out 或 d/h/w 时编译期无法发现。建议让两个 Launch 函数直接接收 const Geometry&,由调用方构造一次。
| out_h, | ||
| out_w, | ||
| c, | ||
| data_layout == DataLayout::NHWC, |
There was a problem hiding this comment.
💡 可维护性建议(类型安全,不阻塞合入):这里用 data_layout == DataLayout::NHWC 判断 channel-last,而同函数的 ExtractNCDWH、dim_out 及原 kernel 都按 data_layout == DataLayout::NCHW 否则视为 channel-last。若 layout 字符串为 "NDHWC"(StringToDataLayout 返回独立的 DataLayout::NDHWC),原路径按 channel-last 计算,compat 路径却按 NCDHW 寻址,结果静默错误。Python API 目前会把 NDHWC 映射为 "NHWC",所以只是防御性问题;建议此处及 interpolate_kernel.cu 2D、interpolate_grad_kernel.cu 两处统一改为 data_layout != DataLayout::NCHW。
| // Both paths are exact. Up to 2x upsampling each input sees at most 64 | ||
| // contributions per corner, cheap enough for one thread; larger factors | ||
| // spread the reduction over a warp as torch does. | ||
| bool small_factor = |
There was a problem hiding this comment.
💡 可维护性建议(底层优雅度,不阻塞合入):注释已说明两条路径都逐位精确,out_* <= 2 * in_* 本身已限制每个输入的贡献数,small_factor 额外的 scale_factor_* <= 2. 只会把 (2.05, 2.05, 2.1) 这类仍在 2 倍以内的情况送去 warp 路径,且与 bilinear_compat::LaunchBackward 的判据不一致,名字也不反映它决定的是归约方式。建议删除该条件,与 bilinear 使用同一判据;若需保留,请改名并注明原因。
| @@ -360,15 +568,9 @@ def test_other_modes_keep_existing_path(self): | |||
| .astype(np.float32) | |||
| ) | |||
| cases = [ | |||
There was a problem hiding this comment.
💡 可维护性建议(测试策略,不阻塞合入):本 PR 把 in_h == out_h && in_w == out_w 的 Copy 快路径移到 compat 分发之后,并依赖 (has_scale || in_h != out_h || in_w != out_w) 保证不带 scale 的同尺寸调用仍走 Copy。trilinear 测试已有对应回退用例,bilinear 这里没有。建议补 (data, {"size": [7, 9], "mode": 'bilinear'}),沿用 flag 开/关逐字节比较。
…l-last check - Add funcs::UseAccuracyCompatibleKernel host predicate shared by the bilinear/trilinear forward and backward compat dispatch so the four call sites can no longer drift apart. - Use data_layout != DataLayout::NCHW for channel-last at the compat dispatch, matching dim_out/ExtractNCDWH and the original kernel (fixes a silent NDHWC mismatch). - Add a same-size, no-scale bilinear case to test_other_modes_keep_existing_path, mirroring the trilinear test's Copy fast-path guard.
|
/re-run all-failed |
1 similar comment
|
/re-run all-failed |
| // trilinear interpolation grad | ||
| CudaAtomicAdd(&in_pos1[0], d2lambda * h2lambda * w2lambda * out_pos[0]); | ||
| CudaAtomicAdd(&in_pos1[0], | ||
| static_cast<T>(d2lambda * h2lambda * w2lambda * grad)); |
|
/re-run all-failed |
PR Category
Operator Mechanism
PR Types
Improvements
Description
在
FLAGS_use_accuracy_compatible_kernel下扩展 CUDA bilinear 对齐范围并新增 trilinear 对齐,目标为与 torch 2.12 在torch.use_deterministic_algorithms(True)下的_upsample_lineardecomposition 逐位一致;同时将原生 trilinear 反向的精度对齐到 torchupsample_trilinear3d_backward。1. bilinear compat kernel 扩展(
interpolate_bilinear_compat.cuh)align_corners=True(此时忽略align_mode)、未 recompute 的scale_factor(attr 与ScaleTensor 两种输入)、FP16/BF16(按 FP32 计算,存储时舍入一次,与 torchpw_cast_for_opmath一致)。1/scale映射坐标;即使输出尺寸等于输入尺寸也不走 Copy 快路径(如 scale=1.1)。align_corners=False且align_mode=1(torch 线性插值无对应模式)、同时给定 scale 与 size(torch 无法表达)、FP64。2. 新增 trilinear compat kernel(
interpolate_trilinear_compat.cuh)3. 原生
KeTrilinearInterpBw精度对齐(flag 关闭的默认路径)AreaPixelComputeSourceIndex/PreCalculatorForLinearInterpInputIndex在 MT 中计算,与前向KeTrilinearInterpFw及 torch 一致;每个贡献在 MT 中算完后只转换为 T 一次,再做 atomicAdd。4. 测试覆盖
test_bilinear_interp_accuracy_compatible.py:删除旧的「NHWC / align_corners / scale 保持原路径」断言,改为与 torch 等价的 NumPy 参考逐位比较;新增 align_corners、FP16/BF16、非 recompute scale(含 1.1、2.05、>2x 边界)、PIRScaleTensor、NHWC 用例。test_trilinear_interp_accuracy_compatible.py(新增):覆盖随机梯度与重复执行、边界与 warp 归约、align_corners、scale、PIRScaleTensor、NDHWC、FP16/BF16,以及回退路径。test_trilinear_interp_v2_op.py:新增TestTrilinearInterpGradLowPrecision,在 flag 关闭时逐位验证 FP16/BF16 原生反向等于 FP32 梯度舍入一次(选取每个输入至多一个贡献的下采样 shape,使 atomicAdd 结果确定)。验证
是否引起精度变化
是