MoE 把推理的计算省下来了,却把显存和带宽的全量账单留给了部署:所有专家都要驻留,每个 token 却只碰其中几个。这篇讲 MoE 特有的部署问题——专家量化、expert offloading、Group GEMM 与 EP 推理、端侧低激活路线;框架使用细节见 vLLM 与 SGLang:大模型结构化生成语言与推理框架,训练侧并行见 专家并行。
先算显存账
MoE 部署的一切问题都源于一个不对称:计算按激活参数走,存储按总参数走。
| 模型 | 总参 | 激活 | fp16 显存 | 每 token 实际计算 |
|---|---|---|---|---|
| Llama-2 70B(dense) | 70B | 70B | ~140 GB | 70B |
| Mixtral 8×7B | 46.7B | 12.9B | ~93 GB | 12.9B |
| DeepSeek-V3 | 671B | 37B | ~1.3 TB | 37B |
对于dense 模型,“装得下”就能“算得动”;但是MoE 里两者解耦——Mixtral 的算力需求接近 13B dense,fp16 却要 90GB+。于是 MoE 部署优化只有一个主题:让不参与计算的专家参数,尽量不占贵的资源(GPU 显存 > CPU 内存 > SSD)。
专家量化:收益最大的单步
量化的显存收益按总参数结算,而精度风险只落在被激活的部分——这是 MoE 量化的结构性优势,所以前沿 MoE 的量化激进程度普遍超过 dense:
- FP8:DeepSeek-V3 训练即用 FP8 混合精度,推理部署顺理成章,671B 压到 ~700GB 级
- 块尺度浮点量化 MXFP4:GPT-OSS 采用 OCP MX 块尺度 4bit 格式,117B 总参压到 ~60GB,单张 80GB H100 放下
- w4a16 权重量化(GPTQ/AWQ):Qwen3-MoE 系列的开源量化生态标配,权重 4bit、激活 16bit
一个工程细节:MoE 量化要按专家粒度做 scale——不同专家的权重分布差异大,全局 scale 精度损失明显。router 和共享专家通常保持更高精度,与训练侧「router 用 fp32」的选择性精度同理(见 Switch Transformer)。
Expert Offloading:按路由预取
显存不够就分层放置:非激活专家放 CPU/SSD,用到再搬。dense 模型 offload 每步要搬整层权重,几乎必然亏;MoE 每层每 token 只需 k 个专家,搬运量天然缩小一个数量级,offload 从亏本变可行。
朴素做法(用到才加载)会被 PCIe 延迟杀死。有效的方案都靠预取:
- 路由相关性预取(Mixtral-offloading):隐藏层之间的路由决策强相关——浅层选中哪些专家,深层大概率还在选同一批。提前若干层把「即将被选中」的专家异步搬入 GPU,计算到该层时已就位
- LRU 专家缓存:热点专家常驻 GPU,冷专家留在 CPU,缓存未命中才触发搬运
- 隐藏搬运于计算:专家搬运与当前层计算用不同 CUDA stream 重叠,PCIe 带宽在计算间隙被填满
代价是 concurrency 受限——预取命中率依赖 batch 内路由分布稳定,大 batch 下各 token 需要的专家并集变大,缓存优势收窄。所以 offload 是单卡/少卡跑大 MoE 的方案,不是吞吐方案。
算子侧:Group GEMM 与 fused kernel
路由把一个 batch 的 token 打散到 N 个专家,每个专家拿到一小撮 token—— naive 实现是 N 个小 GEMM,kernel 启动开销和低占用率把 GPU 打成空闲。两条解法:
- Group GEMM:把同专家的 token 聚成组,多组拼成一次分组矩阵乘(Megatron
--moe-grouped-gemm、DeepGEMM、CUTLASS GroupGEMM)。训练与大 batch 场景主力,机制详见 吞吐优化的核心技术体系 - Fused MoE kernel:推理框架(vLLM 的
fused_moeTriton kernel)把 sort-by-expert → GEMM → unsort 整个流程融进一个 kernel,针对 decode 阶段每专家只有一两个 token 的退化场景(实质是 batched GEMV)做了专门 tile 策略
decode 阶段是 MoE kernel 最难写的场景:token 少、专家多、形状碎——这也是各框架 MoE 支持成熟度差异最大的地方。
并行策略:decode 阶段 EP 优于 TP
多卡推理的两种切法在 MoE 上出现分歧:
- TP 切:每个专家的权重矩阵横切到所有卡,每层每卡两次 all-reduce。decode batch 小时通信占比极高,卡越多越亏
- EP 切:整只专家放一张卡,token 用两次 all-to-all(dispatch/combine)进出。通信量正比于激活 token × 激活专家,与总专家数无关——激活率越低,EP 越占便宜
所以 MoE 推理常见配置是 prefill 用 TP(大 batch 算力密集)、decode 切到 EP(小 batch 通信敏感)。vLLM/SGLang 均原生支持 EP 推理(vLLM --enable-expert-parallel);DeepSeek 开源的 DeepEP 库专为 MoE 的 all-to-all 优化,含 decode 用低精度链路。
EP 的阿喀琉斯之踵是负载不均:所有卡要等最慢的专家(straggler),路由长尾直接变成延迟长尾。推理侧没有 bias 均衡可用(router 是冻结的),只能靠复制热点专家(expert replication)或调度层兜底——部署 MoE 服务时监控专家级负载是必要功课。
端侧:MoE 反而是带宽赢家
直觉上万亿参数模型与端侧无关,但算带宽账会反转:CPU/端侧推理是纯内存带宽受限的,每 token 成本 ≈ 激活参数 × 字节数。
- dense 30B,4bit:每 token 要读 ~60 GB 权重
- Qwen3-30B-A3B 同级 MoE,4bit:每 token 只读 ~6 GB——快近 10 倍,代价是 RAM 要装下全部 30B(~17 GB)
在「内存容量够、带宽小」的端侧环境,MoE 用空间换时间恰好打在痛点上。llama.cpp 对 MoE 的支持自 Mixtral 起已是一等公民,Qwen3-30B-A3B 这类低激活模型在纯 CPU 上跑出可用速率,是这条路线的代表作。端侧 MoE 的真正约束不是算力而是总内存占用——设备 RAM 装不下总参数,一切免谈。
部署决策表
| 场景 | 方案 | 关键点 |
|---|---|---|
| 单卡装得下(量化后) | 全 GPU + fused MoE kernel | 激进量化专家权重,MXFP4/FP8 |
| 单卡装不下、多卡 | decode 走 EP | 监控专家负载,必要时复制热点专家 |
| 卡少显存紧(消费级) | expert offload + 预取 | 小 batch 高并发下命中率崩,慎用 |
| 纯 CPU / 端侧 | 低激活率 MoE(A3B 级) | 只看总内存占用与每 token 读取量 |
| 追求极简运维、频繁微调 | 回到 dense | MoE 的量化/监控/负载复杂度都是持续成本 |
与 KV Cache 串起来看当代 MoE 服务的全貌:权重侧靠稀疏激活省带宽(本篇),KV 侧靠 从 MHA 到 MLA 压缓存——DeepSeek-V3 这类模型两条腿都用上,才能把 671B 做到可商用部署。