
去年年底参加一场大模型后训练方向的闭门技术交流主讲人一上来放了页 PPT万亿参数模型做强化学习RL后训练GPU 用量压到常规方案的十分之一。台下第一反应是怀疑第二反应是拍屏保存。会后我把自己能调动的小规模集群拉起来按这套思路复现了一遍关键环节又把公开资料里的训练账单逐项核对过。结论是这不是标题党而是一套组合拳式的工程优化。核心不是某个单点黑科技而是显存账、带宽账、调度账三本账一起算。这篇把整个拆解完整写下来包括显存计算过程、三层减法的原理、百卡规模的具体配置参数以及复现过程中踩过的几个坑。先说明“10% GPU”的含义它不是说把单卡利用率做到 10% 反而跑通了而是把集群规模从千卡量级压到百卡量级资源总量正好是常规方案的十分之一。下面从算账开始讲。1. 先把账算清楚万亿参数 RL 后训练的显存黑洞1.1 四个模型同台显存不是翻倍而是翻四倍RL 后训练和普通 SFT 最大的区别在于训练过程中不只有一个模型在跑。以主流 PPO 框架为例显存里同时要驻留四类角色策略模型参与训练的唯一主角权重要能更新所以除了权重本身还要有梯度和优化器状态。参考模型和策略模型同结构、同规模但完全冻结用来计算新旧策略的 KL 散度防止策略一步跑飞。奖励模型给采样结果打分模型本身可以比策略小一个量级但推理时同样占显存。采样服务其实就是用当前策略模型做推理生成 responseKV cache 和推理中间状态都要显存。很多人第一次做大规模 RL 时都会犯同一个错误只按“一个模型训练”的账准备显存等跑起来才发现参考模型和采样服务把显存吃光了。策略模型、参考模型、采样服务三套本质上都是同一个万亿参数级别模型显存需求量不是翻一倍而是直接翻三四倍。这是先决条件也是后文所有优化动作的前提。1.2 常规账单为什么动辄上千卡把万亿参数的显存账摊开算。假设模型参数量 P 1T即 10^12 参数采用常见的 BF16 混合精度训练。只算模型状态权重 梯度 优化器状态一个参数在标准 AdamW 流程里要占 16 字节状态精度每参数字节BF16 权重半精度2 字节BF16 梯度半精度2 字节FP32 优化器主权重全精度4 字节一阶动量 m全精度4 字节二阶动量 v全精度4 字节合计16 字节1T 参数乘以 16 字节就是 16TB。一张 80GB 显存的训练卡只放模型状态也要 200 张才装得下。这是策略模型本身的账参考模型冻结权重再加 2TBBF16奖励模型另算采样阶段 KV cache 轻松破几百 GB。叠加上激活值、通信缓冲、中间临时张量常规配置没有 500 到 1000 张卡万亿参数 RL 后训练根本推不动。这里有一层容易忽略的账常规部署还会把训练池和采样池完全分开。训练池 300 卡采样池再 300 卡两套集群各管各的资源总量直接翻倍。所以“千卡才能跑”的结论一点都不夸张。1.3 目标账单100 张卡如何够用这套方案的总思路是把三笔最大开支分别处理优化器状态12TB直接不要了。梯度2TB边算边更算完即丢。权重2TB按层分片到每张卡配合 CPU 内存动态驻留。最终模型状态账单只剩 2TB 的 BF16 权重。摊到 100 张 80GB 卡上每卡本地切片 20GB剩下的 60GB 留给激活值、通信缓冲、KV cache 和临时计算。参考模型量化后常驻 CPU 内存奖励模型用小体量替代采样和训练共用一批卡。这样百卡规模就能闭环跑起来正好对应标题里“十分之一 GPU”这个数字。2. 三层减法为什么能把显存砍一个数量级2.1 第一层不带“记忆”的优化器AdamW 每个参数要占 8 字节动量 二阶矩因为它要记住每个参数的历史梯度一阶矩和二阶矩。在万亿参数规模下这份“记忆”本身就是最大的显存黑洞。第一刀就砍在这里采用无状态的极低显存优化思路不保存动量和方差反向传播计算到某一层时直接用当前层梯度做一次参数更新。生活类比常规优化器像记账式理财每一笔开销都要入账、算历史均值再决定下一步无状态优化器像现金管理手里有多少花多少花完即忘。它在小模型上收敛速度通常逊于 AdamW但在超大模型上省掉的 12TB 显存可以换成更大 batch实际吞吐不降反升。代价是学习率必须给得更保守——实测下来无状态优化器的合理学习率约为 AdamW 的十分之一到二十分之一而且梯度裁剪几乎不能省。2.2 第二层梯度即算即弃标准反向传播会把整张计算图所有层的梯度攒进一个梯度张量等全部算完再统一更新。万亿模型这一攒就是 2TB。进阶做法是彻底取消“攒梯度”这一步反向传播从最后一层往前推算到第 i 层梯度立刻更新第 i 层参数然后释放该层梯度。整个过程只是多了几次零散的参数更新操作但整卡再也不需要一块 2TB 的全局梯度缓冲区。这里有个实现细节容易被忽略梯度不落地通信不能省。分片模式下反向阶段需要再次 gather 权重才能算出梯度所以每轮训练至少要经历两次参数聚合。要做异步流水让通信时间藏进矩阵计算里否则省下显存却跑出一个“通信饥饿”的训练过程。框架层面通常会有 prefetch 或 overlap 选项默认不一定打开务必手工确认。2.3 第三层零冗余分片 CPU 动态驻留权重 2TB 摊到 100 张卡上每卡只有 20GB 本地切片。这里用零冗余参数分片同一份参数在整个集群只保留一份训练时按层 all-gather 聚合。注意是按层不是一次性全 gather。每层权重在万亿模型里通常只有几个 GB算完当前层立刻丢弃再取下一层。这样每卡的峰值占用是“本地 20GB 切片 当前层 gather 结果”而不是恐怖的 2TB 全量。配合 CPU 动态驻留冷参数当前不参与计算的层放在 CPU 内存里GPU 只保留正在计算的那段。参考模型更极端——它完全冻结可以量化到 INT8 甚至更低常驻 CPU推理时按需取。这一层有个很多人没想透的点CPU 内存不是问题CPU 带宽才是。CPU 到 GPU 的互联带宽通常几十 GB/s显存带宽是几个 TB/s差一个数量级。所以 CPU 卸载不是无脑把参数丢内存而是要做预取队列、按层流水、双缓冲。更聪明的做法是只在 pipeline 冷却阶段卸载热阶段保持 GPU 驻留把每一寸带宽都用在刀刃上。3. 实操过程100 张卡上把 RL 闭环跑起来3.1 训练与采样同池化不单独养推理舰队RL 有三件活采样推理、打分推理、训练前向 反向更新。常规方案把训练池和采样池分开各用各的卡显存需求直接翻倍。这套方案的核心动作是把训练和采样放到同一批卡上用交错调度错峰使用pipeline 并行的训练前向/反向之间存在天然气泡某个 stage 算完当前 micro-batch 会空转等待这些空档全部拿去跑采样推理。调度上我建议做一个显式的双环结构训练环按 micro-batch 推进采样环从训练队列尾部拿当前策略参数快照去生成 response。两个环共享同一批 worker靠队列水位控制节奏。还要设一个 min_available_mem 阈值——训练任务把显存吃得太紧时采样环自动降速反之提速。实测下来采样吞吐在训练满载时会下降 20% 左右但省掉一整支推理集群这笔买卖非常划算。3.2 策略模型训练配置一组可以直接用的参数复现时用的配置如下模型规模可以按比例缩放全局 batch2M tokens/stepmicro-batch 4096 tokens梯度累积 512 步。重计算开启按层激活重计算显存峰值约降一半代价是 1.5 倍左右计算量。学习率1e-6 起步warmup 200 步cosine 衰减到 1e-7。无状态优化器对学习率极其敏感宁小勿大。梯度裁剪max_grad_norm 0.3硬裁剪。PPO 侧clip range 0.1KL penalty 系数 0.01 起步后续动态调整。参考锚点每 200 步用当前策略重算一次参考 logits中间步骤用缓存锚点做 KL 近似。这些参数来自小规模复现和公开资料的交叉对照换语言模型、换任务分布后建议重新扫一遍学习率。特别强调无状态优化器没有二阶动量做“自动刹车”调大学习率的后果不是平滑变快而是某一步直接飞掉。我在小模型上验证过学习率从 1e-6 调到 3e-6reward 曲线前期只快 10%后期直接塌方。大幅度更新会让 rollout 分布瞬间偏离锚点KL 惩罚都救不回来。3.3 参考模型与奖励模型的轻量化技巧参考模型是“重量级配角”。完全冻结的特性让它非常适合量化我用 INT8 权重量化 CPU 常驻推理时按层把量化权重拉到 GPU。更进一步可以用 KL 锚点缓存——KL 散度逐 token 计算每隔若干步才用参考模型算一次 logits 并缓存中间步骤直接读缓存。注意这里有个隐患策略在训练中不断偏移锚点会过期。所以必须配 KL 漂移监控当策略输出分布与锚点分布差异超过阈值常用 KL 均值 0.3时强制触发一次锚点刷新。否则旧锚点会让 KL 估计失真训练会跑出假象奖励。奖励模型相对好办。传统做法是单独放大模型当奖励模型这套方案建议“小奖励模型 规则打分器”混合数学、代码类任务用规则验证器或执行结果开放性任务用小一个量级的模型打分实在需要强语义打分的再上 FP8 推理。奖励模型精度直接影响 PPO 的信用分配不要为省显存压太狠——最低我只敢压到原规模的三分之一再小奖励信号就开始失真。3.4 采样阶段的分页 KV 与显存复用采样阶段最大的显存杀手是 KV cache。万亿模型的 attention 层数多、通道数大每个 token 的 KV 要上千字节几万条并发序列随便就是几百 GB。这部分的处理方案分页 KV cache把 KV 按固定 block 管理类似操作系统的虚拟内存分页解决碎片化并支持显存不足时换出。低比特 KVK、V 分别降到 FP8显存直接减半对 RL 采样质量影响可控。冷块换出长时间不访问的旧序列块换到 CPU 内存新序列用 GPU 块。序列长度上限给所有 prompt 设统一 completion 上限避免极少数长尾序列吃穿整个显存池。另一个复现时确认过的细节采样用动态连续批处理而不是静态按 batch 等待。静态批处理在序列长度差异大时短序列会空等长序列浪费的是显存驻留时间连续批处理让短序列先走空出来的 block 立刻给新序列吞吐能提升 30% 以上。这套机制配合训练采样同池化是百卡闭环里最容易被忽略但回报率最高的模块。4. 踩坑实录这些问题网上基本查不到4.1 显存没爆时间爆了CPU 卸载的带宽陷阱第一次跑通时显存峰值很漂亮但训练速度惨不忍睹单 step 比常规方案慢 6 倍。查了半天发现罪魁祸首是 CPU 卸载没做预取每一层都同步等权重从 CPU 搬进 GPU互联带宽成了真正的瓶颈。解决方式是把参数预取队列加长到两层以上开启双缓冲异步传输并且只在 pipeline 冷却阶段做卸载热阶段保持 GPU 驻留。调完之后单 step 只慢 1.8 倍显存峰值稳定在 50GB 以下。这个性价比可以接受。4.2 锚点缓存引发的“隐性奖励坍塌”这是一次很有意思的翻车。用 KL 锚点缓存跑了一个多小时reward 曲线单调上涨正当我以为一切正常reward 突然断崖式下跌并持续震荡。定位后发现原因策略在更新中逐渐偏离早期锚点KL 近似误差越来越大模型学会了用较大的 KL 漂移换取表面高分——本质上是锚点欺骗。加上 KL 均值监控和强制刷新之后reward 曲线才恢复健康。现在的观点是锚点缓存只适合中期提速宁可多花几次前向计算也要保证 KL 估计可靠。4.3 同一批卡既训练又采样差点死锁训练环和采样环共享 worker 的初版跑了半小时全部卡住采样环等训练释放显存训练环等采样环归还通信原语互相等成了死锁。解决方式是加队列水位上限和超时看门狗训练队列积压超过阈值采样环强制削峰任何通信原语等待超过 5 分钟自动丢弃当前采样任务并释放资源。之后还发现一个更稳妥的原则采样任务优先级必须低于训练任务。RL 训练中断的代价远高于采样中断宁可丢几个样本也不要打断训练 step。4.4 梯度范数“心电图”与回滚策略无状态优化器没有二阶矩梯度范数在 RL 的嘈杂奖励下会跳得厉害。我亲眼见过一个 step 梯度范数从 3 跳到 300 再跳回 2。两个对策一是 max_grad_norm 严格限制二是“心跳检查”——每 N 步记录各层梯度范数均值和方差若某层超过 5 倍历史均值跳过这次更新并恢复上一个 checkpoint。这套回滚机制让整体训练稳定很多代价只是偶尔跳过几个 step。现象可能原因处理方式显存低但 step 极慢CPU 卸载同步等待预取队列 双缓冲 热阶段驻留reward 先涨后崩KL 锚点过期KL 漂移监控 强制刷新锚点集群整体卡死训练/采样环互相等待队列水位上限 超时看门狗梯度范数剧烈跳动无状态优化器 嘈杂奖励梯度裁剪 心跳检查 回滚5. 实测效果与这套方案的适用范围5.1 复现实测的数据账我复现的是机制本身用的是开源推理模型在小规模上验证目的不是跑 1T而是确认每一层优化是否成立。在百亿级模型规模下常规方案需要训练池与采样池分离加起来几十张 80GB 卡这套方案只用了大约四分之一的数量同一批卡完成训练和采样显存峰值约 58GB吞吐约为常规方案的 7 成。reward 曲线和 KL 曲线形状与常规方案一致稳定性略差但完全可控。换算到万亿参数就是 80 到 128 张卡对比常规的 800 到 1000 张卡数量级完全对得上。当然也要说实话百卡规模的单 step 时间一定比千卡慢因为 CPU 卸载和重计算都是有代价的。这套方案省的是“资源总量”和“采购成本”不是“单次训练墙钟时间”。如果项目预算充足、时间紧张常规方案仍然更省时间如果卡紧张、预算有限这套方案几乎是唯一解。5.2 适用的场景边界这套方案的甜区是“显存极度紧张 模型极大 奖励信号明确”的 RL 后训练比如代码 RL、数理推理 RL。不适合的场景有三类需要精细优化器的指令微调小模型用无状态优化器收益不大反而容易掉点。极长上下文 RLKV cache 绝对量太大低比特和分页也救不回来。奖励模型本身必须很大才能区分质量的场景奖励模型会变成新的显存瓶颈这个账就不好平衡了。最后分享一点个人体会。这套东西的核心不是变魔法而是把账算清楚——显存账、带宽账、调度账三本账一起算才能把“十分之一 GPU”做实。如果只学一招我建议学它的参数分层驻留策略热驻留、温预取、冷卸载这是整套方案里回报率最高的一层工程优化。用开源框架搭建之前一定确认三件事梯度是否真的即算即弃、参数预取是否流水化、调度器有没有防死锁看门狗。三件事都确认过了百卡万亿 RL 这件事才算真正落地。