news 2026/2/9 4:48:03

verl训练全流程拆解:从rollout到advantage计算

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
verl训练全流程拆解:从rollout到advantage计算

verl训练全流程拆解:从rollout到advantage计算

强化学习在大语言模型后训练中的应用正变得越来越关键,而verl作为专为LLM设计的高效RL框架,其核心流程——尤其是rollout生成与advantage计算——是理解整个训练逻辑的钥匙。本文不讲抽象理论,不堆砌公式,而是带你一步步拆解verl中真实运行的每一步:数据怎么分、模型怎么调、log_prob怎么算、reward怎么来、advantage怎么出。所有内容均基于verl源码实际执行路径,聚焦GRPO这一典型无critic、无reward model的轻量级PPO变体,用可验证的代码片段和明确的数据流向,还原一个完整训练step的真实面貌。

1. 全局视角:一次训练step到底发生了什么

在verl中,一次完整的训练step不是“先rollout再算advantage最后更新”,而是一个高度协同、设备感知、分片驱动的数据流。我们先看整体骨架,再逐层深入。

以单机6卡(trainer.n_gpus_per_node=6)、每步处理60条prompt(data.train_batch_size=60)为例,整个step的核心阶段如下:

  • 阶段一:Prompt分发与并行rollout
    60条原始prompt被划分为3组,每组20条,分别送入3个vLLM推理引擎(每个引擎绑定2张GPU)。每个引擎对20条prompt各生成12条响应(rollout.n=12),产出240条完整序列。3个引擎汇总后,共得720条rollout样本。

  • 阶段二:多策略log_prob并行计算
    这720条样本同时被送入两个计算通道:
    ▪ 旧策略(actor)通道:计算每条序列中每个token由当前actor模型生成的概率对数(old_log_prob);
    ▪ 参考策略(ref)通道:计算同一序列由固定参考模型生成的概率对数(ref_log_prob)。

  • 阶段三:规则化reward与advantage生成
    对每条序列,按预设规则(如答案正确性、长度合规性、格式匹配度)打分,得到token-level reward;
    基于该reward,结合折扣因子γ和GAE参数λ,直接计算出每条序列的advantage(无需critic模型输出value)。

  • 阶段四:Actor模型梯度更新
    利用advantage指导actor模型参数更新,完成一次policy优化。

整个过程没有独立的“价值网络”前向传播,也没有外部reward model调用——这正是GRPO的精简所在。下面,我们从最前端的rollout开始,一层层剥开它的实现细节。

2. Rollout:如何把60条prompt变成720条高质量响应

rollout不是简单地让模型“多生成几次”,而是在分布式环境下,对计算资源、内存带宽、通信开销进行精细编排的结果。verl通过ActorRolloutRefWorker统一调度rollout行为,其核心在于设备网格(device mesh)的构建与分片策略的协同

2.1 设备网格划分:让GPU各司其职

_build_rollout方法中,verl根据配置创建了专门用于rollout的二维设备网格:

infer_tp = self.config.rollout.tensor_model_parallel_size # =2 dp = self.world_size // infer_tp # =6//2=3 rollout_device_mesh = init_device_mesh('cuda', mesh_shape=(dp, infer_tp), mesh_dim_names=['dp', 'infer_tp'])

这行代码定义了一个3×2的GPU网格:

  • dp维度(Data Parallel)负责将60条prompt切分为3份,每份20条;
  • infer_tp维度(Inference Tensor Parallel)表示每份20条prompt由2张GPU协作完成vLLM推理。

最终设备网格结构为:

DeviceMesh('cuda', [[0, 1], [2, 3], [4, 5]], mesh_dim_names=('dp', 'infer_tp'))

即GPU 0&1组成第1个推理单元,GPU 2&3组成第2个,GPU 4&5组成第3个。每个单元独立运行一个vLLM实例,互不干扰。

2.2 Rollout执行:generate_sequences的三段式流水线

generate_sequences是rollout的入口函数,它被@register(dispatch_mode=Dispatch.DP_COMPUTE_PROTO)装饰,意味着它天然支持数据并行下的自动分发与聚合。其执行逻辑可清晰划分为三段:

(1)预处理:数据对齐与元信息注入
prompts = prompts.to(torch.cuda.current_device()) # 将batch移至当前GPU meta_info = { 'eos_token_id': self.tokenizer.eos_token_id, 'pad_token_id': self.tokenizer.pad_token_id, } prompts.meta_info.update(meta_info) # 注入tokenizer关键ID,供vLLM使用

此时输入的prompts是一个包含60条prompt的DataProto对象,但尚未分片。它会被rollout_sharding_manager.preprocess_data()自动切分,并分发至3个vLLM单元。

(2)vLLM推理:每个单元生成240条响应

每个vLLM单元收到20条prompt后,执行n=12次采样:

  • 输入:20条prompt(如“请写一首关于春天的五言绝句”)
  • 输出:20×12=240条完整响应(含output_ids,logprobs,prompt_token_ids等)

注意:vLLM本身不返回token-level logprob,它只返回每个token的top-k logprob。verl后续会用这些logprob重建完整序列的log_prob链。

(3)后处理与聚合:从240×3到720

rollout_sharding_manager.postprocess_data(output)负责:

  • 收集3个vLLM单元各自产出的240条响应;
  • 将它们按原始顺序拼接,形成统一的720条响应batch;
  • 补充必要的元数据(如prompt_lengths,response_lengths),为后续log_prob计算做准备。

最终返回的output是一个标准DataProto,其batch['prompt_token_ids']形状为[720, 8192],与ray_trainer.py中打印结果完全一致。

关键洞察:rollout的“批量”不是静态的,而是动态组合的。data.train_batch_size=60是输入粒度,rollout.n=12是采样倍率,tensor_model_parallel_size=2是硬件约束,三者共同决定了最终的720这个数字。它不是魔法,而是可推导、可复现的工程结果。

3. Log Prob计算:为什么需要两套log_prob?它们怎么算?

rollout生成的720条响应只是“文本”,要进入RL训练,必须知道:这些文本在当前策略下有多大概率被生成?在参考策略下又有多大概率?这就是log_prob计算的意义——它把文本变成了可微分、可比较的数学量。

3.1 Actor log_prob:衡量当前策略的“自信程度”

self.actor_rollout_wg.compute_log_prob(batch)调用的是actor模型的前向传播,目标是为每条响应中的每个token计算: $$ \log \pi_{\text{old}}(a_t \mid s_t, \tau_{<t}) $$ 即:在给定历史τ_<t的前提下,当前策略选择动作a_t(即当前token)的对数概率。

在verl中,这一计算通过以下方式高效完成:

  • 输入:720条响应的input_ids(已拼接好prompt+response)及其attention_mask
  • 模型:FSDP封装的actor模型(如Llama-3-8B)
  • 输出:一个与input_ids同长的log_prob张量,仅对response部分有效(prompt部分mask掉)

由于actor模型采用FSDP,计算在6张GPU上并行展开,但verl通过dispatch_mode=DP_COMPUTE_PROTO确保每个GPU只处理自己分片内的样本,避免冗余计算。

3.2 Ref log_prob:提供稳定的KL散度基准

self.ref_policy_wg.compute_ref_log_prob(batch)调用的是一个冻结的参考模型(通常为SFT后的基座模型),其作用不是参与更新,而是提供一个稳定的概率分布基准: $$ \log \pi_{\text{ref}}(a_t \mid s_t, \tau_{<t}) $$

为什么需要它?因为RLHF/GRPO训练中,必须防止actor模型过度偏离原始能力,导致胡说八道。KL散度惩罚项: $$ \mathcal{L}{\text{KL}} = \mathbb{E}[\log \pi{\text{old}} - \log \pi_{\text{ref}}] $$ 就是靠这对log_prob计算出来的。

ref模型同样走FSDP流程,但它全程不更新参数,且通常配置更轻量(如param_offload=True),以节省显存。

3.3 数据对齐:确保两个log_prob能相减

这是极易被忽略却至关重要的细节。actor和ref模型的tokenizer必须完全一致,且input_ids的padding、truncation策略必须严格同步。verl通过以下方式保障:

  • 所有worker共享同一个self.tokenizer实例;
  • compute_log_prob内部调用prepare_inputs_for_generation,确保prompt和response的拼接逻辑完全一致;
  • 最终log_prob张量的shape、mask位置、有效token索引完全对齐。

若这两套log_prob无法对齐,KL惩罚就失去意义,训练会迅速崩溃。

4. Advantage计算:没有Critic,Advantage从何而来?

这是GRPO区别于标准PPO的核心。PPO需要critic模型预测每个状态的价值V(s),再通过GAE(Generalized Advantage Estimation)计算advantage: $$ A_t^{\text{GAE}} = \delta_t + (\gamma\lambda)\delta_{t+1} + (\gamma\lambda)^2\delta_{t+2} + \cdots $$ 其中δ_t = r_t + γV(s_{t+1}) - V(s_t)

而GRPO彻底抛弃critic,其advantage直接由规则化reward驱动: $$ A_t = r_t + \gamma r_{t+1} + \gamma^2 r_{t+2} + \cdots - b_t $$ 其中b_t是baseline(常取rolling average reward),r_t是token-level reward。

4.1 Token-level Reward:规则即模型

reward_fn(batch)是用户自定义函数,verl不提供默认实现,但给出了典型范式:

def reward_fn(batch): # batch.batch['responses'] 是720条字符串列表 responses = batch.batch['responses'] scores = [] for resp in responses: score = 0.0 if "春天" in resp and "花开" in resp: # 关键词匹配 score += 1.0 if len(resp) > 20 and len(resp) < 50: # 长度合规 score += 0.5 if resp.count("。") == 2: # 标点规范 score += 0.3 scores.append(score) return torch.tensor(scores, dtype=torch.float32)

该函数输出一个[720]的reward张量,verl将其广播为token-level形式(即每个token获得相同reward),存入batch.batch['token_level_rewards']

4.2 GAE计算:verl的compute_advantage函数

compute_advantage是verl中高度优化的advantage计算器,其签名如下:

def compute_advantage( batch, adv_estimator=None, # 此处为None(GRPO不使用) gamma=0.99, lam=0.95, num_repeat=12 # 每条prompt生成的响应数 ):

在GRPO模式下,adv_estimator为None,函数直接走“纯reward”路径:

  • 读取batch.batch['token_level_rewards'](shape:[720, seq_len]
  • 对每条响应,按gammalam进行GAE衰减计算,得到[720, seq_len]的advantage张量
  • 将advantage按token归一化(如除以响应长度),存入batch.batch['advantages']

整个过程不涉及任何神经网络前向,纯CPU/GPU张量运算,毫秒级完成。

关键对比:PPO的advantage依赖critic预测的V(s),易受critic训练不稳定影响;GRPO的advantage直接锚定规则reward,更稳定、更可控,代价是reward设计需足够鲁棒。

5. 训练循环:从advantage到actor更新的最后一步

当720条响应拥有了old_log_probref_log_probadvantages,训练循环就进入了最关键的actor更新阶段。

5.1 KL散度惩罚:防止策略坍缩

apply_kl_penalty中,verl将KL项融入reward:

# token_level_rewards 已包含原始reward # 现在减去 KL 散度项 kl_div = old_log_prob - ref_log_prob # shape: [720, seq_len] kl_penalty = self.config.algorithm.kl_penalty # 如0.01 batch.batch['token_level_rewards'] = batch.batch['token_level_rewards'] - kl_penalty * kl_div

这使得actor在追求高reward的同时,被强制靠近ref策略,避免过拟合规则或生成低质量文本。

5.2 Actor更新:PPO-style policy gradient

self.actor_rollout_wg.update_actor(batch)执行标准的PPO loss计算: $$ \mathcal{L}_{\text{PPO}} = -\mathbb{E}\left[ \min\left( r_t \cdot A_t,\ \text{clip}(r_t, 1-\epsilon, 1+\epsilon) \cdot A_t \right) \right] $$ 其中r_t = \frac{\pi_{\text{new}}(a_t|s_t)}{\pi_{\text{old}}(a_t|s_t)}是重要性采样比。

verl在此处做了关键优化:

  • π_new由当前actor模型实时计算;
  • π_old即前面算好的old_log_prob,无需重复计算;
  • clip操作在CUDA kernel中完成,避免Python循环。

整个更新过程在FSDP下完成梯度同步,6张GPU合力完成一次参数更新。

5.3 实际效果:一次step的耗时分布(实测参考)

在A100×6环境上,一次完整step的耗时大致分布为:

  • Rollout(vLLM生成):~3.2s(占总耗时65%)
  • Log_prob计算(actor+ref):~0.9s(18%)
  • Advantage计算:~0.1s(2%)
  • Actor更新:~0.7s(14%)
  • 其他(I/O、metric收集等):~0.1s(1%)

可见,rollout是绝对瓶颈。这也是verl强调与vLLM/sglang深度集成的原因——优化推理,就是优化整个RL训练的天花板。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/7 12:12:26

Local Moondream2参数说明:为何1.6B模型适合本地部署

Local Moondream2参数说明&#xff1a;为何1.6B模型适合本地部署 1. 为什么是1.6B&#xff1f;轻量不等于简陋 很多人看到“1.6B参数”第一反应是&#xff1a;“这么小&#xff0c;能干啥&#xff1f;” 其实这恰恰是Local Moondream2最聪明的设计选择——它不是在堆参数&…

作者头像 李华
网站建设 2026/2/8 17:50:48

枪战游戏“棋盘化”价值建模

将枪战游戏&#xff08;如《CS:GO》、《Valorant》、《PUBG》等&#xff09;对局信息抽象为类似“下棋”的策略模型&#xff0c;是一种非常有前景的战术分析与AI训练思路。以下是一个系统化的框架&#xff0c;用于记录和转化枪战游戏中的动态信息为可量化的“棋盘”状态&#x…

作者头像 李华
网站建设 2026/2/9 3:12:39

黑客技术入门避坑指南:告别脚本小子,6个月从零基础到可就业

在网络安全学习圈&#xff0c;有个普遍现象&#xff1a;多数人带着“成为黑客大神”的憧憬入门&#xff0c;最终却沦为“工具收藏家”或触碰法律红线的“脚本小子”。其实黑客技术的核心是“以攻促防”的思维与能力&#xff0c;而非单纯的工具使用&#xff0c;这篇文章结合上千…

作者头像 李华
网站建设 2026/2/3 19:30:09

ms-swift轻量训练秘籍:LoRA/QLoRA参数设置全解析

ms-swift轻量训练秘籍&#xff1a;LoRA/QLoRA参数设置全解析 你是否也遇到过这样的困境&#xff1a;想微调一个7B大模型&#xff0c;却发现单卡3090显存直接爆满&#xff1b;好不容易跑通LoRA训练&#xff0c;生成效果却平平无奇&#xff1b;调整了十几个参数&#xff0c;loss…

作者头像 李华