对应 Maps to:Stanford CS349D AI Inference Infrastructure(Spring 2026),#17 Wed May 27 Reinforcement Learning。必读:G. Sheng, C. Zhang, Z. Ye, X. Wu, W. Zhang, R. Zhang, Y. Peng, H. Lin, C. Wu, HybridFlow: A Flexible and Efficient RLHF Framework(EuroSys 2025);Y. Zhong, Z. Zhang, B. Wu, S. Liu, Y. Chen, C. Wan, H. Hu, L. Xia, R. Ming, Y. Zhu, X. Jin, Optimizing RLHF Training for Large Language Models with Stage Fusion(RLHFuse,NSDI 2025)。选读:DeepSeek-AI, DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning(技术报告)。 依据说明:原课没有公开 slides。本讲依据 HybridFlow 和 RLHFuse 的全文,以及 DeepSeek-R1 技术报告(arXiv v2)里与系统有关的部分(GRPO、训练设置、RL 基础设施、训练成本)。§2 的长尾分析、§5 的部分 rollout 与异步、§6 的系统视角和 §7”之后的发展”是我补充的。讲义里的纸上数字全部来自配套代码的实际运行;论文里的数字写成”论文报告”。 配套代码 Code:
code/lecture15/(numpy;4 个脚本 + 1 个模块rl_sim.py:按事件推进的 rollout 模拟器、RLHFuse 的迁移与融合、流水线调度与模拟退火、显式的权重重分片、放置搜索。每个脚本都在 10 秒以内) 预计阅读时间:3–4 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 画出 LLM 强化学习一轮迭代的数据流(生成、准备、训练),说出 PPO 和 GRPO 各需要哪些模型、每个模型做哪种计算(decode、prefill 式的 forward、forward + backward)。
- 解释为什么生成(rollout)往往占一轮的大部分时间,为什么回答长度的长尾让大部分 GPU 在等少数几个样本,以及为什么”加 GPU”治不了长尾。
- 解释 HybridFlow 的混合编程模型(节点间单控制器、节点内多控制器)和 3D-HybridEngine 怎样在训练与生成之间无冗余地切换并行布局,以及放置搜索的思路。
- 解释 RLHFuse 的两种”阶段融合”:把长尾样本迁走、让空出的 GPU 提前做准备阶段;把 actor 和 critic 的训练流水线反向叠在一起互相填气泡。
- 比较融合、部分 rollout、异步三种绕开长尾的办法,说出哪些保持了同步语义、哪些引入了离策略。
- 把 RL 看作”推理 + 训练”的混合负载,用前面各讲的工具(连续批处理、张量并行、前缀共享、投机解码、解耦、多租户)分析它。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲只给直觉,后面再展开 Previewed only |
|---|---|
| 第 1、2 讲:decode 受带宽限制、连续批处理 | 强化学习算法本身的推导(PPO、GRPO 只讲到系统需要的程度) |
| 第 5 讲:投机解码 | 奖励模型的训练、奖励作弊(reward hacking) |
| 第 6 讲:数据 / 张量 / 流水线并行、1F1B、all-gather | 大规模训练的容错与检查点 |
| 第 7 讲:prefill / decode 的解耦(同置还是分开) | MoE 模型的 RL(DeepSeek-R1 的专家并行只点到) |
| 第 12 讲:多个模型共享 GPU |
0.3 本讲地图 Map
§1 LLM 的强化学习是一张数据流图 ← 代码 01
§2 长尾:为什么生成主导、为什么加 GPU 不够 ← 代码 01、02
§3 HybridFlow:混合编程模型、3D-HybridEngine、放置 ← 代码 04
§4 RLHFuse:阶段间融合与阶段内融合 ← 代码 02、03
§5 打破同步:部分 rollout 与异步 ← 代码 02
§6 系统视角
§7 之后的发展
§8–12 小结、常见误区、练习、延伸阅读、下一讲预告
0.4 记号 Notation
| 符号 | 含义 |
|---|---|
| actor / 策略模型 | 正在被训练的 LLM:生成回答,然后被更新 |
| critic / 价值模型 | 估计每个位置的”价值”(PPO 用;GRPO 不用) |
| reference / 参考模型 | actor 的初始版本,冻结;用来算 KL 散度,防止 actor 跑偏 |
| reward / 奖励模型 | 给回答打分(RLHF 用人类偏好训练的模型;RLVR 用规则:答案对不对、代码能不能通过测试) |
| rollout | 生成阶段:actor 对一批提示词生成回答(一个”轨迹”) |
| 生成 / 准备 / 训练 | 一轮迭代的三个阶段(HybridFlow 叫 Generation / Preparation / Training;RLHFuse 叫 Generation / Inference / Training) |
| p-t-d | 流水线、张量、数据并行的大小(HybridFlow 的记法);生成阶段写成 pg-tg-dg-d,dg 是”微数据并行”组的大小 |
| Rt、m | RLHFuse 的迁移阈值(剩余样本数)和接收长尾样本的实例数 |
| N、M | 流水线级数和 micro-batch 数 |
0.5 关于数字 · About the numbers
本讲的数字来自 rl_sim.py 的模拟:每个实例的单步时间来自第 1 讲的纸上 GPU(Llama-3-8B / H100 等),张量并行另加第 6 讲的 all-reduce 时间;准备阶段按 70% 峰值算力、训练按 45% 的 MFU 计时(假设值);回答长度是截断的对数正态分布(形状是假设的)。流水线部分用抽象的时间单位。论文里的数字写成”论文报告”。
1. LLM 的强化学习是一张数据流图 · RL as a dataflow
1.1 为什么要做 RL
预训练让模型学会语言,监督微调(SFT)让它学会按指令回答。但”人类更喜欢哪个回答""这道数学题答对没有”这类信号,很难写成逐 token 的标准答案。强化学习换一种方式:让模型自己生成回答,给回答打分,再把高分回答的概率调高、低分的调低。
- RLHF(从人类反馈中强化学习):先用人类的偏好标注训练一个奖励模型,再用它给 actor 的回答打分。目标是对齐(有用、无害)。
- RLVR(可验证奖励):数学题比对最终答案、编程题跑测试用例,不需要奖励模型。DeepSeek-R1-Zero 就是这样训练的:只奖励”答案正确”和”格式正确”,模型在训练中自己学会了反思、验证、“想得更久”。
两种都要反复做同一件事:大规模地生成,然后训练。对推理系统的研究者来说,这意味着一个新的、非常大的”客户”:RL 训练里的 rollout 就是一次巨大的批量推理。
1.2 一轮迭代的三个阶段
以 PPO 为例(HybridFlow 图 1、RLHFuse 图 1):
┌────────────── 生成 ──────────────┐ ┌──────── 准备 ────────┐ ┌──── 训练 ────┐
提示词 ──▶ actor 自回归地生成回答(decode) ──▶ reference:算 log 概率 ──▶ actor:forward + backward
reward:打分 critic:forward + backward
critic:算价值 (每个 mini-batch 更新一次)
▲ │
└────────── 新的 actor 权重 ◀─────────┘
| 模型 | 生成 | 准备 | 训练 | 计算的性质 |
|---|---|---|---|---|
| actor | 自回归生成 | — | forward + backward + 更新 | 生成受带宽限制;训练受算力限制 |
| critic | — | 一次 forward | forward + backward + 更新 | 受算力限制 |
| reference | — | 一次 forward | — | 受算力限制(像 prefill) |
| reward | — | 一次 forward | — | 受算力限制;RLVR 里换成规则 |
阶段之间有数据依赖:准备要等生成写完,训练要等准备算完,下一轮生成要等训练更新完权重。同一个 actor 在生成和训练两个阶段里做完全不同的计算——这是 HybridFlow 要解决的核心问题之一。
GRPO(DeepSeekMath 提出,DeepSeek-R1 使用)去掉了 critic:对每道题 q,从旧策略采样一组 G 个回答 ,用组内奖励的标准化值作为每个回答的优势(advantage):
直觉:同一道题的回答里,比平均好的就鼓励、比平均差的就抑制,不需要另一个模型去估计”这道题平均能拿多少分”。系统上的后果有两条:少了一个要训练的大模型;每道题要生成一组回答(DeepSeek-R1-Zero 是 16 个),而这一组共享同一个提示词,正好可以用前缀共享(第 3 讲)。
1.3 账本
代码 01 演示 1 算了显存(混合精度 Adam:要训练的模型每个参数约 16 字节,只推理的模型 2 字节):
| Llama-3-8B 规模 | Llama-3-70B 规模 | |
|---|---|---|
| PPO(actor、critic 训练,reference、reward 推理) | 289 GB(3.6 块 H100) | 2.54 TB(31.7 块 H100) |
| GRPO + 规则奖励(actor 训练,reference 推理) | 145 GB(1.8 块 H100) | 1.27 TB(15.9 块 H100) |
这还没算激活和生成时的 KV cache。放不下所有模型同时常驻,就要么分开放(各自在别的阶段闲着),要么同置在一组 GPU 上分时使用、把暂时不用的模型换到 CPU 内存——这就是第 12 讲的多租户问题,只是”租户”变成了同一个训练任务里的几个模型。
代码 01 演示 2 模拟了一轮迭代(512 个样本 = 32 题 × 16 个回答;提示词 512 token;回答长度中位数 956、平均 1,537、最长 8,192;Llama-3-8B;8 块 H100,所有模型同置、依次执行):
| 算法 | 生成 | 准备 | 训练 | 重分片 | 合计 | 生成占比 |
|---|---|---|---|---|---|---|
| PPO | 66.5 s | 8.4 s | 26.2 s | 39 ms | 101.2 s | 66% |
| GRPO | 66.5 s | 2.8 s | 13.1 s | 39 ms | 82.5 s | 81% |
DeepSeek-R1-Zero 的规模(论文报告):每一步 32 道题、每题 16 个回答(训练批 512),回答上限 32,768 token,第 8,200 步之后提高到 65,536;每次 rollout 一次生成 8,192 个回答,随机分成 16 个 mini-batch 各训练一次;一共 10,400 步。用 64 × 8 块 H800 训练了约 198 小时(R1-Zero 约 10.1 万 GPU 小时;包括 R1 在内总共 14.7 万 GPU 小时,按每 GPU 小时 2 美元约 29.4 万美元)。平均每一步约 68.5 秒(198 × 3600 / 10,400)。它的 RL 框架分四个模块:rollout(vLLM 工作进程,MoE 用跨节点的专家并行,热点专家做冗余副本,用 MTP 做自投机解码”有效缩短最长样本的完成时间”)、推理(reward、reference 的 forward)、基于规则的奖励(代码执行器、答案匹配器,异步执行、与 rollout 和推理重叠)、训练(按长度排序 + Best-Fit 打包减少填充,DualPipe 流水线);每个模块做完就把模型从显存换到内存或磁盘,给下一个模块腾地方。
2. 长尾:为什么生成主导、为什么加 GPU 不够 · The long tail
2.1 生成阶段在发生什么
RLHFuse 图 2 用 LMSYS-Chat-1M 说明:各种模型输出长度的 P99.9 都是中位数的十倍以上;一轮要生成上千个样本,几乎每一轮都会遇到长尾样本。准备阶段因为数据依赖必须等所有样本写完。
代码 02 演示 1 画出了 8 个实例同时在写的样本数(512 个样本,横轴是 66.5 秒的生成时间):
0 s ██▇▆▆▅▄▄▄▃▃▃▂▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁ 66.5 s
到生成时间的 25% 还有 132 个样本在写,50% 时只剩 38 个(7%),75% 时只剩 13 个——平均每个实例一两个。decode 每一步都要把 16 GB 的权重读一遍,不管批里有 64 个样本还是 1 个,所以整个生成阶段的平均吞吐(11,829 token/s)只有满批时的约四分之一(47,426 token/s)。代码 01 演示 2:90% 的样本在 29.3 秒内写完,剩下 10% 又用了 37.2 秒,占生成时间的 56%——与 RLHFuse 报告的”长尾样本占生成时间的一半以上”一致。
回答越长,情况越突出(代码 01 演示 3,GRPO):
| 长度(中位数 / 上限) | 平均长度 | 生成 | 生成占一轮 | 最后 10% 占生成 |
|---|---|---|---|---|
| 300 / 1,024 | 402 | 8.1 s | 54% | 4% |
| 1,000 / 8,192 | 1,537 | 66.5 s | 81% | 56% |
| 2,000 / 16,384 | 3,074 | 158.0 s | 84% | 57% |
| 4,000 / 32,768 | 6,148 | 417.9 s | 87% | 59% |
上限只有 1,024 时,11% 的样本写到上限被截断,长尾被”剪平”了;但截断会把还没想完的回答当成错误来惩罚。推理模型的趋势正相反:DeepSeek-R1-Zero 的平均回答长度在训练中持续增长(论文图 1b),上限还要往上提。
2.2 加 GPU 为什么不够
代码 02 演示 2:
| 配置 | GPU | 生成时间 | 最长样本单独写完要多久 |
|---|---|---|---|
| 2 个实例 × TP = 1 | 2 | 98.8 s | 51.8 s |
| 8 个实例 × TP = 1 | 8 | 66.5 s | 51.8 s |
| 32 个实例 × TP = 1 | 32 | 56.2 s | 51.8 s |
| 8 个实例 × TP = 2 | 16 | 37.6 s | 30.1 s |
| 8 个实例 × TP = 4 | 32 | 26.3 s | 22.3 s |
加实例只能让”其他样本”更快写完,最长的那个样本仍然要一个 token 一个 token 地写 8,192 次,每次至少读一遍权重(1 块 H100 上约 6.3 毫秒)——这是一个延迟的下限,吞吐优化帮不上忙。能降低它的是延迟优化:更大的张量并行(每个 token 的权重读取分摊到几块 GPU 上),投机解码(第 5 讲;DeepSeek-R1 用 MTP 自投机解码),以及更快的单步实现。
这给了我们一个有用的视角:RL 的生成阶段前半段是吞吐问题,后半段是延迟问题。前半段需要大批、大量副本;后半段需要低延迟的配置——这和第 7 讲 prefill / decode 的二分很像。本讲后面的几种技术,都是在回答”长尾那段时间,空闲的 GPU 能干点什么”。
3. HybridFlow:混合编程模型、3D-HybridEngine、放置 · HybridFlow
论文卡片 Paper card · HybridFlow(verl)
- 问题:RLHF 的数据流里每个节点是一个分布式的 LLM 程序(训练、推理或生成),每条边是多对多的数据重分发。传统 RL 框架用单个控制器调度一切,对 LLM 的分布式计算开销太大;现有 RLHF 系统用多控制器(每块 GPU 一个程序),计算和数据传输的代码交织在一起,换一种算法或放置就要大改。actor 在训练和生成之间切换并行布局时,通信和显存开销也很大。
- 关键想法:节点间用单控制器(一个 Python 进程按数据流调用各个模型的分布式操作,灵活)、节点内用多控制器(每个模型的分布式计算照常由各 GPU 上的进程执行,高效);用”传输协议”(collect / distribute)封装模型之间的数据重分发;3D-HybridEngine 让 actor 在同一组 GPU 上用不同的并行布局做训练和生成,切换时零冗余、通信最少;一个自动映射算法搜索模型的放置和 GPU 分配。
- 结果(论文报告):PPO、ReMax、Safe-RLHF 上,7B–70B、8–128 块 A100,吞吐是 DeepSpeed-Chat、OpenRLHF、NeMo-Aligner 的 1.53–20.57 倍;训练与生成之间的切换时间平均减少 55.2%,70B 时最多减少 89.1%。开源为 verl。
- 局限:同置的模型分时执行(不做细粒度的 GPU 共享);生成内部的长尾问题不在它的范围内。
3.1 单控制器还是多控制器
单控制器:一个中心进程掌握整个程序,把操作分发给各个工作进程(例如 Ray 上的 RLlib)。好处是全局视角:执行顺序、资源映射、数据流都在一处表达,写起来像单机程序。坏处是每个操作都要从中心发出——LLM 的一次前向有成千上万个算子,分发给几百块 GPU 的开销太大。
多控制器:每块 GPU 上一个进程,各自执行同一份程序(Megatron-LM、vLLM 都是这样)。分发开销小(控制消息在本机的 CPU 和 GPU 之间走)。坏处是没有全局视角:在 RLHF 里,actor 的程序里要写”把结果发给 critic 和 reward”,critic 的程序里要写”在恰当的时刻接收”——计算、集合通信、模型间的点对点传输交织在每个模型的代码里,换个算法(例如去掉 critic)就要改所有相关模型(论文图 2a)。
HybridFlow 的观察:RLHF 的数据流图只有几个节点,在节点之间用单控制器的开销可以忽略;节点内部的分布式计算是开销的大头,继续用多控制器。于是 PPO 写出来就是一个单进程的循环(论文图 6,简化):
for prompts in dataloader:
batch = actor.generate_sequences(prompts) # 第 1 阶段:生成
batch = critic.compute_values(batch) # 第 2 阶段:准备
batch = reference.compute_log_prob(batch)
batch = reward.compute_reward(batch)
batch = compute_advantages(batch, algo_type)
critic.update_critic(batch) # 第 3 阶段:训练
actor.update_actor(batch)
每个调用背后是一个”并行工作组”(3DParallelWorker、FSDPWorker、ZeROWorker 的子类)在多块 GPU 上执行,可以复用 Megatron-LM、FSDP、DeepSpeed、vLLM 的代码。改成 ReMax 只要多调一次 actor 生成、删掉 critic 的几行;改成 Safe-RLHF 多加 5 行。
传输协议:每个模型操作用 @register 绑定一个协议,协议由 collect(把各数据并行组的输出收集起来)和 distribute(把输入按接收方的并行布局分发下去)两个函数组成,内置 8 种(3D_PROTO、DP_PROTO、ONE_TO_ALL 等)。控制器只传”数据的 future”,真正的数据在 GPU 之间直接传输,避免中心瓶颈。模型放在不同的 GPU 上时,输入一到就自动开始执行(异步数据流);放在同一组 GPU 上时按调用顺序执行。ResourcePool 把一组 GPU 虚拟化:两个模型用同一个 ResourcePool 就是同置,用不同的就是分开放——放置方式变了,算法代码一行不改。
3.2 3D-HybridEngine:训练与生成之间的重分片
actor 训练是算力受限的,常用较大的模型并行(例如 7B 切成 8 份放在 8 块 GPU 上);生成是带宽受限的(第 1 讲),模型并行太大反而浪费——更好的是小的张量并行、多几个副本(例如切成 2 份、复制 4 次)。可两种布局之间切换要搬权重:论文提到 70B 的 actor 每轮要从训练搬 140 GB 权重给生成,在两组不同的 GPU 上时最多占一轮的 36.4%。
HybridFlow 让训练和生成用同一组 GPU、同一份权重,生成时的布局记为 pg-tg-dg-d:每个训练的数据并行副本变成 dg 个”微数据并行”副本,。关键在于怎样分组(论文图 8)。设训练是 1-4-2(8 块 GPU,张量并行组 [G1–G4]、[G5–G8]),生成是 1-2-2-2:
- 朴素分组(HybridFlow-V):生成的张量并行组也取连续的 GPU。切换时先在训练组内 all-gather 出完整模型,每块 GPU 再留下自己的生成分片。问题是 G2、G3、G6、G7 的生成分片里没有自己的训练分片,还得另外保存训练分片——冗余。
- HybridFlow 的分组:生成的张量并行组按间隔取 GPU([G1, G3]、[G2, G4]……),微数据并行组取连续的 GPU([G1, G2]、[G3, G4]……)。这样每块 GPU 的生成分片恰好包含它自己的训练分片,只需在微数据并行组内交换另外 dg − 1 份。
论文表 2 的公式(M 是模型大小):
| 通信量 | 峰值显存 | 冗余 | |
|---|---|---|---|
| DeepSpeed-Chat(ZeRO-3 → TP) | (tpd − 1) / (tpd) · M | M | M / (tpd) |
| HybridFlow-V | (tp − 1) / (tp) · M | M | M / (tp) |
| HybridFlow | (tp − tg·pg) / (tg·pg·tp) · M | M / (tg·pg) | 0 |
代码 04 演示 1 没有直接套公式,而是显式地算出每块 GPU 持有哪些分片,得到的数字与公式一致:
| 模型:训练 p-t-d → 生成 pg-tg | 做法 | 每块 GPU 收 | 峰值 | 冗余 |
|---|---|---|---|---|
| Llama-3-8B:1-8-1 → 1-2 | HybridFlow-V | 0.875 M(14.05 GB) | 1.000 M | 0.125 M |
| HybridFlow | 0.375 M(6.02 GB) | 0.500 M | 0 | |
| Llama-3-70B:8-8-2 → 1-8 | DeepSpeed-Chat | 0.992 M(140.01 GB) | 1.000 M | 0.008 M |
| HybridFlow-V | 0.984 M(138.90 GB) | 1.000 M | 0.016 M | |
| HybridFlow | 0.109 M(15.43 GB) | 0.125 M | 0 |
70B 时,前两种做法要在每块 GPU 上拼出一整个 141 GB 的模型——根本放不进 80 GB 的 H100,只能一层一层地收,更慢。实现上,HybridFlow 把生成用的权重在训练时换到 CPU 内存、切换时再换回来,生成完把 KV cache 也换出去。论文报告:切换时间平均减少 55.2%(11.7 秒),70B 时最多减少 89.1%(78.2 秒)。
生成用多大的张量并行(论文图 15:16 块 GPU,训练 1-8-2):论文实测 7B 用 tg = 2、13B 用 tg = 4 时生成最快(生成延迟比 tg = 8 分别低 60.3% 和 36.4%),tg = 8(和训练相同,NeMo-Aligner 的做法)最慢;更小的 tg 也不好,因为每块 GPU 要放更多 KV。代码 04 演示 2:
| 模型 | tg = 1 | tg = 2 | tg = 4 | tg = 8 |
|---|---|---|---|---|
| Llama-3-8B | 65.8 s | 45.0 s | 35.6 s | 42.8 s |
| LLaMA-13B(多头注意力) | 179.1 s(抢占 28 次) | 140.0 s | 108.6 s | 107.3 s |
我们的结果有同样的 U 形,但最好的 tg 偏大:长尾阶段决定时间的是单个 token 的延迟(§2.2),tg 越大延迟越小;我们的通信模型(ring all-reduce 的启动延迟和带宽)比真实便宜,所以 tg = 8 的惩罚来得晚。
3.3 放置:同置还是分开
四个模型有 15 种划分方式(贝尔数),从”全部同置”(DeepSpeed-Chat)到”各自独立”(OpenRLHF),中间有”actor + reference 一组、critic + reward 一组”(NeMo-Aligner)。HybridFlow 的算法 1:枚举每种划分;每个同置组按显存算出最少要多少 GPU,再枚举 GPU 的分配;对每个模型用模拟器搜索最好的并行策略;用 d_cost 估计一轮的时间——同一组的模型在同一阶段串行(时间相加),不同组在同一阶段并行(取最大),各阶段相加。为了加速,缓存”某个模型在 A 块 GPU 上的最好并行策略”,搜索最多半小时。
论文的三条经验(§9):多给 actor 一些 GPU,因为生成不能和其他模型并行;小集群时全部同置最好;大集群时把 actor 和 critic 分开放,让训练和准备阶段并行。论文图 12:16–64 块 GPU 时同置最好;34B 在 96–128 块、13B 在 96 块时两两分组最好;13B 在 128 块时各自独立最好(actor 64 块、critic 32 块、reference 和 reward 各 16 块)。
代码 04 演示 3 用一个粗糙的成本模型复现了这个趋势,并且说明了为什么:
| GPU 数 | 不计梯度同步:同置 | 两两分组 | 计入梯度同步:同置 | 两两分组 | 计入后搜索到的最好放置 |
|---|---|---|---|---|---|
| 16 | 169.0 s | 240.4 s | 188.5 s | 241.4 s | 全部同置 |
| 64 | 71.2 s | 89.3 s | 91.7 s | 99.3 s | 全部同置 |
| 128 | 55.7 s | 63.4 s | 76.4 s | 73.5 s | critic(40)+ 其余三个(88):71.6 s |
- 如果计算完美地随 GPU 数线性扩展,同置永远不会比分开差:同一阶段的几个模型无论并行还是串行,总的 GPU·秒相同,而同置不让任何 GPU 闲着。
- 现实里扩展不完美。数据并行每次更新都要 all-reduce 一份梯度(13B 是 26 GB),跨机器时这一项几乎不随 GPU 数变化(ring all-reduce),而计算随 GPU 数下降;同置时 actor 和 critic 轮流训练,要付两份同步,分开时两者同时进行。所以 GPU 越多,分开越划算。
- 生成被长尾卡住、GPU 多到一定程度就不再变快(§2.2),所以分开放时少给 actor 一些 GPU 损失不大。
我的第一版用”每块 GPU 分到的数据越少效率越低”的经验曲线,在合理的参数下看不到拐点;显式地计入梯度同步之后才出现(代码 README 第 4 条)。拐点的位置取决于这个粗糙的模型,只有趋势可信。
3.4 评测
论文报告:PPO 上 HybridFlow 平均比 DeepSpeed-Chat 快 3.67 倍(最多 7.84 倍)、比 OpenRLHF 快 3.25 倍(最多 5.93 倍)、比 NeMo-Aligner 快 12.52 倍(最多 20.57 倍;NeMo-Aligner 的生成引擎没有 KV cache,生成占它一轮的 81.2%);70B 时平均加速最大(9.64 倍)。在 7B、128 块 GPU 上仍比最好的基线快 1.53–1.71 倍。强扩展效率平均 66.8%。
4. RLHFuse:阶段间融合与阶段内融合 · RLHFuse
论文卡片 Paper card · RLHFuse
- 问题:现有 RLHF 系统把一轮看作若干”任务”的组合,在任务层面选并行策略、减少切换开销,却忽略了任务内部的结构。生产中有两个问题让 GPU 利用率很低:生成阶段的数据倾斜(长尾样本)和训练阶段的流水线气泡。
- 关键想法:把任务拆成更细的子任务,跨任务融合执行。阶段间融合:生成和准备之间的依赖其实是逐样本的;当剩余样本少于阈值 Rt 时,把它们迁移到少数几个实例上,空出的实例立刻开始准备阶段。阶段内融合:actor 和 critic 的训练互相独立,把两条流水线反向叠在同一组 GPU 上,互相填气泡;用模拟退火搜索融合调度。
- 结果(论文报告):在 256 块 Hopper GPU 的生产集群上(13B–65B 的 LLaMA,HH-RLHF),吞吐是 DeepSpeed-Chat 的 2.5–3.7 倍、ReaLHF 的 1.4–2.4 倍、自己的无融合版本(RLHFuse-Base)的 1.2–1.4 倍;生成 + 准备快 1.2–1.6 倍,训练快 1.2–1.3 倍。
- 局限:Rt 要按输出长度的分布离线模拟选取,训练过程中分布会变;准备和训练之间仍是同步屏障(每个 mini-batch 要从全部样本里随机抽,分布要一致)。
4.1 两个问题
- 数据倾斜(§2):生成长度长尾,准备阶段要等最后一个样本。论文在一个上千亿参数的内部模型上观察到,长尾样本(不到 1%)占了生成时间的一半以上,最大长度越大越严重。
- 流水线气泡:大模型训练离不开流水线并行(第 6 讲),1F1B 调度的气泡比例是 。增大 micro-batch 数 M 能减小气泡,但 RL 的一轮先切成若干 mini-batch(每个更新一次参数),再分给数据并行组,最后才切 micro-batch——M 常常和级数 N 差不多,气泡接近一半。交错式 1F1B 能降低气泡,但通信加倍、各级更不均衡。
代码 03 演示 1 用调度模拟器验证了公式:N = 16、M = 16 时气泡 48.4%,M = 64 时 19.0%。
4.2 阶段间融合:把长尾迁走
观察:准备阶段对每个样本的计算互相独立,一个样本写完就可以开始它的准备——依赖是逐样本的,不是逐阶段的(准备和训练之间就不行:训练的每个 mini-batch 要从全部样本里随机抽取,保持分布一致)。
做法(论文 §4.2):
- 何时迁移:剩余样本数降到 Rt 时。太早,长尾实例负担太重、生成本身变慢;太晚,可重叠的时间太少。Rt 通过离线模拟选取(在训练数据上试生成、估计长度分布,模拟 Rt 从批大小的 5% 到 95% 的总时间),运行中按新的样本更新。论文图 9:Rt 约为批大小的 20% 时最好。
- 迁到哪里:选 m 个实例接收剩余样本。约束一:——decode 受带宽限制,“只要批不超过使 GPU 饱和的大小 BSmax,每步时间几乎不变”,这样长尾的生成时间不受影响;约束二:接收实例的显存放得下这些样本的 KV。选剩余样本最多的 m 个实例,迁移量最少。
- 怎样迁移:要么通过 RDMA 把已经生成的 KV cache 传过去,要么只传 token、在目标实例上重新 prefill。论文的集群网络快,选前者,开销可以忽略。
- 迁移后,空出的 n − m 个实例换上准备阶段的模型,先处理已写完的样本,长尾样本写完后流式地交给它们。论文发现一次迁移通常就够了:长尾的生成时间往往比整个准备阶段还长。
代码 02 演示 3 在模拟器里实现了这四步(8 个实例,Rt 与 m 的扫描):
| 准备阶段 | 串行 | 按论文的规则(BSmax = 256) | 扫描到的最好 (Rt, m) |
|---|---|---|---|
| reference、reward、critic 都是 8B(8.4 s) | 75.0 s | 77.2–88.6 s(反而更慢) | Rt = 10%、m = 5:67.6 s(1.11×) |
| reference 8B,reward、critic 70B(56.3 s) | 122.8 s | 最好 89.9 s(Rt = 30%、m = 2) | 同左:1.37× |
两点值得展开:
- 收益的上限是”能被藏起来的准备时间”。准备阶段只有 8 秒时,再好的融合也只能省 8 秒;准备阶段 56 秒时(两个 70B 模型),1.37 倍与论文的 1.2–1.6 倍相当。论文的设置里 critic 和 reward 常常比 actor 大(13B / 33B、33B / 65B),准备阶段很重。
- “每步时间几乎不变”的前提在长上下文时不成立。长尾样本的上下文有几千 token,decode 每步要读的 KV 随批大小线性增长(第 1 讲);把长尾挤到一两个实例上,每一步明显变慢。按论文的规则(m = ⌈Rt / 256⌉,往往只有 1–2 个实例),在准备阶段轻的那组里融合反而比串行慢。m 应当按”长尾变慢多少”来选,而不只是按批大小的上限。这是我们的模拟与论文的一处不同(代码 README 第 1 条)。
4.3 阶段内融合:两条反向的流水线
观察:训练阶段的 actor 和 critic 互相独立。Chimera 曾经为单个模型提出双向流水线:复制一份模型,两份以相反方向流水,互相填气泡(代价是多一份权重)。RL 里天然有两个模型,不用复制。
难点:Chimera 的两条流水线完全对称;RL 的 actor 和 critic 大小不同、并行配置也不同。RLHFuse 先把问题规整化:如果两者的张量并行大小不同(),就把模型 B 每 s 个连续的级合并成一级,使两者每一级用的 GPU 数相同;再把问题看成 条模型 A 的流水线和 条模型 B 的流水线融合(例如一个 16 级的 65B actor 和两个各 8 级的 33B critic)。
搜索:调度是一个矩阵 S,S[i][j] 是第 i 级执行的第 j 个子任务;合法的调度要满足数据依赖、无死锁、每级的激活显存不超过上限。目标是完成时间最短,同样短时显存更低。算法:
- 用贪心算法(能调度就调度,两个模型都就绪时优先大模型)得到初始解;
- 模拟退火(论文算法 1):邻居 = 在某一级上交换两个相邻的子任务(算法 2,无效就重新抽);能量 = 完成时间,用带记忆的递归按”同级前一个任务”和”上一级同一个 micro-batch”两类依赖算(算法 3);
- 再跑一轮只优化显存的退火(只接受完成时间不变差的邻居);
- 用 MPI 在几百个 CPU 核上以不同种子并行搜索。论文报告大多数设置下达到下界;65B / 16 级 + 33B / 8 级时,融合后的时间和单独训练 65B 一样——critic 的训练被完全藏进了 actor 的气泡(论文图 10)。
代码 03 演示 2 实现了这一切(时间单位:一个 micro-batch 在一级上的 forward;backward 是 2):
| 设置 | 串行 | 贪心 | 按 1F1B 叠加 | 模拟退火 | 下界 | 加速 |
|---|---|---|---|---|---|---|
| 两个相同模型,8 级 × 8 | 90 | 69 | 61 | 61 | 57 | 1.48× |
| 两个相同模型,8 级 × 16 | 138 | 129 | 109 | 109 | 105 | 1.27× |
| 13B actor + 33B critic,各 8 级 × 8 | 259 | 231 | 232 | 225 | 162 | 1.15× |
| 65B(16 级)+ 33B(2 × 8 级) | 749 | 523 | 482 | 482 | 381 | 1.55× |
融合确实有效,加速 1.15–1.55 倍,与论文的”训练阶段 1.2–1.3 倍”同一量级。直觉:正向的流水线在前几个设备上末尾空闲(等 backward 传回来)、在后几个设备上开头空闲(等 forward 传过来),反向的流水线正好相反。但我们的模拟退火没有达到下界:第一版用”初始温度 = 完成时间”(论文的设定)几乎是随机游走,降到 1% 后也只在一组里有改进;“按 1F1B 叠加”这个初始解比贪心好得多。论文在 768 个 CPU 核上并行搜索,我们只用一个种子、几千步。融合的代价是激活峰值略高(例如 8 → 9),论文用第二轮退火把它压回串行的水平,我们没有实现。
4.4 其他优化与评测
RLHFuse 基于 Megatron-LM,约 7,000 行代码。并行策略按 ReaLHF、HybridFlow 的”先建模、再搜索”选定;生成用自研的推理引擎(连续批处理、前缀共享、分块 prefill);把 GAE(广义优势估计)的递推展开成一次矩阵乘法,减少内核启动;训练时按序列长度把 mini-batch 均匀分给数据并行组(避免掉队者);reference 和 reward 的权重不变,常驻 CPU 内存、按需换入并与前一个任务重叠。评测里”其他开销”(数据传输、权重重分发、迁移)不到一轮的 3%。
5. 打破同步:部分 rollout 与异步 · Beyond synchronous RL
融合保持了同步 RL 的语义:每一轮的所有样本都由同一版策略生成。如果算法能容忍一点”离策略”(off-policy),还有更激进的办法。代码 02 演示 4:
部分 rollout:每一轮每个样本最多再写 seg 个 token,没写完的保留已生成的部分,下一轮接着写(Kimi k1.5 等系统用过这种思路):
| seg | 每轮生成时间 | 每秒写完的样本 | 平均跨越几轮 | 最多跨越几轮 |
|---|---|---|---|---|
| 8,192(不截断) | 66.8 s | 7.7 | 1.00 | 1 |
| 2,048 | 27.1 s | 18.9 | 1.35 | 4 |
| 1,024 | 21.1 s | 23.8 | 1.93 | 8 |
长尾样本不再拖住整轮,每秒写完的样本数是原来的 3 倍。代价:一个长样本的不同片段来自不同版本的策略(最多跨 8 轮);每轮的训练数据里短样本偏多。
一步异步:把 GPU 分成生成和训练两组同时工作,第 i 轮训练时第 i + 1 轮已经在生成(16 块 H100,GRPO,每轮 1,024 个样本)。同步、同置时每轮 64.4 + 15.4 = 79.8 秒;12 块生成 + 4 块训练时 69.3 秒(1.15 倍);8 + 8 时 74.8 秒;4 + 12 时 99.0 秒(反而更慢)。因为生成被长尾卡住、多给 GPU 也快不了多少,拿走几块去训练几乎不损失生成速度;但生成占一轮的 80% 时,异步最多省下准备 + 训练那十几秒。代价是训练用的样本落后一版策略。
三种办法回答的是同一个问题——长尾那段时间,空闲的 GPU 能不能干点别的:
| 办法 | 空闲 GPU 去做什么 | 算法语义 |
|---|---|---|
| 阶段间融合(RLHFuse) | 提前做准备阶段 | 不变(同步) |
| 部分 rollout | 开始下一轮的生成 | 样本跨越多个策略版本 |
| 异步 | 训练(与下一轮生成重叠) | 样本落后一版(或几版)策略 |
6. 系统视角 · A systems view
RL 是推理与训练的混合负载。 生成阶段是一个巨大的离线批量推理任务,前面各讲的工具都用得上:连续批处理(第 2 讲)、前缀共享——同一题的 G 个回答共享提示词(第 3 讲)、投机解码缩短长尾(第 5 讲)、张量并行降低单 token 延迟(第 6 讲)、MoE 的专家并行与冗余专家(第 8 讲;DeepSeek-R1 的 rollout)。但它和在线服务有两点不同:没有每个请求的 SLO,目标是一轮的完成时间(类似第 13 讲 Parrot 的”任务组”);而且它和训练争用同一批 GPU。
同置还是分开,是第 7 讲的老问题。 prefill / decode 是否解耦、RL 的生成与训练是否放在同一组 GPU 上,背后是同一个权衡:同置让资源不闲置、但两种计算互相切换(重分片、换入换出);分开让每种计算用最合适的配置、但要传数据(KV cache、权重)并承受各自的空闲。HybridFlow 的放置搜索、RLHFuse 的迁移、异步 RL 的 GPU 切分,都是在这个光谱上找位置。
权重同步是新的”KV 传输”。 第 7、9 讲里,跨机器搬的是 KV cache;在 RL 里,每轮都要把新权重从训练布局搬到生成布局(HybridFlow 的重分片),异步时还要跨机器广播给生成集群。它和 KV 传输一样,决定了”分开放”的代价。
延迟和吞吐在同一个阶段里交替。 生成的前半段要吞吐(大批、多副本),后半段要延迟(大张量并行、投机解码)。理想的系统应当在一轮之内动态地改变配置——RLHFuse 的迁移就是这个方向的一步。
7. 之后的发展 · Since then
- verl(HybridFlow 的开源实现)成为常用的 RL 训练框架之一,生成后端可以选 vLLM 或 SGLang;OpenRLHF 等框架也持续发展。
- 异步与部分 rollout:Kimi k1.5 的技术报告使用部分 rollout 处理长回答;AReaL 等系统把生成和训练完全解耦,生成不再等待训练,用算法上的修正处理策略的版本差。
- 智能体 RL:rollout 里夹着工具调用、代码执行、网页交互(第 13 讲的智能体程序变成了训练数据的来源),每个样本可能要在沙箱里执行很多步——第 12 讲的冷启动、第 13 讲的程序级调度在这里重新出现。
- 推理模型的回答越来越长,长尾和生成占比的问题只会更突出;投机解码、KV cache 压缩、长上下文的注意力内核都被用到 rollout 里。
8. 小结 · Summary
- LLM 的 RL 是一张数据流图:actor 生成,reference / reward / critic 准备,actor / critic 训练。PPO 要伺候四个模型,GRPO 去掉 critic、规则奖励再去掉 reward 模型。8B 规模的 PPO 光是权重和优化器状态就要约 290 GB(代码 01)。
- 生成往往占一轮的大部分(代码 01:PPO 66%、GRPO 81%,回答越长越高),而其中一半以上的时间花在最后 10% 的长尾样本上;加 GPU 只能贴近”最长样本单独写完”的下限,要靠降低单 token 延迟的手段(张量并行、投机解码)才能压低它(代码 02)。
- HybridFlow:节点间单控制器、节点内多控制器,几行代码就能写出 PPO、ReMax、Safe-RLHF;3D-HybridEngine 让训练和生成在同一组 GPU 上用不同的并行布局,无冗余地切换(70B 时每块 GPU 要收的权重从约 139 GB 降到约 15 GB,代码 04);放置搜索在小集群选同置、大集群把 actor 和 critic 分开(我们的模型里,要计入梯度同步才出现这个拐点)。
- RLHFuse:阶段间融合把长尾迁走、提前做准备阶段,准备阶段重时有效(代码 02:1.37 倍),轻时有限,而且长上下文让”每步时间不变”的假设失效;阶段内融合让 actor 和 critic 的反向流水线互相填气泡(代码 03:1.15–1.55 倍)。
- 部分 rollout 和异步用”一点离策略”换更高的吞吐(代码 02:每秒写完的样本 3 倍;异步 1.15 倍)。所有这些办法都在回答:长尾那段时间,空闲的 GPU 能干点什么。
9. 常见误区 · Common pitfalls
- “RL 训练主要是训练,推理系统帮不上忙。” 生成往往占一轮的大部分,而且是带宽受限的 decode(代码 01)。
- “生成慢就多加几个副本。” 长尾样本是串行地一个 token 一个 token 写的,副本再多也快不过它单独写完的时间(代码 02 演示 2)。
- “生成用和训练一样的并行配置最省事。” 训练要大的模型并行,生成要小的张量并行、多副本;用同一种配置会让生成很慢(HybridFlow 图 15;代码 04 演示 2),关键是让切换变便宜(3D-HybridEngine)。
- “把所有模型放在同一组 GPU 上永远最好。” 小集群时是;大集群时梯度同步等固定开销让分开放更划算(代码 04 演示 3)。
- “RLHFuse 的迁移总能加速。” 收益不超过准备阶段的时间;接收实例太少时长尾反而变慢(代码 02 演示 3)。
- “decode 的批不超过某个大小,每步时间就不变。” 只在上下文短、读权重为主时成立;长上下文时 KV 读取随批大小线性增长(第 1 讲;代码 02 演示 3)。
- “准备阶段和训练阶段也可以像生成和准备一样逐样本融合。” 不行:训练的每个 mini-batch 要从全部样本里随机抽取,保持分布一致(RLHFuse §4.1)。
- “部分 rollout 和异步只是工程优化。” 它们改变了”样本由哪个版本的策略生成”,需要算法能容忍离策略(§5)。
10. 练习 · Exercises
练习 2、3、4 的参考答案里的数字来自
rl_sim.py的函数或代码的实际输出。
练习 1(GRPO 的优势)。一道题的 4 个回答奖励是 [1, 0, 0, 1]。(a) 每个回答的优势是多少?(b) 如果 4 个回答都对(或都错)呢?(c) 这对系统有什么启示?
参考答案
(a) 平均 0.5、标准差 0.5,优势 [1, −1, −1, 1]。(b) 标准差为 0,所有回答的优势都是 0(实现里分母加一个小常数),这道题对梯度没有贡献。(c) 这些题的生成算力被浪费了。一个系统层面的应对是”动态采样”:发现一组回答全对或全错时丢掉它、补采别的题,保证每个训练批里都有有效信号——代价是生成量变得不确定,进一步加重了”等最后几个样本”的问题。
练习 2(1F1B 的气泡)。(a) N = 16 级、M = 16 个 micro-batch 时气泡是多少?(b) 要让气泡低于 10%,M 至少要多大?(c) RL 里一轮 1,024 个样本,分成 8 个 mini-batch,数据并行 4 路,每个 micro-batch 2 个样本,M 是多少?
参考答案
(a) 15 / 31 = 48.4%(代码 03 演示 1 的模拟与公式一致)。(b) 15 / (15 + M) < 0.1 → M > 135,至少 136。(c) 每个 mini-batch 128 个样本,每个数据并行组 32 个,每个 micro-batch 2 个样本 → M = 16,气泡 48.4%。这就是 RLHFuse 说的”RL 里 M 常常和 N 差不多”:为了每个 mini-batch 更新一次参数,批被切得很碎。
练习 3(重分片的公式)。训练布局 p = 4、t = 8、d = 2,生成用 pg = 1、tg = 4。(a) dg 是多少?(b) 三种做法每块 GPU 要收多少(以 M 为单位)?(c) HybridFlow-V 下一个副本的 32 块 GPU 里有几块的生成分片包含自己的训练分片?
参考答案
(a) dg = pt / (pg·tg) = 32 / 4 = 8。(b) DeepSpeed-Chat:(64 − 1) / 64 ≈ 0.984;HybridFlow-V:(32 − 1) / 32 ≈ 0.969;HybridFlow:(32 − 4) / (4 × 32) ≈ 0.219。可以用 reshard(8, 4, 2, 4, 1, method) 核对。(c) 朴素分组下 GPU r 的生成分片是 r mod 4,覆盖训练分片 8(r mod 4) … 8(r mod 4) + 7;r 要落在里面,需要 r // 8 = r mod 4,32 块里有 r = 0、4、9、13、18、22、27、31 这 8 块满足(reshard 返回的 overlap_gpus 也是 8),其余 24 块都要为训练另外保留自己的分片。HybridFlow 的分组下 32 块全部满足。
练习 4(长尾的下限)。用 Instance(LLAMA3_8B, H100_SXM, tp).step(1, 1, c, c) 可以算出 batch = 1、上下文 c 时一步的时间:tp = 1 时上下文 512 到 32,768 之间每步 6.1–7.7 毫秒,tp = 4 时 2.7–3.1 毫秒。(a) 一个 32,768 token 的回答单独写完,tp = 1 和 tp = 4 各要多久?(b) 如果投机解码平均每次 forward 接受 2 个 token,(a) 的时间大约变成多少?
参考答案
(a) 逐步累加(代码里按每 64 步取一次中点):tp = 1 约 227 秒,tp = 4 约 94 秒(tp = 8 时约 102 秒,all-reduce 开始吃掉收益)。(b) 每次 forward 产出 2 个 token,步数减半;一次验证 forward 比单 token 的 decode 略贵,粗略估计 tp = 1 约 115–130 秒、tp = 4 约 50–55 秒。这正是 DeepSeek-R1 在 rollout 里用 MTP 自投机解码的原因:长尾阶段的瓶颈是延迟,不是吞吐。
练习 5(DeepSeek-R1-Zero 的算术)。论文报告:64 × 8 块 H800,约 198 小时,10,400 步;每次 rollout 生成 8,192 个回答,分成 16 个 mini-batch 各训练一次。(a) 平均每步多久?每次 rollout 周期(生成 + 16 步训练)多久?(b) 如果一次 rollout 的生成占这个周期的 70%,平均回答长度 8,000 token,512 块 GPU 的平均生成吞吐是多少 token/s / GPU?这个数说明了什么?
参考答案
(a) 198 × 3600 / 10,400 ≈ 68.5 秒 / 步;一次 rollout 服务 16 步,周期约 1,097 秒。(b) 8,192 × 8,000 ≈ 6,550 万 token,在 0.7 × 1,097 ≈ 768 秒内生成,约 8.5 万 token/s,摊到 512 块 GPU 约 167 token/s / GPU——远低于一块 GPU 在大批 decode 时的能力(代码 02 演示 1:一块 H100 满批时约 6,000 token/s 的 8B 模型)。即使考虑 671B 的 MoE 模型每 token 计算更重,这也说明长尾和长上下文让生成阶段的平均利用率很低。(70% 和 8,000 token 都是假设的数字,论文没有给出。)
练习 6(迁移什么时候有害)。8B 模型、1 块 H100,batch = b、每个样本上下文 c 时,一步 decode 大约读 16 GB 权重 + b × c × 128 KiB 的 KV。(a) c = 6,000 时,b 从 4 增加到 32,每步时间大约增加多少倍?(b) 据此解释为什么把 100 个长尾样本从 8 个实例挤到 2 个实例上会让长尾变慢,而 RLHFuse 的规则(m ≥ Rt / BSmax,BSmax = 256)认为不会。
参考答案
(a) b = 4:16 GB + 4 × 6,000 × 131 KB ≈ 16 + 3.1 = 19.1 GB;b = 32:16 + 25.2 = 41.2 GB;每步时间约增加 2.2 倍(都受带宽限制)。(b) 8 个实例时每个约 12–13 个样本,挤到 2 个后每个 50 个,每步要读的字节从约 26 GB 增加到约 55 GB,每步时间翻倍——长尾的写完时间也随之变长。BSmax 的假设隐含”权重读取远大于 KV 读取”(短上下文时成立)。长上下文时,应当用每步读取的字节(权重 + KV)来约束 m。
练习 7(思考:为什么准备与训练不能融合)。RLHFuse 把生成和准备融合了,为什么不把准备和训练也融合——一个样本准备好就开始训练?如果一定要做,算法上要怎样改?
参考答案(要点)
PPO / GRPO 的训练把一轮的全部样本随机分成若干 mini-batch,每个 mini-batch 更新一次参数;要求每个 mini-batch 的分布和整体一致。如果按”准备好的先训练”,先训练的 mini-batch 会偏向短回答(短的先写完),带来系统性的偏差。要融合,就要放宽这个要求:例如按长度分桶、用重要性权重修正,或者接受异步 RL 的离策略并在损失里做修正。这正是 §5 的办法要付出的算法代价。
练习 8(思考:智能体 RL 的系统)。如果 rollout 是一个多步的智能体程序(每一步调用工具、执行代码,在沙箱里运行几秒到几分钟),本讲的哪些结论会变?第 12、13 讲的哪些技术会用上?
参考答案(要点)
长尾更严重、来源更多:除了生成长度,还有工具执行时间和步数的方差。生成实例在等工具时是空闲的,需要第 13 讲的程序级调度(Autellix)和”等待时让出 GPU”;沙箱的冷启动和池化来自第 12 讲(Fork in the Road);多步对话的前缀缓存(第 3、9 讲)决定了每一步的 prefill 代价。部分 rollout 和异步更有吸引力,因为一个程序可能跨越很长的时间;同时需要考虑一个样本跨越多个策略版本带来的偏差。
11. 延伸阅读 · Further reading
本讲的必读材料
- G. Sheng, C. Zhang, Z. Ye, X. Wu, W. Zhang, R. Zhang, Y. Peng, H. Lin, C. Wu. HybridFlow: A Flexible and Efficient RLHF Framework. EuroSys 2025(arXiv:2409.19256)。
- Y. Zhong, Z. Zhang, B. Wu, S. Liu, Y. Chen, C. Wan, H. Hu, L. Xia, R. Ming, Y. Zhu, X. Jin. Optimizing RLHF Training for Large Language Models with Stage Fusion(RLHFuse). NSDI 2025(arXiv:2409.13221)。
选读
- DeepSeek-AI. DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. arXiv:2501.12948。
相关工作
- J. Schulman et al. Proximal Policy Optimization Algorithms. 2017。
- L. Ouyang et al. Training language models to follow instructions with human feedback(InstructGPT). NeurIPS 2022。
- Z. Shao et al. DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models(GRPO). 2024。
- Z. Yao et al. DeepSpeed-Chat: Easy, Fast and Affordable RLHF Training of ChatGPT-like Models at All Scales. 2023。
- J. Hu et al. OpenRLHF: An Easy-to-use, Scalable and High-performance RLHF Framework. 2024。
- Z. Mei et al. ReaLHF: Optimized RLHF Training for Large Language Models through Parameter Reallocation. 2024。
- S. Li, T. Hoefler. Chimera: Efficiently Training Large-Scale Neural Networks with Bidirectional Pipelines. SC 2021。
- Kimi Team. Kimi k1.5: Scaling Reinforcement Learning with LLMs. 2025。
背景
- 第 2 讲:连续批处理;第 3 讲:前缀共享;第 5 讲:投机解码;第 6 讲:并行与 1F1B;第 7 讲:同置与解耦;第 8 讲:专家并行;第 12 讲:多模型共享 GPU;第 13 讲:智能体程序。
12. 下一讲预告 · Next lecture
到这里,我们已经从单卡引擎一路讲到了集群、智能体和 RL。第 16 讲:案例研究——SGLang 把视角收回到一个真实的系统:SGLang 怎样从一篇研究论文(RadixAttention 和前端语言,第 3 讲)成长为被大规模生产使用的推理引擎。我们会读 SGLang 团队公开的技术博客,看他们一路补上了什么:把 CPU 调度开销藏到 GPU 计算后面的”零开销”批调度器、缓存感知的负载均衡(第 11 讲)、结构化输出的压缩有限状态机、面向 MLA 的数据并行注意力、以及大规模专家并行 + prefill / decode 解耦部署 DeepSeek 的经验——并用前面各讲的模块拼出一个端到端的迷你引擎。