Prhub

#50833 [Bugfix][Quantization] Fix dynamic INT8 W8A8 MoE config being built as W8A16

原始 PR 作者 ILikeIneine 合并时间 2026-08-07 16:21 文件变更 1 提交数 3 评论 2 代码增减 +5 / -4

执行摘要

修复动态 INT8 W8A8 MoE 配置被误建成 W8A16

PR body 指出:对于 Triton 和 CPU INT8 MoE 后端,int8_w8a8 压缩张量 MoE 配置(动态 per-token 激活量化)在构建 FusedMoEQuantConfig 时被误分类为 W8A16,导致 checkpoint 请求的 per-token INT8 激活量化被禁用。根因是 make_int8_moe_quant_config 仅凭 activation scale 张量是否存在来判断量化位宽,而动态量化场景下 scale 在运行期计算、不随 checkpoint 加载,因此会被误判。

值得精读。虽然改动只有 9 行,但它展示了一个典型的配置契约错误:以“数据是否存在”推断“量化模式”,忽略了动态量化这一显式声明。建议关注 make_int8_moe_quant_config 的分拣条件与 CompressedTensorsW8A8Int8MoEMethod 的调用约定,并跟进补充 int8 W8A8 配置测试,防止回归。

讨论亮点

NickLucche 在 review 中请求为 int8 W8A8 配置补充测试(cc @mgoin),该请求在合并前未落地;claude[bot] 提示 fork PR 自动审查被禁用;CI 通过 /ci run 触发并完成。总体技术讨论聚焦于测试缺口,核心修复本身无反对意见。

实现拆解

  1. 定位根因:vllm/model_executor/layers/fused_moe/oracle/int8.py 的 make_int8_moe_quant_config 中,原先以 a1_scale is None or a2_scale is None 判断 W8A16 配置。
  2. 校验改造:把成对校验从 assert 改为显式 if (a1_scale is None) != (a2_scale is None): raise ValueError(...),并引入 scales_absent 变量,逻辑更清晰且不会被 Python -O 剥离。
  3. 分拣条件修正:W8A16 分支改为 scales_absent and not per_act_token_quant;动态激活量化即使 scale 为 None 也会进入 int8_w8a8_moe_quant_config 分支,从而启用运行期 per-token 激活量化。
  4. 测试与 CI:本 PR 未附带新增测试;NickLucche 在 review 中请求补充 int8 W8A8 配置的测试,合并前未落实。CI 通过 /ci run 触发并最终通过。
文件 模块 状态 重要度
vllm/model_executor/layers/fused_moe/oracle/int8.py 量化配置 modified 6.26

关键符号

make_int8_moe_quant_config

关键源码片段

vllm/model_executor/layers/fused_moe/oracle/int8.py data-contract

修复的核心文件:`make_int8_moe_quant_config` 的分拣条件被修正,动态 INT8 W8A8 不再被误判为 W8A16,同时激活 scale 成对校验从 assert 提升为显式 ValueError。

def make_int8_moe_quant_config(
    int8_backend: Int8MoeBackend,
    w1_scale: torch.Tensor,
    w2_scale: torch.Tensor,
    a1_scale: torch.Tensor | None = None,
    a2_scale: torch.Tensor | None = None,
    w1_bias: torch.Tensor | None = None,
    w2_bias: torch.Tensor | None = None,
    per_act_token_quant: bool = False,
    layer: torch.nn.Module | None = None,
) -> FusedMoEQuantConfig:
    # 激活 scale 必须成对出现:要么同时提供,要么同时为 None。
    # 从 assert 改为显式 ValueError,避免 Python -O 模式剥离断言后失去校验。
    if (a1_scale is None) != (a2_scale is None):
        raise ValueError("a1_scale and a2_scale must both be provided or both be None")
​
    scales_absent = a1_scale is None and a2_scale is None
​
    if int8_backend == Int8MoeBackend.HUMMING:
        # humming 后端直接由层对象生成 quant config,与本修复无关。
        from vllm.model_executor.layers.fused_moe import RoutedExperts
        from vllm.model_executor.layers.quantization.utils.humming_utils import (
            get_humming_moe_quant_config,
        )
​
        assert isinstance(layer, RoutedExperts)
        return get_humming_moe_quant_config(layer)
​
    # 关键修复:只有 scale 缺失且非动态激活量化时才判定为 W8A16。
    # 动态 per-token 量化(per_act_token_quant=True)时激活 scale 在运行期计算、
    # 不随 checkpoint 加载,因此必须继续走 W8A8 配置路径。
    if scales_absent and not per_act_token_quant:
        return int8_w8a16_moe_quant_config(
            w1_scale=w1_scale,
            w2_scale=w2_scale,
            w1_zp=None,
            w2_zp=None,
            w1_bias=w1_bias,
            w2_bias=w2_bias,
        )
​
    return int8_w8a8_moe_quant_config(
        w1_scale=w1_scale,
        w2_scale=w2_scale,
        a1_scale=a1_scale,
        a2_scale=a2_scale,
        w1_bias=w1_bias,
        w2_bias=w2_bias,
        per_act_token_quant=per_act_token_quant,
    )

评论区精华

补充 int8 W8A8 配置测试 测试

NickLucche 在 review 评论中请求为 int8 W8A8 配置添加测试,并 cc @mgoin 负责跟进。

结论:合并前未新增对应测试文件,测试请求未落实,属于遗留事项。 · unresolved

fork PR 自动审查限制 other

claude[bot] 指出该 PR 来自 fork,自动 review 被禁用,需要维护者评论 `@claude review` 手动触发。

结论:流程性提示,无技术结论。 · 已解决

CI 触发确认 other

NickLucche 在 issue 评论中运行 `/ci run`,github-actions[bot] 确认 Buildkite CI 已在运行。

结论:CI 已触发,最终随 PR 合并通过。 · 已解决

风险与影响

行为变化:动态激活 W8A8 的 Triton/CPU MoE 后端将从“关掉激活量化”变为“真正启用 INT8 激活量化”,数值结果与性能表现会随之改变。缺少测试覆盖:唯一修复点没有配套单元测试,动态量化路径较隐蔽,后续重构容易回归。校验严格化:assert 转 ValueError 会在 Python -O 模式下依然生效,可能暴露被掩盖的调用方参数错误。影响范围:仅限配置分拣逻辑,HUMMING 分支不受影响;但所有调用 make_int8_moe_quant_config 的 INT8 MoE 后端都会受此行为影响。

用户影响:使用 compressed-tensors INT8 W8A8 动态激活量化的 MoE 模型在 Triton/CPU 后端下会真正启用 W8A8 激活量化,可能带来吞吐与显存收益,但也会改变数值输出。系统影响:FusedMoEQuantConfig 的构建契约发生变化,动态量化路径不再被误降级为 W8A16。团队影响:改动仅 9 行,风险集中在缺少配套测试;建议后续在量化测试目录补充 int8 W8A8 动态激活用例。

缺少测试覆盖 配置契约变更 动态量化路径回归风险 assert 转 ValueError 暴露新错误

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论