Hugging Face 总结了强化学习库的最佳实践和 Token 使用教训。对构建和优化 RL 系统的程序员有直接参考价值。
问题:在同步 RL(强化学习)训练中,数据生成(通过模型推理创建数据样本)占据了绝大部分实际运行时间——在一个 32B(320 亿参数)模型上生成一批 32K-token 的 rollout 可能需要数小时,而用于训练的 GPU 在此期间却一直处于空闲状态。
大家最终趋同的解决方案:将推理和训练拆分到不同的 GPU 池中,通过 rollout 缓冲区(用于临时存储模型输出)连接二者,并异步传输权重(无需等待),从而使任何一方都不必等待另一方。
我们调研了 16 个实现了这一模式的开源库,并从 7 个维度进行了比较:编排原语、缓冲区设计、权重同步协议、陈旧性管理、部分 rollout 处理、LoRA 支持,以及分布式训练后端。
主要发现:Ray 在编排方面占据主导地位(调研的 16 个分布式计算库中有 8 个使用 Ray)。NCCL(NVIDIA Collective Communications Library)广播是传输模型权重的默认方法。陈旧性管理是指如何处理过时的数据样本,其方案从直接丢弃旧样本到使用高级重要性采样校正不等。LoRA(Low-Rank Adaptation,低秩适配)训练得到的支持较少。分布式 MoE(Mixture of Experts,混合专家)支持正在成为新的差异化因素。
如果你想直接跳到精彩部分,这里是完整的对比表(无需阅读,我们不会评判你)。
不过说真的,如果你愿意继续看下去,或许能了解一两件事:为什么你的 GPU 有 60% 的时间都处于空闲状态。
1.1 TRL 目前如何进行 RL 训练
1.2 共置式训练与解耦式训练
1.3 生成瓶颈
调研的库
对比框架:七个维度 维度 1:编排与并发原语 维度 2:Rollout 缓冲区设计 维度 3:权重同步协议 维度 4:陈旧性管理 维度 5:部分 Rollout 处理 维度 6:LoRA 训练支持 维度 7:分布式训练后端与并行策略
维度 1:编排与并发原语
维度 2:Rollout 缓冲区设计
维度 3:权重同步协议
维度 4:陈旧性管理
维度 5:部分 Rollout 处理
维度 6:LoRA 训练支持
维度 7:分布式训练后端与并行策略
全局概览:一览十六个库
下一波浪潮:设计启示 5.1 无 Critic 算法:释放了内存,但增加了权重同步压力 5.2 过程奖励:一道新的同步屏障 5.3 多智能体协同演化:拖尾问题进一步加剧 5.4 训练与推理不匹配:Deepseek v3.2 MoE 案例研究 5.5 蒸馏:换了一个名字的同一异步问题
5.1 无 Critic 算法:释放了内存,但增加了权重同步压力
5.2 过程奖励:一道新的同步屏障
5.3 多智能体协同演化:拖尾问题进一步加剧
5.4 训练与推理不匹配:Deepseek v3.2 MoE 案例研究
5.5 蒸馏:换了一个名字的同一异步问题
model_version 的有界队列(不使用双缓冲) 2. 使用打包传输的 NCCL 权重同步 3. 面向智能体工作负载的部分 Rollout 支持设计原则:保持编排轻量化
使用逐 token model_version 的有界队列(不使用双缓冲)
使用打包传输的 NCCL 权重同步
面向智能体工作负载的部分 Rollout 支持
异步 RL 训练已经成为大规模后训练的主流范式。现代后训练中的几项趋势,使同步训练循环几乎无法扩展:
推理模型产生的长 rollout。思维链训练会产生非常长的 rollout,而单个同步生成批次在一块 GPU 上可能需要数小时才能完成。在这段时间里,训练 GPU 会完全处于空闲状态。
GRPO 等无价值函数训练器使用组相对优势。这意味着每个提示词最多需要生成 G 倍的 rollout,而且整个批次的进度受制于组内完成速度最慢的样本。
智能体 RL 训练的兴起。当模型通过多轮轨迹与工具、沙箱和外部环境交互时,rollout 的长度和延迟会变得极不稳定。一次简单的 API 调用可能在数秒内返回,而一条包含工具调用的复杂推理链则可能运行数分钟乃至数小时。用于训练 MiniMax-M2.5 的 MiniMax Forge 框架展示了这种模式在实践中能够达到的规模:上下文长度最高达 200K token,拥有超过十万个不同的智能体脚手架和环境,每日吞吐量达到数百万样本量级。在这种规模下,生成与训练之间的任何同步屏障都会成为严重瓶颈。仅拖尾问题(少量缓慢的 rollout 阻塞整个批次)就可能导致数百块 GPU 闲置。
开源生态已经在一种共同的架构方案上形成共识:将推理与训练解耦并部署到不同的 GPU 池中,通过 rollout 缓冲区连接二者,让双方并发运行。
我们正在为 TRL 开发一个新的异步训练器。TRL 是使用最广泛的模型后训练库之一。为了指导设计,我们调研了 16 个从一开始就围绕异步训练构建的开源库,并从七个维度对它们进行了比较:编排原语、缓冲区设计、权重同步协议、陈旧性管理、部分 rollout 处理、LoRA 支持,以及分布式训练后端。本文提炼了我们从这次调研中总结出的设计原则。
除 RL 之外,对异步基础设施的需求也日益明显。例如,在同策略蒸馏中,学生模型生成序列,教师模型对其进行评分;它的结构与 GRPO 类似,只是把奖励函数替换成了教师模型的一次前向传播。认识到这种结构上的相似性后,我们可以发现,本次调研中的所有结论同样适用于异步蒸馏。我们将在第 5 节回到这个更宽泛的话题。
TRL 当前的 GRPOTrainer 在单次同步的 training_step() 调用中实现了完整的 GRPO 循环,包括提示词采样、生成、奖励评分、优势计算、梯度更新和权重同步。这种设计简单且正确,但无法让生成与训练重叠执行,因此大量 GPU 利用率未能得到发挥。
观察 GRPOTrainer 可以发现,每个训练步骤都依次包含以下阶段:
提示词采样:从数据集中抽取一批提示词。这里没什么特别的,我们继续。
生成:调用 model.generate()(或将请求转发给 vLLM 服务器),为每个提示词生成 G 个补全结果。这一过程是自回归的,占据了绝大部分实际运行时间。
奖励评分:使用一个或多个奖励函数评估每个补全结果。
优势计算。
前向和反向传播:计算裁剪后的策略梯度损失并进行反向传播。
优化器步骤:更新模型权重。
权重同步:将更新后的权重推送到推理引擎(vLLM),使下一轮生成使用新的策略。
每个阶段都必须等待完成,下一阶段才能开始。时间线如下:
TRL 提供了 steps_per_generation 配置选项,可在多个梯度步骤中复用同一组 rollout(时间复用),从而摊薄生成成本。但生成调用本身仍然是完全同步且阻塞的;只有当批次中的所有补全结果全部生成完毕后,训练器才能开始计算梯度。
该库还支持以服务器模式将 vLLM 作为独立进程运行。这样可以在生成期间释放训练 GPU,但仍然存在两道严格的同步屏障:HTTP 调用必须等待所有补全结果返回;权重同步则会在传输期间同时阻塞训练器和 vLLM。
在讨论异步训练之前,必须先理解使用独立推理引擎进行 RL 训练时的两种部署拓扑:
共置模式将推理和训练放在同一组 GPU 上。单个 GPU(或 TP 组)同时容纳训练模型(采用 FSDP 或 ZeRO)和推理引擎(vLLM 或 SGLang)。任何时候都只有一个角色处于活动状态:在生成期间,训练模型的参数可能会被卸载,或重新分片为适合推理的布局(例如,从 FSDP 分片转换为 vLLM 的张量并行布局);在训练期间,推理引擎会暂停或进入休眠状态。权重“同步”基本上没有成本;它最多只是在同一 GPU 上进行原地重新分片,而不是通过网络传输。共置模式的优势在于简单且成本较低;所需的 GPU 总数更少。其根本限制是推理与训练无法重叠执行。例如,以下是 Trl 配合 vllm 使用 colocate_mode 的情况:
解耦模式将推理和训练放在不同的 GPU 池中。推理池持续运行 vLLM 或 SGLang;训练池持续运行优化器。两个池通过权重同步协议(NCCL 广播、文件系统检查点、HTTP 等)以及数据传输机制(Ray 对象存储、Redis Streams、共享内存等)进行通信。
解耦模式最大的优势是推理与训练可以并发运行。当训练器在批次 N 上计算梯度时,推理池已经开始为批次 N+K 生成 rollout,从而实现异步训练。然而,这项优势也有代价:需要额外的 GPU。
并发、异步和并行是不同的概念,但它们经常被混为一谈。在本文中,当我们说“异步训练”时,指的是一种特定情况:生成和训练并行运行,并产生有效的执行重叠;推理池在训练池对当前批次计算梯度的同时,生成下一批 rollout。这从根本上说是解耦模式才具备的能力。共置模式可以受益于休眠/唤醒内存管理或快速原地重新分片等优化,以加速推理,但它无法实现真正的同时重叠;推理和训练仍然只能在同一组 GPU 上轮流执行。本次调研中,所有实现了实质性异步重叠的库都以解耦模式为基础。
在推理模型的 RL 训练中,自回归生成占据了绝大部分实际运行时间。对于数学或编程任务,单次 rollout 可能生成 8K–64K 个思维链推理 token(参见 QED-Nano 的 rollout 长度)。
为了给出一个具体参照,请看 vLLM 在单张 H100 80GB GPU 上的基准测试结果(bf16、无量化、离线吞吐量模式)。7B 模型(DeepSeek-R1-Distill-Qwen-7B)的聚合输出吞吐量约为 6,300 token/s;32B 模型(DeepSeek-R1-Distill-Qwen-32B)则下降至约 1,200 token/s。这里的数字是所有并发请求的总吞吐量,也就是无论有多少序列共享 GPU,推理引擎每秒总共可以处理的 token 数量。
现在考虑一个典型的 GRPO 训练步骤:每个提示生成 G=8 个补全 × 每批 64 个提示 = 512 个 rollout。生成需要多长时间?
即使在较短的一端(使用 7B 模型生成 2K token),仅生成阶段在每个训练步骤中就会耗费数分钟。在较长的一端,也就是前沿推理模型越来越常见的工作区间中,在单张 GPU 上,一次生成阶段可能需要数小时。扩展到 8 张推理 GPU 后,这些时间大约可以缩短至原来的 1/8(假设吞吐量能够线性扩展),但即便如此,使用 32B 模型生成 32K-token rollout,每个步骤仍然需要约 28 分钟。
拖尾问题会进一步加剧这一情况。在 GRPO 等基于分组的算法中,每个提示需要采样 G 个补全。在最慢的补全完成之前,整个批次都无法继续。思维链输出长度的差异非常大;同一个提示生成的补全长度可能从 1K 到 32K token 不等。整个批次的进度取决于最长的补全,而连续批处理只能部分缓解这一问题:较短的序列会释放槽位以处理新任务,但 GRPO 分组中的最后一个序列仍然会阻塞该组的奖励计算和训练步骤。
本次调研中的每个库都各自得出了相同的架构原则:在物理上将推理 GPU 与训练 GPU 分离,并异步推送权重,从而让生成永不停顿、训练无需等待。
推理池持续运行,将已完成的 rollout 送入缓冲区。训练池从缓冲区中提取 rollout、计算梯度更新,并定期将新权重推送回推理池,使其保持同步。两个循环按照各自的节奏运行,通过缓冲区实现解耦。
这种设置具有很强的可扩展性,但也引入了一类新的问题:陈旧性(使用旧策略生成的 rollout)、权重同步开销、部分 rollout 的处理等。本文其余部分将详细剖析当前的开源库如何解决这些问题。
为了理解快速扩张的异步 RL 库生态,我们提出了七个相互正交的比较维度。每个维度都代表一项基础设计决策,它会影响库的性能、复杂度和取舍。
维度 1——编排与并发原语:如何协调分布式组件(Ray actor、asyncio、发布/订阅、HTTP)。
维度 2——Rollout 缓冲区设计:rollout 如何从推理端流向训练端。
维度 3——权重同步协议:更新后的权重如何传递至推理服务器,以及系统是必须暂停以接收权重,还是可以继续生成。
维度 4——陈旧性管理:如何处理离策略 rollout,包括版本拒绝、深度限制或重要性采样校正。
维度 5——部分 Rollout 处理:当权重更新在序列生成过程中到达时,如何处理正在进行的生成任务。
维度 6——LoRA 训练支持:通用 LoRA 支持,以及能否仅训练和同步适配器参数,从而实现亚毫秒级权重传输。
维度 7——分布式训练后端与并行策略:训练使用哪种并行策略,这决定了所支持模型规模的上限。
系统如何协调其分布式组件?
编排框架的选择决定了编程模型、故障语义和可扩展性上限。与其逐一罗列各个库的实现细节,不如将整个生态清晰地划分为四种编排类型——它们是基础的协调范式,在抽象层级、故障模型和部署要求方面各不相同:
关于 Tunix 的说明:Tunix(Google)采用 JAX 原生的 mesh 模型,通过 ThreadPoolExecutor 实现异步重叠,并使用 jax.device_put 在不同 mesh 之间传输权重。它在架构上与 PyTorch 生态差异显著,因此无法在编排层面进行有意义的直接比较;它属于 XLA/TPU 世界,使用自己的一套协调原语。
上表揭示了一个显著的规律:本次调研的 16 个库中,有 8 个使用 Ray 作为编排骨干。这并非巧合,而是反映了 actor 模型与 RL 训练结构之间深层次的架构契合。Ray 背后的公司 Anyscale 对面向 LLM 的开源 RL 库所做的调研也证实了这种趋同。在大规模 RL 训练中,本质上存在多个异构组件(推理引擎、训练引擎、环境、奖励模型),必须跨集群进行编排;它们通常运行在不同类型的硬件上,并且具有不同的扩展需求和故障模式。Ray 的 actor 模型与此直接对应:
Actor 隔离与异构资源。每个 RL 组件(vLLM 推理服务器、FSDP 训练器、奖励模型、环境池)都会成为一个 Ray actor,并拥有自己的资源需求(num_gpus、num_cpus、memory)。通过放置组,可以精细控制 GPU 亲和性,而无需手动使用 SSH/torchrun 进行编排。
Actor 隔离与异构资源。每个 RL 组件(vLLM 推理服务器、FSDP 训练器、奖励模型、环境池)都会成为一个 Ray actor,并拥有自己的资源需求(num_gpus、num_cpus、memory)。通过放置组,可以精细控制 GPU 亲和性,而无需手动使用 SSH/torchrun 进行编排。
调度与自动扩缩容。Ray 的调度器负责处理如何将异构 actor 放置到集群各处这一组合问题。当生成所需的 GPU 时数是训练的 8 倍时,只需让 Ray 独立扩展推理 actor 即可。
调度与自动扩缩容。Ray 的调度器负责处理如何将异构 actor 放置到集群各处这一组合问题。当生成所需的 GPU 时数是训练的 8 倍时,只需让 Ray 独立扩展推理 actor 即可。
长期的强化学习训练任务(持续数天至数周)容易遭受GPU故障、内存溢出(OOM)杀死和网络分区的影响。Ray的actor重启策略和对象存储复制提供了弹性恢复能力,这种能力用原始的asyncio和multiprocessing实现需要大量的定制基础设施。一个容错的具体例子是:open-instruct依赖Ray的actor监管来从vLLM引擎在rollout中途的崩溃中恢复。
用于零拷贝数据传输的对象存储。Rollout数据可能很大,超长上下文推理每批次可达数十GB。Ray的共享内存对象存储实现了同一节点上actor之间的零拷贝传输,避免了通常与multiprocessing.Queue方式相关的序列化开销。
成本是对非平凡运行时的硬依赖。这种权衡可能是值得的,特别是对于生产规模训练(64+ GPUs、多天运行、复杂的奖励计算)。
虽然Ray的actor模型是主流方案,但Monarch作为Meta推出的新型PyTorch原生分布式actor框架脱颖而出,专为GPU工作负载而设计。与Ray一样,Monarch也基于actor模型;各个组件是具有邮箱的独立actor,通过消息进行通信,但它是从头开始为PyTorch/CUDA生态设计的,而不是通用的分布式运行时。
Monarch提供了几个与异步强化学习特别相关的功能。GPU Mode讲座系列中的异步强化学习实现示例展示了这种架构:生成器、重放缓冲区和训练器被建模为Monarch actor,重放缓冲区吸收来自掉队rollout的延迟方差,而RDMA权重同步在不阻塞训练的情况下将更新的参数推送到生成器。这个模式在结构上与基于Ray的设计(verl、SkyRL、open-instruct)相同,但使用纯PyTorch原生的基础设施实现。
生成的rollout如何从推理流向训练,管道有多深?
缓冲区是位于生成和训练之间的数据结构。它的深度控制着最大的异步程度,因此也决定了最大的陈旧性。
双缓冲模式是从同步到异步训练的最简单升级:它精确地将一次生成与一次训练步骤重叠,最多引入一步的策略延迟!
更深的队列则会改进吞吐量,但需要陈旧性管理。
缓冲区控制有多少数据在传输中。但数据只是方程的一半。另一半是在这些rollout过期之前将更新的权重传回推理服务器。这就是权重同步的作用所在!
梯度更新后新的模型权重如何到达推理服务器?
范围说明:此轴聚焦于分离模式,其中推理和训练运行在独立的GPU池上,因为这才是异步重叠(进而是权重同步设计)真正重要的部署拓扑。共址设置(两个角色使用相同的GPU)本质上是同步的,不面临下面讨论的传输/中断权衡。
这是架构上最有影响的轴。该协议决定了同步延迟、中断粒度以及是否可能有部分rollout。
这里需要做一个关键区别:传输机制和中断模型。大多数库在粗粒度边界暂停生成——一个HTTP请求、一个完整批次,甚至一个完整训练步骤——然后再启动权重传输。PipelineRL是例外:它完全不停止生成。
在中断模型中,生成何时暂停以接受新权重?
PipelineRL在这里从每个其他库中根本上偏离。与其逐一列举每个库,整个景观可以简化为五个概念层,按从最细到最粗的中断粒度排序:
"永不停止"层在质量上与所有其他情况不同:例如,PipelineRL钩入推理引擎,使得锁在每个transformer前向传递(一个序列的一个令牌步骤)时获取和释放。权重更新最多等待一个前向传递(~几毫秒),交换所有参数,生成立即恢复。所有其他库在粗粒度边界停止生成,从一个HTTP请求(~数百毫秒)到完整批次边界(~秒)。
权重同步控制新权重何时到达。但异步训练意味着rollout始终在某个策略版本下生成,而该生成策略…