1. 一场每小时烧掉 20 万的 RL 实验到底在烧什么第一次看到“小米直播训练大模型每小时烧掉 20 万”这个说法我脑子里冒出来的第一个念头不是“真有钱”而是“这钱到底花在哪了”。因为但凡自己动手跑过强化学习训练的人都知道RL 这东西的烧钱方式和预训练完全不是一个量级。预训练是“一次性投入大、但过程相对稳定”而 RL 是“每一步都在试错每一次试错都要真金白银地跑一遍推理”。先把概念说清楚。这里说的 RL指的是 Reinforcement Learning强化学习。在大模型语境下它通常出现在后训练阶段也就是模型已经通过监督微调具备了基本能力之后再用强化学习去对齐人类偏好、提升推理能力、优化 Agent 行为。小米的 MiMo 系列模型在公开信息里一直强调推理和 Agent 能力而这两块恰恰是 RL 最能发挥价值的地方。那 20 万每小时是怎么来的我按自己的经验拆一下。RL 训练的成本主要压在三个地方推理采样、奖励计算、梯度更新。其中推理采样是大头因为 RL 不像监督学习那样每个样本只用一次它需要模型对同一个 prompt 生成多个候选回答然后由奖励模型或规则打分再根据分数去调整策略。这个“生成多个候选”的过程本质上是把推理成本乘以了一个系数通常是 4 到 16 倍。举个具体的账。假设一个 30B 级别的模型用 8 卡 H 系列做推理单卡吞吐按每秒 2000 token 算8 卡就是 16000 token/s。一个 RL step 如果要做 512 条 prompt、每条采样 8 个回答、每个回答平均 512 token那单 step 的 token 量就是 512 × 8 × 512 ≈ 210 万 token。按 16000 token/s 算光采样就要 131 秒。这还只是一个 step而一个完整的 RL 训练动辄几千到几万 step。再叠加奖励模型的前向计算和策略网络的梯度更新整体算力占用会翻倍甚至更多。如果用的是按小时计费的算力集群几百张卡同时跑每小时 20 万这个数字其实并不夸张。我自己的经验是一个中等规模的 RL 实验单次跑通就要几万到几十万不等所以看到这个数字我第一反应是“合理甚至可能还偏保守”。这篇文章我想聊的不是“小米多有钱”而是一个 RL 实验从设计到跑通中间到底有哪些坑、哪些关键决策、哪些钱是必须花的、哪些钱是可以省的。适合正在做大模型后训练、Agent 训练、或者单纯想搞清楚 RL 训练成本结构的同学。不管你是刚入门还是已经跑过几轮实验下面这些内容应该都能对上你的某些经历。2. 整体设计与思路拆解为什么 RL 训练这么贵2.1 RL 和 SFT 的成本结构差异很多人第一次接触 RL 训练时会有一个误解觉得“不就是换个 loss 函数吗能贵到哪去”。这个误解的根源是把 RL 和 SFT 混为一谈了。SFT 是监督微调数据是固定的每个样本前向一次、反向一次成本是可预测的。而 RL 的核心是“采样-评估-更新”的循环每一轮都要重新生成数据而且生成的数据质量直接决定训练效果。我用一个生活化的类比来解释。SFT 像是老师给学生一套标准答案学生照着改改完交作业成本就是“改作业”的时间。RL 像是老师不给答案只给一个评分标准让学生自己写十遍然后老师挑出最好的那遍告诉学生“往这个方向靠”。学生写十遍的成本就是 RL 的采样成本。写十遍当然比改一遍贵而且写得越多、越接近正确答案成本越高。具体到数字上SFT 的算力利用率通常在 40% 到 60%因为前向和反向可以流水线化。而 RL 的算力利用率往往只有 20% 到 35%因为采样阶段是纯推理GPU 利用率上不去而且采样和训练之间还有等待和同步的开销。这个利用率差异直接导致 RL 的“有效算力成本”是 SFT 的两到三倍。2.2 为什么选择在线 RL 而不是离线 RLRL 训练有两条路线在线 RL 和离线 RL。在线 RL 是模型自己生成数据、自己评估、自己更新数据分布随着策略变化而变化。离线 RL 是用一个固定的数据集去训练不依赖实时采样。小米这种级别的实验几乎可以确定是在线 RL。原因很简单离线 RL 虽然便宜但它有一个致命问题——分布偏移。模型在训练过程中会不断进化如果用的是旧策略生成的数据新策略就会在旧数据上过拟合导致训练不稳定甚至崩溃。在线 RL 虽然贵但它保证了数据分布和当前策略一致训练更稳、上限更高。我自己的经验是如果你的任务对推理能力要求高比如数学、代码、Agent 工具调用在线 RL 几乎是唯一选择。离线 RL 更适合那些“策略变化不大”的场景比如简单的格式对齐、风格迁移。小米的 MiMo 强调推理和 Agent这两个方向都要求模型在训练中不断探索新的解题路径所以在线 RL 是必然选择。2.3 奖励设计RL 训练的灵魂RL 训练贵不贵很大程度上取决于奖励怎么设计。奖励设计得好模型收敛快采样效率高钱花得值。奖励设计得差模型在错误的方向上狂奔采样再多也是浪费。奖励设计通常分三类规则奖励、模型奖励、混合奖励。规则奖励是用代码判断答案对不对比如数学题看最终结果、代码题看单元测试是否通过。模型奖励是训练一个奖励模型Reward Model去打分适合那些难以用规则判断的任务比如写作质量、对话流畅度。混合奖励是两者结合用规则做硬约束用模型做软引导。我踩过的一个坑是一开始全用模型奖励结果奖励模型本身有偏差模型学会了“讨好奖励模型”而不是“真正解决问题”。后来改成“规则奖励为主、模型奖励为辅”训练稳定性明显提升。这个经验对做 Agent 训练的人尤其重要因为 Agent 的任务往往有明确的成功/失败信号规则奖励的性价比远高于模型奖励。2.4 算力选型为什么不用消费级显卡热词里出现了“rx6750gre训练大模型”我猜有不少人想用消费级显卡跑 RL。我的建议是小规模实验可以正式训练别想。原因有三个。第一是显存。RL 训练需要同时加载策略模型、参考模型、奖励模型有时候还要加载价值网络。一个 30B 模型用 FP16 存储就要 60GB三个模型就是 180GB消费级显卡的 24GB 显存根本装不下。第二是通信。RL 训练涉及大量的 all-reduce 和 all-gather消费级显卡之间的互联带宽远低于数据中心卡通信会成为瓶颈。第三是稳定性。RL 训练动辄跑几天消费级显卡的散热和供电在长时间高负载下容易出问题。我自己的做法是用小模型验证算法用大集群跑正式训练。比如用 1B 到 3B 的模型在单机上把整个 RL pipeline 跑通确认奖励设计、超参、数据格式都没问题再迁移到大规模集群。这样能把试错成本压到最低。3. 核心细节解析与实操要点3.1 采样策略温度、top-p 和采样数量的取舍RL 训练的采样阶段有几个参数直接决定成本和效果。温度temperature控制生成的随机性温度越高模型探索的路径越多但生成质量越不稳定。top-p控制候选词的累积概率阈值top-p 越小生成越保守。采样数量num_samples决定每个 prompt 生成多少个候选回答。我的经验配置是这样的训练初期用温度 1.0、top-p 0.95、采样数 8让模型充分探索。训练中期降到温度 0.8、top-p 0.9、采样数 4开始收敛。训练后期用温度 0.6、top-p 0.85、采样数 2做精细调整。这个“从探索到收敛”的节奏比固定参数的效果好很多。采样数量对成本的影响是线性的。采样数从 8 降到 4采样成本直接减半。但采样数太少会导致优势估计advantage estimation的方差太大训练不稳定。我试过采样数 2结果训练曲线抖得没法看。所以我的建议是采样数不要低于 4除非你的任务奖励信号非常密集。3.2 优势估计GAE 的参数怎么调优势估计是 RL 训练里最容易被忽视、但影响最大的环节。常用的方法是 GAEGeneralized Advantage Estimation它有两个参数λ 和 γ。γ 是折扣因子控制未来奖励的权重。λ 控制偏差和方差的权衡。γ 通常设 0.99 或 0.995这个没什么争议。λ 就比较讲究了。λ 接近 1优势估计的方差大但偏差小λ 接近 0方差小但偏差大。我的经验是任务越复杂、奖励越稀疏λ 越应该接近 1。比如数学推理任务奖励只在最后一步给出λ 设 0.95 到 0.98 比较合适。如果是 Agent 的多步工具调用每一步都有中间奖励λ 可以降到 0.9 左右。这里有个实操细节GAE 的计算需要保存每个 token 的 value 估计这会占用大量显存。如果显存紧张可以考虑用 token-level 的近似方法或者把序列截断到固定长度。我试过把序列从 4096 截到 2048显存占用降了将近一半效果损失在可接受范围内。3.3 KL 散度约束防止模型跑偏的缰绳RL 训练最怕的事情是模型“跑偏”——为了拿高奖励生成一些语法混乱、逻辑不通但恰好能骗过奖励模型的回答。KL 散度约束就是防止这种情况的缰绳。它衡量的是当前策略和参考策略之间的差异差异越大惩罚越重。KL 系数β的设置很关键。β 太大模型不敢探索训练停滞β 太小模型放飞自我输出质量崩坏。我的经验是β 从 0.04 开始根据 KL 散度的实际值动态调整。如果 KL 散度持续低于 0.5说明约束太松可以适当调大 β如果 KL 散度超过 10说明约束太紧要调小 β。这里有个坑KL 散度的计算方式有两种一种是 token-level 的一种是 sequence-level 的。token-level 更精细但计算量大sequence-level 更粗糙但便宜。我一般用 token-level因为 RL 训练本来就很贵了不差这点计算量精细控制更重要。3.4 梯度累积与批量大小显存和稳定性的平衡RL 训练的批量大小batch size不能太小否则梯度估计的方差太大训练不稳定。但批量大小受显存限制不能无限增大。这时候就要用梯度累积gradient accumulation。我的配置是micro batch size 设为 1 到 2梯度累积步数设为 8 到 16等效批量大小控制在 16 到 32。这个配置在 8 卡 A100 上跑 30B 模型比较稳。如果显存更紧张可以把 micro batch 降到 1梯度累积加到 32但训练速度会明显变慢。还有一个细节RL 训练的批量大小和采样数量是耦合的。如果批量大小是 32采样数量是 8那每个 step 实际处理的 prompt 数量是 4。这个比例要控制好prompt 太少会导致每个 step 的梯度噪声太大。我的经验是每个 step 至少处理 8 到 16 个不同的 prompt低于这个数训练会很不稳。4. 实操过程与核心环节实现4.1 环境搭建从零到跑通第一个 step假设你现在要从零搭一个 RL 训练环境我按自己的实操顺序给你捋一遍。第一步是确定框架。目前主流的 RL 训练框架有 TRL、OpenRLHF、verl 等。TRL 上手快适合小规模实验OpenRLHF 和 verl 更适合大规模分布式训练。如果目标是复现小米这种级别的实验verl 的性价比更高因为它对 vLLM 的集成更好采样效率高。第二步是准备模型和数据。策略模型和参考模型通常是同一个基座模型参考模型冻结策略模型更新。奖励模型可以单独训练也可以用规则代替。数据方面RL 训练需要的是 prompt 集合不需要标注答案但 prompt 的质量直接影响训练效果。我的做法是从 SFT 数据里筛出那些“有明确对错”的 prompt比如数学题、代码题、逻辑题。第三步是配置采样引擎。vLLM 是目前最常用的采样引擎它的 PagedAttention 机制能显著提升吞吐。配置的时候要注意tensor parallel size 要和模型大小匹配30B 模型一般用 4 卡 TPgpu memory utilization 设 0.85 到 0.9留一点余量给梯度更新max model len 要和训练数据的最大长度一致避免截断。第四步是跑通一个 step。先不要管训练效果就让它跑起来看看采样、奖励计算、梯度更新这三个环节能不能串起来。我见过太多人一上来就调参结果跑了几小时发现是数据格式错了。先跑通再调优这个顺序不能反。4.2 奖励函数实现规则奖励的代码细节规则奖励是 RL 训练里最实用的奖励形式。我以数学题为例给你看一个简化版的实现思路。核心逻辑是从模型输出里提取最终答案和标准答案比对对给 1 分错给 0 分格式不对给 -0.5 分。import re def extract_answer(text): # 提取 \boxed{} 里的内容 match re.search(r\\boxed\{([^}])\}, text) if match: return match.group(1).strip() return None def rule_reward(response, ground_truth): answer extract_answer(response) if answer is None: return -0.5 # 格式错误 if answer ground_truth: return 1.0 # 正确 return 0.0 # 错误这个实现看起来简单但有几个细节要注意。第一答案提取要鲁棒模型可能用不同的格式输出答案正则要覆盖多种情况。第二格式惩罚要适度-0.5 是我试过比较合适的值太大会让模型只关注格式不关注内容。第三奖励要归一化把奖励缩放到 -1 到 1 之间避免梯度爆炸。对于 Agent 任务规则奖励会更复杂一些。比如工具调用任务奖励可以拆成三部分工具选择是否正确、参数是否合法、最终结果是否达成目标。我的做法是给每个部分分配权重比如 0.3、0.3、0.4然后加权求和。这个权重需要根据任务特点调整没有万能公式。4.3 训练循环采样、评估、更新的完整流程RL 训练的主循环可以概括为四步采样、评估、计算优势、更新策略。我用伪代码给你展示一下完整流程。for step in range(total_steps): # 1. 采样 prompts sample_prompts(batch_size) responses policy_model.generate(prompts, num_samples8) # 2. 评估 rewards [reward_fn(r, gt) for r, gt in zip(responses, ground_truths)] # 3. 计算优势 values value_model(prompts, responses) advantages compute_gae(rewards, values, gamma0.99, lam0.95) # 4. 更新策略 for epoch in range(ppo_epochs): loss ppo_loss(policy_model, ref_model, prompts, responses, advantages) loss.backward() optimizer.step()这个流程里采样和更新是串行的这是 RL 训练效率低的主要原因。因为采样用的是推理模式更新用的是训练模式两者不能同时进行。有些框架尝试用异步采样来重叠这两个阶段但实现复杂度高而且容易引入数据不一致的问题。我的建议是先把同步版本跑稳再考虑异步优化。还有一个细节是 PPO 的 epoch 数。PPO 通常会对同一批数据做多次更新但 epoch 太多会导致策略偏离采样时的策略太远训练不稳定。我的经验是PPO epoch 设 2 到 4超过 4 就容易出问题。4.4 成本控制哪些钱可以省哪些不能省回到 20 万每小时这个话题。我按自己的经验把 RL 训练的成本拆成“必须花”和“可以省”两类。必须花的钱包括采样算力、梯度更新算力、奖励计算算力。这三块是 RL 训练的核心省了就没法训练。可以省的钱包括调试阶段的算力、失败实验的算力、过度采样的算力。我的省钱策略有三条。第一用小模型做算法验证。1B 模型跑通整个 pipeline 的成本可能只有 30B 模型的百分之一。第二用规则奖励替代模型奖励。规则奖励几乎不消耗算力模型奖励需要额外的前向计算。第三动态调整采样数量。训练初期用大采样数探索训练后期用小采样数收敛能省下不少采样成本。还有一个容易被忽视的点数据质量比数据数量重要。我试过用 10 万条低质量 prompt 训练效果远不如 1 万条高质量 prompt。RL 训练里每条 prompt 都要被采样多次低质量 prompt 的浪费是成倍的。所以宁可花时间筛数据也不要盲目堆数据量。5. 常见问题与排查技巧实录5.1 训练不收敛从奖励曲线找线索RL 训练不收敛是最常见的问题。我的排查顺序是先看奖励曲线再看 KL 散度最后看梯度范数。奖励曲线如果一直平说明模型没有学到东西。可能的原因有三个奖励信号太稀疏、学习率太小、KL 约束太紧。我的做法是先检查奖励分布如果大部分样本的奖励都是 0说明奖励太稀疏需要调整奖励设计。如果奖励有区分度但模型不学就调大学习率或者放松 KL 约束。奖励曲线如果震荡剧烈说明训练不稳定。可能的原因是批量太小、优势估计方差太大、或者奖励尺度不一致。我的做法是增大批量、调小 GAE 的 λ、对奖励做归一化。KL 散度如果持续上升说明模型在跑偏。这时候要调大 KL 系数或者检查奖励函数是不是有漏洞。我遇到过一次模型发现只要输出特定格式就能拿高分结果所有回答都变成那个格式。后来在奖励里加了多样性惩罚才解决。5.2 显存溢出分层排查法显存溢出是 RL 训练的另一大痛点。因为 RL 要同时加载多个模型显存压力比 SFT 大得多。我的排查方法是分层的先看模型加载占了多少再看采样占了多少最后看梯度更新占了多少。模型加载方面30B 模型用 FP16 要 60GB用 8-bit 量化能降到 30GB用 4-bit 量化能降到 15GB。如果显存实在紧张可以考虑用 LoRA 只训练部分参数参考模型用 4-bit 量化。采样方面vLLM 的 KV cache 会占用大量显存可以通过调小 max model len 或者降低 gpu memory utilization 来缓解。梯度更新方面梯度累积和 gradient checkpointing 是标配能省不少显存。我自己的配置是策略模型 FP16、参考模型 4-bit、奖励模型 4-bit、vLLM 的 gpu memory utilization 设 0.85。这个配置在 8 卡 A100 80GB 上跑 30B 模型比较稳。5.3 采样速度慢吞吐优化的几个方向采样速度直接决定训练成本。如果采样慢GPU 利用率上不去钱就白花了。我的优化方向有四个。第一用 vLLM 或 TensorRT-LLM 替代 HuggingFace 的 generate。HuggingFace 的 generate 实现比较通用但吞吐远不如专门的推理引擎。我实测下来vLLM 的吞吐是 HuggingFace 的 3 到 5 倍。第二调大 batch size。采样阶段是纯推理batch size 越大GPU 利用率越高。但 batch size 受显存限制需要权衡。我的做法是先用小 batch 跑通再逐步调大找到显存的上限。第三用连续批处理continuous batching。vLLM 默认开启连续批处理它能让不同长度的序列共享计算显著提升吞吐。如果用的是其他引擎要确认这个功能是否开启。第四减少不必要的同步。采样和训练之间的数据传递、奖励计算和策略更新之间的同步都会造成 GPU 空转。我的做法是把奖励计算放到 CPU 上异步执行让 GPU 尽量不等待。5.4 常见问题速查表问题现象可能原因排查方法解决方案奖励曲线平坦奖励太稀疏、学习率太小检查奖励分布调整奖励设计、调大学习率奖励曲线震荡批量太小、优势方差大检查批量大小和 GAE 参数增大批量、调小 λKL 散度持续上升奖励有漏洞、KL 约束太松检查奖励函数调大 KL 系数、加多样性惩罚显存溢出模型太多、序列太长分层排查显存占用量化、LoRA、梯度累积采样速度慢引擎效率低、batch 太小检查 GPU 利用率换 vLLM、调大 batch训练后期崩坏过拟合、策略跑偏检查验证集表现早停、调大 KL 系数这张表是我自己踩坑总结出来的基本上覆盖了 RL 训练 80% 的问题。剩下的 20% 往往是数据问题或者框架 bug需要具体问题具体分析。5.5 几个反直觉的实操心得最后分享几个我在实操中总结的、和常规认知不太一样的心得。第一个是学习率不是越小越稳。RL 训练的学习率通常比 SFT 小一个数量级但太小会导致训练停滞。我的经验是 1e-6 到 5e-6 之间比较合适具体要看模型大小和任务难度。第二个是参考模型不一定要和策略模型完全一致。有时候用一个稍弱的模型做参考反而能防止策略跑偏。我试过用 SFT 之前的基座模型做参考KL 约束的效果比用 SFT 之后的模型更好。第三个是训练步数不是越多越好。RL 训练很容易过拟合尤其是当奖励函数不够鲁棒的时候。我的做法是每隔一定步数在验证集上评估一次如果验证集奖励开始下降就停止训练。早停能省下不少算力。第四个是Agent 任务的 RL 训练奖励设计比算法选择重要十倍。我见过太多人在 PPO、GRPO、DPO 之间纠结但真正决定效果的是奖励函数能不能准确反映任务目标。把奖励设计好用最简单的 PPO 也能出效果奖励设计不好用最先进的算法也是白搭。这些心得没有什么理论支撑都是从一次次失败实验里攒出来的。RL 训练这件事理论能帮你理解原理但真正让你跑通的是这些细节经验。希望这些内容能帮你少烧一点钱多出一点结果。
