[Big Tensor] Support iteration space beyond INT32_MAX in GPU index_elementwise_put kernels - #79810
Merged
wanghuancoder merged 3 commits intoSep 24, 2026
Merged
Conversation
The forward kernel rejected numel > INT32_MAX unconditionally, so a large indexed region failed even on the 64-bit offset path. The grad kernel had no check at all and silently wrapped its 32-bit linear index instead. The offset type is chosen from the operands' byte spans, which does not bound the iteration space: a small index tensor broadcast over a large input still produces numel > INT32_MAX. Re-dispatch the 32-bit instantiation to the 64-bit one in that case, and replace the numel guard with a grid-size check, which is the real limit once the linear index is 64-bit wide. Also restrict the value_grad numel guards in the grad kernel to the 32-bit instantiation.
Contributor
Paddle-Bot Review Board (review完成)
Powered by Nyanpasu claude with Opus 4.8 默认推理级别, please check the suggestions carefully. |
risemeup1111
suggested changes
Sep 22, 2026
| // instantiation in that case instead of rejecting the call. `output` has | ||
| // already been allocated and, if needed, copied above, so the inner call sees | ||
| // it initialized on this place and skips both. | ||
| if constexpr (sizeof(OffsetT) == 4) { |
Contributor
There was a problem hiding this comment.
本 PR 修复了标量前向
GPUIndexElementwisePutKernel 与反向 GPUIndexElementwisePutGradKernel 的大迭代空间问题,但同文件内的张量赋值前向 GPUIndexElementwisePutWithTensorKernel(约 161-257 行)未做同样处理。
- 调度端
IndexElementwisePutWithTensorKernel(约 356 行)仍按各操作数的字节跨度选择 32 位实例化;而字节跨度并不约束迭代空间大小(正是本 PR 描述里的核心论点)。因此x[indices] = value_tensor在小x+ 大indices广播场景下会选到 32 位实例化。 - 32 位实例化下
OffsetCalculator<3, uint32_t, true>::get()的形参是uint32_t(见index_elementwise.cu.h:216)。当迭代空间numel越过 32 位索引范围时,第 238 行传入的int64_t idx会被静默截断,写入错误地址且不报错——与本 PR 为反向修复的失效模式完全一致。构造函数里的CheckOffsetRange只校验偏移字节跨度,拦不住线性下标的截断。 - 另外第 230 行
const dim3 grid((N + block.x * vt - 1) / (block.x * vt));同样缺少 grid 维度上限检查和int64_t → unsigned int的显式窄化保护,与本 PR 在两个已修复 kernel 中新增的 grid 守卫不一致。
建议对 GPUIndexElementwisePutWithTensorKernel 施加与标量前向相同的「numel 超限时重派发到 64 位实例化 + grid 守卫」处理,否则张量赋值前向仍会在大迭代空间下静默产生错误结果。
Contributor
There was a problem hiding this comment.
已在 29e30c2 验证修复:GPUIndexElementwisePutWithTensorKernel 现已在 32 位实例化下对 numel > INT32_MAX 重派发到 64 位实例化(置于 MakeOffsetCalculatorPut 之前),并补充了 grid 维度上限检查与 int64_t → unsigned int 的显式窄化保护,与标量前向/反向一致。问题已解决。
…rload GPUIndexElementwisePutWithTensorKernel was left out of the previous commit, but it has the same exposure: the offset type is picked from the operands' byte spans, and a broadcast `value` keeps its span small while the iteration space can still exceed INT32_MAX, so the 32-bit instantiation would truncate the linear index passed to OffsetCalculator::get(). Re-dispatch to the 64-bit instantiation and add the grid-size check.
risemeup1111
approved these changes
Sep 22, 2026
OffsetCalculator's constructor already validates every operand's byte reach against the offset type it was instantiated with (CheckOffsetRange, called whenever signed_strides is set), and that bound is both tighter and more precise than comparing value_grad's element count to INT32_MAX: value_grad here is always contiguous and input-shaped, so its byte reach is (numel - 1) * sizeof(T).
Enigmatisms
approved these changes
Sep 23, 2026
risemeup1111
approved these changes
Sep 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Category
Operator Mechanism
PR Types
Bug fixes
Description
x[index] = value这类 advanced indexing 的 setitem 在 GPU 上走index_elementwise_put/index_elementwise_put_with_tensor及其反向。当被索引区域的迭代空间numel超过INT32_MAX时,当前实现有两个问题:前向:无条件拒绝
index_elementwise_put_kernel.cu里对N = numel做了无条件的PADDLE_ENFORCE,要求N <= INT32_MAX,与实际使用的 offset 位宽无关。因此即使调度端已经选择了 64 位 offset 的实例化,调用一样会失败:实际触发场景:大 padding 率样本下
input_embeds[indices] = value,len(indices) * hidden_size越过INT32_MAX直接报错中断训练。反向:静默截断
index_elementwise_put_grad_kernel.cu连这个检查都没有。32 位实例化下OffsetCalculator::get()的形参类型就是uint32_t,线性下标会被截断且不报错,写入落到错误地址。本 PR 的改动
offset 位宽是调度端按各操作数的字节跨度选的,而字节跨度并不约束迭代空间大小:一个很小的 index 张量广播到大 input 上,跨度全在 int32 以内,但
numel可以远超INT32_MAX。所以:numel > INT32_MAX时,重新派发到 64 位实例化,而不是报错或截断。放在构造OffsetCalculator之前,因为 32 位的构造函数本身会对越界偏移抛错。numel守卫,改为对 grid 维度做检查:线性下标放宽到 64 位后,真正的硬上限是gridDim.x,而且dim3的构造存在从int64_t到unsigned int的隐式窄化,需要显式挡一层。IsInInt32Range(value_grad->numel())enforce守卫:MakeOffsetCalculatorPut里已经对其逐维检查过CPU / XPU 后端的同名守卫本 PR 未改动。
精度测试
可以直接复制到cases.txt中,在PaddleAPITest中通过--api_conig_file="cases.txt" + --accuract_stable=true测试精度
前三条覆盖index_elementwise_put_with_tensor,,后三条覆盖index_elementwise_put,内部依次覆盖
纯int32索引/跨度小→launch GPUxxxKernel时offsetT=uint32,但 N>INT32_MAX/跨度>INT32_MAX是否引起精度变化
否
改动只影响下标与偏移的计算位宽,以及守卫条件的作用范围,不改变任何计算逻辑。