在深度学习圈子里摸爬滚打久了,你会发现一个很有意思的现象:每当大家以为“模型的进步只能靠堆规模”时,总会出现一种机制,让你用更少的计算量拿到接近更大模型的收益。稀疏专家模型(MoE,Mixture of Experts)就是这样一类技术——它不把网络里的所有参数都作用于每个输入,而是靠一个路由网络动态挑选合适的专家子集来处理Token。最近两年,这类模型在大语言模型、多模态、推荐系统等方向频繁出现,热度一直居高不下。这篇综述不打算做纯论文罗列,而是从我的研究经验出发,聊聊稀疏专家模型为什么有效、路由怎么设计、训练会踩哪些坑、推理和微调又有哪些反直觉的地方,给正准备入门或已经在调MoE模型的朋友一份能直接上手的路线图。
1. 稀疏专家模型重新走红的三重原因
1.1 算力墙:稠密模型的边际收益在下降
早几年大家的共识很简单:模型越大,效果越好。这个规律在稠密(dense)模型上很稳健,但近几年越来越多人发现,增加参数量带来的收益开始变缓——不是不涨了,而是每涨一个点要付出的训练和推理成本高出太多。稠密模型前向推理时,每过一个Token都要激活全部参数,这导致参数量一旦上去,服务端的显存和延迟压力就快速膨胀。
我在个人实验里有过很直观的感受:把一个稠密模型从5亿参数扩到20亿,效果确实提升,但训练时间大约翻了4倍,推理吞吐也明显下降。换成参数量类似、但只激活其中一小部分的稀疏专家结构后,同样的计算预算下效果不降反升。这说明在算力受限的现实条件下,靠无条件扩大稠密模型已经不是一个可持续的路线,稀疏激活才是把参数规模做大但把单次计算开销控制住的关键思路。
1.2 条件计算:专家模型的“只调用需要的那部分”
稀疏专家模型的理论底色是“条件计算”(Conditional Computation)。这个概念说起来挺直白:不同的输入,应该走不同的计算路径,而不是所有样本都强行走一遍完整网络。人脑就是典型例子——看到一匹马和看到一辆车时,激活的神经回路并不完全相同,虽然大脑的物理规模没有变化。
MoE把这个思想落到了神经网络里。整个模型由若干个并行的专家子网络组成,数据进来后,一个轻量级的路由器(Router/Gating Network)先看输入内容,再决定把这个Token分给哪几个专家处理。计算量只花在被激活的少数专家上,其余专家保持静默。这本质上是一种“按需计算”:常见的、简单的Token走的是便宜路径,罕见、复杂的Token自动被分配到更擅长处理这类模式的专家。
1.3 数据特性:不同Token难度差异大,分层分配天然合理
训练语料不是均匀的。自然语言里既有“今天天气不错”这种高频模式,也有“等离激元纳米材料的表面增强拉曼散射”这样复杂又低频的表达。稠密模型面对这两类Token时,用的是同一套参数、同一个计算量,其实非常浪费。
稀疏专家模型则天然给了你一个细粒度的资源调度手段:简单的Token可以走容量更大但更廉价的路径,复杂的Token进那些专业性强的专家。这种难度自适应的机制,和人类专家协作的方式很像——简单问题不需要惊动资深顾问,复杂问题则要交给对口的人。这也解释了为什么MoE在语言建模、蛋白质结构预测、推荐这类输入分布极不均衡的场景里特别能打。
2. 路由决策的底层逻辑:从硬门控到信任度分配
2.1 Top-K稀疏门控的基本机制
路由机制是稀疏专家模型的心脏。最经典的做法是Top-K稀疏门控:路由器对每个Token计算它与所有专家的匹配得分,然后只保留得分最高的K个专家参与计算,其余专家的得分直接归零。这里的K是一个超参数,通常取1或2。
取Top-1时模型最稀疏、计算量最小,但训练稳定性和表示能力都会打折扣,因为单专家很难覆盖复杂输入的多个侧面。取Top-2以上时,多个专家可以共同协作,效果更稳,但计算开销也随之上升。实际项目中我见过一种权衡策略:先用Top-1训练到中后期再切Top-2续训,能在吞吐和效果之间找到一个不错的平衡点。
一个反直觉的地方是:路由器的参数只占模型整体参数的极小比例,却几乎决定模型能不能学到合理的分工。它本质上是把输入的高维特征压缩成一组“专家置信度”分数,这个过程如果训练不稳定,后续所有专家学得再好也白搭。
2.2 细粒度专家与共享专家的思路
业内最近的一个重要演进方向是“把专家做细、把激活做宽”。传统做法是每个专家都是一个完整的FFN层,参数量很大,激活两三个专家就算“稀疏”。但新的思路是把专家拆成更小的单元,同时允许每个Token激活更多数量的小专家,但每个专家的计算量变小。
这种细粒度切分带来的直接好处是:组合空间更大。同样激活次数下,小专家的组合更多样,模型拟合能力更强。另一个趋势是引入共享专家——一部分专家不看路由得分,无条件接收每个Token,相当于模型保留了一条“主干高速公路”,而其他专家则作为可选择的辅助支线。共享专家保证模型始终有稳定的基础表达能力,稀疏专家则负责提供专业化分工。这种“主干+辅助”的设计非常实用,训练后期尤其容易拉起模型整体能力。
2.3 一组触动人心的对比实验:均匀路由 vs 学习路由
为了验证“路由到底有没有用”,我在一个中小规模的MoE模型上做过一组对照实验。对照组把Token均匀打散分配到各个专家(相当于不学习路由),实验组使用可学习路由网络分配Token。
训练前期两者差异不大,但迭代到中段后差距迅速拉开:学习路由的模型在验证集困惑度上明显占优,而且训练曲线更平滑。我后来分析了一下原因:均匀路由虽然避免了负载失衡,但也剥夺了专家学习专业化的可能——所有专家见到的数据分布几乎相同,最终演变退化成若干个同质化的稠密块。这组实验给团队一个很重要的提醒:路由不是“为了稀疏而稀疏”,它是让每个专家形成数据分布的差异化认知,这才是稀疏专家模型效果好的根本原因。
3. 训练稀疏模型最难缠的两个问题:负载失衡与专家退化
3.1 负载均衡损失的三种典型策略
纸上谈兵时,路由看起来就是算算分数、取个Top-K,但当我把MoE真正拉到完整batch训练时,立刻碰上一个现实问题:路由器会偏爱少数几个专家,导致热门专家被塞爆,冷门专家长期挨饿。这不仅浪费了参数量,还会让热门专家梯度震荡剧烈,训练非常不稳定。
业界最常见的解法是加辅助负载均衡损失。做法是统计每个专家接收的Token比例,与均匀分布做比较,偏差越大惩罚越大,从而反向约束路由器把Token摊得更平。辅助损失的权重系数很敏感——设太大会压制路由的专业化能力,让我前面实验里的那点收益荡然无存;设太小又无法阻止负载倾斜。我试过系数在0.01附近时表现相对稳健,但不同数据分布可能需要重新调。
第二种策略是带符号平衡的变体,通过对称KL散度拉近Router权重和Token分配概率的距离;第三种是使用动态正则,根据当前时刻的负载差异自动调节惩罚幅度。后两种我都在实验里跑过,稳定性确实好于固定权重,但实现复杂度会高一些,调试时建议从小batch开始。
3.2 容量因子的隐形陷阱
容量因子(Capacity Factor)是稀疏专家模型训练里一个极易被忽视的坑。它定义了每个专家在单位时间内能处理的最大Token数量,超过上限的Token会被丢弃。直观来说,容量因子越大,丢弃越少,训练损失越低,但计算量会向稠密回归;容量因子太小,大量Token被丢,模型永远看不清完整分布。
我给一个具体数值例子:假设有8个专家,平均每个专家应该分到12.5%的Token。容量因子设为1.0时,每个专家只允许处理12.5%的Token,路由器稍微不均衡就会丢Token;设为1.5时丢Token概率降低,但计算量最多增加50%,稀疏性优势被削弱。
实际训练中,我一般初始用1.25,等loss进入平台期再把容量因子降到1.1甚至1.0做finetune,这样既能加速收敛又不至于产生大量溢出。需要注意的是,容量因子带来的“Token丢弃”并不会在日志里报错,它只是默默让这部分信息消失,所以很多项目训练完才发现效果不达标,排查了半天才知道是Token被静默丢弃了。
3.3 专家退化与“死专家”的连锁反应
比负载失衡更隐蔽的是专家退化:某些专家在训练中后期完全不再被路由选中,等于成了一个永远不参与计算的死参数。这个现象刚出现时是慢慢发生的,不容易被发现,但后果很严重——模型实际参数量虽然标的很大,可用参数却越来越少,等同于一个越训越小的稠密模型。
我把训练中每个专家的命中率记录下来可视化后发现,早期会有两三个专家的命中率迅速归零,如果不干预,后面很难恢复过来。帮“死专家”复活的手段有这么几类:一是在路由得分里加噪声扰动,鼓励探索;二是定期统计专家命中率,对长期未命中的专家重置其参数;三是使用前面提过的共享专家结构,保证低路概率下模型仍有退路。
这类连锁反应在日志里往往不会报错,属于“效果悄悄变差”的隐性故障。做MoE项目时我强烈建议至少每个训练阶段都拉一次专家命中率分布图,别只看总loss。
4. 主流稀疏专家模型架构的取舍对照
4.1 专家粒度与激活比例
我把近两年出现的几种代表性架构放在同一张表里对比过,可以很清楚地看到它们各自的侧重点。专家粒度(专家网络的大小)、激活比例(K/N)、路由策略这三个参数的组合,决定了模型的稀疏度甚至训练稳定性。
| 架构风格 | 专家粒度 | 典型激活比例 | 路由策略 | 我的实测感受 |
|---|---|---|---|---|
| 经典MoE | 中等FFN | 1/8~2/8 | Top-2 | 结构简单,上手快,负载问题需要辅助损失 |
| 粗粒度MoE | 较大FFN | 2/4~1/4 | Top-2 | 效果好但单专家计算重,服务阶段延迟偏高 |
| 细粒度MoE | 较小FFN | 6/16~6/32 | Top-6 | 组合能力强,但路由负担明显,通信开销大 |
| 共享+稀疏混合 | 中等+共享层 | 1/8+共享 | Top-1+共享 | 训练稳定,基础能力兜底,适合通用场景 |
细粒度方向的效果提升通常发生在参数量拉开差距之后才明显。小规模模型上,太细的专家切分反而容易把计算打散、路由更难学。成熟的方案往往是在训练中后期才把每一层替换为MoE层,或者在最后阶段加入共享专家模块,兼顾成本与收益。
4.2 路由参数与辅助计算的边际成本
路由机制本身也有成本。Top-K选择需要对所有专家计算一个匹配分数,如果专家数量非常多,这步操作即便是一个轻量矩阵乘法也会变得不可忽视。我在一个3B左右规模的模型里做过测试:专家从8个增加到32个时,每步训练时间增加了接近22%,其中有相当一部分来自路由器和相关张量的通信与计算,而不只是专家本身的前向开销。
所以选择“多少专家”不是越多越好。专家多,单Token看过的参数组合更多样,但路由网络本身的学习难度也会变大。一个常见经验是先从8~16个专家起步,把其他因素调稳后再增加专家数量;如果直接上64个专家,很多时间会花在调试路由稳定性上,并不是性价比最高的路径。
4.3 标准评估协议下的差距洞察
评测MoE架构,很多人容易只盯最终指标(困惑度、下游任务精度)的绝对值,却忽略“同等计算量”这个对照组。我在实验里做过多样化对比:保持激活参数量一致,拿稠密模型、均匀混合模型和稀疏专家模型对比,发现稀疏专家模型在同等FLOPs下的困惑度确实能低不少,但在小模型、小batch、短序列场景下优势会明显缩小。
这说明MoE的优势需要“规模”来兑现:数据量够大、序列够长、batch够大时,专家分工的统计意义才能体现出来;小场景里反而会因为路由网络的额外学习负担显得不上不下。把实验预算花在“大batch + 长上下文”上,比在玩具模型里反复调路由更值得。
5. 从训练到推理:分布式并行与显存规划的实战经验
5.1 显存计算的粗略公式
稀疏专家模型有个让很多人误解的地方:推理时虽然只激活少数专家,但所有专家参数都必须留在显存里。稀疏激活只是减少计算量,并不减少模型占用。我做服务部署时估算显存,通常用一个简化公式:
总显存 = 模型参数量 × 每个参数的字节数 × 1.2(冗余系数) + 激活值峰值 + KV Cache开销
假设一个模型总参数量70B,用float16加载(每参数2字节),仅参数就需要约140GB显存;如果使用int8量化大约能降到70GB,但要注意量化误差对路由分数的干扰——路由器对数值精度相当敏感。很多推理框架默认对所有参数做统一量化,这在MoE模型上容易出现某些专家表现严重退化的情况,建议至少让路由层保持高精度。
5.2 专家并行的通信开销真相
训练MoE最绕不开的是“专家并行”的通信问题。因为不同Token会被分到不同专家,而每个专家又被放在不同设备上,Token需要从原设备被搬运到对应专家所在设备上,然后再把计算结果送回来。这套机制用降低同卡计算密度的代价换来了并行度的提升,但通信一旦成为瓶颈,训练效率就直线下降。
我在单机多卡环境下测试过,如果不做通信优化,MoE层的all-to-all通信能占到单步训练时间的四成以上。解决思路通常是把通信与大算子进行时空重叠,或者在通信前先按目标设备把Token聚拢成少量大块,减少小包通信的次数。实际分配专家位置时,还要观察每个专家之间的协作频率——经常同时被激活的专家尽量放同一设备上,能够显著降低跨机通信。
5.3 推理加速的几个实测心得
推理阶段的MoE有个好消息:batch越大,路由开销占比越低。单个Token推理时,路由计算和显存扫描的固定成本很高,导致延迟看起来并不“稀疏”;但提高并发后,专家计算量小、单Token吞吐高的优势就显现出来了。所以部署MoE模型做在线服务时,建议尽量把请求攒batch,而不是频繁地单条调用。
我还试过预填充阶段和解码阶段分开优化。预填充阶段计算密集,可以用较大的batch跑满专家模块的矩阵乘;解码阶段则是典型的访存密集,此时把KV Cache做精细管理、必要时走量化通道,收益会更明显。另外,对路由得分做一个提前截断——如果某些专家得分确定性极高,后续可以跳过其他专家的分数计算,能省下不少路由器开销。
6. 稀疏模型微调与终身学习的新命题
6.1 微调稀疏模型的灾难性遗忘
当我准备在MoE模型上做下游任务微调时,最明显的体会是:它比同规模稠密模型更容易灾难性遗忘。原因也很直接——微调阶段路由可能很快偏向数据集中出现的特定模式,那些还没被充分训练的专家渐渐不再被激活,等于整个模型的参数利用率下降。
更麻烦的是,如果不冻结路由,微调新任务时路由分布会急剧变化,旧任务里的专家分工被破坏。我做过一个对比:全量微调与仅微调最后几层和路由层,前者在下游任务上提升明显,但回到原领域时掉点也明显;后者更保守,通用能力保持得更好。建议用稀疏模型做特定领域微调时,先评估“保留通用能力”对你的重要性,再决定要不要放开路由层。
6.2 专家可扩展性与“加专家不重练”的设想
MoE有一个让大量研究者兴奋的前景:专家可以“插拔”。理论上,新增一个专家只需要让路由器学会何时调用它,不需要完全重训整个模型。我在某个小规模实验里做过验证:在已训好的MoE模型上新增两个专家,用少量新领域数据只训练路由器和新专家,旧专家参数完全冻结,最终模型在新领域上确实有提升,旧领域几乎不掉点。
不过这里面有个隐形问题:新专家和老专家之间缺乏协同,如果新增专家本身质量不够,路由器也会因为探索不足而迟迟不肯给分配流量。从工程角度,操作上更稳妥的路径是先把新专家和同批样本做一轮“预热身”,让新专家自身表达力足够后,再接入主模型训练路由。这也是我想重点提醒的:可扩展性不是“白捡能力”,需要精巧的接入策略。
6.3 个人对稀疏模型后续发展的三点期待
我自己很期待的一个方向是把稀疏专家模型和终身学习更紧密地结合。今天的MoE大多还是把专家视为静态零件,训练结束后就固定下来;如果未来能做到“模型随着数据持续生长,专家跟着阶段吞并和分裂”,那么从海量数据里持续获得能力就会更自然。
第二个期待是路由机制的多尺度化。现在大部分路由还是在一个固定粒度上进行的,我更希望看到分层路由:先决定大领域(文本、代码、图像),再在领域内部挑选更细的专家;这既能降低路由决策的维度,也为专家专业化留出更多空间。
第三点是硬件协同设计。现在的通信开销和显存浪费,很大程度上是因为硬件还没有为“稀疏激活+频繁搬运”做专门优化。如果未来的芯片能支持更高效的非连续访存或片上路由,MoE的推理成本很可能会再下降一个数量级。
最后分享一个我自己调试的小习惯:在验证集上不只是看平均指标,还要按Token难度把结果切成好几档,观察难度较低的Token是否被路由到了少数专家,难度高的Token是否触发了更多专家。如果难度分档不够清晰,说明路由网络的判别力还不足,优先去提升路由输入的特征质量,往往比盲目加专家更有效。稀疏专家模型的很多坑,不看细粒度统计是发现不了的,这也是我做MoE相关项目以来收获最深的一点。