Experts 后端
所有 Mixture-of-Experts (MoE) 实现都执行相同的高层计算。对于每个 token,路由器会选择 k 个专家。随后,token 的隐藏状态会通过所选专家的参数进行投影,并根据路由权重进行聚合。不同专家后端之间的区别在于这些专家矩阵乘法是如何执行的。
ExpertsInterface 提供了经过优化的专家后端。它将专家的实现与模型代码解耦,从而简化了对不同函数的实验。通过同一接口添加新的后端。
| experts 后端 | 描述 | GPU | CPU |
|---|---|---|---|
"eager" | 参考实现,遍历选定的专家,并对它们的 token 应用投影。 | 无需编译即可实现合理的基线性能。 | 比 grouped_mm 慢,但比 batched_mm 快。 |
"batched_mm" | 为每个 token 复制所选的专家参数,并使用 torch.bmm 在单个批量 GEMM 中投影所有 token。 | 对于小型输入,尤其是启用编译时,速度最快。由于参数复制,会占用更多内存。 | 不推荐(比其他后端显著更慢)。 |
"grouped_mm" | 按选定的专家对 token 进行排序,并使用 torch.nn.functional.grouped_mm 通过单次分组 GEMM 投影所有 token(需要 PyTorch 2.9+)。 | 适用于较大的输入,并且由于避免了重复专家参数,因此内存效率更高。配合编译使用时速度很快。 | 适用于所有输入尺寸的最高效后端。 |
"deepgemm" | 按所选专家对 token 进行排序,并使用来自 kernels-community/deep-gemm 的 DeepGEMM 内核,通过单次 TMA 对齐的分组 GEMM 投影所有 token。 | DeepSeek 模型在 Hopper (SM90+) 和 Blackwell (SM100+) 上的原生后端;支持 bfloat16 以及 FP8/FP4 量化专家。 | 不支持(仅限 CUDA)。 |
"deepgemm_megamoe" | 将专家并行分发、门控 MLP(上投影、SwiGLU、下投影)以及 EP 合并融合为单个 DeepGEMM Mega MoE 内核,使 NVLink 传输与张量核心计算相互重叠。 | 仅适用于 Blackwell(SM100+),用于以专家并行方式运行的 FP4 量化专家。 | 不支持(仅限 CUDA)。 |
"sonicmoe" | 将路由的 bfloat16 MoE 前向传播(路由器分发、门控上投影、激活、下投影)融合为来自 kernels-community/sonic-moe 的 CuteDSL 分组 GEMM 内核(源自 quack 库)。 | 在 Hopper(SM90+)上,针对采用门控激活函数(SwiGLU/GeGLU/ReGLU)的 bfloat16 专家,实现了最先进的吞吐量,尤其适用于训练场景。 | 不支持(仅限 CUDA)。 |
"batched_mm" 和 "grouped_mm" 后端同样通过 Triton finegrained-fp8 内核运行 FP8 和 FP4(int8 打包)量化专家,读取 float32 或 UE8M0 缩放因子。当 "deepgemm" 后端不可用时,它们作为量化检查点的回退方案。
解码阶段切换
在 GPU 上,使用 experts_implementation="grouped_mm" 加载的模型会在生成过程的解码阶段自动切换到 "batched_mm",这在处理较少 token 时速度显著提升。生成结束后,系统会恢复为原始后端。在 CPU 上,grouped_mm 在整个生成过程中保持激活状态,因为它在任何输入规模下都更高效。
该开关会作用于顶层模型以及任意子配置主干中的 MoE 层,例如视觉-语言模型的 text_config。只有 grouped_mm 条目会切换为 batched_mm。运行其他后端的专家将保持原样。
设置 experts 后端
使用 from_pretrained() 中的 experts_implementation 参数,可以实例化一个使用特定 experts 后端的模型。
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen1.5-MoE-A2.7B",
dtype="bfloat16",
experts_implementation="batched_mm",
)使用 set_experts_implementation() 可在运行时切换专家后端,而无需重新加载模型。
model.set_experts_implementation("eager")使用 get_experts_implementation() 读取当前正在运行的后端。它返回一个 dict,其中包含一个针对模型的条目,以及每个子配置各一个条目。
model.get_experts_implementation()
# {"": "grouped_mm", "text_config": "grouped_mm", "vision_config": "eager"}特定骨干的专家后端
多模态模型可以拥有多个子配置(例如,不同的骨干网络)。在加载时,通过向 experts_implementation 传入一个 dict,可以为每个子配置设置不同的专家后端。
映射中的键必须与子配置名称匹配。
from transformers import AutoModelForImageTextToText
experts_implementation_per_backbone = {
"text_config": "grouped_mm",
"vision_config": "eager",
}
model = AutoModelForImageTextToText.from_pretrained(
"Qwen/Qwen3-VL-Moe",
experts_implementation=experts_implementation_per_backbone,
)使用空键全局设置 experts 后端。
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen1.5-MoE-A2.7B",
experts_implementation={"": "batched_mm"},
)DeepGEMM
"deepgemm" 后端通过 kernels-community/deep-gemm 分发的 DeepGEMM 内核来路由专家矩阵乘法。它支持未量化的 bfloat16 专家,以及通过 Fine-grained FP8 加载的 FP8/FP4 量化专家。
"deepgemm" 后端需要:
- 计算能力 ≥ 9.0 的 CUDA GPU(Hopper 或更新架构)。
- 完整的 CUDA 工具包,包含用于内核 JIT 编译的
nvcc,在 Hopper 上版本需为 12.3 或更高,在 Blackwell 上需为 12.9 或更高。仅包含运行时的安装没有nvcc,会被拒绝。Transformers 通过CUDA_HOME、CUDA_PATH、PATH上的nvcc,然后/usr/local/cuda来定位工具包。 - kernels 包。
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"deepseek-ai/DeepSeek-V3",
dtype="bfloat16",
experts_implementation="deepgemm",
)内核会在第一次前向传播时延迟加载。
FP8 和 FP4 量化专家
DeepSeek 风格的检查点通常已预先量化,并自带量化配置,因此无需传入 FineGrainedFP8Config。"deepgemm" 后端会自动选择 FP8(或在 Blackwell 上选择 FP4)分组 GEMM 内核。DeepGEMM 要求使用动态逐行激活缩放(activation_scheme="dynamic"),并拒绝静态(逐张量)激活量化。
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"deepseek-ai/DeepSeek-V3",
experts_implementation="deepgemm",
)对于 FP4 打包的专家权重(DeepSeek V4 风格),GPU 必须是 SM100+(Blackwell)。检查点配置通常设置为 expert_dtype="fp4" 和 scale_fmt="ue8m0"。
在 Blackwell(SM100+)上,
"deepgemm"和"deepgemm_megamoe"专家内核要求使用 2 的幂次 UE8M0 专家缩放因子。使用普通float32缩放因子(scale_fmt="float")量化的检查点,在首次前向传播时会抛出ValueError,而不是静默地损坏输出。请加载使用scale_fmt="ue8m0"量化的检查点,或改用grouped_mm或batched_mm,它们可以直接使用float32块缩放因子。Hopper(SM90+)在 DeepGEMM 路径上直接使用float32缩放因子,无需转换。
为预量化检查点传入 FineGrainedFP8Config 的主要目的是将其反量化回 bfloat16,在这种情况下,专家模块将以 bfloat16 运行,而不是走 FP8/FP4 DeepGEMM 路径。
from transformers import AutoModelForCausalLM, FineGrainedFP8Config
model = AutoModelForCausalLM.from_pretrained(
"deepseek-ai/DeepSeek-V3",
quantization_config=FineGrainedFP8Config(dequantize=True),
experts_implementation="deepgemm",
)Blackwell 上的融合 Mega MoE
在 Blackwell(SM100+)上,设置 experts_implementation="deepgemm_megamoe" 以运行一个融合内核,该内核将专家并行分发、上投影、SwiGLU、下投影以及 EP 合并组合在一起,并将 NVLink 传输与张量核心计算重叠执行。
此后端需要:
- 配备 CUDA 工具包(
nvcc)12.9 或更高版本的 Blackwell GPU(计算能力 ≥ 10.0)。 - FP4 打包的专家权重,搭配 UE8M0 权重缩放因子(预量化检查点通常在其配置中声明
expert_dtype="fp4"和scale_fmt="ue8m0")。 torch.distributed进程组,用于专家并行组。当ep_size > 1时,专家并行封装会自动提供该进程组。
import os
from transformers import AutoModelForCausalLM, DistributedConfig
distributed_config = DistributedConfig(
tp_size=int(os.environ["WORLD_SIZE"]),
ep_size=int(os.environ["WORLD_SIZE"]),
)
model = AutoModelForCausalLM.from_pretrained(
"deepseek-ai/DeepSeek-V4",
experts_implementation="deepgemm_megamoe",
distributed_config=distributed_config,
)SonicMoE
"sonicmoe" 后端将路由式 MoE 的前向传播(dispatch、gated up projection、activation、down projection)融合为一组高度优化的 CuteDSL grouped-GEMM 内核,该内核基于 quack 库构建,并由 kernels-community/sonic-moe 分发。
"sonicmoe" 后端需要:
- 计算能力 ≥ 9.0 的 CUDA GPU(Hopper 或更新架构)。
- kernels 包和
nvidia-cutlass-dsl包。 - 采用门控激活(
silu、gelu或relu,分别映射为 SwiGLU/GeGLU/ReGLU)的专家。
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen1.5-MoE-A2.7B",
dtype="bfloat16",
experts_implementation="sonicmoe",
)如果未满足要求,forward 会抛出 ImportError,此时应选择一个不同的 experts_implementation。
torch.compile
"eager"、"batched_mm" 和 "grouped_mm" 后端在某种程度上与 torch.compile 兼容。下表总结了它们的兼容性。"deepgemm"、"deepgemm_megamoe" 和 "sonicmoe" 后端通过外部 CUDA 内核进行路由,因此不在本表的覆盖范围内。
| 实现 | 编译模式 | 数据类型 | fullgraph=True |
|---|---|---|---|
grouped_mm | None, max-autotune-no-cudagraphs | bfloat16 | 是的 |
grouped_mm(回退) | None, max-autotune-no-cudagraphs | bfloat16, float16, float32 | 是的 |
batched_mm | 全部 | bfloat16, float16, float32 | 是的 |
eager | 全部 | bfloat16, float16, float32 | No |
注意事项:
grouped_mm专家后端目前仅在通过torch.compile编译时支持bfloat16。此外,它与 CUDA graphs 不兼容,因此编译时必须使用mode=None或mode="max-autotune-no-cudagraphs"。eager专家后端使用数据依赖操作来确定前向传播中使用了哪些专家。该操作与完整图编译(fullgraph=True)不兼容。
import torch
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen1.5-MoE-A2.7B",
dtype="bfloat16",
experts_implementation="grouped_mm",
device_map="auto",
).eval()
# Works for grouped_mm (no CUDA graphs)
model.forward = torch.compile(model.forward, mode="max-autotune-no-cudagraphs")基准测试
此基准测试比较了不同输入大小和专家实现,包括使用和不使用torch.compile的情况。