MoE推理工程,清晰解析

你以为MoE只是“多几个专家、少算点矩阵”这么简单,其实真正烧钱的是路由、通信和不均衡。很多团队一上来就调并行度和batch size,却连一个token在MoE层里到底经历了什么都没画清楚。沿着这条执行路径走一遍,你会发现:算力只是表面,内存和网络才是暗礁。

一个密集型 Transformer 会对每个 token 应用同一套前馈网络,批处理只是在输入矩阵上扩了行数,权重本身完全不变。MoE 层把这块前馈网络拆成多个专家,由路由器给每个 token 打分、挑出少数几个专家来算。被选中的专家才会真正参与该 token 的计算,其余专家在这一拍里是“冷”的。

动画示意

这样做显著减少了每个 token 实际执行的专家计算量,但有个现实问题:系统在推理时并不知道下一个 token 会选哪几个专家,所以所有候选专家的权重都得“随时待命”。以 Qwen3-30B-A3B 为例,模型卡给出的总参数是 305 亿,激活参数是 33 亿,每个 token 从 128 个路由专家里选 8 个。

服务端仍然必须让完整模型处于可用状态:注意力权重、嵌入、所有专家权重、临时缓冲区,以及不断膨胀的 KV 缓存。33 亿激活参数大致刻画了单个 token 的活跃计算路径,却既不等于部署时的显存占用,也不等于专家权重本身的大小。

激活参数与常驻参数

激活参数描述的是“这一步到底算了哪些路径”,常驻参数则决定“你得在 GPU 上常驻多少权重”。沿着一个 token 在 MoE 服务链路里的旅程,我们可以依次看清:路由器如何选专家、运行时如何把 token 重排成专家批次、本地内核怎么执行、激活又是怎样在多块 GPU 间来回搬运。

接下来会延伸到更工程化的问题:专家放在哪些 GPU 上、负载怎么被拉歪、容量限制和量化怎么影响性能,以及如何用测量手段把计算、内存带宽和互联流量的真正瓶颈揪出来。

想从代码层彻底理解 MoE?

从零开始构建基于MoE的Transformer,我们用纯Python和PyTorch讲解了LLaMA 4 →

这套教程把 LLaMA 4 和 Mixtral 背后的专家、路由器和稀疏激活拆开讲,配合字符级分词、多头自注意力、RoPE、MoE MLP、RMSNorm、残差与因果掩码,一路写到训练与生成。


MoE层结构与token路由

路由器如何改写前馈路径

Transformer 的一层通常先做注意力,再做前馈网络:注意力在不同 token 位置之间混合信息,前馈网络则对每个位置独立做非线性变换。MoE 层把这一块前馈网络替换成多个“专家”,每个专家本质上都是一套独立的前馈网络。注意力部分依旧对所有 token 全量执行,只有前馈这条支路变成了“按需激活”的稀疏结构。

示意图

想象一个只有 4 个专家的玩具 MoE 层:路由器会对某个 token 分别给这 4 个专家打分,然后选出得分最高的 2 个。被选中的两个专家各自对同一个 token 向量做变换,层的输出再把这两个结果按路由权重加权求和。不同架构会对这些权重做不同的归一化,但核心逻辑是一样的:路由器选出一小撮专家,MoE 层把它们的输出混合成最终结果。

公式

在这个公式里:x 是 token 输入向量,S(x) 是被选中的专家集合,E_e 表示专家 e,w_e(x) 是该专家的路由权重,输出向量记为 y。求和只覆盖被选中的专家,每个专家对同一个输入向量做变换,再用路由权重缩放后相加。很多人会下意识把这理解成“模型路由”(给整个请求选一个 LLM),其实 MoE 路由发生在每一层内部、每个 token 级别,粒度完全不同。

示意图

Qwen3-30B-A3B 的配置是:每个 token 在 128 个专家中选 8 个,模型卡显示共有 48 层。部分架构还会引入“共享专家”,这些专家不看路由得分,对所有 token 都执行一遍;DeepSeekMoE 就在路由专家旁边挂了共享专家。共享专家是“全勤”,路由专家是“按需”,但只有在模型设计里明确写了共享专家,你才能这么假设。

路由决策对批量推理的影响

路由器改变的是每一层内部的前馈计算路径,这对批量推理的调度方式影响很大。服务引擎需要把一批 token 的路由结果,转换成一组适合 GPU 执行的大矩阵:不同专家的目标 GPU 可能不同,矩阵的行数也完全不一样。这里有个常被忽略的认知差异:

据一些推理引擎的用户反馈,他们一开始只盯着“激活参数更少=更省显存”,结果上线后发现显存还是爆了,延迟也没降多少。

真正决定显存的是常驻权重和 KV 缓存,而决定延迟的,往往是路由后的重排、通信和尾部专家的慢矩阵。

所以,理解“token 如何被路由到专家,再被打包成矩阵”这条链路,是做 MoE 推理工程的起点,而不是优化的终点。


批次如何变成专家专用矩阵

从路由结果到dispatch矩阵

路由器是按 token 做决策的,但 GPU 不擅长一次只算一个小矩阵。服务引擎需要把“token→专家”的离散分配,整理成每个专家各自的一块大矩阵。假设有 4 个 token 进入一个 4 专家 MoE 层,采用 top-2 路由,路由结果是:

  • T1 选 E1(权重 0.7)和 E3(权重 0.3)
  • T2 选 E1(权重 0.4)和 E3(权重 0.6)
  • T3 选 E1(权重 0.7)和 E2(权重 0.3)
  • T4 选 E2(权重 0.8)和 E4(权重 0.2)

运行时视角下,这里其实有 8 条“分配记录”:每条记录都包含一个 token 向量、一个被选中的专家,以及对应的路由权重。接下来,运行时会按专家把这些记录分组:E1 收到 T1、T2、T3;E2 收到 T3、T4;E3 收到 T1、T2;E4 只收到 T4,对应的矩阵行数分别是 3、2、2、1。

示意图

每个专家只看自己那块矩阵,运行时会在每一行里保留原始 token ID,方便结果返回时对号入座。比如:T1 会从 E1 和 E3 各拿到一个输出向量,运行时再乘以 0.7 和 0.3,相加得到 T1 的最终专家输出。其他 token 也是同样的流程。把 token 按专家分组这一步叫 dispatch,把专家输出按 token 合并回来叫 combine,在单 GPU 上都是本地操作,多 GPU 时就会牵扯到网络传输。

预填充、解码与Grouped GEMM

这里有个容易被忽略的细节:专家批次的“大小”其实是分配数,而不是唯一 token 数。top-2 路由意味着每个 token 会贡献两行矩阵。预填充阶段(prefill)通常一次处理很多 prompt token,专家矩阵行数自然就大,GPU 利用率往往不错。解码阶段(decode)每一步只新增一个 token,在低并发下专家矩阵会非常小,光是启动矩阵核的开销就足够浪费一大截 GPU 时间。

高并发能缓解这个问题,因为会有更多分配可以打包在一起。Grouped GEMM 的思路就是:把多个专家的小矩阵合并成一次大调用,减少 kernel 启动次数,同时允许每个专家的行数不同。有的引擎会把专家矩阵填充到固定大小,调度起来更简单,但代价是会对“空行”做无效计算。

示意图

预填充和解码的性能都不是常数:prompt 长度、并发请求数会直接改变专家矩阵的行数;隐藏层宽度和硬件特性又决定了矩阵乘法本身的效率。Grouped GEMM 能把已有的专家工作打包得更紧凑,却没法凭空创造工作量——没有 token 的专家,依旧是空的。

示意图

如果把这条链路压缩成一句话:路由产生分配记录,dispatch 把它们重排成专家矩阵,combine 再把结果按 token 合并回来。真正的工程难点,是在不同并发和 prompt 模式下,让这三步都尽量“吃满” GPU,而不是被 kernel 启动和数据搬运拖慢。


本地MoE执行流水线

路由、置换与Grouped GEMM

MoE 层在本地执行时,不只是做几次矩阵乘法那么简单,还要经历:路由打分、top-k 选择、token 行重排、专家计算、结果合并和顺序恢复。每个阶段都可能成为瓶颈。路由器会先为每个候选专家生成分数,再通过 top-k 操作保留被选中专家的索引和权重。运行时接着要把 token 行重排,让每个专家都能拿到一块连续的矩阵,这一步通常叫 permutation。

置换会读取原始 token 向量,按专家顺序写入新的缓冲区,同时记录一份逆映射,留给 combine 阶段恢复顺序。说实话,在小批量解码场景下,单是移动这些行的时间,有时就能和矩阵乘法本身打个平手。Grouped GEMM 则通过一次启动执行多个专家矩阵,行数可以不同,从而减少 kernel 启动次数。

专家计算阶段会应用激活函数和输出投影,运行时再用逆映射把 token 顺序恢复回来,按路由权重缩放并累加同一 token ID 的多路专家输出。整个过程如果拆得太细,每一步都要写回显存,内存带宽和启动开销会被放大。

示意图

核融合与激活量化的取舍

核融合(kernel fusion)会把多步操作合并到一个内核里,避免中间激活频繁写入 GPU 内存,从而同时降低启动开销和内存流量。不过融合通常有不少前提条件:只支持特定数据类型、批次形状或量化格式,一旦不满足,就得退回到更模块化的执行路径。

激活量化是另一条常见路线。运行时可以选择在 dispatch 之前先量化激活,减少传输字节;也可以先用高精度做 dispatch,再在专家侧量化。前者更省带宽,但多了一次精度转换的成本;后者带宽压力更大,却能在关键路径上少做一次转换。我也不太确定哪种方案在所有场景下都更优,这往往得结合你自己的负载模式和硬件来测。

示意图

在解码阶段,专家矩阵通常偏小,权重读取、行移动和 kernel 启动都可能成为主导瓶颈;预填充阶段则因为行数多,矩阵乘法效率更关键。融合路径能把这些操作的边界“抹平”,但不会改变路由选择或分配数量。要想真正定位瓶颈,必须分别测量路由、置换、专家 GEMM 和 combine 的耗时,一个笼统的“MoE 层时间”计时器基本帮不上忙。


模型权重常驻与运行时内存

总参数、激活参数与常驻参数

MoE 部署时,常见的三个参数概念是:总参数、激活参数和常驻参数。总参数描述的是检查点里一共存了多少权重;激活参数描述的是单个 token 在一次前向里实际走过的路径;常驻参数则是当前服务系统在 GPU 上常驻了多少权重。三者完全没必要相等:一个 token 可能只打到少数几个专家,另一个 token 又会选到完全不同的一组专家。

在“完全常驻”的部署里,所有候选专家的权重都会放在 GPU 上,同时还有注意力、嵌入、归一化和输出层权重。稀疏路由只减少了计算量,并没有让这些权重凭空消失。以 Qwen3-30B-A3B 为例,305 亿参数,如果每个参数用 2 字节存储,光权重就要大约 61GB 显存。

公式

这个下界可以写成:B(weights) = P × B(stored),其中 P 是总参数数,B(stored) 是每个参数占用的字节数。对 Qwen 来说,就是 305 亿 × 2 字节 ≈ 61GB,而且这还没算上临时激活、通信缓冲、内存分配器的预留空间,以及为所有活跃序列保存注意力状态的 KV 缓存。

示意图

很多人会误用“33 亿激活参数”来估算权重显存,这一步一错,后面所有容量规划都会偏。权重量化可以减少每个参数的字节数,分片可以把权重摊到多块 GPU 上,但这两件事都不会改变参数总数。稀疏激活只减少专家计算量,不会减少权重存储需求,模型依旧可能需要分片权重才能塞进集群。

专家卸载与GPU数量估算

专家卸载(offloading)会把部分专家权重放在 CPU 内存里,只有当路由选中这些专家时,才把对应权重传到 GPU。这样能节省 GPU 显存,却会在解码路径上引入额外的传输延迟。如果某个专家在当前步骤缺失,解码就可能被迫等待;缓存可以缓解重复访问的专家,但预取只有在未来路由有一定可预测性时才真正有效。

示意图

没有一个“固定 GPU 数量”可以适用于所有 MoE 模型:精度设置、分片策略、内存预留和 KV 缓存容量都会改变需求。激活参数更多是在估算计算量,而常驻参数才真正决定权重显存;分片可以解决容量问题,但路由激活很可能会跨 GPU 流动,这又把问题抛给了网络。


专家并行的dispatch与combine

专家并行如何移动激活

专家并行(expert parallelism)把不同专家分配到不同 GPU 上。假设有 4 个专家分布在 2 块 GPU 上:GPU A 拥有 E1 和 E2,GPU B 拥有 E3 和 E4。某个 token 起始在 GPU A 上,路由结果选中了 E1 和 E3,那么 E1 的分配可以留在本地,E3 的分配就必须通过网络发到 GPU B。

网络上传输的不只是 token 向量,还有一段路由元数据:包括 token ID、目标专家、源 GPU、路由权重等,目标 GPU 需要这些信息来正确执行和回传结果。每个 GPU 会把本地和远程收到的分配一起按专家分组,对每个活跃的本地专家执行矩阵乘法,然后再把结果发回源 GPU。源 GPU 用之前保存的 ID 恢复 token 顺序,应用路由权重并累加贡献,完成 combine。

示意图

在多 GPU 场景下,每块 GPU 可能要同时向多个对等 GPU 发送分配,形成接近全互联的通信模式。专家权重通常固定放在各自的 GPU 上,网络上传输的是 token 激活和元数据,填充和临时缓冲会进一步放大传输字节数。

激活传输的上界估算

可以用一个简单的上界来估算 dispatch 阶段的激活传输量:

公式

其中 B(dispatch) 是激活传输的字节数,T 是进入 MoE 层的 token 数,K 是每个 token 选中的专家数,H 是隐藏层宽度,b 是每个激活值的字节数。这个乘积相当于假设每条分配都要传输一个完整的隐藏向量,是在完全不考虑局部性的情况下的上界。留在同一 GPU 的分配不会消耗网络带宽,实际流量取决于远程分配的比例,元数据和填充会在此基础上再加一截,combine 阶段的返回流量也要算进去。

DeepEP 这类通信库会为大批量和小批量提供不同路径:大批量路径追求吞吐,小批量路径追求低延迟。单看核带宽并不能代表端到端服务速度,因为完整请求还包括注意力、调度、采样、缓存管理和所有非 MoE 层的开销。


网络拓扑与专家放置

NVLink、InfiniBand与放置策略

不同 GPU 之间的链路成本差异很大:同一台服务器内可能通过 NVLink 或 NVSwitch 互联,跨服务器则依赖 InfiniBand 或以太网。跨服务器传输通常比机内传输贵得多,专家放置策略决定了每个专家落在哪块 GPU 上,也就决定了路由激活跨慢链路的频率。

示意图

常见的一种布局是尽量把频繁被访问的专家放在同一个 NVLink 域内,另一种则是跨服务器分布不同层的专家,具体边界要结合模型结构和集群拓扑来定。放置策略只改变“物理目标”,不会改变路由器的输出;如果某些专家被频繁选中,可以尝试把它们搬到更靠近 token 源的位置,或者在多个 GPU 上创建物理副本。

路由约束与测量方法

有些模型在训练阶段就引入了路由约束,比如 DeepSeek-V3 使用“节点限制路由”:每个 token 只能访问有限节点上的专家。这种约束是训练架构的一部分,训练完再强行加类似限制,会直接改变被选中的专家集合,从而影响模型质量。

放置优化需要两类信息:路由轨迹和拓扑测量。路由轨迹告诉你每个专家的工作量和共现关系,拓扑测量告诉你不同 GPU 之间的通信成本。只看“专家热度”是不够的:把所有热门专家堆在一起,可能会减少网络流量,却把某台服务器压到爆;把专家均匀摊开又可能增加跨服务器流量。复制专家只有在 GPU 内存还有富余时才有意义。

按通信域(节点内、节点间)分别测量字节数和时间,会比只看集群总流量更有用。集群级流量计数器无法区分节点内和跨节点流量,最好能记录“哪一对专家之间产生了多少流量”,再结合稳定的请求模式来做放置决策。


张量、专家与数据并行执行布局

三种并行的分工

张量并行、专家并行和数据并行,本质上是在不同维度上切分工作。张量并行会把一个大矩阵拆成几块,每块由不同 GPU 计算,最后通过通信把部分结果拼起来完成一层的计算。专家并行则是把完整的专家(或专家分片)分布到不同 GPU 上,让 token 激活去找专家。数据并行则是把不同请求分配给不同副本,有些引擎会在数据并行组内复制注意力组件,而把专家分布在更大的组里。

示意图

真实部署往往是这三种并行的混合体:注意力层和专家层甚至可能用完全不同的 GPU 分组方式,一个标签很难描述整个系统。例如,张量并行大小为 2,数据并行大小为 4,那么注意力可以在 4 个组中运行,每组 2 块 GPU;专家层则把全部 8 块 GPU 视作一个专家并行组来用。

示意图

vLLM 的专家并行部署指南就记录了这种混合方式:启用专家并行时,EP 组大小等于张量并行大小乘以数据并行大小,注意力在每个数据并行组内用张量并行执行。例如 TP=2、DP=4,会产生 4 个注意力组,每组 2 个 rank,而专家层则使用全部 8 个 rank 作为一个 EP 组。

示意图

张量并行的通信发生在矩阵操作内部,专家并行的通信是移动路由激活,数据并行则通过复制组件来换取吞吐。不同布局的成本结构完全不同:低并发或弱互联下,专家并行的传输效率会很差;在集体通信性能不佳的环境里,张量并行也会被拖慢。


专家负载不均衡与rank级尾延迟

路由偏斜如何放大尾延迟

路由器几乎不可能把工作完美均匀地分配给所有专家。假设有一个专家接收了一半的分配,那它所在的 GPU 上矩阵就会比其他 GPU 大得多。其他 GPU 可能早早算完在那儿干等,整层的延迟却被这块“最慢的 GPU”锁死。

示意图

训练阶段可以通过损失项鼓励更均衡的路由,但线上流量的分布往往和训练数据差别很大:语言、任务类型、prompt 模式都会影响专家选择。专家不均衡发生在单个模型副本内部,而请求不均衡则发生在不同副本之间,这两类问题需要完全不同的测量和解决方案。日常的“平均利用率”或“整体直方图”很容易掩盖单步的极端慢点,必须按“每一步、每块 GPU”来拆开看。

放置与复制的权衡

诊断这类问题时,可以记录每一步的分配数、dispatch 时间、专家执行时间、combine 时间和 GPU 空闲时间,来定位尾延迟的真正来源。放置优化可以把经常一起被选中的专家拆开,或者把热点专家迁移到负载更轻的 GPU 上,前提是不改变路由决策本身。复制则会为同一个逻辑专家创建多个物理副本,路由仍然只看到一个逻辑专家,运行时在多个副本之间做调度。

示意图

复制会占用额外的 GPU 内存,挤压 KV 缓存空间;移动专家会消耗网络带宽,而且流量峰值可能在你完成重平衡之前就已经过去。有些运行时会根据近期负载自动重平衡专家,并支持冗余副本,但这需要足够的内存和相对稳定的负载模式。

👉 可以记住一个边界:重平衡只改变专家的物理位置,不改变逻辑专家的选择和输出。平均利用率解释不了 MoE 的尾延迟,真正有用的是“每步、每 GPU”的细粒度测量,再配合放置和复制来做针对性优化。


推理优化与模型正确性边界

不改变计算内容的优化

MoE 优化大致可以分成两类:一类只改变“怎么执行”,另一类会改变“算什么”。融合、Grouped GEMM、专家放置和通信重叠,都属于前一类:它们保持逻辑上的专家选择不变,只是换了一种更高效的执行方式,可能会引入微小的浮点差异,但不会系统性改变模型行为。

量化则开始触碰数值本身:通过改变权重存储格式或激活传输精度,来减少内存和网络流量。这样做不可避免地引入数值误差,需要在目标负载上做质量评估。更激进的做法是减少 top-k:比如模型原本每个 token 选 8 个专家,运行时只执行其中 4 个,再重新归一化权重,这会直接改变输出的专家集合。

示意图

减少专家数的质量影响

论文《Training-Free Halving of Activated Experts》专门研究了这类优化的差异:在 Qwen3.6-35B-A3B 上,直接把每 token 的专家数从 8 减到 4,会损失约 4.65 个 MMLU 点;如果在归一化时仍然参考更大的专家集合,质量损失可以降到 0.35 点左右,同时计算量减半。在 Qwen3.5-397B-A17B 上,从 10 减到 5 个专家的损失约为 0.55 点,还观察到困惑度和任务准确率对设置的偏好并不完全一致。

这些结果都是针对特定检查点和评估集的实验结论,不能简单外推到所有模型。专家并行只改变计算发生的位置,而减少 top-k 会改变计算内容,两者不是等价优化。容量限制也要格外小心:有些训练系统会在训练时限制每个专家能接收的 token 数,有些运行时会在推理时实现类似限制。MoE 推理本身不会自动丢弃“忙碌专家”的 token,任何丢弃或容量规则都属于特定模型或运行时的行为,需要先确认实现细节。

更稳妥的做法是:先把不改变计算内容的优化做到位,再把量化和 top-k 调整视作“模型变更”,用完整的质量评估来验证。执行路径的变更需要性能测试,量化需要同时看性能和质量,top-k 的变更则最好配合输出对比和任务级评估。


基准设计与瓶颈诊断

如何设计有用的基准

一个有效的基准应该一次只改变一个服务决策:保持检查点、精度、提示内容、输出限制和请求到达模式不变,逐步调整并行布局或内核路径。可以从最小可行布局起步,先在单机或单节点内把布局跑顺,再引入跨服务器的专家并行。内存容量可能会限制某些配置能否加载模型,后端实现也可能不支持某些内核或通信模式。

测试时要覆盖低并发和高并发、短提示和长提示,区分“小矩阵解码”和“提示密集预填充”两种完全不同的负载形态。记录预填充和输出阶段的吞吐,测量首 token 延迟和每 token 延迟,并关注 token 间延迟和 95 百分位请求延迟,这些尾部指标往往能暴露出某些 GPU 的慢点。

从GPU指标反推系统瓶颈

GPU 级别的测量是解释请求指标的关键。可以记录:不同网络域的字节数、分配数量、专家执行时间和空闲时间,把路由、置换、dispatch、GEMM、combine 和逆置换拆开计时,同时记录常驻权重占用和剩余 KV 容量。

示意图

高 dispatch 时间往往指向拓扑、局部性或消息大小的问题,持续慢的某块 GPU 则可能是路由偏斜或专家放置不佳。诊断表可以把常见症状映射到初步测量思路,但具体原因还要结合硬件拓扑和后端行为来分析。

示意图

如果看到“内存使用很高,但专家计算占比不大”,往往说明权重或 KV 缓存成了容量瓶颈;这时可以通过检查剩余 KV 空间来确认。增加并发可能会改善矩阵大小,却进一步挤压缓存空间。更稳妥的做法是:在相同请求轨迹下,只改变一个变量,分别测量内存、计算和通信成本,让最大的那一块决定下一轮实验方向。

示意图


工程清单与实践优先级

Qwen3-30B-A3B 这样的 MoE 模型,一边有 305 亿总参数决定权重存储,一边有 33 亿激活参数刻画单 token 的执行路径。MoE 服务链路包含:路由、token 置换、dispatch、分组专家计算、combine 和逆置换,多 GPU 部署则在此基础上叠加通信域、专家放置和 rank 级负载不均衡。

一个相对靠谱的验证顺序是:先确认权重和 KV 缓存的容量边界,再逐段分析 MoE 路径的耗时,测量分配偏斜和不同通信域的字节数,最后在相同请求轨迹下,对比放置、内核、量化或 top-k 变更的影响。放置和内核优化主要针对运行时开销,量化会改变数值,top-k 会改变参与计算的专家集合,这几类实验最好分开做,方便把性能和质量的变化归因清楚。

从工程视角看,MoE 推理诊断更容易被拆成三块:存储权重、执行被选中的专家、移动路由激活。每一块都可以单独测量,再决定要不要调整服务布局。这个判断方法在不少团队的实践里被反复验证有效,挺适合收藏下来,作为你下次排查 MoE 延迟和显存问题的“起手式”。


常见问题

Q:MoE 模型的“激活参数”和“总参数”有什么实际区别?

A:激活参数描述的是单个 token 在一次前向中实际经过的参数量,而总参数是整个模型检查点里存储的全部权重。激活参数更接近“这一步算了多少东西”,总参数则决定了你需要为权重预留多少显存或内存。做容量规划时,应该用总参数 × 每参数字节数来估算权重占用,再加上 KV 缓存和临时缓冲;激活参数更适合用来估算计算量和推理吞吐的上限,不能直接拿来算显存需求。

Q:部署 MoE 模型时,应该优先排查显存、专家计算还是网络通信?

A:实践里更稳妥的顺序是先看显存,再看计算,最后看通信。原因在于:权重和 KV 缓存的容量会直接限制你能开的并行度和并发度,如果这一步没算清楚,后面所有优化都可能撞到硬上限;在容量允许的前提下,再通过 profiling 看专家 GEMM、路由和置换的耗时,确认是不是算力没吃满;最后才是按通信域拆分网络流量,判断 dispatch/combine 是否成了瓶颈。建议在相同请求轨迹下逐项排查,并记录每次调整对延迟和吞吐的影响。

Q:Grouped GEMM 对 MoE 推理的提升有多大,什么时候效果最好?

A:Grouped GEMM 在解码阶段、小批量或高并发场景下提升最明显,因为它能把很多小专家矩阵打包成一次大调用,显著减少 kernel 启动开销。原理是:不同专家的矩阵行数可以不同,但在一次调用里统一调度,避免频繁启动小矩阵乘法核。判断是否适合用 Grouped GEMM,可以看专家矩阵的平均行数和分布,如果大量矩阵行数很小、启动时间占比高,就值得尝试;同时要注意它对数据布局和量化格式的要求,必要时做 A/B 测试验证收益。

Q:如何判断 MoE 部署中的尾延迟是不是由专家不均衡导致的?

A:可以从“每步、每 GPU”的维度采集指标,而不是只看整体平均。具体做法是:记录每一步在每块 GPU 上的分配数、dispatch 时间、专家执行时间、combine 时间和空闲时间,再对比这些时间序列。如果某些 GPU 在多数步骤里明显慢于其他 GPU,且对应专家的分配数长期偏高,就很可能是路由偏斜或专家放置不佳。此时可以尝试调整专家放置或增加热点专家副本,并在相同请求轨迹下对比优化前后的 95/99 百分位延迟变化。

Q:减少每个 token 的专家数(比如从8减到4)会带来多大质量损失?

A:质量损失取决于具体模型和归一化策略,不能一概而论。有研究在 Qwen3.6-35B-A3B 上发现,直接从 8 减到 4 个专家会损失约 4.65 个 MMLU 点,而在归一化时仍参考更大的专家集合,损失可以压到 0.35 点左右;在更大的 Qwen3.5-397B-A17B 上,从 10 减到 5 个专家的损失约为 0.55 点。实际部署时,建议先在离线评测集上做分档实验(如 8→6→4),同时观察困惑度和任务级指标,再在小流量灰度环境中验证用户侧的质量感知,避免一次性砍得太狠。


从零开始构建基于MoE的Transformer,我们用纯Python和PyTorch讲解了LLaMA 4 →

这套教程会把现代大模型背后的 MoE 架构拆开讲清楚:从字符级分词、多头自注意力与 RoPE,到稀疏路由的多专家 MLP、RMSNorm、残差与因果掩码,再到训练与生成全流程。

👉 轮到你了:在自己的部署里,你会先动哪一块——内存、专家计算,还是通信链路?

祝好!