已关闭
[Bug]: GDN 算子 chunk_gated_delta_rule_fwd开启 cu_seqlens 后必现 nan #287
wlf-darkmatter创建于  3月30日关闭于  4月14日
wlf-darkmatter
3月30日 创建

环境信息

- 操作系统 欧拉
- 昇腾硬件信息 910B
- CANN软件版本 8.5.0
- triton 3.2.0 (pip install triton) 安装,执行安装命令 时间为 2026 年 3 月 30 日


image.png
image.png

🐛 问题描述

mindspeed_mm/fsdp/models/qwen3_5/chunk_gated_delta_rule.py
使能 cu_seqlens 后必现 nan 问题

chunk_scaled_dot_kkt_fwd 和 recompute_w_u_fwd 都会先后出现 nan。

详细细节待定位...

欢迎加入社区,感谢您对社区的贡献 🎉!

likedislike
ascend-robotascend-robot成员
3月30日 添加了label:bug
Wwlf-darkmatter
3月30日 修改标题为 “[Bug]: GDN”,原标题为“[Bug]: ”
Wwlf-darkmatter
3月30日 修改标题为 “[Bug]: GDN 算子 chunk_gated_delta_rule_fwd开启”,原标题为“[Bug]: GDN”
Wwlf-darkmatter
3月30日 修改标题为 “[Bug]: GDN 算子 chunk_gated_delta_rule_fwd开启 cu_seqlens 后必现 nan”,原标题为“[Bug]: GDN 算子 chunk_gated_delta_rule_fwd开启”
Wwlf-darkmatter
3月30日 修改了issue 的描述
Wwlf-darkmatter
3月30日 修改了issue 的描述
js1234567成员
3月31日 评论:

👋 您好,欢迎向 MindSpeed MM 提交 Issue!

我们已收到您的反馈,感谢你对开源社区的支持。🎉

📅 处理时效: 维护团队将在 24 小时内 查看并回复您的问题(工作日)。

🚨 紧急联系: 如果您的问题非常紧急,可通过以下方式联系我们:

💬 微信: WeChat

请确保 Issue 描述清晰,包含复现步骤和日志,这将帮助我们更快定位问题。谢谢!

likedislike
林明哲成员
3月31日 评论:

感谢使用。

当前代码暂不支持cuseqlens场景,建议bugfix通过后再使用,我们将尽快修改。
在那以前,建议优先使用cuseqlens=None的形式。

packing转换为非packing参考代码

def varlen_to_nonvarlen(cu_seqlens, *vars):
    B = len(cu_seqlens) - 1  # batch size
    max_len = max(cu_seqlens[i+1] - cu_seqlens[i] for i in range(B))  # 最长序列长度
    
    # 创建全 0 的非 varlen 输出张量
    nonvarlens = [torch.zeros(B, max_len, *v.shape[2:], device=v.device, dtype=v.dtype) for v in vars]
    
    # 填充数据
    for i in range(B):
        start = cu_seqlens[i]
        end = cu_seqlens[i+1]
        seq_len = end - start
        if seq_len > 0:  # 避免除以 0
            for j in range(len(nonvarlens)):
                nonvarlens[j][i, :seq_len] = vars[j][0, start:end]
    
    return nonvarlens

当前已知问题至少包含:

g = chunk_local_cumsum(g, cu_seqlens=cu_seqlens, head_first=True)

建议改为head_first=False,否则读取数据可能存在问题。

@triton.jit(do_not_specialize=['T'])
def recompute_w_u_fwd_kernel(
    k,
    v,
    beta,
    w,
    u,
    A,
    g,
    gk,
    cu_seqlens,
    chunk_indices,
    T,
    B,
    H: tl.constexpr,
    K: tl.constexpr,
    V: tl.constexpr,
    NT: tl.constexpr,
    BT: tl.constexpr,
    BK: tl.constexpr,
    BV: tl.constexpr,
    USE_G: tl.constexpr,
    USE_GK: tl.constexpr,
    IS_VARLEN: tl.constexpr
):
    core_id = tl.program_id(0)
    total_cores = tl.num_programs(0)
    T_max = T

其中入参T和循环体内变量重名,需要改名,某些版本的CANN存在bug,可能导致概率性输出nan。

likedislike
林林明哲成员
3月31日 将 LinMingZhe 设为负责人
wlf-darkmatter
4月2日 评论:

chunk_scaled_dot_kkt_fwd 的输出也存在极大值,这个问题可以稳定复现。

实际复现条件和整网实际数据有关系,正在自我诊断,有后续进展会在 issue 上更新。

cu_seqlens = [0, 115, 116]

    A = chunk_scaled_dot_kkt_fwd(
        k=k,
        g=g,
        beta=beta,
        cu_seqlens=cu_seqlens,
        chunk_size=chunk_size,
        output_dtype=torch.float32
    )

A: torch.Size([1, 116, 4, 64]),按照 [116, 256] shape绘制

image.png

另外,代码中添加 debug,打印其中的部分数据


            if USE_G:
                p_g = tl.make_block_ptr(g + g_batch_off + bos + i_h * T_, (T_local,), (1,), (i_t * BT,), (BT,), (0,))
                b_g = tl.load(p_g, boundary_check=(0,))
                b_g_diff = b_g[:, None] - b_g[None, :]
                b_g_diff = tl.minimum(tl.maximum(b_g_diff, -50.0), 50.0)
                b_A *= tl.exp(b_g_diff)

            #? DEBUG >>>>
            p_A_ = tl.make_block_ptr(debug_A + A_batch_off + (bos * H + i_h) * BT, (T_local, BT), (BT * H, 1), (i_t * BT, 0), (BT, BT), (1, 0))
            tl.store(p_A_, b_g_diff.to(p_A_.dtype.element_ty), boundary_check=(0, 1))
            #? DEBUG <<<<

            b_A *= b_beta[:, None]

            p_A = tl.make_block_ptr(A + A_batch_off + (bos * H + i_h) * BT, (T_local, BT), (BT * H, 1), (i_t * BT, 0), (BT, BT), (1, 0))
            tl.store(p_A, b_A.to(p_A.dtype.element_ty), boundary_check=(0, 1))

也就是说我把 b_A *= tl.exp(b_g_diff)中的 b_g_diff拿出来了,这部分绘图结果如下:

image.png

这个地方的数据有点太大了,不正常

上述情况可能和模型侧实际数据相关,正在自我排查。

likedislike
林明哲成员
4月2日 评论:

chunk_scaled_dot_kkt_fwd 的输出也存在极大值,这个问题可以稳定复现。

实际复现条件和整网实际数据有关系,正在自我诊断,有后续进展会在 issue 上更新。

cu_seqlens = [0, 115, 116]

   A = chunk_scaled_dot_kkt_fwd(
       k=k,
       g=g,
       beta=beta,
       cu_seqlens=cu_seqlens,
       chunk_size=chunk_size,
       output_dtype=torch.float32
   )

A: torch.Size([1, 116, 4, 64]),按照 [116, 256] shape绘制

image.png

另外,代码中添加 debug,打印其中的部分数据


           if USE_G:
               p_g = tl.make_block_ptr(g + g_batch_off + bos + i_h * T_, (T_local,), (1,), (i_t * BT,), (BT,), (0,))
               b_g = tl.load(p_g, boundary_check=(0,))
               b_g_diff = b_g[:, None] - b_g[None, :]
               b_g_diff = tl.minimum(tl.maximum(b_g_diff, -50.0), 50.0)
               b_A *= tl.exp(b_g_diff)

           #? DEBUG >>>>
           p_A_ = tl.make_block_ptr(debug_A + A_batch_off + (bos * H + i_h) * BT, (T_local, BT), (BT * H, 1), (i_t * BT, 0), (BT, BT), (1, 0))
           tl.store(p_A_, b_g_diff.to(p_A_.dtype.element_ty), boundary_check=(0, 1))
           #? DEBUG <<<<

           b_A *= b_beta[:, None]

           p_A = tl.make_block_ptr(A + A_batch_off + (bos * H + i_h) * BT, (T_local, BT), (BT * H, 1), (i_t * BT, 0), (BT, BT), (1, 0))
           tl.store(p_A, b_A.to(p_A.dtype.element_ty), boundary_check=(0, 1))

也就是说我把 b_A *= tl.exp(b_g_diff)中的 b_g_diff拿出来了,这部分绘图结果如下:

image.png

这个地方的数据有点太大了,不正常

上述情况可能和模型侧实际数据相关,正在自我排查。

@wlf-darkmatter

可否提供chunk_scaled_dot_kkt_fwd 的输入数据,我们此前未发现此算子存在问题,需要复现一下,谢谢

保存方法参考

    A = chunk_scaled_dot_kkt_fwd(
        k=k,
        g=g,
        beta=beta,
        cu_seqlens=cu_seqlens,
        chunk_size=chunk_size,
        output_dtype=torch.float32
    )
    torch.save(dict(
        A=A,
        k=k,
        g=g,
        beta=beta,
        cu_seqlens=cu_seqlens,
        chunk_size=chunk_size,
        output_dtype=torch.float32
    ), "chunk_scaled_dot_kkt_fwd.pt")
likedislike
wlf-darkmatter
4月3日 评论:

经过定位,发现存在两个问题引发了这个,已经修复

  1. 如您所述,使用 head_first 稳定会造成数据异常,如下是走 chunk_local_cumsum 采用不同head_first时, A=chunk_scaled_dot_kkt_fwd() 的输出 A 的数据绘图

head_first=True
image.png

head_first=False
image.png

  1. w, u = recompute_w_u_fwd() 存在已知 bug,

ref to https://gitcode.com/Ascend/MindSpeed/pull/3360/diffs

我会尝试更优雅的临时修复方式,后续提出 PR 进行修复。

另外建议暂时默认使用 head_first=False,如果认可,我会在 pr 中带上这一点
https://gitcode.com/Ascend/MindSpeed-MM/blob/master/mindspeed_mm/fsdp/models/qwen3_5/chunk_gated_delta_rule.py#L30

likedislike
林明哲成员
4月3日 评论:

经过定位,发现存在两个问题引发了这个,已经修复

  1. 如您所述,使用 head_first 稳定会造成数据异常,如下是走 chunk_local_cumsum 采用不同head_first时, A=chunk_scaled_dot_kkt_fwd() 的输出 A 的数据绘图

head_first=True
image.png

head_first=False
image.png

  1. w, u = recompute_w_u_fwd() 存在已知 bug,

ref to https://gitcode.com/Ascend/MindSpeed/pull/3360/diffs

我会尝试更优雅的临时修复方式,后续提出 PR 进行修复。

另外建议暂时默认使用 head_first=False,如果认可,我会在 pr 中带上这一点
https://gitcode.com/Ascend/MindSpeed-MM/blob/master/mindspeed_mm/fsdp/models/qwen3_5/chunk_gated_delta_rule.py#L30

@wlf-darkmatter

那看来都是已知问题,我上面的回复已经覆盖了。
recompute的问题,如我前面回复所述,实际为NPUIR编译器的bug,此问题当前主线已经修复,可以参考我在NPUIR提出的相关issue
因此我们在core上的代码实际也是临时规避,可能不需要太优雅

但是当前仍然不推荐使用NPUIR主线,3.13修复recompute问题,3.18又引入了新问题需要规避,未在issue中跟踪。

likedislike
wlf-darkmatter
4月3日 评论:

补充说明 head_first 的输出情况,方便日后问题跟踪
cu_seqlens = tensor([ 0, 113, 114, 115, 116]

原始输入的 g

image.png


head_first 为 False 时,输出 g 的数据:

image.png

head_first 为 True 时,输出 g 的数据:

image.png

可以看到底部的数据是有差异的

likedislike
林林明哲成员
4月10日 关联了pull request:feat: GDN support varlen when seqlen<64k
CoderMiao
CoderMiao
4月14日 评论:

@LinMingZhe 你好 当前GDN 支持varlen场景了吗?项目急需支持。

likedislike
林明哲成员
4月14日 评论:

@LinMingZhe 你好 当前GDN 支持varlen场景了吗?项目急需支持。

@gcw_8i0fCozD

可以参考这个PR,前段时间卡CI了,预计最快今天合入,急需的话可以参考PR修改,或者直接克隆PR代码

PS1:varlen场景还需要注意下conv1d等计算的varlen支持度,此PR仅处理GDN
PS2:PR版本代码在seqlen>64K时,可能触发卡死问题,为编译器问题,内部问题单跟踪中

likedislike
CoderMiao
CoderMiao
4月14日 评论:

@LinMingZhe 你好 当前GDN 支持varlen场景了吗?项目急需支持。

@gcw_8i0fCozD

可以参考这个PR,前段时间卡CI了,预计最快今天合入,急需的话可以参考PR修改,或者直接克隆PR代码

PS1:varlen场景还需要注意下conv1d等计算的varlen支持度,此PR仅处理GDN
PS2:PR版本代码在seqlen>64K时,可能触发卡死问题,为编译器问题,内部问题单跟踪中

@LinMingZhe

好的,了解。另外,我们当前环境是cann8.5.0,这个需要升级到cann9.0.0吗?

likedislike
林明哲成员
4月14日 评论:

@LinMingZhe 你好 当前GDN 支持varlen场景了吗?项目急需支持。

@gcw_8i0fCozD

可以参考这个PR,前段时间卡CI了,预计最快今天合入,急需的话可以参考PR修改,或者直接克隆PR代码

PS1:varlen场景还需要注意下conv1d等计算的varlen支持度,此PR仅处理GDN
PS2:PR版本代码在seqlen>64K时,可能触发卡死问题,为编译器问题,内部问题单跟踪中

@LinMingZhe

好的,了解。另外,我们当前环境是cann8.5.0,这个需要升级到cann9.0.0吗?

@gcw_8i0fCozD

当前上仓的版本是在8.5.1下验证的,理论上8.5.0区别不大,cann9.0.0的一些版本我们有发现别的问题在跟踪

likedislike
林林明哲成员
4月14日 issue状态由 TODO 改变为 Feedback
林明哲成员
4月14日 评论:

@wlf-darkmatter

最新PR已合入,请验证是否能解决您的问题,如有问题欢迎反馈
如此issue长时间不活跃,我们可能会关闭

likedislike
wlf-darkmatter
4月14日 评论:

已验证解决前向 nan 的问题,感谢支持

likedislike
林林明哲成员
4月14日 issue状态由 Feedback 改变为 DONE
林林明哲成员
4月14日 关闭了 issue
ascend-robotascend-robot成员
4月14日 添加了label:resolved