1. 为什么稠密模型撞上了“算力墙”MoE 由此登场1.1 稠密模型每个 Token 都要过全部参数前阵子帮团队做大模型选型被同事问了一个很本质的问题“同样是几百B的模型凭什么有的要几十张卡才能跑起来有的几台机器就能做推理”这个问题的答案就藏在大模型近年来最值得关注的结构性创新里——MoEMixture of Experts混合专家架构。先看传统路线。从 GPT 到 Llama主流的Transformer大模型走的是“稠密”路线模型里所有参数构成一个整体无论输入什么 token前向计算时都要把全部参数过一遍。这带来的结果非常直观——参数规模每翻一倍推理算力需求基本跟着翻一倍。Llama 3.1 405B 训练时需要几万张 GPU推理单卡的batch size稍微开大一点就要多卡并行根本原因不在工程优化不够好而在于结构上“全员参与”的设定实在太烧算力。这里要区分几个概念很多人把“参数量”和“计算量”混为一谈。稠密模型里两者强绑定参数量越大每个 token 的计算量越大显存和带宽压力也同步变大。于是行业撞上了一堵墙想要更强的能力就得把模型做得更大要把模型做得更大训练和推理的账单谁都扛不住。1.2 稀疏化的思路让参数“按需上岗”MoE 的思路直白地说就是别让所有参数都干活改成“按需上岗”。把模型拆成很多个子网络每个子网络叫一个“专家”输入进来之后先由一个调度器判断该让谁处理只有被选中的那几个专家才参与计算。这样总参数量可以做得很大但每次推理用到的只是其中一小部分。这个思想最早可以追溯到 2017 年 Shazeer 等人的工作真正进入主流视野是 2021 年 Google 的 Switch Transformer 和更早的 GShard再到后来 Mixtral 8x7B 在开源社区一炮而红以及近年 DeepSeek-V2/V3 把 MoE 做到 671B 总参数、37B 激活的极致规模。很多人喜欢用“革命”来形容这条路我理解这个“革命”革的主要就是稠密 Transformer 的命它打破了“参数量决定推理成本”的铁律把模型的容量和单次推理开销解耦。举一个大家都有体感的对比。Mixtral 8x7B 总参数约 47B但推理时只激活约 13B 参数DeepSeek-V3 总参数 671B激活只有 37B。放在稠密模型里671B 参数的模型每个 token 都要让 671B 参数全部参与计算而在 MoE 架构里只有大约 5% 的专家被激活。虽然实际工程中还要考虑通信、带宽等额外开销但“算力账单”已经差出了至少一个量级。这也是为什么“大模型、稀疏化、MoE、架构”这几个关键词放在一起本质上讲的是同一个故事如何用更少的钱买到更大的模型。2. 拆开 MoE 层门控网络、专家列表与 Top-K 路由2.1 MoE 层的基本结构与数据流先建立直觉MoE 的改造通常发生在 Transformer 里的 FFN前馈网络那一层。传统 FFN 就是一套全连接网络所有 token 进来都走同一条路。MoE 则把这一层替换成一组专家集合每个专家本身就是一个 FFN数据流变成了这样输入 token 的 hidden state 先送到门控网络Router。门控网络给每个专家打一个分数表示“这个输入和哪个专家更匹配”。按分数排序只取分数最高的 K 个专家Top-K。把 token 分别送入这 K 个专家计算得到 K 份输出。把 K 份输出按门控权重加权求和得到最终的输出。整个过程看起来就是给 FFN 层加了一个“派单系统”。我用公司协作来类比会更直观传统模式是每来一个需求全公司所有人都放下手头的事一起响应MoE 模式是来了需求先找派单员派单员根据需求类型只叫相关部门的几个人来处理其他部门继续干自己的活。派单员就是门控网络被叫到的部门就是被激活的专家。2.2 关键超参num_experts、top_k 与专家容量第一次接触 MoE最先要看清楚的三个超参是总专家数num_experts、激活专家数top_k、专家容量expert capacity。总专家数就不展开了它是模型容量的基础直接影响参数量。top_k决定每次激活几个专家。K1 是最极端的稀疏化代价是门控一旦选错就没有任何纠错空间容易造成训练不稳定Switch Transformer 为了训练稳定用了 K1 加简化门控开源社区里主流是 K2Mixtral、DeepSeek 都走这个路子它允许两个专家互相补充容错性好很多。专家容量是工程上特别容易忽略、但直接决定显存和效率的参数。简单理解每个专家在每个 batch 内最多能处理多少 token。设一个 batch 里有 T 个 token、N 个专家、激活 K 个专家理想情况下每个专家平均应该处理T * K / N个 token。但路由结果不可能这么均匀所以工程实现里会给一个容量因子capacity factor通常取 1.25 或 2.0expert_capacity capacity_factor * (T * K / N)算下来假设 T1024K2N8capacity_factor1.25那么每个专家最多接收 320 个 token。超出容量上限的 token 会被直接截断计算时走残差连接跳过专家层相当于这次“没派到单”。容量因子设太小大量 token 不会被任一专家处理MoE 等于白加设太大每个 expert 都要预留更大显存浪费计算资源。实测下来 1.25 到 2.0 是一个比较常见的区间具体值要看路由的均匀程度。2.3 门控后的合并加权求和与 FFN 改造门控网络本身很简单最常见的形式就是一个线性层加 softmaxscore_i softmax(W_gate · h_t)_i打分之后选出分数最高的 K 个专家。那这 K 个专家的输出怎么合并标准做法是加权求和output Σ_i score_i * FFN_expert_i(h_t)这里面有个很少有人提的细节如果 Top-K 的 K 个专家分数没有做归一化加权求和的输出幅值会比单专家的输出大很多影响后续层的数据分布。所以很多实现会在选出 K 个专家之后把 K 个分数单独做一次 softmax 归一化再加权。另外token 从门控到专家计算之间还有一层 padding 和 mask 的处理在框架层面会写成 group GEMM 的形式把多个专家的矩阵乘法合并执行以便用满 GPU 的 tensor core。这部分属于后端优化后面推理章节再展开。MoE 层替换了 FFN 之后Attention 部分基本保持不变因此 MoE 模型依然可以用各种成熟的 Attention 优化手段比如 GQA、MLA、稀疏注意力等。换句话说MoE 和 Attention 的优化是正交的两者可以叠加DeepSeek-V3 就是同时用了 MoE 和 MLA 的代表。3. 训练 MoE 的真实难点路由崩溃、负载均衡和专家退化3.1 路由崩溃都会收敛到几个“老黄牛”专家实操过 MoE 训练的人应该都体会过这个现象门控网络训着训着就“躺平”了所有 token 都往少数几个专家身上堆其他专家长时间得不到梯度更新变成“死专家”。这个现象在文献里叫 routing collapse也叫专家退化。一旦出现稀疏化就名存实亡——模型看参数挺大实际有效容量还不如一个稠密小模型。为什么会出现这个问题从门控网络的训练目标来看它最初并没有任何机制保证“每个专家都必须被用到”。梯度下降只会让门控朝着“减少当前损失的路径”去走而这条路很容易就是极度偏斜的分布。可以用一个简单的直觉理解如果少数几个专家已经能拟合训练集里的多数样本门控在更新时没有额外压力去尝试别的专家那它会一直在安全区内打转新专家永远没有机会被选中也就永远得不到有效训练。学术界对这个问题的处理有一条清晰的演进线。早期 Shazeer 2017 年那篇稀疏门控混合专家的文章用的办法是给门控的 logits 加噪声Noisy Top-K Gating让路由在训练时保持一定的探索性即使某个专家目前得分稍低也有机会被选中并收到梯度。噪声幅度会随着训练步数退火后期逐步收敛到“纯靠打分”的稳定状态。3.2 负载均衡 Loss 是怎么把专家“拉回正轨”的噪声是好办法但不够“硬约束”。到了 Switch Transformer 时代Google 在门控得分上直接加了一项负载均衡辅助损失auxiliary load balancing loss用惩罚项逼着路由尽量均匀分配 token。最经典的实现长这样L_aux α * N * Σ_i ( f_i * P_i )其中f_i表示这批 token 里实际被路由到专家 i 的比例P_i表示门控分配给专家 i 的平均概率。这个公式的巧妙之处在于它同时惩罚了两个东西。如果某个专家实际处理了远超平均的 tokenf_i 大惩罚变大如果门控给某个专家的总概率偏高P_i 大惩罚也变大。理想状态下 f_i 和 P_i 都接近均匀分布乘积的和接近 1/N整体损失最小。系数 α 是一个实际的超参太小起不到约束作用太大则会把任务本身的损失盖过导致模型表达能力下降。我个人的习惯是从 0.01 起步观察训练早期每个 batch 的专家负载分布再逐步调整。在 DeepSeek-V3 这类更极致的模型里出现了一种折中方案用一个基于偏置项的负载均衡控制也就是在门控得分上给每个专家加一个可学习的 bias动态调整路由倾向但不同时引入辅助损失。这种做法能在保持路由质量的同时让负载分布更均匀还避免了辅助损失和主损失之间的拉扯。它的启发在于负载均衡本质上是一个在线控制问题不是一锤子买卖要在训练中持续监测、持续调节。3.3 专家是“领域专家”还是“位置专家”关于 MoE 训练还有一层更隐性的现象。很多人天然以为 MoE 的专家会自动形成“领域分工”比如一个专家擅长处理名词另一个擅长处理数学表达式或者一个专家管代码另一个管自然语言。但实际观测结果往往并不是这个剧本。好几篇论文在训练完成之后去统计 token 的路由分布发现有些专家对 token 的“语义类别”其实没有明显偏好反而是对“位置信息”更敏感特定层数的专家倾向于接收靠近句首或句尾的 token或者接收来自注意力层某个位置 pattern 的 token。专家擅长的东西往往不是我们人类意义上理解的“领域”而是模型内部某种统计结构。这个现象对实践的影响很大。如果你想着“微调 MoE 时固定住某些领域专家”可能根本不知道应该固定哪个专家。更常见的做法是不要预设专家的语义分工而是把它当作模型容量的一种分布方式——容量放在哪里不重要关键是容量确实被有效利用了。3.4 训练稳定性的几个工程因素除了算法层面的路由问题MoE 训练还有几个让我印象深刻的工程坑。第一MoE 层的梯度噪声通常比稠密层更大。因为每个 token 只流过部分专家不同 token 的梯度来源不同batch 内部的路径天然是“分叉”的。这导致同样的学习率在 MoE 模型上可能会震荡得更明显。很多团队的做法是引入梯度裁剪、降低峰值学习率或者对 MoE 层的参数用独立的学习率衰减策略。第二混合精度训练尤其要注意溢出。稀疏 mask 和 padding 的存在让 MoE 的矩阵乘法和稠密层不同中间结果容易产生微妙的数值差异所以对 bf16/FP8 的 scale 处理要更保守。DeepSeek-V3 在 FP8 训练上跑通的关键就是对专家部分的量化做了更精细的分块处理。第三死专家不是只有训练初期才出现。训练中后期如果某些专家长期低激活它们的参数会慢慢“荒废”。所以训练平台通常会在日志里持续打印每个专家收到的 token 数出现方差过大就要要人为干预。我在实际项目中监控过一个指标每个 batch 里 token 在专家上的分布标准差。初期波动大是正常的但如果训练到一半标准差还在持续上升那大概率是负载均衡 loss 的系数不够需要上调。4. 部署和推理阶段更现实的问题显存、通信与框架选择4.1 MoE 的激活参数少但全部参数仍要进显存每次聊 MoE都会有人问一个非常关键的问题“MoE 架构要全部参数进显存吗”答案是肯定的。MoE 省的是计算量不是显存占用。虽然单次推理只激活一小部分专家但模型的所有权重都必须加载到显存里否则被路由到的专家可能不在当前设备上也读不到数据。做一道简单的算术题。DeepSeek-V3 总共 671B 参数按 BF16 精度存储每个参数 2 字节光权重就是 1342GB 左右。加上 KV cache、中间激活值和运行时开销哪怕 MLA 已经大幅压缩了 KV cache单张 80GB 的 H100 肯定装不下必须通过多卡并行切分。所以“参数小、显存小”是这个架构最大的误解真实的情况是计算量稀疏激活每 token FLOPs 大幅下降显存所有专家权重都要驻留内存带宽门控选出专家后要读取这些专家的权重实际上每个 token 还是要从权重池子中取一部分在 GPU 推理里很多稠密模型是“算力瓶颈型”——计算时间占主导MoE 往往是“带宽瓶颈型”——虽然矩阵乘法变少了但每次要读的权重仍然很多。这也是为什么有些 MoE 模型没有比同参数量级的小模型快很多倍的原因省下来的计算被通信和读取开销又吃掉了一部分。4.2 推理的通信瓶颈与 Expert Parallelism既然全部参数要进显存单卡放不下那就得把不同的专家分布到不同 GPU 上这个策略叫 Expert ParallelismEP。典型做法是保留全部 Attention 层或者只做张量并行切分只把专家按行切到多张卡上。每张卡上放一部分完整专家路由到本地专家的 token 直接在本地算路由到远端专家的 token 就要通过 all-to-all 通信传过去。这就带来了 MoE 推理最有名的痛点——通信密集。每个 token 的路由目标都是独立决定的如果把专家切到 16 张卡上每张卡的请求都可能要和其他 15 张卡通信。推理延迟里通信时间经常和计算时间五五开。工程上的对策主要有这么几类专家复制。热门专家会收到更多请求如果只切分不复制它们的卡会变成瓶颈。常见的做法是对热点专家做多副本分布在不同卡上同时配合路由把压力均摊出去。减少跨卡路由。把每个请求的路由尽量限制在单机内部避免跨机通信。单机内的 NVLink 带宽远高于跨机所以大概率优先单机多卡。P/D 分离。Prefill 阶段和 Decode 阶段对通信的敏感度完全不同前者计算密集后者带宽密集很多团队会把这两个阶段拆到不同的 GPU 实例上分别优化。4.3 常见开源推理框架对 MoE 的优化如果你不想从零造轮子几个主流的开源推理框架对 MoE 支持已经相当成熟。vLLM 对 MoE 层做了 grouped GEMM 合并把多个专家的矩阵乘法合并成少数几个大 GEMM减少 kernel 启动次数能显著提高 GPU 利用率。SGLang 在处理 MoE 路由时利用 bitmask 这类紧凑数据结构来表示专家选择降低调度开销对高并发的场景更友好。DeepSeek 自研的推理引擎则在量化上做了更多文章——MoE 层以 FP8 存储权重关键计算保持更高精度显存占用进一步缩减。这些框架的核心思路其实是一致的把“稀疏的 MoE 计算”在 GPU 上尽量重新编排成“稠密的大计算”。因为 GPU 的强项是规则的大矩阵乘法稀疏计算如果 spawn 太多小 kernel瓶颈会转移到调度开销上。顺着这个思路去选框架重点应该看它对 expert route、padding、grouped GEMM 的支持深度而不是只比较模型加载速度。4.4 落地选型什么场景该用 MoE什么场景还是稠密好谈到部署选择我给团队的建议通常按两个维度割模型体量和业务并发。模型体量在 7B 到 14B 这个区间稠密模型往往是更稳妥的选择。MoE 省下的计算在这么小的规模上体现不明显反而会引入部署复杂度和通信开销而且小模型的训练数据量有限强行拆专家容易在一个均衡 loss 上过度消耗算力。但模型体量超过几十B或者你明确知道需要“很大的模型容量”来做复杂任务MoE 的优势就非常明显了。服务端高并发场景下多个请求同时进来不同请求走不同专家的概率天然有差异GPU 上的计算可以更充分地被并行利用。我自己实测的感受是同一批 8 卡 A100 服务器上7B 稠密模型和同 Token 量的“总参数 40B 激活 10B”的 MoE 模型相比吞吐量往往是 MoE 占优——只要路由均匀性和通信优化做到位稀疏化就是明显的省钱方案。5. 开源 MoE 模型盘点与微调踩坑建议5.1 值得研究的开源 MoE 模型给想入门的同学整理几个值得研究的开源 MoE 模型覆盖了不同体量和技术路线适合按顺序学习模型总参数激活参数Top-K特点Mixtral 8x7B约 47B约 13B2最早让 MoE 在开源社区普及的模型单机 8 卡可跑Qwen1.5-MoE-A2.7B约 14.3B约 2.7B2小激活量适合受限显存场景测试负载均衡调优的好样本DeepSeek-V2约 236B约 21B6引入 MLA 压缩 KV cacheMoE 工程化的成熟范本DeepSeek-V3671B37B8超大 MoE FP8 训练门控和负载均衡的经验都很值得借鉴Grok-1约 314B约 50B?2基于公开资料整理的 MoE 方案专家数量范围极大适合做规模对比实际训练和部署的时候这些模型的准确数字要以官方发布为准尤其是激活参数会随上下文和实现细节变化。但光是看这个表就能发现不同模型的稀疏策略差异巨大有的走大专家少数量如 Mixtral 8 个专家有的走小专家多数量如 Grok-1 的 64 个专家层稀疏比例可以从 10% 到 30% 不等。这个差异直接决定了你在推理时要怎么切卡、怎么设 batch size。5.2 微调 MoE 的显存与策略选择微调 MoE 是另一个容易踩坑的地方。你需要先搞清楚一个关键事实虽然单 token 只激活少数专家但一个 batch 里的不同 token 会激活不同专家如果把 batch 开大最终所有专家对应的梯度都会被触发。因此微调时的显存压力和全量稠密模型几乎没有区别——你的 optimizer states、梯度都是对所有专家参数而言的。如果 GPU 资源有限我建议优先考虑这样的策略组合LoRA 冻结大部分专家。只对 Attention 层、门控网络和少量专家注入 LoRA adapter既能保留 MoE 的容量灵活性又不用背全量梯度的显存开销。微调门控网络。有些下游任务模型整体不需要大改动只调整关键模块相当于换派单规则就够用。门控参数量很小显存开销可控效果往往比随机初始化新任务头好。全参微调后做蒸馏回稠密。如果你真的把 MoE 全参微调到某个领域部署时还想省资源可以用蒸馏把知识搬回一个同量级的稠密模型。代价是能力会有折扣但部署成本会大幅下降。微调过程中还要再次关注负载均衡 loss 的行为。很多开源模型的权重里负载均衡项的系数是按预训练分布调好的你的下游任务如果数据分布偏移很大路由分布也会跟着漂移。建议微调时先冻结负载均衡 loss 观察几个 step如果专家利用率出现严重倾斜再考虑微调过程中也开启它。5.3 给入门者的上手路径如果第一次接触 MoE我的建议是不要一上来就挑战 671B 这种庞然大物。先从 Mixtral 8x7B 开始单机 8 卡 A100/H100 基本能跑vLLM 直接支持路由过程中可以用 profiling 工具看每个专家收到的 token 分布。再换到 Qwen1.5-MoE-A2.7B体会一下“激活 2.7B 但总参数 14B”是种什么感觉顺带理解为什么小激活量也需要足够的训练数据支撑。动手之后重点观察三件事一是门控权重的分布是否均匀二是 batch size 变化对专家利用率的影响三是 multi-GPU 环境下不同 EP 配置对吞吐的影响。这套流程走完你对 MoE 的理解会比只看论文深得多。实战中还有一个绕不开的细节值得提醒常见 HuggingFace Transformers 代码里MoE 的 expert 权重加载往往走的是多文件 shard如果手动改权重结构很容易碰到键名对不上的问题。改模型结构和微调脚本之前先把model.state_dict()里专家的命名规律捋一边能省掉大量排查时间。最后说一点个人感受。我不太喜欢把 MoE 神话成“免费的午餐”它真正带来的是一场权衡用更复杂的数据流、更密集的通信和更麻烦的训练控制去换取更大的模型容量和更低的单 token 计算成本。衡量这笔账到底划不划算取决于你手里的卡、你的业务流量模型以及你的工程团队有没有能力解决分布式路由问题。但如果你问我现在做大模型选型值不值得认真考虑 MoE——我的答案很干脆值得而且越早开始摸后面越从容。上面提到的小体量 MoE 模型显存估算和微调显存结论来自我在不同卡型上的实操记录具体数据会因框架版本和 batch 配置浮动。建议以你自己的资源为准先用小模型验证一轮再决定要不要为一个大 MoE 下单买卡。