考虑这个场景在 RL 微调大模型的过程中我们让模型生成了一批回答每个回答是一串文字然后我们给每个回答里的每个字token算了一个“损失值”可以理解为这个字写得“好不好”的评分损失越大说明越不好。同时我们还有一个“掩码”mask标记哪些字是有效的比如忽略填充的无意义字。此时为了最小化损失值我们需要把这堆零散的字级别的损失汇总成一个总的损失值然后用这个总损失去更新模型。这个汇总方式可以有很多种就像我们计算平均分可以用“所有字的总分除以字数”也可以用“每句话的平均分再平均”等等不同的汇总方式会影响模型学习的方向。VeRL 将这一部分封装为agg_loss函数以下为该函数的具体实现# 位于 verl/trainer/ppo/core_algos.pydefagg_loss(loss_mat:torch.Tensor,loss_mask:torch.Tensor,loss_agg_mode:str,dp_size:int1,batch_num_tokens:Optional[int]None,global_batch_size:Optional[int]None,loss_scale_factor:Optional[int]None,): Aggregate the loss across global batch to ensure the loss is invariant to fsdp/megatron parallelism. NOTE: The returned loss has different behaviors for different backend: - FSDP: the loss is directly used for backward. - Megatron: the loss should be scaled by num_microbatches and cp_size for pp schedule. Args: loss_mat: micro batch loss matrix, (bs, response_length) loss_mask: micro batch loss mask, (bs, response_length) loss_agg_mode: method to aggregate the loss matrix into a scalar dp_size: data parallel size batch_num_tokens: number of valid tokens in global batch global_batch_size: global batch size loss_scale_factor: scale factor for seq-mean-token-sum-norm mode. If None, uses loss_mask.shape[-1]. Set this to a constant value to ensure consistent normalization throughout training. Returns: loss: a scalar torch.Tensor aggregated loss ifloss_agg_modetoken-mean:ifbatch_num_tokensisNone:batch_num_tokensloss_mask.sum()lossverl_F.masked_sum(loss_mat,loss_mask)/batch_num_tokens*dp_sizeelifloss_agg_modeseq-mean-token-sum:seq_lossestorch.sum(loss_mat*loss_mask,dim-1)# token-sumseq_mask(torch.sum(loss_mask,dim-1)0).float()# exclude fully masked sequencesifglobal_batch_sizeisNone:global_batch_sizeseq_mask.sum()lossverl_F.masked_sum(seq_losses,seq_mask)/global_batch_size*dp_size# seq-meanelifloss_agg_modeseq-mean-token-mean:seq_masktorch.sum(loss_mask,dim-1)# per-sequence token countseq_lossestorch.sum(loss_mat*loss_mask,dim-1)/(seq_mask1e-8)# token-meanseq_mask(seq_mask0).float()# exclude fully masked sequencesifglobal_batch_sizeisNone:global_batch_sizeseq_mask.sum()lossverl_F.masked_sum(seq_losses,seq_mask)/global_batch_size*dp_size# seq-meanelifloss_agg_modeseq-mean-token-sum-norm:seq_lossestorch.sum(loss_mat*loss_mask,dim-1)ifloss_scale_factorisNone:loss_scale_factorloss_mask.shape[-1]losstorch.sum(seq_losses)/loss_scale_factorelse:raiseValueError(fInvalid loss_agg_mode:{loss_agg_mode})returnloss1 输入参数回顾loss_mat: 形状(bs, response_length)每个 token 的损失值例如策略梯度损失或 KL 散度。loss_mask: 相同形状标记哪些 token 是有效的1 表示有效0 表示 padding 或忽略。loss_agg_mode: 聚合方式可选值有token-mean,seq-mean-token-sum,seq-mean-token-mean,seq-mean-token-sum-norm。dp_size: 数据并行度分布式训练时使用的 GPU 数量用于将局部损失缩放为全局等价损失。batch_num_tokens: 全局批次中有效 token 的总数跨所有 GPU。如果未提供会在token-mean模式中自动计算局部和。global_batch_size: 全局批次中有效序列的数量。如果未提供会在某些模式中自动使用局部有效序列数。loss_scale_factor: 仅用于seq-mean-token-sum-norm模式作为分母的固定缩放因子。如果未提供默认使用loss_mask.shape[-1]即固定的响应长度。2 聚合模式详解2.1token-mean所有有效 token 的平均损失lossverl_F.masked_sum(loss_mat,loss_mask)/batch_num_tokens*dp_size直观理解把每个回答里所有有效字的损失加起来然后除以所有有效字的总数。最后得到一个“平均每个字有多差”的值。计算先计算所有有效 token 的损失总和masked_sum相当于(loss_mat * loss_mask).sum()然后除以有效 token 总数batch_num_tokens得到每个 token 的平均损失。最后乘以dp_size使结果相当于全局 token 平均损失在分布式训练中每个 GPU 只计算局部平均乘以dp_size是为了统一到全局视角。作用这是最直观的平均方式每个有效 token 对损失的贡献权重相等。verl 的 GRPO 默认使用此模式因为它简单稳定尤其适合长文本生成任务。2.2seq-mean-token-sum先对每个序列内 token 损失求和再对所有序列求平均seq_lossestorch.sum(loss_mat*loss_mask,dim-1)# 每个序列的总损失seq_mask(torch.sum(loss_mask,dim-1)0).float()# 哪些序列至少有一个有效 tokenlossverl_F.masked_sum(seq_losses,seq_mask)/global_batch_size*dp_size直观理解第一步对每个回答把里面所有有效字的损失加起来得到“这个回答的总损失”。第二步把这些回答的总损失加起来再除以回答的数量得到“平均每个回答的总损失”。把每个回答当成一个整体先看这个回答整句话写得有多差总损失然后看看所有回答的平均整句损失。这样一个很长的回答虽然字多但它的总损失可能会很大所以它对最终结果的影响也比较大。计算对每个序列将有效 token 的损失相加得到序列级总损失seq_losses。生成序列掩码seq_mask有效序列为 1全填充序列为 0。对有效序列的总损失求和除以全局序列数global_batch_size得到序列平均总损失。最后乘以dp_size。作用这种聚合方式将每个序列视为一个样本不论序列长度如何每个序列对损失的贡献权重相同。因此长序列的 token 级损失会被隐式地“压缩”成序列级损失可能更适合某些任务。2.3seq-mean-token-mean先对每个序列内 token 损失求平均再对所有序列求平均seq_masktorch.sum(loss_mask,dim-1)# 每个序列的有效 token 数seq_lossestorch.sum(loss_mat*loss_mask,dim-1)/(seq_mask1e-8)# 每个序列的平均损失seq_mask(seq_mask0).float()# 有效序列掩码lossverl_F.masked_sum(seq_losses,seq_mask)/global_batch_size*dp_size直观理解第一步对每个回答把里面所有有效字的损失加起来除以这个回答的有效字数得到“这个回答每个字的平均损失”。第二步把这些回答的平均字损失加起来除以回答的数量得到“平均每个回答的平均字损失”。先看每个回答里平均每个字写得有多差然后把这些平均值再平均。这样不管一个回答是长是短它对最终结果的贡献只取决于它内部字的平均质量而不是总损失。这样可以避免长句子因为字多而主导训练。计算计算每个序列的有效 token 数seq_mask即序列长度。对每个序列计算有效 token 损失的平均值seq_losses。对有效序列的平均损失求和除以全局序列数得到序列平均损失的平均。作用这种模式是原始 GRPO 论文中使用的聚合方式。它将每个序列的损失归一化到相同尺度每个序列的平均损失然后再平均。这样做的动机是让每个序列对梯度的贡献相等避免长序列因 token 多而主导梯度。但在长思维链场景中每个序列的平均损失可能波动较大导致训练不稳定因此 verl 默认未采用此模式。2.4seq-mean-token-sum-norm所有序列的总损失之和除以一个固定常数seq_lossestorch.sum(loss_mat*loss_mask,dim-1)# 每个序列的总损失ifloss_scale_factorisNone:loss_scale_factorloss_mask.shape[-1]# 默认使用固定的响应长度losstorch.sum(seq_losses)/loss_scale_factor直观理解第一步把每个回答的总损失算出来和模式2一样。第二步把所有回答的总损失加起来然后除以一个固定的数字比如你预设的最大回答长度或者直接使用固定的响应长度。这个固定数字在训练过程中不变。通俗理解把所有回答的“总损失”加起来然后除以一个固定的大数。这个固定的大数不随当前批次回答的长度变化所以最终损失的大小不受句子长短的影响。这样可以避免模型为了降低损失而故意把句子写得很长因为长句子总损失更大除以固定数后可能仍然大但不会因为短句子分母小而被放大。计算先计算每个序列的总损失然后对所有序列的总损失求和最后除以一个固定的缩放因子loss_scale_factor可以是一个常数如最大响应长度。注意这里没有乘以dp_size也没有使用global_batch_size。作用这是 DrGRPO 中引入的模式旨在消除长度偏差。在标准 GRPO 中组内奖励归一化可能导致模型偏向生成长响应尤其是错误答案时而此模式通过使用固定的分母例如预定义的最大响应长度来保证损失大小不受序列实际长度影响从而缓解优化偏差。如果loss_scale_factor设置为一个全局常数如 2048那么不论当前批次序列长度如何损失的计算都会除以这个常数使得梯度更新步长与长度解耦。3 为什么需要这么多聚合模式在强化学习训练 LLM 时损失的计算方式会影响梯度更新的方向和幅度。不同的聚合策略对应着不同的假设token-mean每个 token 同等重要适合希望模型在 token 级别精细调整的场景。seq-mean-token-sum每个序列同等重要但保留序列内 token 损失的原始和适合希望模型优化序列整体回报的任务。seq-mean-token-mean每个序列同等重要且每个序列的损失被归一化到 token 平均适合希望平衡长短序列贡献的场景。seq-mean-token-sum-norm消除长度对损失的影响专门用于纠正 GRPO 可能产生的长度偏差。4 分布式训练的注意事项参数dp_size用于将局部损失单个 GPU 上的聚合结果放大到全局等效值。因为在分布式训练中每个 GPU 只处理一部分数据计算出的损失通常是局部平均但反向传播时需要保证梯度与全局 batch 大小匹配。乘以dp_size是一种常见的做法相当于将局部损失视为全局损失的一部分然后通过 all-reduce 平均梯度时能得到正确结果。batch_num_tokens和global_batch_size通常由框架在全局范围内计算并传入确保聚合时使用的是全局统计数据而不是局部统计。
企业数字化 ERP 产品动态
相关推荐
解读 VeRL 框架源码:PPO 和 GRPO 算法如何计算优势 (Advantage) 最近正在入门大模型 RL 微调,阅读 VeRL 框架代码。在这篇博客中,我们从 VeRL 源码入手,解读一下 ppo 和 grpo 算法的 advantage 计算方法:
# 来自 verl/trainer/ppo/core_algos.py
register_adv_est(AdvantageEstimator.GAE) # … · 2026/11/5 1:30:31
轻量级 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
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模型版本管理:原理与实践 1. 云原生AI模型版本管理的核心价值在AI工程化实践中,模型版本管理正成为MLOps流程中最关键的痛点之一。我们团队在金融风控场景中曾经历过这样的困境:某次模型迭代后AUC指标意外下降5个百分点,但由于缺乏规范的版本追踪,花了整整… · 2026/11/5 2:17:48
虚拟电厂行业早报(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# For ECharts 模型层建模库是面向.NET开发者,特别是使用ASP.NET MVC框架构建数据可视化应用的中高级工程师的高效工具。它解决了在C#后端直接生成ECharts标准配置JSON的痛点,避免手动拼接、类型错配与结构维护困难等问题,显… · 2026/11/5 2:17:48
键盘与鼠标:结构原理与选购指南 1. 键盘与鼠标:人机交互的核心工具键盘和鼠标作为计算机最基础的输入设备,它们的设计原理和结构直接影响着我们的工作效率和使用体验。作为一名长期与各种输入设备打交道的技术爱好者,我深刻理解选择合适设备的重要性。不同类型的键盘和鼠标在… · 2026/11/5 2:16:48
双极步进电机控制实战: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 步进电机驱动实战解析 /* 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工业级双极步进电机控制方案 /* 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驱动调试 /* 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 步进电机驱动实战解析 /* 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工业级双极步进电机控制方案 /* 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