对应 Maps to:CMU 15-779(Fall 2025,Zhihao Jia),Lecture 19 · Wed 11/12 · Guest Lecture: New Problems in LLM Post-training Systems,讲者 Banghua Zhu(UW / NVIDIA)。 依据说明:这一讲的 slides 和录像没有公开,课表也没有列必读论文。 能查到的讲者公开报告是 2024 年 4 月在 UW 的 Towards Principled Post-Training of Large Language Models,讲的是后训练的算法与数据(基于统计决策理论的 RLHF 算法、开放的 RLHF 数据集、Starling-7B、NexusRaven-13B),不是系统。所以本讲不是对这次讲座的转述,而是按题目”后训练系统的新问题”,根据公开的系统论文整理:
- 主线:G. Sheng et al., HybridFlow: A Flexible and Efficient RLHF Framework(EuroSys 2025,开源实现 veRL);W. Fu et al., AReaL: A Large-Scale Asynchronous Reinforcement Learning System for Language Reasoning(NeurIPS 2025);
- 参考:M. Noukhovitch et al., Asynchronous RLHF(ICLR 2025);DeepSpeed-Chat、OpenRLHF、NeMo-Aligner 的公开设计。
课上实际讲了什么、哪些问题是讲者自己的观点,请以讲者的公开材料为准。论文数字只做转述。
rlsys.py(生成 / 训练的时间模型、三种调度的事件驱动模拟器、权重重分片、放置搜索、陈旧数据上的 PPO 玩具)和全部实验都是本讲义自己设计的;时间来自 roofline 模型,回答长度是合成的,不是测量。 配套代码 Code:code/lecture19/(4 个脚本 + 一个共享模块;只需 numpy;最长的约 10 秒) 预计阅读时间:2.5 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标
学完这一讲,你应该能够:
- 说出 RL 后训练(RLHF、RLVR)的一次迭代里有哪些模型、哪些阶段,以及为什么它同时是推理负载和训练负载。
- 解释回答长度的长尾为什么让同步的 RL 大量空等,以及一步重叠、完全异步各自能挽回多少。
- 说明”陈旧度”从哪里来,为什么朴素地在陈旧数据上做 PPO 会变慢,解耦的 PPO 目标怎样修正。
- 计算训练、生成两种并行切分之间切换时的通信量和冗余显存,解释 HybridFlow 的分组方式为什么能做到零冗余。
- 比较”全部共置""两两分组""各自独立”三类模型放置,说明它们分别适合什么规模的集群。
0.2 先修与本讲范围
| 默认你已经会 | 本讲只给直觉,后面再展开 |
|---|---|
| 第 16 讲:连续批处理、解码访存受限、KV 缓存 | RL 算法本身(PPO、GRPO、DPO 的推导) |
| 第 14 讲:张量 / 流水线 / 数据并行、3D 并行 | 奖励模型、验证器的训练与服务 |
| 第 13 讲:ZeRO、训练的显存账 | 智能体(多轮、工具调用)的 RL(§6 简述) |
| 第 18 讲:微调、LoRA(后训练的监督部分) | 第 20 讲的偏好优化(SimPO) |
0.3 本讲地图
§1 RL 后训练的一次迭代:几个模型、几个阶段 ← 代码 01
§2 生成的长尾与调度:同步、重叠、异步 ← 代码 02
§3 陈旧数据:算法要跟着改 ← 代码 03
§4 同一个模型,两种切分:训练 ↔ 生成的权重切换 ← 代码 04 演示 1–3
§5 模型放在哪里,以及怎样写这个程序 ← 代码 04 演示 4
§6 把它们放在一起,以及更多的新问题
§7 论文精读:HybridFlow;AReaL
§8 小结 §9 常见误区 §10 练习 §11 延伸阅读 §12 下一讲预告
0.4 关于 rlsys.py
- 时间模型:沿用第 16 讲的 roofline,换成 H100(3.35 TB/s,BF16 峰值;解码 60% 峰值,训练 MFU 40%),模型带 GQA 的 KV 大小。
- 事件驱动的生成引擎:连续批处理,每个序列记录它的每一段 token 是哪个权重版本生成的;两次事件之间批的组成不变。
- 三种调度:
sync:同一批卡先生成、再训练;overlap:两组卡,生成第 k+1 批时训练第 k 批;async:AReaL 式,连续生成、按 η 限流、权重更新时可选打断。
- 权重重分片:把模型参数看成区间 [0, 1),按并行配置切分,精确计算每块卡要收多少、多存多少。
- 玩具 RL 任务:表格型的”推理题”,只用来比较目标函数在陈旧数据上的行为。
1. RL 后训练的一次迭代 · Anatomy of an RL post-training step
1.1 从 SFT 到 RL
今天的 LLM 在预训练之后有一个后训练阶段:
- 监督微调(SFT,第 18 讲):在高质量的指令—回答数据上做交叉熵训练;
- 基于人类反馈的强化学习(RLHF,InstructGPT 的流程):先用人类的偏好对训练一个奖励模型,再用 RL(PPO)让策略最大化奖励,同时用 KL 惩罚不要离 SFT 模型太远;
- 基于可验证奖励的强化学习(RLVR):数学题的答案对不对、代码能不能通过测试,奖励由规则或验证器给出,不需要奖励模型。推理模型(“思考”很长再回答)主要靠这一类训练。
和 SFT 最大的不同:训练数据是模型自己当场生成的。每一次迭代都要先让当前的策略回答一批问题,再用这批回答训练。
1.2 几个模型、三个阶段(代码 01 演示 1)
PPO 的数据流(HybridFlow 图 1):
| 模型 | 是什么 | 每次迭代做什么 |
|---|---|---|
| actor(策略) | 要训练的 LLM | 生成回答;训练 |
| reference(参考策略) | SFT 模型的冻结副本 | 给回答打 log 概率,算 KL 惩罚 |
| critic(价值模型) | 和 actor 差不多大的 LLM | 估计每个位置的价值;训练 |
| reward(奖励模型) | 从人类偏好训练出的 LLM | 给整条回答打分(RLVR 里换成验证器 / 规则) |
三个阶段:
- 生成(rollout):actor 对一批提示自回归地生成回答——推理负载,访存受限;
- 准备:reference、critic、reward 对生成的序列各做一次前向——推理负载,输入完整、可以并行;
- 训练:算优势,更新 actor 和 critic——训练负载,计算受限。
GRPO 去掉了 critic(用同一个问题的一组回答的平均奖励当基线);RLVR 去掉了奖励模型。但无论哪种,同一个 actor 都要在”推理引擎”和”训练引擎”两种身份之间来回切换。
1.3 时间花在哪里(代码 01 演示 2–3)
7B 的四个模型共置在 16 块 H100 上,1024 条回答(中位数 968、平均 1274、截断在 4096):
| 阶段 | 时间 | 占比 |
|---|---|---|
| 生成 | 25.6 s | 34% |
| 准备(三个模型打分) | 14.7 s | 19% |
| 训练(actor + critic) | 36.1 s | 47% |
回答越长,生成越占大头:
| 回答长度中位数 / 上限 | 256 / 1k | 1k / 4k | 4k / 16k | 8k / 32k |
|---|---|---|---|---|
| 生成占比 | 19% | 34% | 58% | 64% |
HybridFlow 在它的设置下测到生成占 RLHF 时间的 58.9%;推理模型的 RL 里回答长达几万 token(AReaL 用 32k 上下文),生成的比例还会更高。
1.4 生成为什么慢:长尾(代码 01 演示 4)
单看每个 token 的代价,解码并不比训练贵多少:每块卡每秒训练约 8.7k 个 token,解码(每卡 64 条并发)约 9.3k 个。真正的问题是长尾:
- 同样的 1024 条回答,长度有长尾时生成要 25.6 s;全部等于平均长度时只要 9.5 s(2.7 倍);
- 有 31% 的生成时间里,只剩不到 10% 的序列还在跑——GPU 访存受限、批又小,利用率极低;
- 同步的 RL 必须等这一批全部写完才能开始训练。
还在生成的序列数(满格 = 1024 条)随时间的变化:
|████▇▇▆▆▅▅▄▄▃▃▃▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁|
2. 生成的长尾与调度 · Scheduling around the long tail
2.1 三种调度方式
| 方式 | 做法 | 陈旧度 | 代表 |
|---|---|---|---|
| 同步(共置) | 同一批卡先生成、再训练,轮流进行 | 0 | DeepSpeed-Chat、veRL 默认 |
| 一步重叠 | 两组卡,生成第 k+1 批的同时训练第 k 批 | ≤ 1 | 多个系统的”one-step off-policy” |
| 完全异步 | 生成连续不断,训练凑够一批就训练 | 有上限 η | AReaL |
AReaL 的四个组件:
- 可打断的生成 worker:收到”更新权重”请求时,打断正在进行的生成,丢掉旧权重算的 KV,用新权重重新算,再接着生成;
- 奖励服务:例如执行代码、跑单元测试;
- 训练 worker:从回放缓冲区里凑够一批就做 PPO 更新,每条数据只用一次;
- rollout 控制器:在它们之间调度,并且按陈旧度上限限流:提交新的生成请求时要求 ⌊(N_r − 1)/B⌋ ≤ i + η(N_r 是已生成的轨迹数,B 是批大小,i 是当前策略的版本)。
2.2 能快多少(代码 02 演示 1)
1.5B 的模型,16 块 H100(异步时 12 块生成、4 块训练),每步 512 条轨迹,回答中位数 2000、截断在 16384:
| 调度 | 吞吐(k token/s) | 相对同步 | 平均陈旧度 | 最大陈旧度 | 生成忙 | 训练忙 |
|---|---|---|---|---|---|---|
| 同步 | 43.0 | 1.00× | 0 | 0 | 94% | 6% |
| 一步重叠 | 43.4 | 1.01× | 0.88 | 1 | 97% | 25% |
| 异步 η = 0 | 35.6 | 0.83× | 0 | 0 | 79% | 21% |
| 异步 η = 1 | 125.2 | 2.91× | 0.80 | 4 | 100% | 73% |
| 异步 η = 2 | 150.2 | 3.49× | 1.47 | 6 | 100% | 88% |
| 异步 η = 4 | 145.1 | 3.38× | 2.24 | 7 | 100% | 85% |
| 异步 η = ∞ | 134.4 | 3.13× | 2.22 | 7 | 100% | 78% |
AReaL 论文的表(1.5B,32k 上下文):η = 0 / 1 / 2 / 4 / 8 / 16 / ∞ 时 128.7 / 269.3 / 356.6 / 356.6 / 371.7 / 382.4 / 396.8 k token/s;端到端训练时间比同步系统少 2.77 倍。
- 同步:94% 的时间在生成,而且大部分时间被长尾拖着。
- 一步重叠几乎没用:生成仍然按批等最长的那条,而生成本来就比训练慢得多。
- 异步:η = 0 时退化成”同步但只用一部分卡生成”,比共置的同步还慢;η = 1、2 时吞吐跳到约 3 倍——生成引擎一直是满的,短回答写完马上补新的,长回答不再挡住别人。
- η 再大:AReaL 的表里仍然略有上升;我们的模型里不升反降,因为在飞的长回答越来越多,每次更新都要重新预填充它们(§2.3)。
- η 限制的是提交的速度,不是每个 token 的陈旧度:长尾的回答写得久,训练时最旧的 token 可能比 η 还旧(最大陈旧度那一列)。
2.3 打断还是不打断(代码 02 演示 2)
| 吞吐 | 平均陈旧度 | |
|---|---|---|
| η = 2,打断 | 150.2 | 1.47 |
| η = 2,不打断 | 158.7 | 1.61 |
| η = ∞,打断 | 134.4 | 2.22 |
| η = ∞,不打断 | 158.1 | 2.84 |
打断:后半段用新权重生成,陈旧度更低,代价是每次更新都要把所有在飞的上下文重新预填充(吞吐低 5%–15%)。不打断:在飞的序列用旧权重写完(实际系统里要同时留着两份权重,或者等它们写完),陈旧度更高。打断还带来一个算法问题:一条轨迹的不同段来自不同版本的策略(§3.3)。
2.4 分卡与长尾(代码 02 演示 3–4)
- 生成和训练怎样分卡(η = 4):训练用 1 / 2 / 4 / 6 / 8 块卡时,相对同步 0.98 / 1.90 / 3.38 / 3.64 / 3.28 倍。训练的卡太少,训练成了瓶颈、数据堆着变旧;太多,训练的卡闲着。AReaL 的说法是”平衡生成和训练两边的负载来控制陈旧度”;这个比例还会随训练进行(回答越来越长)而变化。
- 长尾越重收益越大:σ = 0.2 / 0.5 / 0.8 时异步加速 1.19 / 2.22 / 3.38 倍。σ = 1.1 时降到 2.68 倍,因为很多回答被截断在上限、而异步引擎里堆积的长回答更多。
- 其他缓解长尾的办法(这里没有实现):
- 过采样后丢掉最慢的几条(会让数据偏向短回答);
- 把没写完的回答留到下一轮接着写(部分 rollout);
- 按长度动态分配微批。
3. 陈旧数据:算法要跟着改 · Off-policy data and the algorithm
3.1 陈旧度从哪里来
异步调度下,训练第 i 步用的数据由第 i − s 版本的策略生成(s 是陈旧度)。这就是”在线但离策略”的 RL(Asynchronous RLHF 的说法):数据是当场生成的,但不是当前策略生成的。两个后果:
- 分布偏移:旧策略的回答不代表当前策略会怎么回答;
- 版本不一致:打断式生成让一条轨迹的前后两段来自不同版本。
3.2 朴素 PPO 为什么变慢(代码 03 演示 1–2)
PPO 的目标:
J(θ) = E[min(u·Â, clip(u, 1 − ε, 1 + ε)·Â)],u = π_θ(a|s) / π_old(a|s)
裁剪把每一步的更新限制在 π_old 附近的”信任区域”里。朴素地用陈旧数据时,π_old 就是生成数据的那个旧策略,而当前策略早就离开了那个区域:比率一开始就在裁剪区间外的样本,梯度直接是 0。
AReaL 的解耦目标(借鉴 Hilton et al. 的做法):把行为策略 π_behav(生成数据的策略)和近端策略 π_prox(信任区域的中心)分开:
J(θ) = E_{a∼π_behav}[ (π_prox / π_behav) · min(u^{prox}·Â, clip(u^{prox}, 1 − ε, 1 + ε)·Â) ],u^{prox} = π_θ / π_prox
π_prox 取”这一步开始更新前”的参数;π_prox / π_behav 是重要性权重,纠正分布的偏移。AReaL 的说法:用行为策略做中心,会把最新的策略拉回到旧的、质量更低的策略附近。
玩具任务(32 道题,每题 16 个候选答案,初始答对的概率 3.5%)上,学到期望奖励 0.8 要几步:
| 陈旧度 s | 0 | 1 | 2 | 4 | 8 | 16 |
|---|---|---|---|---|---|---|
| 朴素 PPO | 61 | 80 | 87 | 109 | 152 | 学不会 |
| 解耦目标 | 61 | 59 | 63 | 61 | 79 | 86 |
| 朴素 PPO 被裁成 0 的有信息样本 | 0% | 6% | 13% | 25% | 38% | 44% |
AReaL 论文表 2(1.5B,AIME24):朴素 PPO 在最大陈旧度 4 时就从 42.0 掉到 23.3;解耦目标到 8 都在 41 以上,到 ∞ 降到 36.9。方向一致:陈旧数据上必须换目标函数,而且陈旧度也不能无限大。
3.3 混合版本的轨迹(代码 03 演示 3)
AReaL 命题 1:一条由策略版本 θ, θ+1, …, θ+k 分段生成的序列,等价于从某一个行为策略 π_behav 采样。代码里的检验:前一个 token 用旧策略、后一个 token 用新策略,联合分布之和为 1;用生成时真实使用的逐 token 概率做重要性加权,估计精确(0.4908 = 0.4908);如果误以为整条都来自旧策略,估计完全失真。所以异步系统要把生成时的 log 概率和样本一起存下来。
3.4 墙钟时间:η 取多少(代码 03 演示 4)
把 02 号脚本的”每步多少秒”和玩具任务的”学会要几步”乘起来(每一步的陈旧度从模拟器测到的分布里抽):
| 调度 | 秒 / 步 | 朴素 PPO:学到 0.8 | 解耦目标:学到 0.8 |
|---|---|---|---|
| 同步 | 35.3 | 2152 s | 2152 s |
| 异步 η = 1 | 11.4 | 808 s | 739 s |
| 异步 η = 2 | 9.6 | 829 s | 617 s |
| 异步 η = 4 | 10.3 | 944 s | 698 s |
朴素 PPO 在陈旧数据上要多走很多步,异步的收益被吃掉一部分;解耦目标基本保住了 3.5 倍。系统设计(异步、打断、限流)和算法设计(解耦目标)必须一起做。
Asynchronous RLHF(ICLR 2025)从另一个角度研究同一个问题:在 RLHF 的几种目标函数里,在线 DPO 对离策略的数据最鲁棒,而且模型越大越鲁棒;在 LLaMA 3.1 8B 的指令跟随任务上,异步训练比同步快约 40%,最终效果相同。
4. 同一个模型,两种切分 · Switching between training and generation
4.1 为什么要重新切分
- 训练:计算受限、要存梯度和优化器状态,通常用大的张量并行 / 流水线并行(例如 7B 用 8 路张量并行);
- 生成:访存受限,小的张量并行、多个副本吞吐更高(例如 7B 用 2 路张量并行、4 个副本)。
如果用同一种切分,生成的吞吐低(HybridFlow 指出 NeMo-Aligner 就是这样);如果用不同的切分,每次迭代都要在两种布局之间搬权重。
4.2 HybridFlow 的 3D-HybridEngine(代码 04 演示 1–2)
训练用 p-t-d(流水线 p 段、张量并行 t 份、数据并行 d 份),生成用 p_g-t_g-d_g,其中 micro-DP 的大小 d_g = p·t / (p_g·t_g):训练的每个数据并行副本,在生成时变成 d_g 个副本。
图 8 的例子(8 块卡,训练 1-4-2 → 生成 1-2-2-2):
| 卡 | 训练时持有 | 生成需要(连续编号) | 复用? | 生成需要(HybridFlow) | 复用? |
|---|---|---|---|---|---|
| G1 | [0, 1/4) | [0, 1/2) | 是 | [0, 1/2) | 是 |
| G2 | [1/4, 1/2) | [1/2, 1) | 否 | [0, 1/2) | 是 |
| G3 | [1/2, 3/4) | [0, 1/2) | 否 | [1/2, 1) | 是 |
| G4 | [3/4, 1) | [1/2, 1) | 是 | [1/2, 1) | 是 |
- 连续编号(生成的张量并行组 [G1,G2]、[G3,G4]…):G2、G3 的训练分片和生成分片不相交,既要收整整一半的模型,又得把训练分片另外存着(下一次训练还要用)——这就是冗余显存。
- HybridFlow 的分组(生成的张量并行组按间隔选 [G1,G3]、[G2,G4]…,micro-DP 组连续 [G1,G2]、[G3,G4]…):每块卡生成时需要的区间包含它训练时持有的区间,训练分片直接复用,只在 micro-DP 组里收缺的那 1/4。
表 2(以模型大小 M 为单位):
| 实现 | 通信量 | 峰值显存 | 冗余显存 |
|---|---|---|---|
| DeepSpeed-Chat(全部 all-gather) | (tpd − 1)/(tpd)·M | M | M/(tpd) |
| HybridFlow-V(模型并行组内 all-gather) | (tp − 1)/(tp)·M | M | M/(tp) |
| HybridFlow | (tp − t_g p_g)/(t_g p_g t p)·M | M/(t_g p_g) | 0 |
代码按区间精确计算,四组配置都和公式一致;生成时 p_g·t_g = 1(每块卡一个完整副本)的那一组,理想情况下没有冗余(表里的冗余是上界)。70B 的 actor、32 块卡、训练 2-8-2 → 生成 1-4:HybridFlow 每卡只收 26 GB、峰值 35 GB;另外两种要收齐 140 GB。
4.3 分开部署时的代价(代码 04 演示 3)
如果训练和生成在不同的卡上(OpenRLHF 的做法),每次迭代要把整个模型从训练端传到生成端:70B 是 140 GB,有效带宽 25 GB/s 时 5.6 s。HybridFlow 引用 OpenRLHF 的数字:最多占迭代时间的 36.4%。好处是两边各用最合适的并行方式、还能同时运行(§2 的异步就需要这样)。共置省掉了传输,但两种负载不能同时跑;分开能同时跑,但要传权重——这是 §2 和 §4 之间的取舍。
5. 模型放在哪里,以及怎样写这个程序 · Placement and programming model
5.1 放置(代码 04 演示 4)
四个模型的分组方式一共 15 种(集合划分,贝尔数 B₄ = 15),从”全部共置在同一组卡上、按时间分片轮流用”(DeepSpeed-Chat)到”各自独立”(OpenRLHF),中间有 NeMo-Aligner 的”actor + ref | critic + reward”。HybridFlow 的自动映射(算法 1)枚举放置方式和每组的卡数,用模拟器估计每种的迭代时间,取最快的。
我们的简化代价模型(工作量 / 卡数 + 固定的梯度同步时间 + 生成的长尾下限):
| 场景 | 卡数 | 最快的放置 | 全部共置 | 两两分组 | 各自独立 |
|---|---|---|---|---|---|
| 全是 7B | 16 | 两两分组 66.5 s | 68.1 | 66.5 | 158.1 |
| 128 | 两两分组 33.4 s | 38.3 | 33.4 | 35.3 | |
| 13B actor + 70B critic / reward | 32 | 全部共置 192.9 s | 192.9 | 203.5 | 291.1 |
| 128 | actor+ref | critic+reward(16, 112)109.1 s | 118.0 | 109.1 | 123.7 |
HybridFlow §8.3 的三条经验:
- 多给 actor 分卡能减少生成的延迟,而生成不能和其他模型并行;
- 每个模型的计算都能把 GPU 用满时,小集群上全部共置最好(论文里 16–64 块卡);
- 集群变大(强扩展)后,批大小固定、每块卡分到的计算变少,通信占比上升,共置不再线性扩展;把 actor 和 critic 放在不同的卡上、在训练和准备阶段并行执行更好。
我们的模型复现了第 3 条的方向(卡越多,分组的优势越大),但转折点比论文早(全是 7B 时 16 块卡就略优于共置)。“各自独立”在小集群上很差:生成阶段只有 actor 那组卡在干活。
5.2 编程模型:单控制器 + 多控制器
HybridFlow 的另一半贡献是编程模型:
- 单控制器(single-controller):一个中心进程按数据流图调度各个模型的执行、协调模型之间的数据传输——灵活,容易写出 PPO、ReMax、Safe-RLHF 等不同的算法(论文图 6:在 PPO 的基础上加减几行代码);但如果用它去指挥每块卡上的每个算子,调度开销太大。
- 多控制器(multi-controller):每块卡一个进程,各自执行同一个程序(SPMD,Megatron、vLLM 都是这样)——高效,但要在一份代码里同时写计算、集合通信、模型之间的点对点传输,难以修改。
- 混合:模型之间用单控制器,模型内部用多控制器;用层次化的 API 封装”一个分布式模型”和”模型之间的数据重分布”(例如按数据并行分发、收集)。
6. 把它们放在一起,以及更多的新问题 · Putting it together
RL 后训练系统的设计空间:
| 维度 | 选项 | 取舍 |
|---|---|---|
| 调度 | 同步 / 一步重叠 / 完全异步 | 吞吐 vs 陈旧度(算法要配合) |
| 生成的权重更新 | 打断 / 不打断 | 陈旧度 vs 重新预填充的开销、多一份权重 |
| 训练和生成的部署 | 共置(轮流)/ 分开 | 免传权重、不能同时跑 vs 能同时跑、要传权重 |
| 并行切分 | 两种切分之间重分片 | 通信量、峰值显存、冗余(HybridFlow 的分组) |
| 放置 | 全部共置 / 分组 / 独立 | 小集群用满 GPU vs 大集群并行执行 |
公开文献和开源系统里正在出现的其他问题(这里只列出,不展开):
- 奖励 / 验证器的服务:RLVR 的验证器可能要执行代码、跑测试、调用外部工具,延迟长、资源需求不同(AReaL 有独立的奖励服务);
- 智能体的 RL:多轮交互、工具调用让一条轨迹在”生成”和”等待环境”之间来回切换,长尾更长;
- 推理引擎与训练引擎的数值不一致:两边用不同的 kernel、精度,算出的 log 概率不完全相同;离策略的修正到底用哪一边的概率,会影响训练的稳定性;
- 训练越来越长的回答:回答长度随训练增长,生成 / 训练的最优分卡比例随之变化(§2.4)。
7. 论文精读 · Paper reading
7.1 HybridFlow: A Flexible and Efficient RLHF Framework(Sheng et al., EuroSys 2025)
1. 问题:RLHF 是一个数据流:每个节点是一个分布式的 LLM 训练或生成程序,每条边是模型之间多对多的数据重分布。怎样既灵活(容易实现各种 RLHF 算法、各种放置)又高效地执行它?
2. 为什么重要又困难:
- 模型的负载各不相同:actor 生成访存受限、训练计算受限;critic、reward 可能比 actor 大得多;
- actor 在训练和生成之间要用不同的并行方式,重分片的通信和显存开销很大(70B 的 actor 每次迭代要搬 140 GB);
- 放置方式影响很大:共置时阶段之间串行、负载不均;分开时一部分卡闲着;
- 传统 RL 框架的单控制器调度大规模分布式计算时开销太大。
3. 以前的工作为什么不行:
- DeepSpeed-Chat、OpenRLHF、NeMo-Aligner 都用多控制器:计算、集合通信、模型间传输混在一份代码里,换一种算法或放置要大改;只支持 PPO、并行方式有限;
- 各自只支持一种放置方式(全部共置 / 各自独立 / 两两分组);
- DeepSpeed-Chat 的重分片要在所有卡上 all-gather,OpenRLHF 存两份 actor 权重并频繁同步,NeMo-Aligner 训练和生成用同一种并行,生成吞吐低。
4. 新意:
- 混合编程模型:模型之间单控制器(灵活编排数据流),模型内部多控制器(高效执行);层次化的 API 封装分布式模型和数据重分布;
- 3D-HybridEngine:同一组卡上训练和生成用不同的 3D 并行,通过新的分组方式做到重分片零冗余、通信最少;
- 自动设备映射:枚举放置方式和卡数分配,配合每个模型的并行策略搜索和模拟器,找出迭代时间最短的映射。
5. 结果:
- 16 台机器 128 块 A100-80GB 上,PPO、ReMax、Safe-RLHF 三种算法;
- 吞吐比 DeepSpeed-Chat、OpenRLHF、NeMo-Aligner 高 1.53–20.57 倍(PPO 7B 上 1.68–8.63 倍、13B 上 2.70–18.96 倍);
- 最优放置随规模变化:16–64 块卡共置最好,96–128 块卡分组或独立更好;
- 重分片的开销显著降低,生成阶段约占 RLHF 时间的 58.9%。
本讲的验证:
- 用区间计算复现了表 2 的通信量、峰值、冗余(图 8 的例子逐卡对照);
- 用简化的代价模型复现了”规模越大,分组越有利”的方向。
- 额外的发现:生成用完整副本时公式里的冗余是上界;我们的模型里转折点比论文早。
局限:
- 面向同步的 RLHF:生成和训练仍然在同一组卡上轮流进行,生成的长尾没有解决(这正是 AReaL 的出发点);
- 自动映射依赖模拟器的准确度和枚举的规模;
- 共置模型时间分片共享 GPU,同一组卡上的模型不能同时运行。
7.2 AReaL: A Large-Scale Asynchronous Reinforcement Learning System for Language Reasoning(Fu et al., NeurIPS 2025)
1. 问题:推理模型的 RL 训练里,回答长达几万 token、长度差异极大。同步系统(生成完一批再训练)里,生成要等最长的那条,GPU 大量空闲;而且同步系统把生成分散到所有卡上,每块卡的解码批变小,进一步落入访存受限的区间,加卡也不能提高吞吐。
2. 为什么重要又困难:
- RL 是推理模型能力的主要来源,训练要上千条长回答一批、跑很多步,系统效率直接决定成本;
- 完全异步就意味着用旧策略的数据训练新策略,算法上的分布偏移会让训练变差;
- 打断正在生成的序列换上新权重,会让一条轨迹混合多个策略版本,违反了 PPO “所有动作来自同一个旧策略”的前提。
3. 以前的工作为什么不行:
- 同步系统(veRL 等)在长回答时利用率低、扩展性差;
- “一步重叠”仍然按批生成,长尾还在;
- 已有的异步 RL(游戏、RLHF)没有处理超长、长度不一的生成和打断带来的版本混合。
4. 新意:
- 系统:完全解耦生成和训练;可打断的 rollout worker(权重更新时丢掉 KV、用新权重重算再继续);独立的奖励服务;rollout 控制器按陈旧度上限 η 限流;训练端优先用最旧的数据、每条只用一次;另有动态微批分配等优化;
- 算法:解耦的 PPO 目标——行为策略和近端策略分开,近端策略取每次更新前的参数;证明混合版本的轨迹等价于一个合法的行为策略(命题 1)。
5. 结果:
- 数学和代码推理任务上,模型最大到 32B;
- 训练速度最多比同步系统快 2.77 倍,最终效果相当或更好;
- 吞吐随 η 增加(128.7 → 396.8 k token/s),强扩展接近线性;
- 消融:没有解耦目标时,稍有陈旧效果就明显下降;有解耦目标时 η ≤ 8 和同步相当,η → ∞ 仍然变差。
本讲的验证:
- 事件驱动的模拟器复现了”η 从 0 到 2 吞吐大幅上升”(约 3.5 倍于同步);
- 打断降低陈旧度、代价是重新预填充;
- 玩具任务复现了朴素 PPO 随陈旧度变慢、解耦目标基本不受影响,并用裁剪比例解释了原因;
- 混合版本的重要性加权在精确计算下无偏。
- 和论文不同的地方:我们的模型里 η > 2 之后吞吐略降(打断时要重算的在飞上下文更多)。
局限:
- 需要调 η 和生成 / 训练的分卡比例,最优值随回答长度变化;
- 解耦目标需要额外计算近端策略的 log 概率;
- 陈旧度无限大时效果仍然下降,异步不是免费的;
- 实验集中在可验证奖励的推理任务上。
7.3 两篇论文之间的联系
- 两条互补的路线:HybridFlow 优化的是”同步 RL 里每个阶段怎样执行得更快”(重分片、放置、编程模型);AReaL 质疑”为什么要同步”,把生成和训练彻底解耦。HybridFlow 的共置让训练和生成轮流用同一组卡,AReaL 恰恰要把它们分开、让它们同时跑——前者省掉了权重传输,后者省掉了等待。
- 都从”生成占大头”出发:HybridFlow 测到生成占 58.9%,AReaL 指出推理模型的长回答让问题更严重。
- 系统和算法的边界变模糊了:AReaL 的系统设计(异步、打断)直接改变了训练数据的分布,必须配合算法修改(解耦目标)。这和第 15、17 讲”系统优化要保证结果不变”不同——在 RL 里,系统可以有意地改变数据,只要算法能接受。
- 一个可以讨论的问题:未来的 RL 系统可能同时需要两者——用 HybridFlow 式的数据流编程和自动映射来管理越来越复杂的多模型、多阶段流程,用 AReaL 式的异步来应对长尾。
8. 小结 · Summary
- RL 后训练 = 推理 + 训练:一次迭代要先生成、再打分、再训练;同一个 actor 在两种身份之间切换。
- 生成占大头,长尾是主因:回答越长生成越占时间(19% → 64%);同样的回答,长度有长尾时生成慢 2.7 倍。
- 调度:同步要等最长的那条;一步重叠几乎没用;完全异步(AReaL)让生成引擎一直满载,吞吐约 3 倍于同步,代价是陈旧的数据。
- 算法要配合:朴素 PPO 在陈旧数据上被裁剪卡住;解耦目标把信任区域的中心换成当前策略,基本保住了异步的收益;混合版本的轨迹要记录逐 token 的行为概率。
- 两种切分:训练要大的模型并行、生成要多副本;HybridFlow 的分组让重分片零冗余、通信最少;分开部署则每次都要传整个模型。
- 放置:小集群全部共置用满 GPU;大集群上分组让不同模型在同一阶段并行。
9. 常见误区 · Common misconceptions
- “RL 训练的瓶颈是训练。” 在长回答的设置下,大部分时间在生成(代码 01:中位数 8k 时 64%),而且是被少数最长的回答拖着。
- “生成慢是因为解码比训练贵。” 单个 token 的代价是同一个量级(每卡每秒约 9k vs 8.7k);慢在长尾——大部分时间 GPU 上只剩几条序列。
- “把生成和训练重叠起来就解决了。” 一步重叠仍然按批等最长的那条(代码 02:1.01 倍);要连续生成、谁写完补谁,才能填满长尾留下的空闲。
- “异步的陈旧度不超过 η。” η 限制的是提交新请求的速度;长尾的回答写得久,最旧的 token 可能比 η 还旧(代码 02:η = 1 时最大陈旧度 4)。
- “陈旧数据直接用 PPO 训练就行,裁剪会兜底。” 正是裁剪的问题:信任区域的中心是旧策略,大量样本一开始就被裁成 0,训练变慢甚至停滞(代码 03:s = 8 时 38% 的样本没有梯度)。
- “训练和生成用同一种并行切分最省事。” 省掉了重分片,但生成的吞吐低;换切分时如果分组不当,还会多存一份冗余的权重(HybridFlow 表 2)。
- “全部共置总是最好。” 小集群上通常是;集群变大后,批大小固定、通信占比上升,分组让模型并行执行更好(HybridFlow §8.3)。
10. 练习 · Exercises(含参考答案)
练习 1 一批 100 条回答:99 条长 100 个 token,1 条长 1000 个 token。假设每一步解码的时间都一样,同步生成这一批要多少步?GPU 槽位的利用率是多少?如果长回答可以不等(异步),每一步平均完成多少有用的工作?
答案:
- 同步要 1000 步(等最长的那条);
- 槽位利用率 = (99 × 100 + 1000) / (100 × 1000) = 10.9%;
- 异步时,短回答写完马上补新的提示,100 个槽位一直是满的,每一步都在做 100 个 token 的有用工作——利用率接近 100%,代价是那条长回答训练时已经陈旧了。
练习 2 批大小 B = 512、η = 2、当前策略版本 i = 5(已完成 5 个训练步)。按 AReaL 的限流规则 ⌊(N_r − 1)/B⌋ ≤ i + η,最多能提交到第几条轨迹?
答案:⌊(N_r − 1)/512⌋ ≤ 7 → N_r − 1 ≤ 4095 → N_r ≤ 4096。也就是说,第 8 批(第 3585–4096 条)可以提交,第 9 批要等第 6 个训练步完成。
练习 3 某个回答 a 的优势 Â > 0。生成它的旧策略 π_behav(a) = 0.10;训练开始时当前策略已经变成 π(a) = 0.20。ε = 0.2。分别算朴素 PPO 和解耦目标下这个样本的梯度是否为 0。
答案:
- 朴素:比率 u = 0.20 / 0.10 = 2 > 1 + ε = 1.2,且 Â > 0,min(u·Â, 1.2·Â) 取被裁剪的那一项,对 θ 的梯度为 0——这个”好”样本白白浪费了。
- 解耦:π_prox = 0.20(这一步开始时的策略),u^{prox} = 1,在裁剪区间内,梯度不为 0;乘上重要性权重 π_prox / π_behav = 2,纠正”这个回答在旧策略下被采到得太少”的偏差。
练习 4 为什么打断式生成要把每个 token 生成时的 log 概率和样本一起存下来?只存”这条轨迹是第几版开始生成的”会怎样?
答案:
- 打断后,轨迹的后半段由新版本生成,真实的行为概率是”每个 token 用当时版本的概率”的乘积(AReaL 命题 1)。
- 只知道起始版本时,训练端会用旧版本的概率当后半段的行为概率,重要性权重就错了。代码 03 演示 3 里,这种错误的估计完全失真(真值 0.49,错误的估计 200 多)。
练习 5 actor 训练用 p = 1、t = 8、d = 1(8 块卡),生成改用 t_g = 2(p_g = 1,micro-DP d_g = 4)。按 HybridFlow 的分组,每块卡要收多少参数?峰值显存多少?70B 的模型(M = 140 GB)是多少 GB?连续编号的分组呢?
答案:
- HybridFlow:通信 (8 − 2)/(2 × 8) = 3/8 M = 52.5 GB;峰值 M/2 = 70 GB;冗余 0。
- 连续编号(HybridFlow-V):先在 8 块卡上 all-gather 整个模型,通信 7/8 M = 122.5 GB,峰值 M = 140 GB,冗余 1/8 M = 17.5 GB——峰值已经超过一块 80 GB 的卡,实际只能逐层地做。
练习 6 训练和生成放在不同的卡上,每次迭代要传 70B 的权重(140 GB),有效带宽 50 GB/s。如果迭代的其余部分要 20 s,传权重占多少?怎样减少这个开销?
答案:
- 140 / 50 = 2.8 s,占 2.8 / 22.8 = 12%。
- 办法:
- 用更快的互连,或多条链路并行;
- 和下一批的生成重叠(异步时生成端先用旧权重继续);
- 只传变化的部分(例如 LoRA 时只传几十 MB 的增量);
- 把训练和生成共置,改成卡内重分片(§4.2)。
练习 7 为什么四个模型的放置方式有 15 种?“全部共置”在什么情况下最好、什么情况下不好?
答案:
- 把 4 个模型分成若干组(组内共置),就是集合 {actor, critic, ref, reward} 的划分,个数是贝尔数 B₄ = 15。
- 全部共置的好处:每个阶段都能用上所有 GPU(生成阶段所有卡一起生成,训练阶段所有卡一起训练)。小集群上每个模型的计算都能把卡用满,共置最好。
- 不好的情况:集群很大、批大小固定时,每块卡分到的计算太少,梯度同步等固定开销占比上升,扩展效率下降;这时把 actor 和 critic 分开,让它们在训练和准备阶段并行执行,等于把固定开销并行掉了一份(代码 04:128 块卡时分组快约 13%)。
练习 8 (开放)你要为”智能体 RL”设计训练系统:每条轨迹是多轮的,模型每说一句话就要调用一次工具(搜索、执行代码),工具的延迟从 0.1 秒到 30 秒不等。§2 的哪些思想还适用?会出现什么新问题?
参考思路:
- 长尾更严重了:轨迹的时长不仅取决于生成长度,还取决于工具延迟。连续生成、异步训练的思想更加重要;
- 生成引擎在等工具时 GPU 空闲,可以把等待中的轨迹的 KV 换出、先服务别的轨迹(类似第 16 讲的抢占),或者让一个引擎同时跑更多的轨迹;
- 陈旧度更难控制:一条轨迹可能跨越很多个训练步,打断 / 不打断的取舍更尖锐;
- 环境本身也是一个需要扩展的服务(沙箱、并发限制、失败重试),奖励的计算可能很贵;
- 重要性加权要覆盖”多轮、每轮的版本不同”的情况,同样要记录逐 token 的行为概率。
11. 延伸阅读 · Further reading
- L. Ouyang et al., Training Language Models to Follow Instructions with Human Feedback(NeurIPS 2022)——InstructGPT,RLHF 的标准流程。
- J. Schulman et al., Proximal Policy Optimization Algorithms(2017);Z. Shao et al., DeepSeekMath(2024)——GRPO。
- M. Noukhovitch et al., Asynchronous RLHF: Faster and More Efficient Off-Policy RL for Language Models(ICLR 2025)。
- J. Hu et al., OpenRLHF: An Easy-to-use, Scalable and High-performance RLHF Framework(2024);Z. Yao et al., DeepSpeed-Chat(2023)。
- J. Hilton, K. Cobbe, J. Schulman, Batch Size-Invariance for Policy Optimization(NeurIPS 2022)——解耦 PPO 目标的出处。
- B. Zhu, E. Frick, T. Wu, H. Zhu, J. Jiao, Starling-7B: Improving LLM Helpfulness & Harmlessness with RLAIF(项目报告,2023 年 11 月)——讲者在后训练数据(Nectar 排序数据集)与算法方面的工作之一。
12. 下一讲预告 · Next lecture
第 20 讲是另一场嘉宾讲座《推进开放语言模型训练的帕累托前沿》(Mengzhou Xia)。slides 同样没有公开;讲者在 Princeton 的博士答辩报告(同名)摘要提到三个方向,讲义按她的公开论文整理:
- 结构化剪枝:从一个大模型剪出小模型再继续训练,只用从头训练约 3% 的算力(Sheared-LLaMA);
- 数据选择:用梯度相似度挑出 5% 的指令数据,效果可以超过用全部数据(LESS);
- 新的后训练方法:不需要参考模型的偏好优化(SimPO)。
共同的主题是:在固定的算力、数据、模型预算下,怎样得到更好的模型——把”质量—成本”的帕累托前沿往外推。