资讯动态

ZeRO-3与MoE结合:大模型显存优化与训练实战指南

发布时间:2026/9/29 7:23:35 来源:尧图企业网站定制
1. 显存账本先算清为什么 ZeRO-3 和 MoE 总被放在一起谈先说个很多人刚接触这两个概念时会有的困惑MoE 模型不是已经把参数拆到不同专家里、每个 token 只激活一小部分了吗那为什么还要 ZeRO-3再进一步像热搜里反复出现的那个问题——MoE 架构要全部参数进显存吗——答案其实不是简单的要或不要而是取决于你打算用什么并行策略、什么训练框架。我三年前第一次在 8 卡 A100 上尝试 MoE 模型时思路很天真既然专家是稀疏激活的那把 64 个专家平均放到 8 张卡上每张卡只放 8 个专家显存不就不炸了吗这个想法本身没错实际训练也确实能跑起来。但真正的问题在于一个标准的 Transformer MoE 层不只是专家 FFN它还有 attention 层、LayerNorm、路由网络router、embedding 层。这些共享参数是所有 token 都要用的它们的体量虽然比专家少但当模型规模到几百 B 时依然远超单卡显存。这时候如果你用的是普通的张量并行或流水线并行每张卡要么得存全量共享参数副本要么得忍受极复杂的切分逻辑。ZeRO-3 在这个局里的角色一句话概括它负责把所有非专家参数以及通信开销可承受范围内的专家参数都给分片掉。MoE 解决的是稀疏激活——并不是所有参数都需要参与每个 token 的计算ZeRO-3 解决的是显存冗余——并不是每张卡都得全量保存一份参数副本。两者一横一纵叠加起来才是大模型训练的完整显存解法。这篇文章我不会给你那种ZeRO-3 是第三代零冗余优化器的教科书定义而是直接拆开来讲两件事ZeRO-3 内部到底干了什么活MoE 和它配合时哪些配置能开、哪些配置一开就炸。最后我会贴一份我在实际训练中验证过的 DeepSpeed 配置模板并把踩过的通信瓶颈、路由崩溃、负载不均这些坑挨个说清楚。适合谁看已经在用 DeepSpeed 跑普通稠密模型、想往 MoE 迁移的工程师以及对显存优化机制有好奇心的研究者。2. ZeRO-3 的分片逻辑它到底帮你省下了哪些显存代价又是什么2.1 从 ZeRO-1 到 ZeRO-3省显存是分步走的先回顾一下 ZeRO 系列的基本思路因为很多人直接把三个 stage 当成三个独立的显存优化器其实它们是层层递进的。ZeRO-1只分片优化器状态Adam 的 momentum 和 variance。参数和梯度还是要全量存。ZeRO-2在 ZeRO-1 基础上把梯度也分片。每张卡只保留自己负责的那部分梯度反向传播时需要跨卡做 reduce。ZeRO-3把参数本身也分片。每张卡只持有模型参数的一个切片前向和反向过程中通过通信把需要的参数临时聚合起来。所以 ZeRO-3 的关键特征就是那句很经典的话每张卡永远只拥有参数的一部分但在计算某个层时会临时把这一层的完整参数搬到自己卡上来算算完就丢。这个机制类比起来就像图书馆的书不是每本复印一份放在你桌上而是你读哪本管理员就把哪本送到你桌上读完还回去。省的是书架空间显存费的是递书的时间通信带宽。落到具体数字上假设一个 100B 参数的模型如果单卡显存 80GBA100 80G 这样的卡不用任何并行策略直接塞连 FP16 都装不下100B × 2 bytes 200GB。用张量并行对半切每张卡也还要 100GB。而 ZeRO-3 把参数分到 N 张卡上后每张卡的静态参数持有可能只有几十 GB前提是通信能跟上。2.2 前向和反向中 ZeRO-3 做了什么具体到计算流上ZeRO-3 的工作流程是这样的模型初始化阶段每张卡只分配全局参数中的 1/N 切片优化器状态在 ZeRO-1 语义下也只存对应参数切片的状态。前向传播到第 L 层时先触发一个all-gather操作把所有卡上的第 L 层参数切片汇聚成完整参数加载到计算设备内存里。计算完第 L 层的前向结果完整参数立即释放。下一层重复上述过程。反向传播到第 L 层时再次 all-gather 一次第 L 层的参数因为前向后已经释放了需要重新拿回来算梯度——这也是 ZeRO-3 的一个隐藏成本反向需要额外通信一次。梯度计算完成后对梯度做reduce-scatter操作把各卡产生的梯度分片归并到对应的参数拥有者卡上用于优化器更新。所以 ZeRO-3 和 ZeRO-2 相比多出来的开销主要是前向和反向各一次的全参数 all-gather。通信总量和模型大小成正比可见当模型达到千亿级别时通信会是整个训练流程的绝对瓶颈。这也是为什么 ZeRO-3 论文里强调它通信开销大约是 ZeRO-2 的 1.5 倍但在极大规模下依然能跑的原因——因为如果你不用 ZeRO-3显存直接爆了。2.3 MoE 场景下 ZeRO-3 的省和不省回到 MoE 模型。一个标准的 MoE Transformer 层核心组件是attention 部分共享参数router共享参数一般是一个小的线性层N 个专家 FFN每个专家自己的参数使用 DeepSpeed 的 MoE 支持时有一种部署模式是专家采用专家并行EP把 N 个专家平均分配到各卡上每个 token 经 router 决定去哪些卡上的专家计算计算完再回来。这种模式下专家参数本身就不需要在每张卡都保存一份所以 ZeRO-3 对专家的参数分片意义就不大了——你再分片专家还是要通过 all-to-all 把 token 送过去TF 的通信和 ZeRO 的 all-gather 叠加起来效果只会是通信量爆炸。但 attention、router、embedding 这些非专家参数如果模型很大反而成了显存大头。这时候 DeepSpeed 的官方做法就很明确了当使用 DeepSpeed MoE 时ZeRO-3 默认应用于非 MoE 参数而 MoE 专家参数交给专家并行来管理。换言之MoE 架构要全部参数进显存吗这个问题的准确答案是专家参数不必全进每张卡但非专家参数如果特别大仍然需要 ZeRO-3 或张量并行来解决。好消息是大多数 MoE 模型的共享参数占比不高通常 5%~15%所以 ZeRO-3 需不需要开取决于你非专家部分到底有多大、以及单卡能否塞下。2.4 一个很容易忽略的点ZeRO-3 不解决显存碎片化说个实操中很恶心的问题ZeRO-3 虽然把参数放进显存了但如果你用的是 PyTorch 默认的缓存分配器训练几百步之后显存可能不减反增。原因是每次 all-gather 出来的临时完整参数、以及不同层反复申请释放的 buffer会制造大量显存碎片。DeepSpeed 在配置里有一个contiguous_memory选项开启之后它会预分配一整块连续的缓存来容纳这些临时通信 buffer碎片问题会明显缓解。我自己的经验是开不开 contiguous_memory同等配置下显存峰值能差 10%~20%。但它也有新问题——如果开启后你的 batch size 太大了连续缓冲区不够用DeepSpeed 会直接报 OOM 而不是像不开启时那样侥幸逃过。所以你需要针对自己的 batch size 反复调这个开关不能无脑开。3. MoE 的显存和路由机制为什么说它和 ZeRO-3 是互补但不重叠的关系3.1 专家并行EP如何决定专家参数的去向MoE 训练里最经典的并行方式是专家并行。做法如下假如你有 64 个专家、8 张 GPU每张卡放置 8 个专家。输入序列的每个 token经过 router 计算出一个 gating score决定送往哪几个专家比如 top-2即只挑分数最高的两个专家。系统执行all-to-all 通信把 token 从当前所在卡发送到目标专家所在的那张卡。专家前向计算之后再通过一次性 all-to-all 把计算结果送回原来的卡。在这种设计下专家参数完全不需要每个 rank 都存一份——谁拥有这个专家谁就只在自己本地存。显存布局上一张卡只需要保存它分配到的 8 个专家参数即总专家参数量的 1/8这其实比 ZeRO-3 对参数的分片粒度更接近物理划分。那 ZeRO-3 还对这个模型有用吗有但只对非专家参数有用。比如 8 卡环境下如果 attention 层参数有 40GB单卡显然塞不下完整副本ZeRO-3 会把它切成 8 份每卡 5GB前向计算时再临时聚合。这时候整体显存账本是共享参数每卡 1/8ZeRO-3 分片专家参数每卡 1/8专家并行物理分布激活值随 batch size 变化但 MoE 的激活值远比同体量稠密模型小——因为只有部分专家被激活这就是为什么 MoE ZeRO-3 在超大模型上是双保险一个负责把共享参数压到极限一个负责让专家参数天然分布。二者并不冲突但也不能互相替代。3.2 Router 的 Top-1 与 Top-k 选择直接影响显存和通信再说一个很实际、也常被新手忽略的选型问题router 到底选 top-1 还是 top-2这会影响显存占用和训练稳定性而不只是精度。Top-1 路由每个 token 只访问一个专家。通信量最少、专家计算量最小但缺点很明显——如果一个专家被大量 token 命中会形成热点而其他专家饿死。为了缓解这个问题老一代 MoE如 Switch Transformer用的就是 top-1 load balancing loss训练时强行均匀化 token 分配。即便如此热点仍然可能偶尔出现尤其训练到后半程。Top-2GShard 风格每个 token 访问两个专家训练更稳router 的决策更平滑但通信量翻倍计算量也加倍。显存上因为同时激活两个专家激活值和中间缓存都会增加。DeepSpeed 里对应配置是top_k。我实际对比过同一模型规模下 top-1 和 top-2 的表现top-1 吞吐更高但收敛波动明显更大top-2 吞吐大约掉 15%~20%但训练过程非常平滑。如果你的集群很大、带宽好新手优先选 top-2因为好调如果追求极限吞吐且你已经有足够调参经验可以试 top-1。3.3 Load Balancing Loss路由必须加但加多了会毁掉稀疏性MoE 的一个核心训练技巧是负载均衡损失auxiliary load balancing loss。目的是让 token 尽量均匀地分配到各个专家上避免几个专家被踩爆、其他专家完全不参与计算。但这里有个反直觉的点负载均衡损失加得越多MoE 的稀疏优势就越弱。因为如果你强制所有专家接收完全等量的 token那就和普通的稠密 FFN 没本质区别了——每个专家都忙每个专家都重要稀疏激活带来的计算节省、参数容量优势就没有了。一个好的 MoE 训练配置负载均衡损失系数l_aux一般设得很小比如 0.01 甚至更低目的只是防止极端情况下路由崩溃而不是追求完全均匀。DeepSpeed 的noisy_gate_policy也是干这事的——在 router 打分上加入噪声让路由不会过早固化。新手很容易把这两个机制搞混我建议这样理解load balancing loss 是让分配结果均匀noisy gate 是让分配过程有机会探索二者一起用效果稳定很多。3.4 MoE 微调与 LoRA稀疏结构对低秩适配的限制热搜词里出现了大量 lora训练、moe架构要全部参数进显存吗 的关联内容这里我多说两句微调场景。很多人想拿 LoRA 微调一个 MoE 大模型做法是在专家 FFN 上挂低秩矩阵。听起来顺理成章实际效果参差不齐原因是专家 FFN 本身是稀疏激活的单个专家只处理一小部分 token 分布低秩矩阵的容量可能比专家本身的容量还小起不到微调注入知识的作用。Router 才是 MoE 里最需要微调的部分之一——如果你能微调 router 的 gating 权重让 token 流向更适合的专家收益往往远超在固定专家上挂 LoRA。但 router 本身参数少分布式训练时通常也在共享参数里用 LoRA 处理反而复杂。所以我的个人建议是MoE 模型的微调先考虑全参数微调一小部分层比如只微调最后一个 FFN 和 router不要一股脑在全部专家上搭 LoRA。你省下的显存有限但引入的训练不稳定性和调参成本很高。4. DeepSpeed 实战配置ZeRO-3 与 MoE 组合的正确打开方式4.1 一份验证过的 ZeRO-3 MoE 配置模板下面这份 JSON 配置来自我在 8×A100-80G 上跑过一个约 200B MoE 模型的实战模板模型实际约 56B 稠密参数 144B 专家参数里面每个字段我都加了作用注记直接抄可以但一定要根据你模型和集群情况改。{ train_batch_size: 128, gradient_accumulation_steps: 8, train_micro_batch_size_per_gpu: 2, optimizer: { type: Adam, params: { lr: 1e-4, betas: [0.9, 0.999], eps: 1e-8, weight_decay: 0.01 } }, scheduler: { type: WarmupDecayLR, params: { warmup_min_lr: 1e-6, warmup_max_lr: 1e-4, warmup_num_steps: 2000, total_num_steps: 50000 } }, zero_optimization: { stage: 3, contiguous_memory: true, stage3_max_live_parameters: 8e9, stage3_max_reuse_distance: 8e9, stage3_prefetch_bucket_size: 5e7, stage3_param_persistence_threshold: 1e6, reduce_bucket_size: 5e8, allgather_bucket_size: 5e8, overlap_comm: true, reduce_scatter: true }, moe: { type: deepspeed, num_experts: [32], top_k: 2, min_capacity: 4, noisy_gate_policy: Jitter, drop_tokens: true, use_residual: false, encoder: { type: dense }, decoder: { type: moe, num_experts: [32], top_k: 2, min_capacity: 4 } }, activation_checkpointing: { number_checkpoints: 12 }, communication_data_type: fp16 }配置里的几个关键决定我逐个说为什么stage3_max_live_parameters和stage3_max_reuse_distance这是控制 ZeRO-3 参数预取的视野范围。设成 8e9 意味着模型参数被分成若干块每一块占 8GB 级别的显存来管理预取。设小了预取不够提前设大了缓存时间长显存容易顶爆。我实测 8 卡 80G 时这两个值在 8e9 左右比较平衡。reduce_scatter: true把梯度归并方式改成 reduce-scatter避免每个 rank 都保留一份全量梯度再聚合节省梯度阶段显存。这是 ZeRO-2/3 时代的标准配置但必须和 allgather_bucket_size 配合调优。overlap_comm打开后通信可以和计算重叠。对于 MoE ZeRO-3这个开关基本必开否则 all-to-all 和 all-gather 串行执行训练速度会惨不忍睹。min_capacity: 4每个专家最少要接收的 token 数量。这个值设得太大会强制塞 token 给那些本来没被选中的专家破坏路由语义太小又可能在 batch 较小时出现专家完全空闲的问题。drop_tokens: true当某些专家接收的 token 超过设定上限时直接丢弃超额 token。很多人不理解这个配置其实它才是 MoE 训练能稳定跑下去的关键。如果不丢弃那些爆满的专家后面所有层都要排队等这些 token 算完整个 step 时间被拖长到不可接受。4.2 为什么我用了 activation checkpointing 而不是浮点省显存ZeRO-3 把参数和梯度从显存里删掉了但激活值仍然还在。MoE 模型因为专家是稀疏的激活值比稠密模型小很多但 attention 部分的激活值依然是 batch size × 序列长度 × hidden size 的平方级别增长。我实际跑的时候发现第一个撑爆显存的反而不是专家参数而是 attention 层的激活。所以我在配置里开了 activation checkpointing。通俗说就是不保存每一层的激活值而是前向时只保留少量中间结果反向需要时重新算一遍。空间换时间显存节省 60% 以上代价是计算量增加大概 30%。对于 MoE 这种本就通信密集的模型这个取舍非常值。其实有更极端的做法——比如混合精度下用 BF16 存激活值、或者把激活值也分片ZeRO-3 的进阶模式但工程复杂度较高不是第一次上手 MoE 训练的人该碰的。4.3 训练脚本里需要关注的三个隐性配置第一数据加载的 Token 批处理方式。很多 MoE 训练框架要求你把同一 batch 内的 token 先按专家路由结果排序再送给不同专家这样 all-to-all 通信的粒度更整齐。DeepSpeed 会自动完成排序但前提是你不能在一个 micro-batch 里混入不同长度的序列还开 padding 到同一个长度——那样排序失效通信效率大打折扣。我建议统一 pad 到该 batch 的最大长度宁可浪费一点计算也不要打乱 token 顺序。第二混合精度策略。专家参数如果用 FP16 存储all-to-all 通信时传输量是逐 token 的 hidden stateFP16 相比 FP32 能显著降低带宽压力。但别为了省显存把全部参数降到 FP8——目前 MoE 的路由部分对精度极其敏感gating score 稍微失真路由就乱套了。稳妥做法是共享参数和专家参数都用 BF16/FP16router 参数专门用 FP32。DeepSpeed 允许你以communication_data_type指定通信数据的精度但对 router 的精度控制需要单独实现。说实话这块我在项目中是通过正则注册钩子做的不建议新手在最开始就折腾。第三梯度裁剪的时机。MoE 模型的梯度分布很不均匀——有的专家梯度小有的专家梯度巨大尤其训练初期路由不稳定时。如果你按全局梯度范数裁剪那些饿死的专家梯度很容易被误伤。我在项目中尝试过按专家维度分别裁剪梯度比全局 Clipping 训练稳定得多。DeepSpeed 原生不支持这个需要自定义优化器钩子。5. 通信瓶颈的定位与 tuning跑 MoE ZeRO-3 最容易踩的坑5.1 显存不爆了但吞吐量惨不忍睹先看通信是不是瓶颈很多人在普通稠密模型上开了 ZeRO-3 后发现训练速度还能接受但把 MoE 叠上去后直接发现吞吐量掉了一半还多。这时候第一反应是调 batch size但往往没什么用。因为 MoE ZeRO-3 的通信是双重叠加的非专家参数每层都要 all-gather / reduce-scatter。专家 token 每一步都要 all-to-all。二者都在同一个 NVLink 或 InfiniBand 总线上跑互相抢带宽。我自己的排查方法论很直接先用nsys或者nvprof抓一下 kernel 时间线看计算和通信有没有 overlap然后把overlap_comm: false和true各跑 50 步比较 step time。如果 false 反而快说明你在用计算换通信此时建议减少 ZeRO 分片范围比如把 attention 层改为张量并行而不是 ZeRO-3让通信量降低。另外一个容易被忽略的点all-to-all 的通信量和序列长度、top_k 有关但和模型参数量完全无关。也就是说如果你的模型很小、但序列很长通信瓶颈可能反而主要来自 MoE 的路由 part而不是 ZeRO-3。此时与其升级集群网络不如调小 top_k 或者降低 batch 内 token 量。5.2 路由崩溃一个专家吃掉 92% 的 token这是我在训练中真实遇到过的严重故障某个专家在训练到 3000 步左右时突然开始接收 92% 的 token其他 31 个专家几乎完全空闲。典型表现是 loss 不再下降但吞吐量反而升高——因为只有少数专家在计算其他专家处于 idle 状态。排查链路是这样的先确认是不是 load balancing loss 配置失效。我检查过配置和代码l_aux在正常生效但系数只有 0.001修正能力太弱。再把 top-2 降成 top-1 测试问题依旧存在说明不是多专家路由选择的问题。最后定位到是路由网络的学习率设置过大导致 router 权重在训练初期快速固化形成正反馈某个专家分数高→得到更多 token→梯度更大→分数更高。修复方法是把 router 参数单独设 learn rate比如主模型 lr1e-4router lr5e-6同时把 noise gate 的噪声方差加大一点。改完之后路由分布稳定多了没有再次崩。这个经验放到这里就是给你们提个醒MoE 训练调参时router 的 lr 永远要比主模型低一个数量级以上除非你想专门练一个快速适应的 router。至于 noisy_gate_policyJitter 的作用就是给 router 的 logits 加一点均匀噪声打破那个正反馈循环。5.3 专家死亡永远不被选中的专家和路由崩溃对应的另一头问题是专家死亡——某些专家从头到尾几乎没被选中。这种问题更隐蔽因为 loss 不会变差训练也没报错但模型有效参数量白白少了一块。如何发现统计每个专家接收 token 的数量分布画出来看一眼就知道。最典型的死亡原因是初始化问题DeepSpeed 对专家 FFN 的初始化方式如果直接用全 0 偏置和标准正态权重部分专家在初始时 gating score 就低后续再没有 token 进来就永久失活了。解决思路有两个给每个专家加一个独立的偏置初始化为 0然后在训练过程中学习。这样即使 router 对某个专家打分低偏置也能让它在后期被拉一把。用noisy gate让 router 在前期有更强的随机探索能力提升冷门专家被选中的概率。实际调优中我还会在训练早期阶段提高min_capacity值强制每个专家每 step 至少接收固定 token 数避免从第 1 步就开始出现死亡专家。等到训练稳定后再降回来。5.4 关于要不要让专家参数也走 ZeRO 分片的最终判断我相信你读到这里其实已经能把最初热搜里那个问题回答出来了MoE 专家参数并不一定全部进显存但也不意味着 ZeRO-3 对专家完全没有用处。在个别场景下——比如你的专家太多单卡计算完后显存仍有富余——是可以让专家参数也参与 ZeRO-3 分片以进一步降低各卡静态占用比如 DeepSpeed 的stage3_param_persistence_threshold就控制着哪些小参数块可以持久保留、哪些大块必须通信聚合。但绝大多数情境下专家并行EP已经天然完成了专家参数的分布再叠 ZeRO-3 只会让通信更复杂、吞吐更低。所以在工程选型上我的经验总结成一句话能走 EP 的走 EPZeRO-3 留给共享参数二者各司其职比硬塞到一起高效得多。如果共享参数本来就薄比如 100B MoE 中只有 6B 共享参数8 卡 A100 完全可以每卡塞下 0.75B 的共享层副本那连 ZeRO-3 都可以不开直接 EP 数据并行是最省事的方案。6. 训练稳定性和收敛质量的三个细节6.1 激活值的稀疏性对 loss 曲线的影响MoE 模型和稠密模型在 loss 行为上有明显差异训练早期 loss 下降通常很快因为有效的参数量巨大但到中期会出现一个平台期表现为 loss 基本不动持续几百步。很多新手以为卡在局部最优了就开始调学习率、换优化器其实往往只是路由正在重新分配 token 分布。我的经验是平台期先不要动 lr先去观察路由的熵值。如果 router 输出的 gating score 分布逐渐尖锐化熵下降说明在正常收敛如果熵值长时间不变化再考虑调 load balancing loss 系数。另外建议把 loss 曲线按专家路由分布的均匀度画一条辅助线能帮你判断当前 loss 的变化到底是因为拟合数据更好还是仅仅因为路由分布变了。6.2 梯度累积与 MoE 路由的相互作用MoE 训练里有个和稠密模型很不一样的地方路由决策是在 micro-batch 粒度上做的但梯度累积会跨多个 micro-batch。如果累积步数很大可能出现一种别扭的场景——同一个 data batch 内前几个 micro-batch 的路由分布和累积梯度更新时的实际参数状态已经脱节了。解决方案是尽量让一个优化器更新步内的 micro-batch 数量少一些或者使用动态批采样保证每个 micro-batch 的 token 分布大致均匀。我在 200B 模型上实测gradient_accumulation_steps 超过 16 时top-1 路由的训练稳定性明显变差top-2 好一些但也会隐约出现 loss 抖动。如果你的集群带宽有限、被迫加大累积步数那就把 top_k 提到 2比调一堆其他参数都管用。6.3 checkpoint 保存与恢复专家参数要单独管这是工程里最容易出事故、但几乎没人写的地方。DeepSpeed 的 checkpoint 默认会保存所有模型参数包括专家参数。但因为专家参数是物理分布在不同 rank 上的所以 checkpoint 保存格式和稠密模型不同不同 rank 保存的是不同专家的参数。这意味着如果你改变了专家分配策略比如从 4 卡专家并行改成 8 卡旧 checkpoint 不能直接加载。如果训练中途某张卡挂了从 checkpoint 恢复时DeepSpeed 通常能找齐专家参数但前提是你用的是官方save_checkpoint/load_checkpointAPI而不是自己手动拿 PyTorch 的torch.save去存 model.state_dict()。我在实践中踩过一次用torch.save保存了model.state_dict()然后试图在一个改了 world size 的环境里加载结果一堆专家参数映射错位模型 loss 直接飞了。从那以后MoE 模型我全部统一走 DeepSpeed 自己的 checkpoint API同时额外保存一份metadata记录专家分配方式、top_k、当前步数等恢复时先看 metadata再对专家参数做精确的 placement 验证。结束语从能跑到跑得稳中间隔着一堆看不见的通信细节这篇文章从 ZeRO-3 的内部机制讲到 MoE 的专家并行再到我把两者组合在一起的实证经历核心就是想传达一件事它们分别解决的是显存维度和计算稀疏维度的独立问题组合的关键在于理解各自边界不要试图让一套机制包办一切。很多刚接触大模型训练的朋友会陷入一个误区——为了显得极致优化把所有能开的开关都打开结果训练不稳定、吞吐反而降了一半。我从不会在一个正常训练的稠密模型上无脑加 ZeRO-3同样也不会为了让 MoE 看起来更省显存就把专家参数强行塞给 ZeRO-3 管理。如果你现在正准备把某个稠密模型改造成 MoE 架构我建议按这个节奏走第一步先用普通稠密模型验证数据 pipeline 和并行策略没有 bug第二步只在模型最后一层换成 MoE用很小的专家数4~8个跑通全流程第三步再慢慢扩大到 32 专家同时关注路由分布的统计输出。整个过程里不断用 profiler 确认通信比例比你任何理论推断都靠谱。最后分享一个我最近在实验里的小技巧把 router 的 gating score 也打印到日志里。很多人只在 loss 异常时才去看模型内部但 MoE 模型的健康状态几乎全写在路由统计里——均匀度、top-1 命中概率、专家接收 token 的方差这些指标比 loss 更早暴露问题。训练脚本里加两行代码的事却能帮你省下好几天排查时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑