系列:强化学习训练手记

强化学习训练手记(一):分布式 RL 训练 —— PPO / GRPO 怎么从单卡跑到多机

0. 一句话定位

分布式 RL 训练 = 用 Ray 做编排,把 Actor(策略)/ Critic(价值)/ Reference(参考模型,算 KL)/ Reward(打分) 四个角色拆到不同 GPU 池,中间插一个 vLLM 或 SGLang 的 Rollout Engine 专门负责生成,再用高速 Weight Sync 把参数从训练侧广播回推理侧——这是 RLHF、RLAIF、偏好微调、机器人 VLA 偏好对齐共同的工程基座。

它不是什么新算法,而是把”一个模型在一张卡上又当演员又当裁判”这件蠢事彻底拆开。

1. 为什么 RLHF 不能”一锅炖”

PPO-RLHF 的教科书实现(TRL / HF Trainer 早期版本)是单进程顺序跑:

同一份参数 fp 前向生成 → reward 打分 → 同一份参数反向更新

这在 <1B 模型上还能扛,7B 以上必须拆,原因有三个浪费:

  1. 同一份参数被当成两个角色用:既是 Actor(要梯度),又是 Reference(要冻结算 KL)。两份都要常驻显存,浪费一倍。
  2. 推理与训练抢同一组 SM:生成 256 个 token 的 response 是纯推理负载(吃带宽、batch 越大越好),梯度下降是计算负载(吃算力)。硬塞在一起,两边都不在最佳工作点。
  3. 时间分布极度不均:一个 PPO step 里 rollout(生成)占大约 80% 的时间,DeepSpeed 训练只占 20%。用同一批卡顺序做,等于让 80% 的卡在训练阶段闲着。

一句话:rollout 和训练是两种完全不同的负载,必须异步。

2. 四角色解耦 + vLLM Rollout Engine

分布式 RL 训练:四角色解耦 + 独立 Rollout 引擎 vLLM / SGLang Rollout Engine PagedAttention 生成 占一个 PPO step 的 ~80% 时间 切换阶段时 enable_sleep 让出显存 Actor GPUs 主策略,要梯度 DeepSpeed ZeRO-3 / FSDP PPO 或 GRPO 更新 Critic GPUs value head GAE 优势估计 GRPO 可整个去掉 Reference 冻结,算 logp Reward RM 或规则校验 Weight Sync:训练侧 → 推理侧(不能省的一步) ① Ray Object Store:GPU → CPU → 序列化 → CPU → GPU,通信量 O(N × 参数量),配置简单但慢; ② NCCL broadcast:GPU → GPU 直通,用 StatelessProcessGroup 建 side-channel 一把广播,零拷贝。 OpenRLHF、veRL、NeMo-RL、Miles 走的都是第二条。 不同步会怎样:policy 不一致 Actor 更新完参数却没广播回 vLLM,推理引擎还在用上一版权重生成 rollout, 于是"训练用的策略"和"采样用的策略"不是同一个,importance ratio 失真,PPO 直接不收敛。

图:四个角色各占独立 GPU 池,靠 Ray Object Store 共享 experience buffer;每轮更新后必须把权重广播回推理引擎。

这个结构没有任何一行是”算法创新”,全是工程。它要回答的问题是:怎么让 80% 的时间花在最有价值的那件事(生成)上,而不浪费卡。

3. 一个 PPO step 的六阶段流水线

① Rollout generation        : vLLM 生成 response(最长的一段)
② Reward scoring            : RM 或规则校验器打分
③ Reference forward + KL    : 冻结模型对每条样本算 logp_ref
④ GAE advantage             : Critic 估计优势
⑤ Critic / Policy gradient  : 反向更新
⑥ Weight sync back to vLLM  : 参数广播回推理引擎,进入下一轮

真正的难点在 ③ 和 ⑥:③ 决定了你需要多少显存(Reference 的权重和 KV),⑥ 决定了你的流水线会不会”卡在等同步”。

4. PPO 与 GRPO 的损失

PPO 的核心四行:

A_t      = R_t - V(s_t)                                  # 优势(实际用 GAE)
rho_t    = pi_theta(a_t|s_t) / pi_old(a_t|s_t)            # importance ratio,必须 >= 0
L_CLIP   = E[ min( rho_t*A_t, clip(rho_t, 1-eps, 1+eps)*A_t ) ]
L_KL     = -beta * E[ log pi_theta(a_t) - log pi_ref(a_t) ]
L_PPO    = L_CLIP - c1 * L_VF + c2 * L_KL

其中 eps 默认 0.2;beta 随实测 KL 自适应上调(KL 大了说明漂移太多,要拉回来);c1、c2 是 value 与 KL 的系数;Reference 在算 logp_ref 时必须处于冻结状态。

GRPO 的价值在于把 Critic 整个删掉:不训 value head,而是对同一个 prompt 采样一组(group)答案,用组内相对优劣当优势:

A_i = (r_i - mean(r_group)) / std(r_group)      # 组内标准化,替代 Critic

少一整个 GPU 池、少一份显存、少一个训练目标。代价是 group size 要 >= 4,否则组内方差估计不稳。

5. Weight Sync:两条路径

def sync_weights_to_vllm(actor, vllm):
    for name, param in actor.named_parameters():
        if param.requires_grad:
            # 走 side-channel NCCL process group,GPU -> GPU 零拷贝广播
            vllm.collective_rpc("load_weights", param.data)
路径机制评价
Ray Object StoreGPU → CPU → 序列化 → CPU → GPU通信量 O(N × 参数量),好在配置简单
NCCL broadcastGPU → GPU 直通,广播 tensor所有 serious 框架的默认选择

vLLM 0.7+ 暴露了 WorkerExtension 与 collective_rpc,训练侧用 StatelessProcessGroup 建一条旁路 NCCL 组,即可做到零拷贝广播。

6. 实测收益

框架结果
OpenRLHF70B 模型 RLHF 全程 PPO 收敛,相对 TRL 原版约 3× 提速
veRL(字节 Seed)Qwen2.5-32B 上 PPO RLHF 一个迭代从 1.5 小时降到 25 分钟
DeepSeek V4 自研 CANN-GRPOKL 校正与奖励建模融合进单次前向,RLHF 迭代周期 7 天 → 19 小时,SWE-bench 42.1 → 58.2(+38.2%)
DeepSeek V4 + MilesMegaMoE 把通信与计算融成单 GPU kernel,rollout 路径 1.96× 提速
AReaL(蚂蚁)完全异步 rollout + replay buffer,70B 推理模型 RL 训练利用率 >80%
NeMo-RL(NVIDIA)70B+ 全栈 RLHF 训练,GB300 上的 RTX-only pipeline

把这些放在一起看,能读出一个趋势:RL 训练的效率提升,绝大部分来自”把 rollout 和训练解耦”这一件事,而不是新的损失函数。

7. 四个常见坑

  1. Sync gap(同步空窗):Weight sync 太久,就会训练用 v1 权重、推理用 v2 权重,policy gradient 直接失真。建议每个 mini-batch 后立即同步。
  2. Actor 显存爆炸:Reference 不能 unload 到 CPU,否则算 KL 时 I/O 阻塞,整条流水线等它。
  3. vLLM 不 sleep:切换 rollout / train 阶段时要把 vLLM engine enable_sleep,把显存让给训练,否则 OOM。
  4. GRPO 组内方差爆炸:group size < 4 时组内优势估计方差过大,训练抖动。要么加大 group,要么退回 PPO + Critic。

8. 与机器人 VLA 的关系

这套基础设施不止服务文本 RLHF,机器人策略的 RLAIF(用 reward model 做偏好对齐) 走的是同一套:

VLA 生成轨迹 → reward model 打分 → 组内相对优劣(GRPO)→ 更新策略 → 同步回推理侧

9. 总结

维度答案
要解决什么rollout 与训练是两种负载,硬塞在一起浪费 80% 的卡
怎么解决四角色解耦 + 独立 Rollout Engine + NCCL Weight Sync
最大收益来自解耦本身,而不是新损失函数(veRL 1.5h → 25min)
要不要 Critic可选。GRPO 去掉 Critic 换更简单,代价是 group size >= 4
与 VLA 的关系RLAIF 与文本 RLHF 共用同一套基础设施,GRPO 可直接用于 VLA 微调

一句话记住:RLHF 的瓶颈从来不在算法,而在”让生成和训练各就各位”。分布式 RL 训练做的就是把这件事工程化。


系列导航:本篇是本系列开篇。相关背景见 fa4-deepseek-v4(V4 的训练与压缩)与 sys8-parallel-strategies-pd-disaggregation(并行切分与 PD 分离)。

觉得有用?欢迎点赞、收藏,或请作者喝咖啡 ☕️

支付宝收款码

支付宝

微信收款码

微信

💬 留言

评论由 Giscus 驱动(基于 GitHub Discussions)。 当前仓库 NaphJohn/LLM-blog 尚未启用 Discussions:请在 GitHub 仓库 Settings → General → Features 勾选 Discussions 后刷新本页,评论区即自动显示。