跳转到正文

异步训练架构(已并入 B.1)

这一页保留为旧链接入口。核心内容已经合并到 B.1 RL 训练系统:采样、异步与分布式 的“异步训练架构”部分。下面保留原文,方便从旧链接进入的读者对照。

LLM RL 训练有一个核心矛盾:生成(推理)极慢,训练极快,两者串行导致 GPU 大量空闲。 异步训练就是来解决这个矛盾的。

本节只回答一个问题:生成和训练怎么并行跑? 先量化问题有多严重,再讲三种部署方式,然后深入两个工程问题——新参数怎么同步、旧数据怎么处理。

生成和训练串行,GPU 99% 时间在空等

用 TRL 跑 GRPO 的时候,每一步训练是这样的:

① 让模型生成 512 条回答      ← 推理,很慢,训练 GPU 在等
② 用这些回答算 loss、更新参数  ← 训练,很快,推理 GPU 在等
③ 拿新模型再生成 512 条回答    ← 又回到第①步

①和②是串行的——总有一边的 GPU 在空等。那到底慢多少?

在单张 H100 上(bf16,vLLM 离线模式),一个典型的 GRPO 步(G=8 × 64 prompts = 512 条 rollout):

每条输出多长总 token 数7B 模型耗时32B 模型耗时
2K token~100 万3 分钟14 分钟
8K token~400 万11 分钟56 分钟
32K token~1600 万45 分钟3.7 小时

而训练这一步(反向传播 + 参数更新)大概只要 30 秒。

也就是说,训练 GPU 有 99% 的时间在等生成完成。还有"慢人问题":GRPO 要求同一个 prompt 生成 8 条回答,必须等最慢的那条写完才能继续。

三种部署方式

同步模式(Synchronous)

最简单的做法。一组 GPU,先生成,再训练,再生成,再训练。

时间轴:  [生成 b0] [训练 b0] [生成 b1] [训练 b1] [生成 b2] ...
              ↑ 空闲     ↑ 空闲     ↑ 空闲

优点:代码简单,GPU 用得少。缺点:训练和生成不能同时跑。

同步模式也能快:Seer

Seer(Moonshot AI / Kimi)走的是另一个方向——不转向异步,而是在同步框架内消灭"慢人问题"。它的核心观察是:同一 prompt 生成的多条回答,长度和模式高度相似。利用这个特性,Seer 引入三项优化:divided rollout(动态负载均衡)、context-aware scheduling(减少长尾等待)、adaptive grouped speculative decoding(加速慢请求)。结果是 rollout 吞吐提升 74–97%,尾延迟降低 75–93%,同时保持严格的 on-policy 保证——不改变 GRPO 算法。Seer 基于 Mooncake 分离式 KV cache + vLLM + Megatron,详见 arXiv:2511.14617

共置模式(Colocated)

还是一组 GPU,推理和训练轮替使用。生成时把参数重排成推理格式(从 FSDP 分片格式转成 vLLM 张量并行格式),训练时再转回来。格式转换比重新加载模型快很多,但本质还是轮替。

时间轴:  [生成 b0] [转换] [训练 b0] [转换] [生成 b1] [转换] ...

优点:省 GPU。缺点:生成和训练仍然不能重叠。适合预算有限的团队。

分离模式(Disaggregated / 异步)

真正让两边同时跑。推理和训练各占一组 GPU,中间用一个缓冲区(Buffer)连起来:

推理 GPU 组:  [生成 b0] [生成 b1] [生成 b2] [生成 b3] ...
                ↓ 存入buffer  ↓ 存入buffer
训练 GPU 组:     [训练 b0]  [训练 b1]  [训练 b2] ...
                ↑ 权重同步    ↑ 权重同步

推理 GPU 不停地生成数据塞进 buffer,训练 GPU 从 buffer 取数据训练。两边互不等对方。这是大规模 RL 训练的标配。

模式GPU 数量能同时跑吗适用场景
同步一组不能学习、小实验
共置一组不能(但切换快)中等规模、GPU 预算有限
分离两组或更多大规模生产训练

分离模式带来两个核心工程问题:权重怎么同步旧数据怎么处理

工程问题一 与 新参数怎么同步给推理 GPU

训练 GPU 更新了参数,推理 GPU 怎么拿到?涉及两个决策:用什么方式传,传的时候要不要停生成。

用什么方式传?

传输方式要多久传多少数据适用场景
NCCL 一次性广播100-500ms全部参数大多数框架
NCCL 打包传输(veRL)~20ms全部参数优化传输
GPU 显存直传(NeMo-RL)极低全部参数高带宽互联
只传 LoRA adapter<1ms~50MB最佳实践
写文件再读(PRIME-RL)较慢全部参数跨节点

关键洞察:如果用 LoRA 训练,只需要同步 adapter 部分(~50MB),不到 1 毫秒。这是 LoRA + 异步训练成为最佳实践的重要原因。

传的时候要不要停生成?

推理 GPU 正在生成一条 32K token 的回答,生成到一半,新参数来了。四种处理方式:

  1. 不停(PipelineRL):在生成两个 token 之间的间隙(~1-10ms)悄悄换参数。最优雅但实现最复杂。
  2. 等手头做完再换(veRL、AReaL):不再接受新请求,等当前请求完成后同步参数。简单可靠。
  3. 直接中断(SkyRL、SLIME):正在生成的请求作废,同步完成后用已生成部分作为前缀重新提交。浪费一些 token。
  4. 等整个 batch 做完(NeMo-RL、Tunix):最保守,等待时间最长。

用 LoRA 的话同步只要 <1ms,这四种方式的区别就不大了。

工程问题二 与 旧模型生成的数据还能用吗

分离模式下,推理 GPU 可能在用旧版本的模型生成数据。

例如:训练 GPU 在第 100 步更新了参数,同步要 20ms,这期间推理 GPU 还在用第 99 步的模型生成数据。这些数据是"旧策略"生成的,用它来更新"新策略",严格来说有偏差——这就是 off-policy 问题(你在本书 第 5 章 学过)。

偏差有多大?取决于新旧策略差了几步。差 1-2 步通常问题不大,差 10 步就可能出问题。三种处理思路:

给数据打版本号,太旧的扔掉

每条数据记录是第几步策略生成的。训练时发现太旧(比如超过 5 步)直接丢掉。简单直接,不引入错误梯度,但浪费算力。

把缓冲区做小,限制过期程度

不让缓冲区存太多数据——比如最多 2 批。这样数据最多"过期" 2 步。靠缓冲区大小物理约束,不需要打版本号。

不扔数据,用数学修正

根据新旧策略的差异给数据加权:差异大的降权,差异小的正常用。这叫"重要性采样校正"(Truncated IS)。不浪费数据,但新旧策略差异很大时权重会变极端,导致训练不稳定。所以实践中会截断权重。

实际选择

大多数框架组合使用。比如 PRIME-RL 三种都用:缓冲区深度限制兜底 + 版本号追踪做安全网 + 重要性采样做精细修正。

思路代表框架简单说
扔旧数据PipelineRL、TorchForge简单粗暴
限制缓冲区AReaL队列兜底
数学修正veRL、ROLL不扔但降权
三重保险PRIME-RL最稳

工业界趋势:队列深度兜底 + 可选的数学修正,兼顾效率和稳定性。

参考文献

现代强化学习实战课程