执行摘要
- 一句话:重构 W8A8 Int8 MoE 量化方法,引入模块化后端选择架构。
- 推荐动作:建议精读此 PR 以了解模块化内核选择的设计决策,特别是
int8.py 中的后端选择逻辑和 compressed_tensors_moe_w8a8_int8.py 中的集成方式。关注 review 中讨论的参数顺序问题,以学习如何避免类似错误。
功能与动机
根据 PR body,目的是添加对 Int8 W8A8(8-bit weights, 8-bit activations)MoE 量化的支持,使用新的模块化内核架构。这包括引入后端选择和配置系统,以遵循 FP8 oracle 模式,实现更灵活和可扩展的量化支持。
实现拆解
- 新增 Int8 oracle 模块:在
vllm/model_executor/layers/fused_moe/oracle/int8.py 中,定义 Int8MoeBackend 枚举、_get_priority_backends、backend_to_kernel_cls、map_int8_backend 等函数,实现后端选择逻辑。这样改的原因是将 Int8 MoE 的后端选择模块化,便于未来添加更多后端;影响是统一了 Int8 MoE 的初始化路径。
- 更新 CompressedTensorsW8A8Int8MoEMethod:在
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_int8.py 中,修改 __init__ 以调用 select_int8_moe_backend,重写 process_weights_after_loading 以使用 make_int8_moe_kernel,并添加 maybe_make_prepare_finalize 抛出异常。这样改的原因是将现有量化方法集成到新架构;影响是确保 Int8 W8A8 MoE 使用模块化内核。
- 扩展量化支持:在
vllm/model_executor/layers/quantization/utils/quant_utils.py 中,新增 kInt8StaticChannelSym 和 kInt8DynamicTokenSym QuantKey 常量。这样改的原因是定义 Int8 量化方案的标识符;影响是使系统能识别 Int8 W8A8 量化。
- 更新 TritonExperts 支持:在
vllm/model_executor/layers/fused_moe/fused_moe.py 和 vllm/model_executor/layers/fused_moe/fused_batched_moe.py 中,修改 _supports_quant_scheme 方法,添加 Int8 支持并基于平台能力(如 CUDA compute capability >= 7.5)动态构建支持列表。这样改的原因是统一量化方案检测逻辑;影响是确保 Triton 后端能正确处理 Int8 W8A8。
- 清理和修复:提交历史显示多次调整,如移除 BatchedTritonExperts 的 Int8 支持、修复类型错误和参数顺序。这样改的原因是确保代码正确性和一致性;影响是减少回归风险。
关键文件:
vllm/model_executor/layers/fused_moe/oracle/int8.py(模块 MoE模块;类别 source;类型 data-contract;符号 Int8MoeBackend, _get_priority_backends, backend_to_kernel_cls, map_int8_backend): 这是新增的 Int8 oracle 模块,定义了后端选择架构,是 PR 的核心变更。
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_int8.py(模块 量化层;类别 source;类型 core-logic;符号 process_weights_after_loading, maybe_make_prepare_finalize, get_fused_moe_quant_config, init): 这是 Int8 W8A8 MoE 量化方法的主要实现,集成了新 oracle 架构,是关键集成点。
vllm/model_executor/layers/fused_moe/fused_moe.py(模块 MoE模块;类别 source;类型 core-logic;符号 _supports_quant_scheme): 这是核心 MoE 实现文件,更新了 _supports_quant_scheme 以支持 Int8 量化方案。
vllm/model_executor/layers/fused_moe/fused_batched_moe.py(模块 MoE模块;类别 source;类型 core-logic;符号 _supports_quant_scheme): 这是批处理 MoE 实现文件,类似地更新了 _supports_quant_scheme,但移除了 Int8 支持。
vllm/model_executor/layers/quantization/online/int8.py(模块 量化层;类别 source;类型 core-logic;符号 init): 这是在线量化模块,更新以使用新的 oracle 选择逻辑。
vllm/model_executor/layers/quantization/utils/quant_utils.py(模块 量化层;类别 source;类型 data-contract;符号 kInt8StaticChannelSym, kInt8DynamicTokenSym): 这是量化工具文件,新增了 Int8 量化方案的 QuantKey 常量。
关键符号:select_int8_moe_backend, process_weights_after_loading, _supports_quant_scheme, make_int8_moe_kernel, backend_to_kernel_cls
关键源码片段
vllm/model_executor/layers/fused_moe/oracle/int8.py
这是新增的 Int8 oracle 模块,定义了后端选择架构,是 PR 的核心变更。
from enum import Enum
import torch
import vllm.model_executor.layers.fused_moe.modular_kernel as mk
from vllm.config.kernel import MoEBackend
from vllm.model_executor.layers.quantization.utils.quant_utils import (
QuantKey,
kInt8DynamicTokenSym,
kInt8StaticChannelSym,
)
class Int8MoeBackend(Enum):
TRITON = "TRITON" # 定义 Int8 MoE 后端枚举,目前仅支持 Triton
def select_int8_moe_backend(
config: FusedMoEConfig,
weight_key: QuantKey | None = kInt8StaticChannelSym,
activation_key: QuantKey | None = kInt8DynamicTokenSym,
) -> tuple[Int8MoeBackend, type[mk.FusedMoEExperts]]:
"""
选择主要的 Int8 MoE 后端。
注意:运行时仍可能发生形状特定的回退。
"""
if config.is_lora_enabled:
# 如果启用了 LoRA,直接返回 Triton 后端
return Int8MoeBackend.TRITON, backend_to_kernel_cls(Int8MoeBackend.TRITON)[0]
AVAILABLE_BACKENDS = _get_priority_backends(config) # 获取可用后端优先级列表
activation_format = (
mk.FusedMoEActivationFormat.BatchedExperts
if config.moe_parallel_config.use_batched_activation_format
else mk.FusedMoEActivationFormat.Standard
)
def _make_log_backend(backend: Int8MoeBackend) -> str:
# 生成日志消息,用于记录使用的后端
available_backend_strs = [b.value for b in AVAILABLE_BACKENDS]
return f"Using {backend.value} Int8 MoE backend out of potential backends: {available_backend_strs}."
def _return_or_raise(backend: Int8MoeBackend) -> tuple[Int8MoeBackend, type[mk.FusedMoEExperts]]:
# 检查后端是否支持配置,支持则返回,否则抛出异常
for k_cls in backend_to_kernel_cls(backend):
supported, reason = k_cls.is_supported_config(
k_cls, config, weight_key, activation_key, activation_format
)
if supported:
logger.info_once(_make_log_backend(backend), scope="local")
return backend, k_cls
raise ValueError(f"Int8 MoE backend '{backend.value}' does not support the deployment configuration.")
# 处理用户指定的 moe_backend
runner_backend = config.moe_backend
if runner_backend != "auto":
requested_backend = map_int8_backend(runner_backend)
return _return_or_raise(requested_backend)
# 按后端优先级自动选择
for backend in AVAILABLE_BACKENDS:
for k_cls in backend_to_kernel_cls(backend):
supported, reason = k_cls.is_supported_config(
k_cls, config, weight_key, activation_key, activation_format
)
if supported:
logger.info_once(_make_log_backend(backend), scope="local")
return backend, k_cls
else:
logger.debug_once(f"Backend {backend.value} unsupported: {reason}", scope="local")
raise NotImplementedError("No Int8 MoE backend supports the configuration.")
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe/compressed_tensors_moe_w8a8_int8.py
这是 Int8 W8A8 MoE 量化方法的主要实现,集成了新 oracle 架构,是关键集成点。
class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
"""W8A8 Int8 MoE quantization using compressed tensors."""
def __init__(
self,
weight_quant: QuantizationArgs,
input_quant: QuantizationArgs,
moe: FusedMoEConfig,
layer_name: str | None = None,
):
super().__init__(moe)
self.weight_quant = weight_quant
self.input_quant = input_quant
# 验证量化策略
per_channel = (
self.weight_quant.strategy == QuantizationStrategy.CHANNEL
and self.input_quant.strategy == QuantizationStrategy.TOKEN
)
if not per_channel:
raise ValueError("For INT8 Fused MoE layers, we require channelwise, dynamic per token quantization.")
# 选择 Int8 MoE 后端
self.int8_backend, self.experts_cls = select_int8_moe_backend(
config=self.moe,
weight_key=kInt8StaticChannelSym,
activation_key=kInt8DynamicTokenSym,
)
def process_weights_after_loading(self, layer: FusedMoE) -> None:
# 加载权重后,创建 MoE 内核
self.moe_quant_config = self.get_fused_moe_quant_config(layer)
assert self.experts_cls is not None
self.moe_kernel = make_int8_moe_kernel(
moe_quant_config=self.moe_quant_config,
moe_config=self.moe,
experts_cls=self.experts_cls,
routing_tables=layer._maybe_init_expert_routing_tables(),
shared_experts=layer.shared_experts,
)
def apply(
self,
layer: FusedMoE,
x: torch.Tensor,
topk_weights: torch.Tensor,
topk_ids: torch.Tensor,
shared_experts_input: torch.Tensor | None,
) -> torch.Tensor:
assert not self.is_monolithic
assert self.moe_kernel is not None
# 调用 MoE 内核,注意参数顺序:topk_ids 在前,topk_weights 在后
return self.moe_kernel.apply(
x,
layer.w13_weight,
layer.w2_weight,
topk_ids, # 修复:topk_ids 应在前
topk_weights, # 修复:topk_weights 应在后
activation=layer.activation,
global_num_experts=layer.global_num_experts,
expert_map=layer.expert_map,
apply_router_weights=layer.apply_router_weights,
shared_experts_input=shared_experts_input,
)
评论区精华
review 中主要讨论了 apply 方法的参数顺序错误:
风险与影响
- 风险:技术风险包括:
- 回归风险:新架构可能引入未覆盖的边缘情况,尤其是在
process_weights_after_loading 和内核初始化路径中,可能导致模型加载或推理失败。
- 性能风险:模块化选择逻辑可能增加运行时开销,但影响较小;Int8 量化本身可能带来性能提升,但需验证平台兼容性。
- 兼容性风险:Int8 支持依赖于 CUDA compute capability >= 7.5 或 ROCm gfx9,旧硬件可能无法使用;
fused_batched_moe.py 中移除了 Int8 支持,可能影响某些配置。
- 正确性风险:review 中发现的参数顺序错误已修复,但其他类似错误可能未被捕获;新代码路径缺乏直接测试文件变更。
- 影响:影响范围:
- 用户影响:用户现在可以使用 Int8 W8A8 MoE 量化,可能降低内存占用和提升推理速度,但需确保硬件兼容性。
- 系统影响:MoE 模块的架构更模块化,便于未来扩展;量化方案检测更统一,减少代码重复。
- 团队影响:工程师需要熟悉新的 oracle 选择模式,可能影响后续开发和维护。
- 风险标记:参数顺序错误, 平台兼容性限制, 缺少测试覆盖
关联脉络
- PR #40132 [xpu][rocm] Update
current_platform.supports_fp8() for TritonExperts: 都涉及更新 TritonExperts 的量化支持逻辑,当前 PR 扩展了 Int8 支持。
- PR #38877 [compile] mla + group fp8 fusion: 都涉及 MoE 和量化融合,当前 PR 专注于 Int8 W8A8 量化。
- PR #40550 [AMD][CI][BugFix] Override normalize_e4m3fn_to_e4m3fnuz for fnuz machines in test_moe_layer_no_parallel: 都涉及 MoE 层测试和平台兼容性修复。
参与讨论