Prhub

#49610 [Refactor] refactor humming linear and moe backends to use explicit layer configs

原始 PR 作者 jinzhen-lin 合并时间 2026-08-08 01:03 文件变更 37 提交数 40 评论 27 代码增减 +448 / -341

执行摘要

Humming 后端改用显式 LayerConfig 契约

PR body 明确说明目标:“This PR refactor the Humming linear and MoE backends to use explicit layer configs and tensors instead of passing vLLM layers into the backend. Also update Humming CI coverage and pin the dependency to the latest upstream commit.” 旧实现中 HummingMethod.forward_layer(layer=...)prepare_layer_meta(layer=...)get_default_tuning_configs(layer=...) 均要求把 vLLM 的 LinearBase / RoutedExperts 层对象传给外部库,导致 vLLM 模型层与第三方内核库强耦合、上游 API 变更时返工成本高;同时 Humming 上游已切换到 LayerConfig + 独立张量函数的契约,vLLM 需要跟随,并补齐 CI 覆盖与依赖锁定。

值得精读。这是“外部内核库集成解耦”的典型案例——通过显式 LayerConfig + 张量契约替代层对象直传,把 vLLM 模型层与第三方 kernel 库的耦合降到最低,设计模式可复用到其他后端。重点阅读 humming_utils.pyprepare_humming_linear_layer_config / apply_humming_linearfused_humming_moe.pyHummingExpertsBase;review 中关于“layer 参数为何暂不能移除”的讨论揭示了一个真实的量化布局兼容问题,值得关注其后续进展。

讨论亮点

review 中最有价值的交锋集中在三处:

  • 删除 layer 参数的边界:bnellnm 在 humming_utils.py:506 质疑 “Is it safe to delete all the parameters in the layer? … worried that there are other required parameters that might not be transformed that need to be preserved?”。jinzhen-lin 回应:该阶段 layer 内所有参数均为 humming 相关张量,且同函数早前已有“删除再重建”处理,已把两处逻辑合并到一处。

  • _supports_batch_invariance 用途:bnellnm 两次追问 “What is this method used for? Is it for future work?”。jinzhen-lin 贴出 modular_kernel.py 中候选内核过滤的调用点(L663-L670 / L577-L578),说明 Humming 支持 batch invariant,必须 override 才能进入内核候选集。

  • layer 参数能否彻底移除:bnellnm 在 fp8.py / int8.py / nvfp4.py 三处追问 “Are you planning on eventually removing the layer argument here as well? Why not pass layer.humming_configs?”。jinzhen-lin 解释:目前仍需 layer 读取权重张量——Humming 预处理可能产生比原始更多的张量(如 mxfp4×fp8 会把 e8m0 scale 拆成 group scale + tensor/channel scale),而 mxfp4 MoE oracle 没有为后者预留空间,计划在未来工作中解决。

最终 bnellnm 与 mgoin 均 APPROVED,mgoin 评价 “Very nice work, appreciate it!!”。

实现拆解

  1. 数据契约重构(humming_utils.py):以新增 HummingMoEQuantConfig(FusedMoEQuantConfig) dataclass 为枢纽,把原先挂在 layer 上的 humming_metas / compute_config / locks 等隐式状态显式化为 w1_humming_config / w2_humming_config 两个 LayerConfig 字段。prepare_humming_layer 被拆解为三个职责单一的 API:prepare_humming_linear_layer_config(用 prepare_layer_config + transform_humming_tensors 替代就地改写 layer 的 prepare_layer_meta + transform_humming_layer,返回 LayerConfig)、get_humming_linear_compute_config(序列化 compute 配置)、apply_humming_linear(forward 时只把张量与配置传给 humming_forward)。make_humming_moe_quant_config 新增必填的 humming_configs 参数并返回新类型;get_humming_moe_quant_config 透传 gemm1_alpha / gemm1_beta / gemm1_clamp_limit,并把读取的 scale 属性从 w13_global_scale / w2_global_scale 改为 w13_weight_scale_2 / w2_weight_scale_2make_humming_moe_kernel_prepare_and_transform_sublayer 均去掉 layer 依赖。

  2. MoE 专家类解耦(fused_humming_moe.py)HummingExpertsBase.__init__ 不再接收 RoutedExperts 层对象,改从 HummingMoEQuantConfig 读取 w13/w2 的 LayerConfiglocks 由专家自建,num_experts 取自 moe_configinit_humming_moeget_heuristics_config(layer_config=...) 取代旧的 HummingMethod.get_default_tuning_configs(layer=...)。新增 quantize_input(内部走 may_quant_input)与 humming_forward(按子层从 quant_config 取 w1/w2 的 scale/zp/bias)两个方法,承接 modular kernel 的输入量化与前向调用。moe_problem_sizeget_buffer_metas 由 config 的 shape_k - pad_shape_k 推导中间维度,并新增 intermediate_dim == adjust_N_for_activation(...) 断言,同时修正输出 buffer 可能与 workspace1 别名的处理。新增 _supports_batch_invariance() 声明以通过 modular kernel 的候选内核过滤。

  3. 线性内核与量化方法统一改造scaled_mm / mxfp4 / mxfp8 / nvfp4 / mixed_precision 下的 Humming 线性内核统一改为在 process_weights_after_loading 里生成 self.layer_config / self.compute_config / self.locksapply_weights 收敛到 apply_humming_linearis_supported 增加 has_humming() 检查以改善未安装依赖时的报错路径;apply_scaled_mmpass 改为 raise NotImplementedError,避免静默空操作。quantization/humming.pyHummingLinearMethodprocess_weights_after_loading / apply 同步迁移到 config + 张量模式,locks 不再作为 layer buffer 注册;HummingMoEMethodget_fused_moe_quant_config 传入 self.humming_configs 与 swiglu 参数,convert_to_humming_moe_kernel_format 的返回值被保留为 self.humming_configs

  4. oracle 路径联动fused_moe/oracleint8.py / fp8.py / nvfp4.py / mxfp4.py / int_wna16.pymake_*_moe_kernel 全部移除 layer 参数与 extra_kwargs 特判;make_*_moe_quant_configget_humming_moe_quant_config 透传 gemm1 参数;int8.py 的转换逻辑对齐“Humming 读取 canonical CT scale 名称”,在线 int8 的 per-channel scale 以 (E, N, 1) 形状暴露给 Humming 转换。

  5. 测试、CI 与依赖配套:更新 MoE 相关单测以适配新 API(含 MXFP4 MoE kernel factory 调用);CI/eval 覆盖新增 NVIDIA-Nemotron-3-Nano-30B-A3B-NVFP4-humming 与 GPT-OSS INT8 eval,并调整 Nemotron Nano、Qwen3-4B 的精度阈值;humming-kernels 依赖钉到 0.1.12,CUDA 扩展构建配置同步调整,期间为排查 CI 反复切换 dependency 的 optional: true 标记,并删除一个 Humming 后端单测(提交 b4befa9)。整体 40 个 commit 中多次与 main 合并解决冲突、反复修复 pre-commit,作者在最终 CI 上表示失败测试与本 PR 无关。

文件 模块 状态 重要度
vllm/model_executor/layers/quantization/utils/humming_utils.py 量化工具 modified 9.0
vllm/model_executor/layers/fused_moe/experts/fused_humming_moe.py 专家内核 modified 8.76
vllm/model_executor/layers/quantization/humming.py 量化方法 modified 7.16
vllm/model_executor/kernels/linear/scaled_mm/humming.py 线性内核 modified 7.13
vllm/model_executor/layers/fused_moe/oracle/int8.py 后端编排 modified 6.53
vllm/model_executor/layers/fused_moe/oracle/fp8.py 后端编排 modified 6.37

关键符号

prepare_humming_linear_layer_config get_humming_linear_compute_config apply_humming_linear make_humming_moe_quant_config get_humming_moe_quant_config make_humming_moe_kernel convert_to_humming_moe_kernel_format HummingExpertsBase.__init__ HummingExpertsBase.init_humming_moe HummingExpertsBase.quantize_input HummingExpertsBase.humming_forward HummingExpertsBase._supports_batch_invariance HummingExpertsBase.get_buffer_metas HummingLinearMethod.process_weights_after_loading HummingLinearMethod.apply HummingMoEMethod.get_fused_moe_quant_config make_fp8_moe_quant_config make_int8_moe_quant_config

关键源码片段

vllm/model_executor/layers/quantization/humming.py data-contract

HummingLinearMethod / HummingMoEMethod 的权重后处理与 apply 迁移到 config + 张量模式,locks 不再注册为 layer buffer;MoE 侧 process_weights_after_loading 保存 humming_configs 并在 get_fused_moe_quant_config 透传 gemm1 参数。

def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
    if layer.is_fallback:
        return None
​
    # 前半部分:checkpoint -> humming 标准格式(convert_humming)与
    # force requant(原始量化 -> fp16/bf16 -> 新量化)逻辑保持不变,此处省略
​
    # 旧实现:HummingMethod.prepare_layer_meta(layer=...) + transform_humming_layer(layer)
    # 新实现:生成独立 LayerConfig,再原地替换 layer 参数
    self.layer_config = _hm.prepare_layer_config(
        shape_n=layer.output_partition_sizes_sum,
        shape_k=layer.input_size_per_partition,
        weight_schema=self.weight_schema,
        input_schema=self.input_schema,
        pad_n_to_multiple=256,
        pad_k_to_multiple=128,
        has_bias=layer.has_bias,
        torch_dtype=layer.param_dtype,
    )
    tensors = _hm.transform_humming_tensors(
        self.layer_config, dict(layer.named_parameters())
    )
    for name, _ in list(layer.named_parameters()):
        delattr(layer, name)
    for name, tensor in tensors.items():
        param = torch.nn.Parameter(tensor, requires_grad=False)
        setattr(layer, name, param)
​
    # compute_config / locks 移到方法对象上维护,不再作为 layer 的 buffer 注册
    self.compute_config = get_humming_linear_compute_config()
    self.locks = torch.zeros(1024, dtype=torch.int32, device=layer.weight.device)
​
​
def apply(
    self,
    layer: torch.nn.Module,
    x: torch.Tensor,
    bias: torch.Tensor | None = None,
) -> torch.Tensor:
    # forward 与线性内核共享同一套 humming_forward 入口
    flatten_inputs = x.reshape(-1, x.size(-1))
    output = _hm.humming_forward(
        self.layer_config,
        inputs=flatten_inputs,
        weight=layer.weight,
        weight_scale=getattr(layer, "weight_scale", None),
        zero_point=getattr(layer, "zero_point", None),
        bias=getattr(layer, "bias", None),
        weight_scale_2=getattr(layer, "weight_scale_2", None),
        locks=self.locks,
        compute_config=self.compute_config,
    )
    output = output.view(*x.shape[:-1], output.size(-1))
    return output

评论区精华

prepare_humming_linear_layer_config 中删除 layer 全部参数是否安全 正确性

bnellnm: “Is it safe to delete all the parameters in the layer? I'm not very familiar with all the parameters used by linear layers but I'd be worried that there are other required parameters that might not be transformed that need to be preserved?”

结论:jinzhen-lin: 该阶段 layer 内所有参数均为 humming 相关张量;同函数先前已有删除重建处理,且已把两处逻辑合并到一处。 · 已解决

_supports_batch_invariance 的用途 question

bnellnm: “What is this method used for? I didn't see it referenced anywhere else. Is it for future work?”

结论:jinzhen-lin: 用于 modular_kernel.py 中候选内核的过滤(L663-L670 / L577-L578);Humming 支持 batch invariant,必须 override 才能通过筛选。 · 已解决

make_*_moe_quant_config 的 layer 参数是否可移除 设计

bnellnm 连续在 fp8.py / int8.py / nvfp4.py 追问 : “Are you planning on eventually removing the layer argument here as well? Why not pass layer.humming_configs?”

结论:jinzhen-lin: 暂不能移除,负责读取权重张量;Humming 预处理可能产生额外张量(如 mxfp4×fp8 将 e8m0 scale 拆为 group scale + tensor/channel scale),而 mxfp4 MoE oracle 未预留空间,列为未来工作。 · 待处理

风险与影响

  • 数据契约破坏make_humming_moe_quant_config 新增必填 humming_configsassert is not None,所有调用方必须同步更新;PR 内 oracle 虽已联动,但未同步的分支或第三方调用会直接断言失败。由于 Humming 是可选依赖(has_humming() 门控),风险面限于启用 Humming 的场景。
  • 权重张量命名变更get_humming_moe_quant_config 读取属性由 w13_global_scale / w2_global_scale 改为 w13_weight_scale_2 / w2_weight_scale_2,同时 scaled_mm/humming.py 删除了 per-tensor 场景下 global_scale 的 name_map 特判。若 nvfp4 / mxfp4 / mxfp8 各路径在预处理阶段产出的张量名与转换假设不一致,可能出现 scale 绑定错误,需依赖新增的 NN 与 Qwen3-4B eval 兜底。
  • MoE workspace 与输出别名get_buffer_metas 明确“最终输出 buffer 由 modular kernel 提供,可能与 workspace1 别名”,并新增维度断言;提交历史里也有专门的 “Fix Humming MoE output alias handling” 与 “Fix Humming MoE workspace dimensions”,说明该处对 batch-invariant 与激活类型组合较敏感,回归风险集中在 batched 专家模式。
  • 行为变化apply_scaled_mmpass(静默返回 None)改为 raise NotImplementedError,更安全但可能让此前依赖空操作的调用链转为运行时异常。
  • 测试覆盖变化:删除一个 Humming 后端单测,同时新增 eval 覆盖;但 Nemotron Nano、Qwen3-4B 的 accuracy_threshold 被调整过,存在“为过 CI 放宽阈值”的可能,需警惕精度回归被阈值掩盖。
  • 依赖与构建humming-kernels 钉到 0.1.12,PR 过程中一度移除再恢复 optional: true,若最终 optional 标记或 CUDA extension 构建配置有误,会影响默认安装体验。
  • 用户影响:仅影响安装了 humming-kernels(NVIDIA CUDA SM75+)并启用 Humming 量化后端的用户;非 Humming 路径无行为变化。重构后 forward 不再把 vLLM 层对象传入外部库,后续升级 Humming 时 vLLM 侧适配成本显著降低。
  • 系统影响:量化配置对象(FusedMoEQuantConfigHummingMoEQuantConfig)与内部 kernel factory 签名变化,影响面横跨 fused_moe oracle、线性内核、量化方法三个子系统共 37 个文件,但均在同一 PR 内联动完成。
  • 团队影响:CI 覆盖扩展(新增 2 个 eval 配置)为 Humming 后端提供更强回归保障;同时 review 中暴露的 mxfp4×fp8 量化布局不匹配问题,为后续工作立项提供了依据。
数据契约变更 依赖锁定 humming-kernels 0.1.12 权重张量命名变更 MoE workspace 输出别名 精度阈值调整 删除一个后端单测

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论