基于VeRL源码深度拆解字节Seed的DAPO

news2025/5/13 6:16:44

在这里插入图片描述

1. 背景与现状:从PPO到GRPO的技术演进

1.1 PPO算法的基础与局限

Proximal Policy Optimization(PPO)作为当前强化学习领域的主流算法,通过重要性采样比率剪裁机制将策略更新限制在先前策略的近端区域内,构建了稳定的策略优化框架。其核心目标函数可表示为:
J P P O ( θ ) = E [ min ⁡ ( r t ( θ ) A ^ t , clip ⁡ ( r t ( θ ) , 1 − ε , 1 + ε ) A ^ t ) ] \mathcal{J}_{PPO}(\theta)=E\left[\min\left(r_t(\theta)\hat{A}_t,\operatorname{clip}(r_t(\theta),1-\varepsilon,1+\varepsilon)\hat{A}_t\right)\right] JPPO(θ)=E[min(rt(θ)A^t,clip(rt(θ),1ε,1+ε)A^t)]
其中 r t ( θ ) = π θ ( a t ∣ s t ) / π θ o l d ( a t ∣ s t ) r_t(\theta)=\pi_\theta(a_t|s_t)/\pi_{\theta_{old}}(a_t|s_t) rt(θ)=πθ(atst)/πθold(atst)为重要性采样比率。这种对称式剪裁机制虽然保证了训练稳定性,但在处理复杂推理任务时逐渐暴露出三个关键问题:

  • 探索能力受限:默认的对称剪裁区间(如 ε = 0.2 \varepsilon=0.2 ε=0.2)对低概率token的采样提升形成压制。例如当初始概率 π θ o l d ( a t ) = 0.01 \pi_{\theta_{old}}(a_t)=0.01 πθold(at)=0.01时,新策略概率最大可提升至 0.012 0.012 0.012,而高概率token(如0.9)却可提升至 1.08 1.08 1.08,这种不对称限制导致模型过早收敛到某种局部最优。
  • 长序列优化失效:在需要多步推理的数学证明、代码生成等场景中,传统PPO的样本级损失计算方式(先对每个样本的token损失取平均,再对样本间取平均)导致长序列的有效梯度信号被稀释。
  • 奖励噪声敏感:基于规则的奖励机制(如最终答案正确性)在长推理场景中面临严重的延迟奖励问题。特别是在响应长度达到16k+token的复杂数学题场景下,很多正确推理过程因中途截断被错误标记为负奖励。

1.2 GRPO的改进与瓶颈

Group Relative Policy Optimization(GRPO)通过群体相对优势估计和显式KL惩罚项对PPO进行了重要改进:
A ^ i , t = R i − m e a n ( { R i } ) s t d ( { R i } ) \hat{A}_{i,t}=\frac{R_i-mean(\{R_i\})}{std(\{R_i\})} A^i,t=std({Ri})Rimean({Ri})
J G R P O = E [ ∑ min ⁡ ( r i , t A ^ i , t , c l i p ( r i , t , 1 − ε , 1 + ε ) A ^ i , t ) − β D K L ] \mathcal{J}_{GRPO}=E\left[\sum\min(r_{i,t}\hat{A}_{i,t},clip(r_{i,t},1-\varepsilon,1+\varepsilon)\hat{A}_{i,t})-\beta D_{KL}\right] JGRPO=E[min(ri,tA^i,t,clip(ri,t,1ε,1+ε)A^i,t)βDKL]
虽然GRPO在数学推理任务上取得了突破,但在实际工业级应用中仍面临三大挑战:
在这里插入图片描述

  • 熵崩溃现象:如图2b所示,PPO/GRPO策略熵会有一个骤降的过程,导致采样多样性丧失。在AIME测试集上,模型效果也随着训练进行而逐渐收敛不变。上述现象证明,如PPO或者GRPO等算法严重限制复杂推理路径的探索。
  • 梯度稀释效应:当某一批次中存在部分全正确或全错误的样本组时,优势函数计算结果趋近于零。零优势导致策略更新没有梯度,从而降低了样本效率。实验证明,训练过程中准确性等于1的样本数量会持续增加,这意味着每批中的有效提示数量不断减少,这可能导致梯度方差增大,并削弱模型训练中的梯度信号。
  • 长度失控风险:在未施加长度约束的情况下,模型响应长度呈现指数级增长趋势。默认情况下,我们对截断样本施加惩罚性奖励,这种方法可能会在训练过程中引入噪声,因为一个合理的推理过程可能仅仅因为过长而受到惩罚。这种惩罚可能会让模型对其推理过程的有效性产生混淆。

2. DAPO的核心创新:突破大规模RL训练瓶颈

DAPO,即Decoupled Clip and Dynamic sAmpling Policy Optimization,解耦裁剪与动态采样的策略优化算法。在这一节中,将结合代码来讲解DAPO的核心创新。

在讨论核心创新之前,原文中先讨论了KL散度损失。KL正则化机制的核心功能在于平衡在线学习策略与固定参考策略之间的策略偏移。在RLHF框架中,训练的核心诉求是在保持预训练模型基准特性的前提下优化模型响应。但当处理长链思维推理任务时,模型输出分布可能发生显著漂移,此时继续施加分布约束反而会阻碍模型性能提升。基于此认知,DAPO算法框架选择移除KL loss。

2.1 解耦剪裁机制(Clip-Higher)

DAPO通过非对称剪裁区间设计重构了策略优化边界:
clip ⁡ ( r i , t , 1 − ε l o w , 1 + ε h i g h ) \operatorname{clip}(r_{i,t},1-\varepsilon_{low},1+\varepsilon_{high}) clip(ri,t,1εlow,1+εhigh)
其中 ε l o w = 0.2 \varepsilon_{low}=0.2 εlow=0.2, ε h i g h = 0.28 \varepsilon_{high}=0.28 εhigh=0.28。这种设计在保持策略更新稳定性的同时,显著提升了低概率token的探索空间:

  • 概率提升上限解禁:对于初始概率为0.01的token,最大可提升至 0.01 ∗ ( 1 + 0.28 ) = 0.0128 0.01*(1+0.28)=0.0128 0.01(1+0.28)=0.0128,相比标准PPO提升28%。对应配置:
actor_rollout_ref:
  actor:
    clip_ratio_low: 0.2
    clip_ratio_high: 0.28

无论是PPO还是GRPO,默认的裁剪上下限都是0.2。作者在原文中声称,传统GRPO的对称剪裁范围(如ε=0.2)限制低概率token的探索,导致策略快速收敛(熵崩溃)。作者提出的解决办法是,将剪裁范围解耦为ε_low(抑制高概率token)和ε_high(放宽低概率token限制)​​,允许低概率token有更大提升空间,增加生成多样性。

具体来说,在配置文件中,clip_ratio_high从0.2提高至0.28。

2.2 动态采样策略(Dynamic Sampling)

data:
  gen_batch_size: 256
  train_batch_size: 64
algorithm:
  filter_groups:
    enable: True
    metric: acc # score / seq_reward / seq_final_reward / ...
    max_num_gen_batches: 10 # Non-positive values mean no upper limit

DAPO中第二个关键改进点是动态采样。原文中说,当所有样本奖励相同(如全正确/全错误),梯度信号消失(Zero Advantage)。作者提出的解决方案为,预采样时过滤掉奖励为0或1的样本,仅保留有效梯度样本填充批次。

我一开始理解的是,如果某个大小为64的batch中有5个prompt不满足要求,则对这5个重新采样,或者对64个都重新采样,直到满足要求。

但显然,上面的想法是错误的。核心代码如下:

prompt_bsz = self.config.data.train_batch_size  # 原始的batch_size,这里为64
if num_prompt_in_batch < prompt_bsz:  # num_prompt_in_batch为统计出来的std不为0的group数量
    print(f'{num_prompt_in_batch=} < {prompt_bsz=}')
    num_gen_batches += 1  # 继续采样一次
    max_num_gen_batches = self.config.algorithm.filter_groups.max_num_gen_batches
    if max_num_gen_batches <= 0 or num_gen_batches < max_num_gen_batches:
        # 没有达到最大采样上限,这里需要取下一个批次
        print(f'{num_gen_batches=} < {max_num_gen_batches=}. Keep generating...')
        continue
    else:
        # 已经达到采样次数上限了,但是还是没有满足要求,此时会报错
        raise ValueError(
            f'{num_gen_batches=} >= {max_num_gen_batches=}. Generated too many. Please check your data.'
        )
else:
    # Align the batch
    traj_bsz = self.config.data.train_batch_size * self.config.actor_rollout_ref.rollout.n
    batch = batch[:traj_bsz]

代码逻辑解析:

# 外层循环从dataloader获取prompt batch
for batch_dict in self.train_dataloader:
    # 每次生成全新的gen_batch(包含新的prompt集合)
    gen_batch = new_batch.pop(...)
    gen_batch_output = self.actor_rollout_wg.generate_sequences(gen_batch)
    
    # 动态过滤逻辑
    if self.config.algorithm.filter_groups.enable:
        # 计算当前gen_batch的有效prompt
        kept_prompt_uids = [...] 
        num_prompt_in_batch += len(kept_prompt_uids)
        
        # 如果有效prompt不足,继续生成新的gen_batch
        if num_prompt_in_batch < self.config.data.train_batch_size:
            continue  # 跳回外层循环,获取下一个batch_dict

假设存在以下场景:

  • 初始batch:包含64个prompt,每个生成8个response
  • 过滤结果:其中5个prompt的response标准差为0(被过滤),剩余59个有效
  • 保留有效prompt:将59个有效prompt加入累积池
    • 检查数量:num_prompt_in_batch = 59 < train_batch_size(假设为64)
    • 触发重新生成:通过continue语句跳回外层循环,从self.train_dataloader获取下一个batch_dict
    • 处理新batch:对新batch中的prompt(可能是全新的64个)重复生成和过滤流程
    • 累积结果:将新batch的有效prompt加入累积池,直到总数≥train_batch_size
    • 上述过程最多持续max_num_gen_batches次,如果连续max_num_gen_batches次都没有凑够64个有效样本,那说明数据很有问题了,直接报错即可。

设计特点

  1. 全量更新:每个gen_batch来自数据加载器的独立prompt集合,而非针对特定prompt重新采样
  2. 增量累积:有效prompt会跨多个gen_batch累积,直到满足train_batch_size

2.3 灵活的损失聚合模式

示例配置如下:

actor_rollout_ref:
  actor:
    loss_agg_mode: "token-mean" # / "seq-mean-token-sum" / "seq-mean-token-mean"
    # NOTE: "token-mean" is the default behavior

将loss_agg_mode设置为token-mean将意味着小批量中将计算所有序列的所有标记的(策略梯度)损失。

2.4 长度惩罚

DAPO对过长的生成进行了惩罚,相关示例配置如下:

data:
  max_response_length: 20480 # 16384 + 4096
reward_model:
  overlong_buffer: 
    enable: True
    len: 4096
    penalty_factor: 1.0

原文中的公式如下:
R length ( y ) = { 0 , ∣ y ∣ ≤ L max − L cache ( L max − L cache ) − ∣ y ∣ L cache , L max − L cache < ∣ y ∣ ≤ L max − 1 , L max < ∣ y ∣ R_{\text{length}}(y) = \begin{cases} 0, & |y| \leq L_{\text{max}} - L_{\text{cache}} \\ \frac{(L_{\text{max}} - L_{\text{cache}}) - |y|}{L_{\text{cache}}}, & L_{\text{max}} - L_{\text{cache}} < |y| \leq L_{\text{max}} \\ -1, & L_{\text{max}} < |y| \end{cases} Rlength(y)= 0,Lcache(LmaxLcache)y,1,yLmaxLcacheLmaxLcache<yLmaxLmax<y

具体来说,当response长度超过预设的最大长度时,定义一个惩罚区间,在这个区间内长度越长收到的惩罚越大。根据上述公式,首先会预设一个最大长度 L m a x L_{max} Lmax,即max_response_length;然后预设一个惩罚区间长度 L c a c h e L_{cache} Lcache,即overlong_buffer.len;接着:

  • 如果回复长度小于max_response_length - overlong_buffer.len,那么没有额外奖励也没有额外惩罚
  • 如果回复长度大于max_response_length - overlong_buffer.len但又小于预设的最大长度max_response_length,则施加一个软惩罚机制,回复越长,额外添加的reward越小。
  • 如果回复长度大于了预设的最大长度,则额外奖励为-1,即惩罚。
    相关代码如下:
if self.overlong_buffer_cfg.enable:
    overlong_buffer_len = self.overlong_buffer_cfg.len  # 惩罚区间长度
    expected_len = self.max_resp_len - overlong_buffer_len # L_max - L_cache
    exceed_len = valid_response_length - expected_len  # 超出的长度
    overlong_penalty_factor = self.overlong_buffer_cfg.penalty_factor
    overlong_reward = min(-exceed_len / overlong_buffer_len * overlong_penalty_factor, 0)
    reward += overlong_reward

3. 实验

在实验中,DAPO成功将 Qwen-32B Base模型训练成一个强大的推理模型。在AIME 2024测试集上,DAPO展现出显著优势:
在这里插入图片描述

此外,根据图1
在这里插入图片描述
DAPO将Qwen2.5-32B模型在AIME上的准确率从接近 0% 提升至 50%,并且这一提升仅使用了 DeepSeek-R1-Zero-Qwen-32B所需训练步数的 50%。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zst-2001 历年真题 软件工程

软件工程 - 第1题 b 软件工程 - 第2题 c 软件工程 - 第3题 c 软件工程 - 第4题 b 软件工程 - 第5题 b 软件工程 - 第6题 0.未完成&#xff1a;未执行未得到目标。1.已执行&#xff1a;输入-输出实现支持2.已管理&#xff1a;过程制度化&#xff0c;项目遵…

基于WSL用MSVC编译ffmpeg7.1

在windows平台编译FFmpeg&#xff0c;网上的大部分资料都是推荐用msys2mingw进行编译。在win10平台&#xff0c;我们可以采用另一种方式&#xff0c;即wslmsvc 实现window平台的ffmpeg编译。 下面将以vs2022ubuntu22.04 为例&#xff0c;介绍此方法 0、前期准备 安装vs2022 &…

java命令行打包class为jar并运行

1.创建无包名类: 2.添加依赖jackson 3.引用依赖包 4.命令编译class文件 生成命令: javac -d out -classpath lib/jackson-core-2.13.3.jar:lib/jackson-annotations-2.13.3.jar:lib/jackson-databind-2.13.3.jar src/UdpServer.java 编译生成class文件如下 <

vue注册用户使用v-model实现数据双向绑定

定义数据模型 Login.vue //定义数据模型 const registerData ref({username: ,password: ,confirmPassword: })使用 v-model 实现数据模型的key与注册表单中的元素之间的双向绑定 <!-- 注册表单 --><el-form ref"form" size"large" autocompl…

Nacos源码—8.Nacos升级gRPC分析六

大纲 7.服务端对服务实例进行健康检查 8.服务下线如何注销注册表和客户端等信息 9.事件驱动架构源码分析 一.处理ClientChangedEvent事件 也就是同步数据到集群节点&#xff1a; public class DistroClientDataProcessor extends SmartSubscriber implements DistroDataSt…

SpringBoot 自动装配原理 自定义一个 starter

目录 1、pom.xml 文件1.1、parent 模块1.1.1、资源文件1.1.1.1、resources 标签说明1.1.1.2、从 Maven 视角&#xff1a;资源处理全流程​ 1.1.2、插件 1.2、dependencies 模块 2、启动器3、主程序3.1、SpringBootApplication 注解3.2、SpringBootConfiguration 注解3.2.1、Con…

【C++进阶篇】多态

深入探索C多态&#xff1a;静态与动态绑定的奥秘 一. 多态1.1 定义1.2 多态定义及实现1.2.1 多态构成条件1.2.1.1 实现多态两个必要条件1.2.1.2 虚函数1.2.1.3 虚函数的重写/覆盖1.2.1.4 协变1.2.1.5 析构函数重写1.2.1.6 override和final关键字1.2.1.7 重载/重写/隐藏的对⽐ 1…

《AI大模型应知应会100篇》第60篇:Pinecone 与 Milvus,向量数据库在大模型应用中的作用

第60篇&#xff1a;Pinecone与Milvus&#xff0c;向量数据库在大模型应用中的作用 摘要 本文将系统比较Pinecone与Milvus两大主流向量数据库的技术特点、性能表现和应用场景&#xff0c;提供详细的接入代码和最佳实践&#xff0c;帮助开发者为大模型应用选择并优化向量存储解…

Java学习手册:客户端负载均衡

一、客户端负载均衡的概念 客户端负载均衡是指在客户端应用程序中&#xff0c;根据一定的算法和策略&#xff0c;将请求分发到多个服务实例上。与服务端负载均衡不同&#xff0c;客户端负载均衡不需要通过专门的负载均衡设备或服务&#xff0c;而是直接在客户端进行请求的分发…

Docker私有仓库实战:官方registry镜像实战应用

抱歉抱歉&#xff0c;离职后反而更忙了&#xff0c;拖了好久&#xff0c;从4月拖到现在&#xff0c;在学习企业级方案Harbor之前&#xff0c;我们先学习下官方方案registry&#xff0c;话不多说&#xff0c;详情见下文。 注意&#xff1a;下文省略了基本认证 TLS加密&#xff…

Redis+Caffeine构建高性能二级缓存

大家好&#xff0c;我是摘星。今天为大家带来的是RedisCaffeine构建高性能二级缓存&#xff0c;废话不多说直接开始~ 目录 二级缓存架构的技术背景 1. 基础缓存架构 2. 架构演进动因 3. 二级缓存解决方案 为什么选择本地缓存&#xff1f; 1. 极速访问 2. 减少网络IO 3…

【计算机网络】NAT技术、内网穿透与代理服务器全解析:原理、应用及实践

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;以太网、MAC地址、MTU与ARP协议 下篇文章&#xff1a;五种IO模型与阻…

Python训练打卡Day21

常见的降维算法&#xff1a; # 先运行预处理阶段的代码 import pandas as pd import pandas as pd #用于数据处理和分析&#xff0c;可处理表格数据。 import numpy as np #用于数值计算&#xff0c;提供了高效的数组操作。 import matplotlib.pyplot as plt #用于绘…

node .js 启动基于express框架的后端服务报错解决

问题&#xff1a; node .js 用npm start 启动基于express框架的后端服务报错如下&#xff1a; /c/Program Files/nodejs/npm: line 65: 26880 Segmentation fault "$NODE_EXE" "$NPM_CLI_JS" "$" 原因分析&#xff1a; 遇到 /c/Program F…

并发笔记-信号量(四)

文章目录 背景与动机31.1 信号量&#xff1a;定义 (Semaphores: A Definition)31.2 二元信号量 (用作锁) (Binary Semaphores - Locks)31.3 用于排序的信号量 (Semaphores For Ordering)31.4 生产者/消费者问题 (The Producer/Consumer (Bounded Buffer) Problem)31.5 读写锁 (…

【HTOP 使用指南】:如何理解主从线程?(以 Faster-LIO 为例)

htop 是 Linux 下常用的进程监控工具&#xff0c;它比传统的 top 更友好、更直观&#xff0c;尤其在分析多线程或多进程程序时非常有用。 以下截图就是在运行 Faster-LIO 实时建图时的 htop 状态展示&#xff1a; &#x1f50d; 一、颜色说明 白色&#xff08;或亮色&#xf…

数据同步DataX任务在线演示

数据同步DataX任务在线演示 1. 登录系统 访问系统登录页面&#xff0c;输入账号密码完成身份验证。 2. 环境准备 下载datax安装包&#xff0c;并解压到安装目录 3. 集群创建 点击控制台-多集群管理 计算组件添加DataX 配置DataX引擎,Datax.local.path填写安装目录。 4. …

telnetlib源码深入解析

telnetlib 是 Python 标准库中实现 Telnet 客户端协议的模块&#xff0c;其核心是 Telnet 类。以下从 协议实现、核心代码逻辑 和 关键设计思想 三个维度深入解析其源码。 一、Telnet 协议基础 Telnet 协议基于 明文传输&#xff0c;通过 IAC&#xff08;Interpret As Command…

TAPIP3D:持久3D几何中跟踪任意点

简述 在视频中跟踪一个点&#xff08;比如一个物体的某个特定位置&#xff09;听起来简单&#xff0c;但实际上很复杂&#xff0c;尤其是在3D空间中。传统方法通常在2D图像上跟踪像素&#xff0c;但这忽略了物体的3D几何信息和摄像机的运动&#xff0c;导致跟踪不稳定&#xf…

uniapp 生成海报二维码 (微信小程序)

先下载qrcodenpm install qrcode 调用 community_poster.vue <template><view class"poster-page"><uv-navbar title"物业推广码" placeholder autoBack></uv-navbar><view class"community-info"><text clas…