Prhub

#37384 [NPU] Fix error due to missing parameter quant_linear passing

原始 PR 作者 ZeyuanChen2000 合并时间 2026-09-14 14:37 文件变更 1 提交数 6 评论 7 代码增减 +1 / -0

执行摘要

NPU 量化 RMSNorm 包装补 kwargs 修报错

PR body 明确记录了动机:全量测试中 test_npu_qwq_32b_w8a8 报错 —— "TypeError: npu_wrapper_rmsnorm_forward.._rmsnorm_forward_oot() received an unexpected keyword argument 'quant_linear'"。作者判断根因是「The internal function _rmsnorm_forward_oot does not accept the quant_linear keyword argument passed by the caller」,于是选择在包装层补上可变参数("Add variable parameters **kwargs in npu_wrapper_rmsnorm_forward()"),而不是去改调用方,属于最小侵入的调用契约对齐。

建议快速浏览而非精读:实现只有一行,理解「调用方透传 quant_linear → 包装层签名不收 → TypeError」这一因果链即可。值得关注的两个设计决策:一是选择在包装层吞参而不是修改调用方或显式声明 quant_linear,好处是最小侵入,代价是失去参数校验;二是该文件在同一 PR 家族里持续以「包装/适配」方式兼容 NPU 量化,长期看这类隐式契约容易积累技术债。后续建议补一个 CPU 可跑的轻量单元测试,直接断言包装后的 forward 能在接收 quant_linear 时正常返回并与朴素实现数值一致,同时考虑给 **kwargs 加注释说明可安全忽略的原因。

讨论亮点

本 PR 没有一条行级 review 评论,唯一的正式评审是 sglang-npu-bot 的 APPROVED(review body 为空)。全部 7 条 issue 评论都是 CI 触发指令:sglang-npu-bot 发过一次 /tag-and-rerun-ci,作者 ZeyuanChen2000 连续 5 次 /rerun-failed-ci,Hide-on-bushsh 补了 1 次 /rerun-failed-ci。也就是说讨论焦点不在方案本身,而在「PR Test / PR Test Extra / AMD ROCm 10」三组 CI 的反复失败与重跑;**kwargs 这种静默吞参方式是否应该换成显式声明 quant_linear 形参,评审中并未被提出或澄清。

实现拆解

  1. 定位调用契约缺口(入口):通用 RMSNorm 调用链在量化后端下会向 forward 透传 quant_linear,而 ModelSlim 在 python/sglang/srt/layers/quantization/modelslim/modelslim.py 里用 npu_wrapper_rmsnorm_forward 包装出的 _rmsnorm_forward_oot 只声明了 self/x/residual/post_residual_addition 三个形参,多余关键字参数在 Python 层直接被拒绝,抛 TypeError 而非走通量化分支。
  2. 修复方式:在 _rmsnorm_forward_oot 的签名末尾追加 **kwargs,让包装层接收并忽略调用方透传的额外关键字参数。两个计算分支完全未动 —— 带 residual 时仍走 sgl_kernel_npu.norm.add_rmsnorm_bias.add_rmsnorm_bias 融合算子,无 residual 时仍走 torch.ops.npu.npu_rms_norm 再叠加量化 bias,因此数值结果与修复前一致。
  3. 风格一致性:同文件中的 npu_wrapper_rmsnorm_init 早已采用 **extra_args 承接额外参数(并借此注册 w8a8_int8 所需的 self.bias),本次改动使 forward 包装与 init 包装的容参风格统一。
  4. 测试与配套改动缺失:本次没有新增或修改任何测试文件,PR body 的 Checklist(pre-commit 格式化、单测、文档、精度/性能数据)全部未勾选,验证实际依赖 test_npu_qwq_32b_w8a8 这类端到端大模型用例以及 run-ci 标签触发的 NPU/AMD CI。

影响面收敛在单文件单函数:非 NPU 平台与未启用 ModelSlim 量化的路径不会走到该包装器,签名追加可变参数对外也是向后兼容的。

文件 模块 状态 重要度
python/sglang/srt/layers/quantization/modelslim/modelslim.py NPU 量化 modified 4.79

关键符号

npu_wrapper_rmsnorm_forward _rmsnorm_forward_oot

关键源码片段

python/sglang/srt/layers/quantization/modelslim/modelslim.py data-contract

本 PR 唯一改动文件。ModelSlim 是 NPU 专属的量化配置实现,文件中的 `npu_wrapper_rmsnorm_forward` 负责把 RMSNorm 的 forward 替换成 Ascend 融合实现;本次在 `_rmsnorm_forward_oot` 签名上补 `**kwargs`,直接决定量化模型 forward 阶段能否接受调用方透传的 quant_linear,是修复 TypeError 的全部内容。

# func 指向 RMSNorm.__init__:在 Ascend w8a8_int8 量化路径下,
# 包装后的 init 会额外注册一个 bias 参数,供融合算子 add_rmsnorm_bias 使用。
def npu_wrapper_rmsnorm_init(func):
    def init(self, hidden_size: int, **extra_args) -> None:
        func(self, hidden_size, **extra_args)
        self.ignore_anti = True
        self.bias = torch.nn.Parameter(torch.zeros(hidden_size), requires_grad=False)
​
    return init
​
​
# func 指向 RMSNorm.forward_oot
def npu_wrapper_rmsnorm_forward(func):
    def _rmsnorm_forward_oot(
        self,
        x: torch.Tensor,
        residual: Optional[torch.Tensor] = None,
        post_residual_addition: Optional[torch.Tensor] = None,
        # 本 PR 的唯一改动:接收并忽略调用方透传的额外关键字参数。
        # 通用 RMSNorm 调用链在量化后端下会传 quant_linear,这里的 NPU 实现用不到它;
        # 缺少 **kwargs 时 Python 会直接抛 TypeError,导致 NPU W8A8 用例整体失败。
        **kwargs,
    ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
        if not x.is_contiguous():
            x = x.contiguous()
​
        # 分支一:带 residual,走 sgl_kernel_npu 的 add_rmsnorm_bias 融合算子,
        # 同时产出归一化结果与新的 residual,供后续层继续累加;
        # post_residual_addition 会先并入 residual 再进入融合算子。
        if residual is not None:
            if post_residual_addition is not None:
                residual = residual + post_residual_addition
            from sgl_kernel_npu.norm.add_rmsnorm_bias import add_rmsnorm_bias
​
            out, residual_out = add_rmsnorm_bias(
                x,
                residual,
                self.weight.data,
                self.bias,
                self.variance_epsilon,
            )
            return out.to(x.dtype), residual_out
​
        # 分支二:无 residual,走 torch_npu 原生 npu_rms_norm,
        # 再手动加回量化所需的 bias(Ascend w8a8_int8 的约定),最后转回输入 dtype。
        out = torch.ops.npu.npu_rms_norm(x, self.weight.data, self.variance_epsilon)[0]
        out = out + self.bias
        return out.to(x.dtype)
​
    return _rmsnorm_forward_oot

评论区精华

评审过程只围绕 CI rerun,缺少对 **kwargs 方案本身的讨论 other

全 PR 没有任何行级 review 评论,7 条评论均为 CI 指令:sglang-npu-bot 的 `/tag-and-rerun-ci`,作者 ZeyuanChen2000 连续 5 次 `/rerun-failed-ci`,以及 Hide-on-bushsh 的 1 次 `/rerun-failed-ci`;PR body 中的 CI 状态显示 PR Test、PR Test Extra、AMD ROCm 10 均为失败 / 未通过。

结论:最终由 sglang-npu-bot 直接 APPROVED 并 merge,方案未经代码层面的质疑或补充;重跑记录说明合并主要卡在 CI 波动而非代码争议。 · 已解决

用 **kwargs 静默吞参,还是显式声明 quant_linear 设计

该分歧并未出现在 review 评论中,而是由 diff 本身引出的设计问题:修复选择让 `_rmsnorm_forward_oot` 接收并忽略所有额外关键字参数,而非显式接收 caller 传入的 quant_linear 或修改调用方契约。

结论:当前实现选择了最小侵入、向后兼容的写法,与同文件 npu_wrapper_rmsnorm_init 的 `**extra_args` 风格一致;但「传了却不用」的语义没有被注释或测试固化,属于遗留的设计模糊点。 · unresolved

风险与影响

  1. 静默吞参会掩盖调用错误(主要风险):**kwargs 让 _rmsnorm_forward_oot 对任何未来新增的关键字参数都不再报错。若后续某参数(例如真正需要参与该 NPU 分支计算的量化相关开关)被引入并透传,这里会默默忽略,表现为精度偏差或指标异常,而不是像现在这样立刻抛 TypeError,诊断成本显著上升。
  2. 缺少针对性测试覆盖:没有为 npu_wrapper_rmsnorm_forward 增加单元测试来固化「传入 quant_linear 不报错且结果等价」这一契约,回归保护完全依赖 test_npu_qwq_32b_w8a8 这种重资产端到端用例,一旦该用例被跳过或 CI 环境抖动(本 PR 就出现了多次 /rerun-failed-ci),修复效果缺少低成本守门人。
  3. 兼容性与回归面可控:改动只放宽入参,不涉及 add_rmsnorm_bias / npu_rms_norm 的计算路径,也未触碰 ModelSlimConfig 的权重加载与 ModelSlimLinearScheme;对非 NPU 后端、非 modelslim 量化模型无影响。
  4. 局部语义不明确:quant_linear 由调用方传入却在本实现中未被使用,说明调用契约里存在「传了但不需要」的模糊地带,代码中也没有注释解释为何可以安全忽略。

用户影响:在 Ascend NPU 上运行 ModelSlim W8A8 int8 量化模型(典型如 QwQ-32B-W8A8)的用户,不再在 forward 阶段因 quant_linear 关键字直接崩溃,模型可用性恢复。系统影响:改动位于 python/sglang/srt/layers/quantization/modelslim/modelslim.py 单文件,属于量化后端的局部调用契约修补,不影响调度、KV cache、注意力等核心链路,跨模块外溢风险低。团队影响:该 PR 是标准的 NPU CI 阻塞类修复,合并流程高度依赖 run-ci 标签和反复 rerun,暴露出 NPU 测试链路稳定性与 reviewer 注意力都集中在「让 CI 变绿」而非代码本身。

缺少测试覆盖 静默吞参掩盖调用错误 依赖重资产 NPU 端到端用例 CI 反复重跑

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论