首页/新闻资讯/正文详情

解读 VeRL 框架源码:PPO 和 GRPO 算法如何计算优势 (Advantage)

发布时间:2026/11/5 1:30:31 来源:云帆数科 栏目:资讯中心
解读 VeRL 框架源码:PPO 和 GRPO 算法如何计算优势 (Advantage)
最近正在入门大模型 RL 微调阅读 VeRL 框架代码。在这篇博客中我们从 VeRL 源码入手解读一下 ppo 和 grpo 算法的 advantage 计算方法# 来自 verl/trainer/ppo/core_algos.pyregister_adv_est(AdvantageEstimator.GAE)# or simply: register_adv_est(gae)defcompute_gae_advantage_return(token_level_rewards:torch.Tensor,values:torch.Tensor,response_mask:torch.Tensor,gamma:torch.Tensor,lam:torch.Tensor,):Adapted from https://github.com/huggingface/trl/blob/main/trl/trainer/ppo_trainer.py Args: token_level_rewards: (torch.Tensor) shape is (bs, response_length) values: (torch.Tensor) shape is (bs, response_length) response_mask: (torch.Tensor) shape is (bs, response_length). [EOS] mask. The token after [EOS] have mask zero. gamma is (float) discounted factor used in RL lam: (float) lambda value when computing Generalized Advantage Estimation (https://arxiv.org/abs/1506.02438) Returns: advantages: (torch.Tensor) shape: (bs, response_length) Returns: (torch.Tensor) shape: (bs, response_length) withtorch.no_grad():nextvalues0lastgaelam0advantages_reversed[]gen_lentoken_level_rewards.shape[-1]fortinreversed(range(gen_len)):deltatoken_level_rewards[:,t]gamma*nextvalues-values[:,t]lastgaelam_deltagamma*lam*lastgaelam# skip values and TD-error on observation tokensnextvaluesvalues[:,t]*response_mask[:,t](1-response_mask[:,t])*nextvalues lastgaelamlastgaelam_*response_mask[:,t](1-response_mask[:,t])*lastgaelam advantages_reversed.append(lastgaelam)advantagestorch.stack(advantages_reversed[::-1],dim1)returnsadvantagesvalues advantagesverl_F.masked_whiten(advantages,response_mask)returnadvantages,returns# NOTE(sgm): this implementation only consider outcome supervision, where the reward is a scalar.register_adv_est(AdvantageEstimator.GRPO)# or simply: register_adv_est(grpo)defcompute_grpo_outcome_advantage(token_level_rewards:torch.Tensor,response_mask:torch.Tensor,index:np.ndarray,epsilon:float1e-6,norm_adv_by_std_in_grpo:boolTrue,config:Optional[AlgoConfig]None,)-tuple[torch.Tensor,torch.Tensor]: Compute advantage for GRPO, operating only on Outcome reward (with only one scalar reward for each response). Args: token_level_rewards: (torch.Tensor) shape is (bs, response_length) response_mask: (torch.Tensor) shape is (bs, response_length) index: (np.ndarray) index array for grouping epsilon: (float) small value to avoid division by zero norm_adv_by_std_in_grpo: (bool) whether to scale the GRPO advantage config: (Optional[AlgoConfig]) algorithm configuration object Note: If norm_adv_by_std_in_grpo is True, the advantage is scaled by the std, as in the original GRPO. If False, the advantage is not scaled, as in Dr.GRPO (https://arxiv.org/abs/2503.20783). Returns: advantages: (torch.Tensor) shape is (bs, response_length) Returns: (torch.Tensor) shape is (bs, response_length) scorestoken_level_rewards.sum(dim-1)id2scoredefaultdict(list)id2mean{}id2std{}withtorch.no_grad():bszscores.shape[0]foriinrange(bsz):id2score[index[i]].append(scores[i])foridxinid2score:iflen(id2score[idx])1:id2mean[idx]torch.tensor(0.0)id2std[idx]torch.tensor(1.0)eliflen(id2score[idx])1:scores_tensortorch.stack(id2score[idx])id2mean[idx]torch.mean(scores_tensor)id2std[idx]torch.std(scores_tensor)else:raiseValueError(fno score in prompt index:{idx})foriinrange(bsz):ifnorm_adv_by_std_in_grpo:scores[i](scores[i]-id2mean[index[i]])/(id2std[index[i]]epsilon)else:scores[i]scores[i]-id2mean[index[i]]scoresscores.unsqueeze(-1)*response_maskreturnscores,scores以上的两段代码来自 VeRL 框架分别实现了PPO 中的 GAE广义优势估计和GRPO组相对策略优化的 advantage 计算方法。下面我们逐一解读并对比它们的设计思路。文章目录1 PPO GAE 优势计算 (compute_gae_advantage_return)1.1 函数签名1.2 核心逻辑GAE 原理2 GRPO 优势计算 (compute_grpo_outcome_advantage)2.1 函数签名2.2 核心逻辑GRPO 原理3 PPO(GAE) 与 GRPO 优势计算对比1 PPO GAE 优势计算 (compute_gae_advantage_return)1.1 函数签名defcompute_gae_advantage_return(token_level_rewards:torch.Tensor,values:torch.Tensor,response_mask:torch.Tensor,gamma:torch.Tensor,lam:torch.Tensor,):token_level_rewards: 形状(batch_size, response_length)每个 token 的即时奖励通常由奖励模型或规则给出。如果是 LLM 做数学题整个回答的 reward 可能只会给在最后一个 token。values: 形状与 reward 相同Critic 网络输出的每个 token 的状态价值估计。response_mask: 形状相同标记哪些 token 属于有效响应[EOS] 之后的 token 被 mask 掉值为0。gamma: 折扣因子控制未来奖励的重要性。lam: GAE 中的 λ 参数平衡偏差与方差。1.2 核心逻辑GAE 原理GAE 的递推公式为δ t r t γ ⋅ V ( s t 1 ) − V ( s t ) , A t δ t γ ⋅ λ ⋅ A t 1 δ_t r_t γ·V(s_{t1}) - V(s_t), \quad A_t δ_t γ·λ·A_{t1}δt​rt​γ⋅V(st1​)−V(st​),At​δt​γ⋅λ⋅At1​其中A t A_tAt​是优势V VV是价值函数。δ t Q ( s t , a t ) − V ( s t ) \delta_t Q(s_t, a_t) - V(s_t)δt​Q(st​,at​)−V(st​)而 advantage 的这种计算方法相当于不仅考虑当前时刻的 advantage还以 γ 的 discount factor 考虑未来的 advantage。代码中从最后一个 token 反向计算避免了显式循环的多次张量操作同时利用response_mask处理变长序列。nextvalues,lastgaelam0,0advantages_reversed[]gen_lentoken_level_rewards.shape[-1]fortinreversed(range(gen_len)):# 计算 TD 误差 deltadeltatoken_level_rewards[:,t]gamma*nextvalues-values[:,t]# 递推计算优势lastgaelam_deltagamma*lam*lastgaelam# 用 mask 控制哪些位置的 value 和 advantage 要传播nextvaluesvalues[:,t]*response_mask[:,t](1-response_mask[:,t])*nextvalues lastgaelamlastgaelam_*response_mask[:,t](1-response_mask[:,t])*lastgaelam advantages_reversed.append(lastgaelam)advantagestorch.stack(advantages_reversed[::-1],dim1)# 恢复正序returnsadvantagesvalues# 计算 returns (用于价值网络更新)advantagesverl_F.masked_whiten(advantages,response_mask)# 对有效 token 做白化标准化returnadvantages,returns关键点使用response_mask确保填充位置不参与计算也不传播梯度。masked_whiten对每个 batch 的有效 token 进行标准化均值 0方差 1有助于稳定训练。最终返回的advantages和returns形状均为(batch_size, response_length)。2 GRPO 优势计算 (compute_grpo_outcome_advantage)2.1 函数签名defcompute_grpo_outcome_advantage(token_level_rewards:torch.Tensor,response_mask:torch.Tensor,index:np.ndarray,epsilon:float1e-6,norm_adv_by_std_in_grpo:boolTrue,config:Optional[AlgoConfig]None,):token_level_rewards: 形状(batch_size, response_length)每个 token 的奖励。这里假设是结果监督outcome supervision即一个响应只对应一个标量奖励如正确/错误因此所有 token 的奖励和等于该响应的最终得分。response_mask: 同上标记有效 token。index: 形状(batch_size,)每个样本所属的组 ID例如同一个 prompt 的不同采样。GRPO 需要在组内进行标准化。norm_adv_by_std_in_grpo: 如果为 True则按原始 GRPO 方式除以标准差如果为 False则只减均值Dr.GRPO 风格。epsilon: 防止除零。2.2 核心逻辑GRPO 原理GRPO 不使用 Critic 网络而是用同一 prompt 下多个采样输出的平均奖励作为 baseline。advantage 就是组内标准化的奖励将 token 奖励求和得到每个 response 的标量得分scorestoken_level_rewards.sum(dim-1)# shape: (batch_size,)按 index 分组计算每个 group 的均值和标准差id2scoredefaultdict(list)foriinrange(bsz):id2score[index[i]].append(scores[i])foridxinid2score:scores_tensortorch.stack(id2score[idx])id2mean[idx]torch.mean(scores_tensor)id2std[idx]torch.std(scores_tensor)如果组内只有一个样本均值为 0标准差为 1避免除零。根据均值和标准差对每个得分进行标准化foriinrange(bsz):ifnorm_adv_by_std_in_grpo:scores[i](scores[i]-id2mean[index[i]])/(id2std[index[i]]epsilon)else:scores[i]scores[i]-id2mean[index[i]]标准化后每个组内的平均优势为 0可能方差为 1。每个 token 都被赋值为相同的标量 advantage非响应位置仍为 0scoresscores.unsqueeze(-1)*response_mask# shape: (bs, response_length)returnscores,scores# 这里 returns 和 advantages 相同GRPO 不更新价值网络关键点GRPO 完全抛弃了价值网络baseline 来自同组的其他样本避免了训练 Critic 的开销和不稳定性。标准化操作可以在组内消除奖励尺度差异使策略更新更稳健。返回的两个张量相同因为 GRPO 没有独立的 returns 概念一般直接使用优势更新策略。3 PPO(GAE) 与 GRPO 优势计算对比维度PPO GAEGRPObaseline 来源Critic 网络估计的状态值V ( s t ) V(s_t)V(st​)同一 prompt 下多个样本的平均奖励优势形式每个时间步t tt都有一个 advantageA t A_tAt​整个响应共用一个标量 advantage广播到每个 token是否需要价值网络是否处理变长序列通过 mask 控制逐 token 计算汇总为标量后广播mask 仅用于置零计算复杂度较高需维护价值网络并做反向传播较低仅需组内统计适用场景一般 RLHF需要细粒度信用分配结果监督任务如数学推理、代码生成可节省资源总结PPO-GAE代码是标准的 GAE 实现考虑了 mask 和最终的 whitening适用于需要 Critic 的在线策略优化。GRPO代码则利用了结果监督和分组归一化的思想简化了优势计算适合大模型微调中每个响应只有一个标量奖励的场景如 RLHF 中的“正确/错误”信号。这两段代码清晰体现了两种算法在设计哲学上的差异PPO 追求细粒度时序信用分配而 GRPO 通过组内比较降低方差并简化实现。

相关推荐

轻量级 jQuery 折叠插件 jQuery-Collapse:3 分钟读懂内容渐进式披露的终极方案
轻量级 jQuery 折叠插件 jQuery-Collapse:3 分钟读懂内容渐进式披露的终极方案

【免费下载链接】jQuery-Collapse A lightweight (~1kb) jQuery plugin that enables expanding and collapsing content 项目地址: https://gitcode.com/gh_mirrors/jq/jQuery-Collapse 点击查看 免费下载 网页内容太多时,直接全部展示会让用户感到 ov… · 2026/11/5 1:30:31

气象数据接入天气预报
气象数据接入天气预报

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 1:29:31

Ubuntu20.04.6安装RTXPRO6000驱动
Ubuntu20.04.6安装RTXPRO6000驱动

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 1:29:31

C# ECharts模型库:解决序列化乱码与运行时崩溃问题
C# ECharts模型库:解决序列化乱码与运行时崩溃问题

简介:这是一套专为C# MVC开发者设计的ECharts模型层建模库,解决.NET后端与前端图表库深度集成难题,显著降低数据可视化开发门槛。资源共369个文件,涵盖110个核心C#模型类(如图表配置、坐标轴、系列项等)、8… · 2026/11/5 2:17:49

企业知识库搭建指南:架构、工具与实战
企业知识库搭建指南:架构、工具与实战

1. 知识库搭建的核心价值与场景解析十年前我刚入行时,第一次听说"知识库"这个概念还以为是图书馆的数字版本。直到参与企业级文档管理系统建设才明白,真正的知识库是能让你在3秒内找到三年前某个项目的技术方案,在会议前5分钟快速调… · 2026/11/5 2:17:49

云原生AI模型版本管理:原理与实践
云原生AI模型版本管理:原理与实践

1. 云原生AI模型版本管理的核心价值在AI工程化实践中,模型版本管理正成为MLOps流程中最关键的痛点之一。我们团队在金融风控场景中曾经历过这样的困境:某次模型迭代后AUC指标意外下降5个百分点,但由于缺乏规范的版本追踪,花了整整… · 2026/11/5 2:17:48

虚拟电厂行业早报(11月4日)|贵州能源集团568万建平台,365天含3个月试运行
虚拟电厂行业早报(11月4日)|贵州能源集团568万建平台,365天含3个月试运行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 2:17:48

C#强类型ECharts图表配置模型库:告别JSON拼接
C#强类型ECharts图表配置模型库:告别JSON拼接

简介:C# For ECharts 模型层建模库是面向.NET开发者,特别是使用ASP.NET MVC框架构建数据可视化应用的中高级工程师的高效工具。它解决了在C#后端直接生成ECharts标准配置JSON的痛点,避免手动拼接、类型错配与结构维护困难等问题,显… · 2026/11/5 2:17:48

键盘与鼠标:结构原理与选购指南
键盘与鼠标:结构原理与选购指南

1. 键盘与鼠标:人机交互的核心工具键盘和鼠标作为计算机最基础的输入设备,它们的设计原理和结构直接影响着我们的工作效率和使用体验。作为一名长期与各种输入设备打交道的技术爱好者,我深刻理解选择合适设备的重要性。不同类型的键盘和鼠标在… · 2026/11/5 2:16:48

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码