配方:完全异步策略训练器

作者: https://github.com/meituan-search

最后更新:2025 年 10 月 18 日。

本文档介绍了一个完全异步的 PPO 训练系统,该系统完全解耦了训练器(Trainer)和采样器(Rollouter), 支持异步样本生成和训练。 在该系统下,我们在使用 128 个 GPU 训练 Qwen2.5-7B 模型时,实现了 2.35 倍到 2.67 倍的性能提升,且未显著影响训练结果。

简介

背景

相比于共址(colocate)架构,分离式采样和训练架构可以更灵活地分配资源、设计更灵活的训练逻辑,从而解决由长尾问题(long-tail problems)导致的 GPU 利用率低和训练效率不高等问题。 one_step_off_policy 通过设计分离式架构并对一轮采样和训练进行异步处理,缓解了长时间采样的问题,并在一定程度上提高了训练效率。 然而,它强制使用一轮异步训练的数据,不够灵活,也无法完全消除长尾问题对训练效率的影响。 在 AReaL、Magistral、StreamRL 和 AsyncFlow 等其他框架中,基于分离式架构已经实现了异步训练和流式训练,并取得了成效。 我们借鉴了它们的方法,并将其应用到了 VERL 中。fully_async_policy 支持异步、流式和部分采样(partial rollout)训练。 通过合理设置资源分配和参数同步频率等参数,fully_async_policy 可以显著提高训练效率。

Magistral https://arxiv.org/abs/2506.10910

AReaL: A Large-Scale Asynchronous Reinforcement Learning System for Language Reasoning https://arxiv.org/abs/2505.24298

StreamRL: Scalable, Heterogeneous, and Elastic RL for LLMs with Disaggregated Stream Generation https://arxiv.org/abs/2504.15930

AsyncFlow: An Asynchronous Streaming RL Framework for Efficient LLM Post-Training https://arxiv.org/abs/2507.01663

核心贡献

  • 资源隔离:与 hybrid_engine 不同,采样器(Rollouter)和训练器(Trainer)使用独立的计算资源,并且需要分别指定它们占用的资源。

  • 并行生成与训练:在训练器(Trainer)进行训练的同时,采样器(Rollouter)正在生成新的样本。

  • 多步异步:相比于单步离策略(one step off policy),它支持从 0.x 步到多步的异步设置,使异步解决方案更加灵活。

  • NCCL 参数同步:使用 NCCL(Nvidia Collective Communications Library)通信原语进行采样器(Rollouter)和训练器(Trainer)之间的参数通信。

  • 流式推理与训练:采样器(Rollouter)逐个样本生成数据,数据传输以单个样本作为最小传输单元。

  • 异步训练与新鲜度控制:通过设置参数 async_training.staleness_threshold,支持使用旧参数生成的样本进行训练。

  • 部分采样(Partial Rollout):采样器(Rollouter)的推理过程支持部分采样逻辑。在参数同步期间,通过添加 sleep()resume() 逻辑,它会保存正在进行的采样中的样本,并在下一次采样中继续使用,从而减少在参数同步期间等待进行中任务完成所花费的时间。

目前支持的使用模式是 fsdp+vllmvllm 必须使用基于 AgentLoop 的服务器模式。

设计

fully_async_policy 的整体架构如图所示。fully_async_policy 主要包含四个部分:采样器(Rollouter)、消息队列(MessageQueue)、训练器(Trainer)和参数同步器(ParameterSynchronizer)。

fully_async_policy_structure

  1. 采样器(Rollouter)逐个样本生成序列,并将生成的样本放入消息队列(MessageQueue),生成速度由新鲜度(freshness)控制。

  2. 消息队列(MessageQueue)用于临时存储采样器(Rollouter)生成的样本。

  3. 训练器(Trainer)逐个样本从消息队列(MessageQueue)中获取样本。在获取了 require_batches*ppo_mini_batch_size 个样本后,它将执行训练。训练 async_training.trigger_parameter_sync_step 轮后,它将触发与采样器(Rollouter)的参数同步。

  4. 参数同步器(ParameterSynchronizer)实现 NCCL 同步参数同步功能。

与基础方案相比,其优势在于:在共址(colocate)情况下,使用更多资源进行采样无法解决由长尾样本引起的空闲问题。 在我们进行资源隔离后,采样和训练的时间可能会比之前长(因为使用的资源较少), 但它们时间消耗的重叠减少了端到端的总时间消耗。

fully_async_policy_revenue

用法

参数说明

超参数

含义

trainer.nnodes

训练器(Trainer)的节点数

trainer.n_gpus_per_node

训练器(Trainer)的每节点 GPU 数

rollout.nnodes

采样器(Rollouter)的节点数

rollout.n_gpus_per_node

采样器(Rollouter)的每节点 GPU 数

data.train_batch_size

在完全异步策略下,此值无效(默认为 0)

data.gen_batch_size

在完全异步策略下,使用流式样本生成逻辑(默认为 1)

rollout.total_rollout_steps

总采样步数(总采样样本数)

rollout.test_freq

采样器(Rollouter)更新参数多少次后执行一次验证

actor_rollout_ref.actor.ppo_mini_batch_size

ppo_mini_batch_size 是所有工作节点/GPU 的全局数量

async_training.require_batches

FullyAsyncTrainer 一次性获取的 ppo_mini_batch_size 的数量

async_training.trigger_parameter_sync_step

指示 FullyAsyncTrainer 在执行参数同步前执行多少次本地更新

async_training.staleness_threshold

新鲜度控制

async_training.partial_rollout

是否执行部分采样(partial_rollout)

async_training.use_rollout_log_probs

使用采样器(Rollouter)生成的 log_probs

详细解释:

  • rollout.total_rollout_steps

    与共址(colocate)相比,可以通过 train_batch_size 和“步数”来对齐数量: rollout.total_rollout_steps = data.train_batch_size * step

  • async_training.trigger_parameter_sync_step

    在完全异步策略下,它表示训练器(Trainer)在与采样器(Rollouter)进行参数同步前执行多少次本地更新(即获取 require_batches * ppo_mini_batch_size 样本的次数)。 在采样器(Rollouter)和训练器(Trainer)的两次参数同步之间,训练器(Trainer)将处理 trigger_parameter_sync_step* require_batches*ppo_mini_batch_size 个样本。 为了公平地与共址(colocate)比较速度,trigger_parameter_sync_step 应设置为 data.train_batch_size / (require_batches * ppo_mini_batch_size)

  • async_training.staleness_threshold

    在完全异步策略下,它表示允许使用的陈旧样本(stale samples)的最大比例。

    • staleness_threshold=0,表示同步训练。 采样器(Rollouter)将在两次参数更新之间生成固定数量的样本,样本数量为: $$rollout_num = (trigger_parameter_sync_steprequire_batchesppo_mini_batch_size)$$

    • staleness_threshold>0,表示异步训练,可以设置为小数以实现更灵活的异步调用。 采样器(Rollouter)将在两次参数更新之间最多生成以下数量的样本: $$rollout_num = (1+staleness_threshold)(trigger_parameter_sync_steprequire_batches*ppo_mini_batch_size) - num_staleness_sample $$

    num_staleness_sample 表示上次采样过程中超额生成的陈旧样本数量。

    由于这是一个流式系统,采样器(Rollouter)会持续生成,训练器(Trainer)会持续消耗。如果采样器(Rollouter)速度较慢,训练器(Trainer)会提前触发参数同步,而采样器(Rollouter)实际上不会生成 rollout_num 个样本。 当采样器(Rollouter)速度足够快时,将 staleness_threshold 设置为 1 基本上等同于 one_step_off_policy。 为避免过多的陈旧样本影响训练精度,建议将此值设置为小于 1。

  • async_training.partial_rollout

    partial_rollout 仅在 staleness_threshold>0 时才真正生效。

  • async_training.use_rollout_log_probs

    在强化学习算法中,log_probs 与参数版本和 token 存在隐式关联。由于 PPO/GRPO/DAPO 等算法的设置,在计算重要性采样时, old_log_prob 必须使用与采样参数和 token 相对应的 log_probs,以确保算法的正确性。在完全异步策略中,我们默认 old_log_prob 由采样器(Rollouter)计算,而不是由训练器(Trainer)计算。

  • async_training.require_batches

    在流式训练中,require_batches 应设置为 1,表示生成足够的 ppo_mini_batch_size 样本后进行训练。 在实际测试中,我们发现一次发放的样本数较少时,由于数据分发的顺序问题,可能导致训练不稳定和响应长度变长。 在此,我们额外提供了 require_batches 用于流式分发,并控制一次参与训练的样本数量。

支持的模式

  1. On policy pipeline(同步策略流水线)

    1. trigger_parameter_sync_step=1, staleness_threshold=0

    2. 采样器(Rollouter)一次性生成 require_batches*ppo_mini_batch_size 个样本,训练器(Trainer)获取这些样本进行训练,训练完成后,训练器(Trainer)和采样器(Rollouter)进行参数同步;

    3. 在采样阶段,如果存在长尾样本但采样样本数很少,短样本无法填满空闲资源,导致部分资源浪费。

    4. 如图 a 所示;

  2. Stream off policy pipeline(流式离策略流水线)

    1. trigger_parameter_sync_step>1, staleness_threshold=0

    2. 将执行同步流式训练。采样器(Rollouter)一次性生成 require_batches*ppo_mini_batch_size*trigger_parameter_sync_step 个样本,训练器(Trainer)在每次获取 require_batches*ppo_mini_batch_size 个样本后执行一次本地训练,训练 trigger_parameter_sync_step 次后,训练器(Trainer)和采样器(Rollouter)进行参数同步;

    3. 与模式 a 相比,由于一次生成更多样本,资源空闲率会更低。

    4. 在单步训练中,会存在两个资源空闲期:在获取第一批样本时,训练(Trainer)等待 require_batches*ppo_mini_batch_size 个样本生成;在最后一次参数更新时,采样器(Rollouter)等待训练完成。

    5. 如图 b 所示;

  3. Async stream pipeline with stale samples(带陈旧样本的异步流式流水线)

    1. trigger_parameter_sync_step>=1, staleness_threshold>0, partial_rollout=False

    2. 每次参数更新后,采样器(Rollouter)计划生成最多 rollout_num 个样本(实际上,样本生成数量可能少于此值,取决于采样速度)。

    3. 如果采样过程相对较快,采样器(Rollouter)将在参数同步前生成一些额外的样本 num_stale_samples,供训练器(Trainer)在同步后立即使用。 触发参数同步时,如果采样器(Rollouter)有正在进行的任务,它将等待任务完成,而不是添加新任务;

    4. 与模式 b 相比,除了第一次训练步骤外,后续训练不会有等待第一批采样完成的时间,但会有等待活动任务完成的时间。

    5. 如图 c 所示;

  4. Async stream pipeline with partial rollout(部分采样异步流式流水线)

    1. trigger_parameter_sync_step>=1, staleness_threshold>0, partial_rollout=True

    2. 与模式 c 相比,在触发参数同步时,如果采样器(Rollouter)有正在生成的样本,它将中断采样过程并进行参数同步。中断的样本将在同步后继续生成。这减少了等待活动任务完成的时间。

    3. 如图 d 所示;

fully_async_policy_mode

关键指标

指标

含义

trainer/idle_ratio

训练器(Trainer)的空闲率

rollouter/idle_ratio

采样器(Rollouter)的空闲率

fully_async/count/stale_samples_processed

训练中使用的陈旧样本总数

fully_async/count/stale_trajectory_processed

训练中使用的陈旧轨迹总数(一个样本产生 rollout.n 条轨迹)

fully_async/partial/total_partial_num

两次 trigger_parameter_sync_step 之间训练器(Trainer)处理的部分样本数量

fully_async/partial/partial_ratio

两次 trigger_parameter_sync_step 之间训练器(Trainer)处理的部分样本比例

fully_async/partial/max_partial_span

两次 trigger_parameter_sync_step 之间训练器(Trainer)处理的部分样本的最大参数跨度(parameter span)

参数调整建议

  • 资源分配与调整

    • 合理的资源分配是达到良好训练效率的前提。理想的资源分配应使采样时间(rollout time)和训练时间(train time)接近,从而最小化整个训练过程中的流水线气泡(pipeline bubbles),避免资源空闲,并确保训练器(Trainer)不使用陈旧样本。在实际训练场景中,可以根据实际训练期间采样器(Rollouter)和训练器(Trainer)的空闲时间进行调整,这些信息可以从 rollouter/idle_ratiotrainer/idle_ratio 中获取。如果 rollouter/idle_ratio 较高而 trainer/idle_ratio 较低,则应增加训练器(Trainer)的资源并减少采样器(Rollouter)的资源,反之亦然。

  • 关键参数

    • staleness_threshold:设置过高会导致使用更多陈旧样本,影响模型性能。建议设置为小于 1。

    • require_batches:越接近 1,越接近纯流式处理,训练气泡越小,可实现的加速效果越快,但会影响样本处理顺序;

    • trigger_parameter_sync_step:设置值越小,越接近同步策略(on policy),但会导致频繁的参数同步。长尾样本浪费了短样本无法填补的资源,导致资源利用率低下。 设置值越大,计算效率越高,但准确性会受到离策略(off policy)的影响。

    • rollout.test_freq:它会占用采样器(Rollouter)的资源,不建议设置得过小。

  • 模式选择:通过调整不同参数,完全异步(Fully Async)架构支持不同级别的优化加速,适用于不同场景下的任务。

    • 对于需要确保训练稳定性、同步策略性质,且对速度要求不高的中小型任务,可以尝试同步策略流水线模式(模式 1)。

    • 对于需要提高训练吞吐量但对陈旧样本敏感的场景,可以尝试流式离策略流水线模式。即通过设置 trigger_parameter_sync_step>1 来提高训练效率,同时保持同步机制(staleness_threshold=0)(模式 2)。

    • 对于大规模、高训练速度要求且能容忍一定程度离策略和陈旧样本的任务,设置为 staleness_threshold>0partial_rollout=True 可以提高训练效率,使用异步流式流水线模式(模式 3 或 4)。

快速开始

rollout_mode="async"
rollout_name="vllm" # sglang 或 vllm
if [ "$rollout_mode" = "async" ]; then
    export VLLM_USE_V1=1
    return_raw_chat="True"
fi

train_prompt_bsz=0
gen_prompt_bsz=1
n_resp_per_prompt=16
train_prompt_mini_bsz=32
total_rollout_steps=$(((512*400)))
test_freq=10
staleness_threshold=0
trigger_parameter_sync_step=16
partial_rollout=False


python -m recipe.fully_async_policy.fully_async_main \
	train_batch_size=${train_prompt_bsz} \
    data.gen_batch_size=${gen_prompt_bsz} \
    data.return_raw_chat=${return_raw_chat} \
    actor_rollout_ref.rollout.n=${n_resp_per_prompt} \
    actor_rollout_ref.actor.strategy=fsdp2 \
    critic.strategy=fsdp2 \
    actor_rollout_ref.hybrid_engine=False \
    actor_rollout_ref.actor.use_dynamic_bsz=${use_dynamic_bsz} \
    actor_rollout_ref.ref.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
    actor_rollout_ref.rollout.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
    actor_rollout_ref.rollout.name=${rollout_name} \
    actor_rollout_ref.rollout.mode=${rollout_mode} \
    actor_rollout_ref.rollout.calculate_log_probs=True \
    trainer.nnodes="${NNODES_TRAIN}" \
    trainer.n_gpus_per_node="${NGPUS_PER_NODE}" \
    rollout.nnodes="${NNODES_ROLLOUT}" \
    rollout.n_gpus_per_node="${NGPUS_PER_NODE}" \
    rollout.total_rollout_steps="${total_rollout_steps}" \
    rollout.test_freq="${test_freq}" \
    async_training.staleness_threshold="${staleness_threshold}" \
    async_training.trigger_parameter_sync_step="${trigger_parameter_sync_step}" \
    async_training.partial_rollout="${partial_rollout}"

实验

7B 模型异步训练

我们使用 Qwen2.5-Math-7B 来验证完全异步策略在长候选(long candidates)和多资源下的优势。 使用“带陈旧样本的异步流式流水线(async stream pipeline with stale samples)”策略,我们在 32 卡、64 卡和 128 卡上实现了约 2 倍的性能提升,且未显著影响实验结果。

  • 机器:H20

  • 模型:Qwen2.5-Math-7B

  • 采样长度:max_response_length FSDP2: 28K tokens;

  • 算法:DAPO

  • 数据集:TRAIN_FILE: dapo-math-17k.parquet TEST_FILE: aime-2024.parquet

  • 引擎:vllm+FSDP2

  • rollout.n: 16

  • ppo_mini_batch_size: 32

  • test_freq: 20

  • 共址同步(colocate sync):

    • 步数(step):400

    • 训练批次大小(train_batch_size):512

  • 完全异步策略(fully_async_policy):

    • total_rollout_steps: 512*400

    • require_batches: 4

    • trigger_parameter_sync_step: 4

    • staleness_threshold: 0.5

    • partial_rollout: True

训练模式

资源分配

步数(step)

生成(gen)

log_prob

更新 actor

100 步总时长

200 步总时长

300 步总时长

400 步总时长

准确率/均值@1

共址同步 (colocate sync)

32

790.10

357.41

107.71

313.81

13h 44m

1d 3h 43m

2d 9h 22m

3d 17h 5m

max: 0.3313
last: 0.2448

完全异步策略 (fully_async_policy)

16:16

294.77

21.26

\

269.80

7h 58m
(1.72x)

16h 21m
(1.70x)

1d 0h 53m
(2.31x)

1d 9h 26m
(2.66x)

max: 0.3302
last: 0.2333

共址同步 (colocate sync)

64

365.28

150.72

70.26

133.41

10h 22m

20h 45m

1d 7h 6m

1d 17h 32m

max: 0.3365
last: 0.2333

完全异步策略 (fully_async_policy)

32:32

189.26

28.46

\

156.98

4h 57m
(2.09x)

10h 14m
(2.03x)

16h 58m
(1.83x)

21h 40m
(1.92x)

max: 0.3677
last: 0.3406

共址同步 (colocate sync)

128

356.30

177.85

53.92

113.81

8h 36m

17h 56m

1d 5h 6m

1d 16h 48m

max: 0.3573
last: 0.2958

完全异步策略 (fully_async_policy)

64:64

150.63

33.14

\

113.16

3h 13m
(2.67x)

6h 46m
(2.65x)

10h 53m
(2.67x)

17h 22m
(2.35x)

max: 0.3521
last: 0.3094

原始数据来源:https://wandb.ai/hou-zg-meituan/fully-async-policy-colocate_async?nw=nwuserhouzg

128 卡 7B 模型异步模式实验

我们使用 Qwen2.5-Math-7B 来验证完全异步策略所支持的各种模式的效果。 我们可以看到,流式处理带来的收益约为 1.6 倍,结合陈旧样本和部分采样后,收益达到了 2.35 倍。

模式

步数(step)

生成(gen)

log_prob

更新 actor

100 步总时长

200 步总时长

300 步总时长

400 步总时长

准确率/均值@1

共址同步 (colocate sync)

356.30

177.85

53.92

113.81

8h 36m

17h 56m

1d 5h 6m

1d 16h 48m

max: 0.3573
last: 0.2958

流式离策略流水线
(+fully async: trigger_parameter_sync_step= 4,
require_batches= 4)

231.34

128.47

\

98.77

4h 25m

9h 41m

15h 2m

1d 1h 53m

max: 0.2844
last: 0.2604

带陈旧样本的异步流式流水线
(+staleness_threshold=0.5)

带部分采样的异步流式流水线
(+partial_rollout=True)

150.63

33.14

\

113.16

3h 13m

6h 46m

10h 53m

17h 22m

max: 0.3521
last: 0.3094

原始数据来源:https://wandb.ai/hou-zg-meituan/fully-async-policy-stream_stale_partial?nw=nwuserhouzg

128 卡陈旧样本消融实验

在“带部分采样的异步流式流水线(async stream pipeline with partial rollout)”模式下,我们验证了陈旧样本设置对训练效率的影响。 我们发现,陈旧度(staleness)越大,最终收益越明显。 我们还注意到,staleness_threshold 为 0.3 和 0.5 时的耗时非常接近,这是因为随着训练步数的增加,响应长度发生显著变化,导致训练不稳定。 这个问题还需要进一步的分析和优化。

staleness_threshold

步数(step)

生成(gen)

log_prob

更新 actor

100 步总时长

200 步总时长

300 步总时长

400 步总时长

准确率/均值@1

0

231.34

128.47

\

98.77

4h 25m

9h 41m

15h 2m

1d 1h 53m

max: 0.2844
last: 0.2604

0.1

171.30

58.17

\

109.12

3h 53m

8h 37m

14h 25m

19h 59m

max: 0.3542
last: 0.2979

0.3

146.11

38.88

\

103.22

3h 18m

6h 49m

11h 40m

17h 20m

max: 0.3469
last: 0.2865

0.5

150.63

33.14

\

113.16

3h 13m

6h 46m

10h 53m

17h 22m

max: 0.3521
last: 0.3094

原始数据来源:https://wandb.ai/hou-zg-meituan/fully-async-policy-stream_stale_partial?nw=nwuserhouzg

128 卡 7B require_batches 消融实验

在多次测试中,我们发现流式处理中每次发放的样本数量会影响训练时的响应长度,进而影响训练时间。我们通过修改 async_training.require_batches 来验证其对结果的影响。

require_batches

步数(step)

gen

log_prob

更新 actor

100 步总时长

200 步总时长

300 步总时长

准确率/均值@1

1

203.47

30.88

\

181.08

3h 31m

8h 29m

17h 36m

max: 0.349
last: 0.326

2

158.72

26.32

\

128.08

3h 35m

7h 38m

13h 57m

max: 0.351
last: 0.3406

4

124.64

25.62

\

95.06

3h 13m

6h 46m

10h 53m

max: 0.3521
last: 0.3521

原始数据来源:https://wandb.ai/hou-zg-meituan/fully-async-policy-ablation_require_batches?nw=nwuserhouzg

30B 模型模式实验

待续:30B 模型实验仍在进行中。

  • 机器:H20

  • 模型:Qwen2.5-32B

  • 采样长度:max_response_length FSDP2: 20K tokens;

  • 算法:DAPO

  • 引擎:vllm+FSDP2

  • rollout.n: 16

  • ppo_mini_batch_size: 32

  • test_freq: 20

  • 共址同步(colocate sync):

    • 步数(step):200

    • 训练批次大小(train_batch_size):512

  • 完全异步策略(fully_async_policy):

    • total_rollout_steps: 512*200

    • trigger_parameter_sync_step: 512/32 = 16

    • staleness_threshold: 0

    • partial_rollout: False

training mode

Resource allocation

mode

step

generate_sequences

old_log_prob

update_actor

total time

acc/best@32/mean

colocate sync

128

fully_async_policy

64:64

stream off policy pipeline

fully_async_policy

64:64

async stream pipeline with stale samples

fully_async_policy

64:64

async stream pipeline with partial rollout

未来计划

  • GRPO 实验

  • Megatron 适配

  • SGLang 集成

  • Transfer Queue 集成

  • 异步参数同步

  • AReaL 异步算法实现

  • TPPO 算法实现

  • 多轮对话和工具支持