Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

NLP——Agent-Learning-via-Early-Experience

注:本文包含 AI 辅助创作

  • 参考链接:
    • 原始论文:Agent Learning via Early Experience, arXiv 202451009, Meta

Paper Summary

  • 论文核心介绍了通过 Early Experience 范式来训练 Agent 的策略
    • 提出 Early Experience 作为一种可扩展的、无奖励的范式,在强化学习环境完全准备好之前推进语言智能体
    • 通过将智能体自身的动作和结果状态转换为监督,而无需外部奖励信号,论文在八个多样化的环境中取得了一致的增益,涵盖了具身导航、科学实验、长程规划、多轮工具使用和网络导航
    • 在此范式下提出的两种方法:隐式世界建模 (implicit world modeling) 和自反思 (self-reflection)
      • 这两种方法可以改善领域内的有效性和领域外的鲁棒性(in-domain effectiveness and out-of-domain robustness),并且在用于热启动(warm-start)强化学习时保持了其优势
      • 在即将到来的经验时代 (era of experience) 中,作者将 Early Experience 定位为构建更强语言智能体的实用和通用基础(practical and general foundation)
  • 思考:
    • 论文所谓的隐式世界建模和自反思,侧重于短程轨迹,将这些扩展到解决没有显式奖励的长程信用分配仍然是一个开放的挑战
    • 未来的工作将探索(来自原文)
      • 方向一:将 Early Experience 与更丰富的自监督目标相结合 ,利用跨环境迁移,并在持续学习设置中将其与基于奖励的微调相集成
      • 方向二:研究除了论文提出的两种方法之外的其他 Early Experience 实例
      • 论文也希望将该范式扩展到大规模、真实世界的部署中,在那里交互数据被有机地收集并可以驱动策略的持续改进
  • 问题提出:语言智能体的一个长期目标是通过自身经验进行学习和改进,最终在复杂的现实世界任务中超越人类
    • 但在许多环境中,使用经验数据通过强化学习来训练智能体仍然很困难
    • 这些环境要么缺乏可验证的奖励(例如网站),要么需要低效的 Long-horizon 展开(例如多轮工具使用)
  • 目前大多数智能体依赖于在专家数据上进行监督微调,这种方法难以扩展且泛化能力差
    • 这种局限性源于专家 Demonstrations 的本质:只捕捉了狭窄范围的场景,并且让智能体接触到的环境多样性有限
  • 论文通过一种论文称之为 Early Experience 的中间范式来解决这个局限性:
    • 由智能体自身行动产生的交互数据,其中产生的未来状态作为监督信号 ,无需奖励信号
  • 在这个范式中,论文研究了使用这种数据的两种策略:
    • (1) 隐式世界建模(Implicit World Modeling) ,它使用收集到的状态来使策略基于环境动态;
    • (2) Self-Reflection ,智能体从其次优行动中学习以改进推理和决策制定
  • 论文在八个不同的环境和多个模型系列中进行评估
  • 论文的方法持续提高了有效性和领域外泛化能力,突显了 Early Experience 的价值
  • 在具有可验证奖励的环境中,论文的结果提供了有希望的信号,表明 Early Experience 为后续的强化学习奠定了坚实的基础,将其定位为模仿学习和完全由经验驱动的智能体(fully experience-driven agents)之间的实用桥梁
  • 问题:为什么不试试 IWM 和 Self-Reflection 同时生效的策略?

Introduction and Discussion

  • 自主智能体(Autonomous agents) (1995; 1997) 长期以来一直是人工智能的核心目标,旨在无需人工干预的情况下,在复杂环境中感知、行动和学习以完成目标
  • 随着语言智能体 (2024;) 的出现,这一愿景正变得越来越现实,这些智能体构建在大语言模型 (2024) 之上
    • 凭借从大规模预训练中获得的知识以及语言接口的灵活性,语言智能体现在被应用于广泛的环境中
    • 它们可以浏览网站和移动应用程序 (2023; 2024;),控制各种工具 (2024),并辅助科学研究 (2025;),显示出作为下一代智能系统基础的强大潜力
  • 构建此类语言智能体 ,一个有前途的解决方案是强化学习 ,即通过优化环境返回的期望累积奖励来训练智能体
    • 这种范式使得像 AlphaGo (2016) 这样的传统智能体在具有明确定义环境和奖励结构的领域(如 Atari 游戏 (2013) 和围棋游戏)中实现了超人的性能,呼应了语言智能体新兴的 经验时代 (2025) 的愿景
    • 但将强化学习应用于现实世界的语言智能体目前仍然极具挑战性
      • 许多感兴趣的环境缺乏可验证或密集的奖励信号 ,特别是在开放式设置中,比如网站,平台不暴露真实反馈
        • 例如,一个表单可能看起来提交成功,但智能体没有收到任何关于每条信息是否填写正确的指示
      • 此外,多轮工具使用环境中的任务通常涉及长的交互序列 (2025),结果延迟或模糊 ,使得信用分配和训练低效且不稳定
  • 作为一种变通方法,目前大多数语言智能体转而使用监督微调 (2023; 2025;) 在专家策划的数据上进行训练
    • 这种范式通过学习人类 Demonstrations 来规避对奖励信号的需求,智能体使用静态数据集将状态映射到行动
    • 虽然监督微调训练起来简单高效,但它有其固有的局限性
      • 在此范式下的智能体在训练期间不与环境交互;它不观察自身行动的结果
      • 这限制了它从失败中学习、改进其决策制定或泛化到未见情况的能力 (2025)
    • 此外,这种方法假设数据是专家或接近最优的,然而扩展高质量的人类 Demonstrations 既昂贵又难以持续
    • 更关键的是,它将智能体锁定在一个被动的角色中,受限于其训练数据的想象力和覆盖范围,而不是主动地从自身经验中学习
  • 鉴于这些局限性以及前述可靠奖励信号通常不可用,我们遇到了一个问题:如何训练智能体从其自身经验中成长 ,无需任何外部奖励信号呢?
  • 受这些局限性启发,论文引入了 Early Experience 范式,作为模仿学习和强化学习之间的中间地带,如图 1 所示
    • 在这种设置中,智能体不仅从人类策划的数据中学习,还从其自身在环境中提出的行动所驱动的未来状态中学习
    • 这些未来状态是智能体自身的经验,并且可以转化为监督信号,使其能够直接从其行动的后果中成长,而无需依赖外部奖励信号
  • 论文探索了两种将这些未来状态转化为监督的策略:
    • (1) 隐式世界建模 :使用收集到的未来状态来帮助智能体建立对环境动态的内部表征,使其通过预测未来状态来更好地理解环境
    • (2) Self-Reflection :引导智能体将其行为与专家 Demonstrations 进行比较,识别次优决策,并提取经验教训以改进未来的决策制定
  • 这两种策略共享相同的原则:在缺乏外部奖励的情况下,智能体自身的行动及其产生的未来状态仍然可以构成经验,作为直接的监督来源
    • 通过将由其自身行动产生的未来状态转化为学习信号,语言智能体可以在不依赖额外人类数据或外部奖励的情况下持续改进
  • 论文在八个不同的环境中全面评估 Early Experience,涵盖具身导航、网络导航、多轮工具使用、 Long-horizon 规划和多领域 API 任务,并使用多种基础架构
    • 在所有设置中,两种方法都一致地优于纯模仿学习基线,在成功率上平均绝对增益为 +9.6 ,在领域外泛化上平均绝对增益为 +9.4
    • 此外,在具有可验证奖励的环境中,使用 Early Experience 方法训练的检查点初始化强化学习,与标准的模仿学习热启动相比,能带来显著更强的性能,最终成功率提高了 +6.4
    • 这表明 Early Experience 阶段带来的性能增益可以延续到强化学习后最终模型的性能上
  • 除了这些经验性收益之外,论文的分析表明, Early Experience 实现了仅通过模仿学习无法获得的能力
    • 它能有效扩展,仅用一半甚至更少的专家数据就能达到相当或更优的性能
    • 该范式可无缝应用于更大的模型,在不同规模上保持其有效性
  • 这些结果表明, Early Experience 不仅仅是模仿学习的替代品,而且是通向强化学习的一个实用且可扩展的桥梁,既带来了有效性的即时收益,也为 经验时代(era of experience) 的训练机制带来了长期益处
  • 论文的贡献总结如下:
    • (1) 论文倡导并将 Early Experience 范式形式化,作为构建自主语言智能体的模仿学习和强化学习之间的一个实用且可扩展的桥梁
      • 它使智能体能够将其自身经验转化为学习信号,而无需依赖外部奖励,并且可以无缝集成到现有的训练流程中
    • (2) 论文在此范式下提出并系统研究了两种训练策略:
      • 隐式世界建模,通过直接从收集的经验中建模环境动态来增强决策制定;
      • Self-Reflection ,从智能体自身行动中提炼细粒度的经验教训
    • (3) 论文在八个不同的环境和多个模型系列中进行了全面评估
      • 论文的方法持续提高了任务有效性、领域外泛化能力和下游强化学习性能,在多个基准测试中取得了 SOTA 结果,并通过详细分析提供了可行的见解

Preliminaries

  • 论文将语言智能体决策制定问题形式化为马尔可夫决策过程 (MDP, 1957),这为论文的 Early Experience 范式提供了数学基础
  • 论文考虑一个由下面元组 定义的 MDP
    $$ \mathcal{M}=(\mathcal{S},\mathcal{A},T,R,\gamma,\rho_{0})$$
    • 其中 \(\mathcal{S}\) 表示状态空间,\(\mathcal{A}\) 表示行动空间
    • 状态转移函数 \(T\colon \mathcal{S}\times \mathcal{A}\to \Delta(\mathcal{S})\) 支配状态动态,其中 \(\Delta(\mathcal{S})\) 表示 \(\mathcal{S}\) 上的概率单纯形
    • 奖励函数 \(R\colon \mathcal{S}\times \mathcal{A}\to \mathbb{R}\) 在可用时提供反馈信号,尽管在许多现实世界设置中,此函数在训练期间可能未知或不可验证
    • \(\gamma\in [0,1]\) 是折扣因子,\(\rho_{0}\in \Delta(\mathcal{S})\) 指定了初始状态分布
  • 在语言智能体环境中:
    • 状态 \(s\in \mathcal{S}\) 编码智能体可访问的环境配置,例如网页内容、工具输出或文本环境描述
      • 理解:还包括了之前的 所有 Prompt 吧
    • 行动 \(a\in \mathcal{A}\) 对应于离散选择,例如点击元素、调用工具或生成文本响应
    • 智能体维护一个由 \(\theta\) 参数化的策略,将状态映射到行动分布 (1992):
      $$ \pi_{\theta}\colon \mathcal{S}\to \Delta(\mathcal{A}) $$

Learning without Rewards

  • 现实世界语言智能体环境中的一个关键挑战是缺乏可靠的奖励信号
    • 许多环境要么完全缺乏可验证的奖励,要么仅在长的交互序列之后提供稀疏、延迟的反馈
  • 这促使论文从替代的监督源中学习
  • 给定一个专家 Demonstrations 数据集
    $$ \mathcal{D}_{\text{expert} }=\{(s_{i},a_{i})\}_{i=1}^{N}$$
    • 其中 \(a_{i}\) 表示在状态 \(s_{i}\) 下的专家行动
  • 模仿学习 (1991; 1996; 2017) 旨在最小化监督学习损失:
    $$ \mathcal{L}_{\text{IL} }(\theta)=-\sum_{i=1}^{N}\log \pi_{\theta}(a_{i} \mid s_{i}). $$
  • 然而,这种方法会遭受分布偏移并且缺乏对行动后果的认知
  • 分布偏移的发生是因为智能体学习到的策略 \(\pi_{\theta}\) 在部署时不可避免地会偏离专家策略,导致训练数据未覆盖的状态,其中错误会复合 (2011)
  • 智能体缺乏对行动后果的认知,因为它从未观察到当其采取非专家行动时会发生什么;它只看到专家状态-行动对,而没有体验替代选择的后果
  • 这限制了其从错误中恢复或推理某些行动为何失败的能力 (2010)

Early Experience

  • 论文引入了 Early Experience 范式,在这种范式中,语言智能体通过与环境进行无奖励但信息丰富的未来状态交互来改进
  • 为了建立直观理解,考虑一个学习在网络上预订航班的语言智能体
    • 在传统的模仿学习中,它只看到成功预订的专家演示
    • 而有了 Early Experience ,智能体还会探索当它点击不同的按钮或错误填写表格时会发生什么,观察错误消息、页面变化和其他结果
      • 这些观察结果成为了没有显式奖励的学习信号
    • 从专家轨迹开始,智能体在每个访问状态提出自己的动作,通过探索(Thrun, 1992)收集额外的环境反馈

Notation for Early Experience

  • 对于专家数据集 \(\mathcal{D}_{\text{expert} }=\{(s_{i},a_{i})\}_{i=1}^{N}\) 中的每个专家状态 \(s_{i}\),论文定义一个候选动作集 \(\mathcal{A}_{i}=\{a_{i}^{1},a_{i}^{2},\ldots,a_{i}^{K}\}\),其中论文从初始策略 \(\pi_{\theta}(\cdot \mid s_{i})\) 中采样 \(K\) 个 alternative 动作
    • 论文在分析中也包括专家动作 \(a_{i}\)
  • 对于专家动作 \(a_{i}\),执行它会跳转到下一个状态 \(s_{i+1}\)
    • 对于每个 alternative 动作\(a_{i}^{j}\in \mathcal{A}_{i}\) ,在环境中执行它会从转移函数 \(T(s_{i},a_{i}^{j})\) 中采样得到一个下一个状态 \(s_{i}^{j}\)
    • 这些下一个状态捕捉了在状态 \(s_{i}\) 采取动作 \(a_{i}^{j}\) 的直接后果,反映了环境中的变化,例如更新的 DOM 结构、新的工具输出、错误消息或任务进展
  • 论文将这些交互收集到一个 rollout 数据集中:
    $$\mathcal{D}_{\text{rollout} }=\{(s_{i},a_{i}^{j},s_{i}^{j})\mid i\in[N],j\in[K]\},$$
    • 其中每个三元组表示一个状态、在该状态采取的一个 alternative 动作以及产生的下一个状态
    • 所有 alternative 动作 \(a_{i}^{j}\) 都与专家动作 \(a_{i}\) 不同 ,允许智能体从其自身提出的动作中体验多样化的状态转移
      • 这个 rollout 数据集 \(\mathcal{D}_{\text{rollout} }\) 提供了丰富的监督信号,而不需要显式的奖励
    • 下一个状态 \(\{s_{i}^{j}\mid j\in[K]\}\) 通过环境响应编码了关于动作质量的隐式反馈,使智能体能够从专家和非专家行为的后果中学习
  • 图 2:两种 Early Experience 方法的概述
    • 隐式世界建模(左)用 alternative 动作和预测的下一个状态增强专家轨迹,在部署前训练策略以内化转移动态
    • Self-Reflection(右)用自我生成的解释 \(c_{1}\) 增强专家动作,训练策略对其自身决策进行推理和修正
    • 两种方法都使用初始策略(LLM)提出的 alternative 动作
    • alternative 动作的数量(\(K\))是一个超参数;为简洁起见,图中仅展示了一个
  • 基于第 3 节的符号,论文利用专家数据集 \(\mathcal{D}_{\text{expert} }=\{(s_{i},a_{i})\}_{i=1}^{N}\) 和 rollout 数据集 \(\mathcal{D}_{\text{rollout} }=\{(s_{i},a_{i}^{j},s_{i}^{j})\mid i\in[N],j\in[K]\}\) 来在同一 Early Experience 原则下开发两种不同的训练方法
    • 关键的洞见是,由非专家动作产生的下一个状态 \(s_{i}^{j}\) 提供了有价值的监督信号,而无需显式奖励
    • 论文现在描述论文的两种 Early Experience 方法如何利用这个数据集

Implicit World Modeling

  • 论文将世界建模制定为一个辅助预测任务 ,帮助智能体从其自身的 Early Experience 中内化环境动态
  • 在论文的设定中,状态完全用自然语言表示,这允许论文将下一个状态(Next-State)预测建模为一个标准的 Next-Token 预测目标
  • 受先前将 LLM 训练为世界模型(2025)的工作启发,论文使用 rollout 集 \(\mathcal{D}_{\text{rollout} }\) 中的下一个状态作为语言智能体策略 \(\pi_{\theta}\) 的直接训练信号
    • 例如,在网络上预订航班时,模型可能预测输入无效日期后的页面状态,从作为下一个状态自然语言表示的文本错误消息中学习
    • 这种设计移除了对单独模块的需求,并自然地契合了 LLM 微调范式
  • 对于每个 rollout 三元组 \((s_{i},a_{i}^{j},s_{i}^{j})\in \mathcal{D}_{\text{rollout} }\),论文构建一个预测任务,其中模型以状态-动作对 \((s_{i},a_{i}^{j})\) 作为输入,并学习预测产生的下一个状态 \(s_{i}^{j}\)
    • 论文将训练目标定义为一个 Next-Token 预测损失:
      $$\mathcal{L}_{\text{IWM} }=-\sum_{(s_{i},a_{i}^{j},s_{i}^{j})\in \mathcal{D}_{\text{rollout} } }\log p_{\theta}(s_{i}^{j}\mid s_{i},a_{i}^{j}),$$
    • 其中 \(p_{\theta}\) 表示语言模型的输出分布
    • 注意,论文对状态预测(在世界建模期间)和动作预测(在策略执行期间)使用相同的模型参数 \(\theta\),允许策略直接内化环境动态
  • 这个训练目标鼓励模型捕捉环境行为中的规律性,包括常见的转移、副作用和无效动作结果
    • 与用于规划的推理时世界模型不同,论文的 隐式 (implicit) 表述将预测信号直接集成到策略学习中,作为监督学习或下游优化之前的轻量级预热
    • 它将智能体暴露于多样化的非专家行为中,提高了对分布偏移的鲁棒性,并减少了对脆弱专家轨迹的依赖
    • 在实践中, rollout 数据通常比 \(\mathcal{D}_{\text{expert} }\) 大一个数量级
    • 论文采用一个两阶段流程 :
      • 首先用 \(\mathcal{L}_{\text{IWM} }\) 训练以内化粗略动态
      • 然后在 \(\mathcal{D}_{\text{expert} }\) 上微调(即 \(\mathcal{L}_{\text{IL} }\))

Self-Reflection

  • 论文将 Self-Reflection 制定为一种机制,使智能体能够从其自身的探索性结果中学习

  • 智能体不仅仅依赖专家状态-动作对 ,而是在每个状态将专家动作与其策略中采样的 alternative 动作进行比较 ,利用产生的下一个状态生成自然语言解释 ,说明为什么专家选择更好

    • 这些解释比单独的专家动作提供了更丰富、可转移的监督,利用了 LLM 在处理语言方面的优势,以内化能够跨任务泛化的决策原则
  • 具体来说

    • 对于每个专家状态 \(s_{i}\),论文首先执行专家动作 \(a_{i}\) 以获得专家下一个状态 \(s_{i+1}\)
    • 对于每个 alternative 动作 \(a_{i}^{j}\)(其中 \(j\in\{1,…,K\}\))
      • 论文先获得相应的下一个状态 \(s_{i}^{j}\)
      • 然后提示一个语言模型生成一个思维链 \(c_{i}^{j}\) ,根据其结果状态 \(s_{i+1}\) 和 \(s_{i}^{j}\) 之间的差异,解释为什么专家动作 \(a_{i}\) 优于 alternative 动作\(a_{i}^{j}\)
      • 这个提示旨在引发自然语言推理,突出 \(a_{i}^{j}\) 中潜在的局限性或低效性,并以观察到的实际状态转移为基础
    • 产生的三元组 \((s_{i},a_{i}^{j},c_{i}^{j})\) 被收集到一个数据集 \(\mathcal{D}_{\text{refl} }\) 中
    • 然后论文训练智能体在给定状态 \(s_{i}\) 的条件下 ,联合预测思维链和专家动作 ,使用在连接的目标序列 \(c_{i}^{j}\circ a_{i}\) 上的 Next-Token 预测损失:
      $${\cal L}_{\rm SR}=-\sum_{(s_{i},a^{j}_{i},c^{j}_{i})\in{\cal D}_{\rm refl} }\log p_{\theta}(c^{j}_{i},a_{i}\mid s_{i}),$$
    • 其中 \(p_{\theta}\) 表示语言模型的输出分布,与智能体的策略 \(\pi_{\theta}\) 对齐
  • 在实践中,论文将 Self-Reflection 数据 \({\cal D}_{\rm refl}\) 与专家数据集 \({\cal D}_{\rm expert}\) 混合 ,并使用标准的 Next-Token 预测损失来训练模型

    • 思维链推理仅为 Self-Reflection 训练数据生成 ,并且只要专家轨迹提供了原始的思维链推理,论文就在所有使用 \({\cal D}_{\rm expert}\) 训练的模型中保留它
    • 这种联合训练设置平衡了来自演示的 grounded 决策和来自探索性结果的对比性洞见
      • 理解:即专家决策和自己的探索性决策之间的对比性不同

        This joint training setup balances grounded decision-making from demonstrations with contrastive insights from exploratory outcomes.

  • 从这两个来源学习鼓励模型超越死记硬背的模仿,并发展出更可泛化的决策标准 ,举个例子来说:

    • 在 WebShop 中,当专家动作是“点击 15 美元的蓝色衬衫”时,一个 alternative 动作可能是“点击 30 美元的红色衬衫”
    • 生成的反思可能是:“虽然红色衬衫符合颜色偏好,但它超过了查询中指定的 20 美元预算限制。蓝色衬衫既满足了风格要求,也符合预算限制。”
    • 这教会了模型优先考虑约束条件,这是一个可以超越这个特定项目的经验教训。论文在下面展示了跨环境使用的提示模板
  • Self-Reflection 提示模板 (Self-Reflection Prompt Template)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    你将看到一个需要你在多个可能动作之间进行选择的情境。你的任务是分析该情境,并提供关于论文为何决定采取专家动作的推理

    * **情境描述 (\\(s_{i}\\)):** {Situation Description}
    * **专家动作 (\\(a_{i}\\)):** {Expert Action}
    * **预期结果 (\\(s_{i+1}\\)):** {Future State of Expert Action}
    * ** alternative 动作(alternative 动作Actions):**
    1. 动作 \\(a^{1}\_{i}\\): {Alt Action 1}, 结果状态 \\(s^{1}\_{i}\\): {State 1}
    2. 动作 \\(a^{2}\_{i}\\): {Alt Action 2}, 结果状态 \\(s^{2}\_{i}\\): {State 2}
    3. ...
    提供一个详细的 **Self-Reflection** (self-reflection),作为你对此情境推理过程的 **内心独白** (internal monologue)。你的独白应该:
    1. 分析情境和目标
    2. 比较可能的动作,解释为什么每个可能不那么优化
    3. 证明为什么专家动作最合适,以预期结果为基础
    4. 突出情境中任何相关的线索、约束或后果

    **指南 (Guidelines):**
    * 严格保持在提供的信息范围内
    * 避免关于自己是 AI 的元评论
    * 使用自然的、逐步的推理
    * 专注于逻辑决策

    **输出 (Output):** 直接写出 Self-Reflection 独白,不要额外的标题、免责声明或外部注释
  • 隐式世界建模和 Self-Reflection 都遵循相同的原则 :

    • 将智能体自身的动作和产生的未来状态转化为可扩展的监督,从而实现更可泛化的 语言智能体 策略

Experiments

  • 论文通过在此范式中提出的两种方法,在一套多样化的语言智能体环境中评估 Early Experience 范式,测试其有效性(第 5.2 节)、领域外泛化能力(第 5.3 节)以及与事后强化学习的兼容性(第 5.4 节)
  • 表 1:跨三个主要领域和任务类型使用的基准
    • “# Traj.” 是论文收集/使用的专家轨迹数量;
    • “# \(\mathcal{D}_{\text{expert} }\)” 是用于模仿学习的状态-动作(SA)对的结果计数
    • 破折号表示该值在论文的数据构建文本中未指定

Experiment Setup

  • 环境 (Environments)
    • 论文在八个语言智能体环境上进行实验,涵盖了广泛的领域和任务格式,包括多轮工具使用 (2025; 2025; 2025)、网络导航 (2022; 2024)、具身模拟 (2021)、科学模拟 (2022) 和 Long-horizon 规划 (2024a)
    • 这些基准的详细信息列于表 1,更多细节可在附录 B 中找到
  • 模型和专家轨迹 (Models and Expert Trajectories)
    • 论文使用来自两个模型系列的三个经过指令调优的模型来评估 Early Experience :
      • Llama-3.2-3B、Qwen-2.5-7B 和 Llama-3.1-8B
    • 无论是否使用 Early Experience 增强,每个模型都在固定数量的专家演示上进行训练
    • 这些演示来自跨环境的不同来源
    • 更多细节在附录 B 中提供
  • 训练和评估 (Training and Evaluation)
    • 论文在所有设置中使用一致的提示格式和解码策略
    • 由于环境在数据大小和视野上有所不同,论文做了以下工作:
      • 首先为每个环境探索模仿学习基线的优化步数 ,并选择在验证集上具有最低训练损失和最佳性能的检查点
      • 然后固定这个步数预算 ,并在论文的方法中保持不变地使用它以确保公平比较
        • 对于隐式世界建模 ,论文从 WM 目标的一个 Epoch 开始 ,然后继续进行监督更新 ,使得总更新次数等于模仿预算 ,没有额外的步骤
        • 对于 Self-Reflection ,论文训练与模仿学习相同数量的 Epoch
        • 所有实验在训练和评估时最多使用 8 个 H100 GPU
    • 在评估方面,论文报告每个基准的主要原生指标,并遵循其官方验证器。完整的评估结果请参考附录 B

Effectiveness

  • 表2,八个基准的结果
    • 除非另有说明,所有值均为成功率(%)
    • 相对于模仿学习的改进以绿色显示
    • Prompt 表示指令调优模型的性能
    • IWM 和 SR 分别表示隐式世界建模和 Self-Reflection
    • 附录 B 显示了完整结果
  • 论文在跨越多轮工具使用、网络导航等的八个环境中进行评估(表 2)
    • 所有模型都使用相同的提示格式和解码策略为每个环境进行训练
  • 总体收益 (Overall Gains)
    • Early Experience 在几乎所有设置和两种模型大小下都优于模仿学习
    • 隐式世界建模 (IWM) 在结构化模拟器和事务性站点中产生稳定收益(ALFWorld/ScienceWorld +2.3 到 +5.5;WebShop +11.3 到 +18.4)
    • Self-Reflection (SR) 在任务需要多步推理和约束满足时带来最大的提升(TravelPlanner +12.8 到 +15.0;ScienceWorld +13.3;BFCLv3 在 3B 模型上 +8.0)
    • 即使在最具挑战性的设置中,收益也是一致的,尽管绝对值较小(WebArena +1.2 到 +3.6;SearchQA +0.6 到 +3.3)
  • 动作空间视角 (Action-Space Perspective)
    • 在论文的八个环境中,动作空间分为三种情况
      • 封闭且有限的动作集(例如,用于具身导航的 ALFWorld ,用于科学程序的 ScienceWorld ,以及用于行程规划的 TravelPlanner)从一开始就呈现一个小的、固定的允许动作列表
        • 在这里,IWM 帮助策略内化转移规律,而 SR 为 Long-horizon 计划增加了有针对性的修正(例如,在 TravelPlanner 上的巨大 SR 收益)
      • 结构化但大的动作集(例如,用于终端任务的 BFCLv3 和用于多域 API 的 Tau-Bench)需要从许多带有参数的类型化工具中选择并正确排序它们
        • 在这种情况下, Early Experience 减少了工具的误用并改善了排序;
        • 当策略错误主要是逻辑性错误时,SR 通常更有帮助
      • 开放动作集(例如,具有自由形式搜索查询的 SearchQA,具有细粒度网页元素交互的 WebArena)允许大量可能的动作,通常是组合性质的
        • 这些是最困难的机制;尽管如此, Early Experience 仍然通过将探索性 rollout 转化为密集的训练信号而产生了可靠的收益,而不需要奖励
  • 观察空间视角 (Observation-Space Perspective)
    • 论文的基准涵盖了广泛的观察复杂性
      • 在低端,ALFWorld 提供场景的简短、干净的文本描述;ScienceWorld 产生正在进行的实验的程序性读数
      • 中等范围的设置,如 BFCLv3 和 Tau-Bench,返回结构化的 API 模式和工具输出,必须正确解析和排序
      • 在高端,WebArena 将嘈杂的、细粒度的网页状态呈现为可访问性树,需要对数百个类似 DOM 的元素进行推理
      • 论文在附录 B 中提供了每个环境的示例
    • 在状态转移一致且可预测的设置中(例如,WebShop),IWM 通过帮助智能体内化环境动态和改进下一个状态预测而表现出色
    • 当失败主要源于推理错误或需要修复 Long-horizon 计划时(例如,TravelPlanner, ScienceWorld),SR 通过明确地将动作与专家轨迹进行比较而带来更大的收益
    • 总的来说,无论环境的观察多么简单或复杂, Early Experience 方法都持续地将智能体自身的动作和结果状态转化为有效的监督信号,从而在没有奖励的情况下改进策略学习
  • Takeaway
    • Early Experience 可靠地将智能体自身的动作和结果状态转化为超越专家演示的可扩展监督
    • 在此范式下的两种方法都在动作空间和观察复杂性截然不同的环境中加强了策略
    • 这些效应在三个模型大小和三个环境家族中均成立,证明了论文 Early Experience 范式的强大可泛化可行性

Out-Of-Domain Generalization

  • 为了评估训练策略在领域内性能之外的鲁棒性,论文在具有 领域外(out-of-domain,OOD)splits 的环境中探索 Early Experience ,使用与第 5.2 节评估相同的检查点
  • 在设置方面,对于 ALFWorld 和 SearchQA,论文遵循其原始工作中定义的 OOD splits
  • 对于 BFCLv3:
    • 领域内设置是多轮 base;
    • OOD 设置是对多轮 missing function、missing argument 和long context 进行平均
  • 论文训练模型的结果如表 3 所示,从中我们可以得出以下观察结果
    • OOD 分数在所有任务中相对于领域内都有所下降,但 Early Experience 持续恢复了差距的很大一部分
    • 在几种情况下,相对收益大于领域内收益(例如,SearchQA),这表明将自身的 rollout 转化为监督可以使策略为演示未覆盖的状态做好准备
    • 方法上的模式反映了领域内趋势:
      • IWM 在动态稳定的地方帮助最大(例如,ALFWorld);
      • SR 在分布偏移改变工具可用性或参数时最强(例如,BFCLv3);
      • IWM 和 SR 都在检索偏移下(例如,SearchQA)对所有模型大小都有帮助
  • 表 3:领域外评估结果(%);相对于模仿学习的改进以绿色显示;Prompt 表示指令模型的性能;IWM 和 SR 分别指隐式世界建模和 Self-Reflection
  • Takeaway
    • Early Experience 在多样化的 OOD 机制下提高了鲁棒性:
      • IWM 在动态稳定时表现出色,SR 在偏移影响工具可用性、参数或检索分布时表现出色
    • 在几个基准测试中(例如,ALFWorld, SearchQA),OOD 收益达到或超过领域内收益,这强化了智能体自身的经验提供了超越专家演示的监督

Reinforcement Learning Following Early Experience

  • 为了评估一旦环境提供可验证奖励(“经验时代”的决定性条件)时 Early Experience 的影响,论文在第 5.2 节训练的模型后附加了一个强化学习阶段
  • 论文专注于三个有奖励可用的基准:WebShop、ALFWorld 和 SearchQA,并采用广泛使用的 GRPO 算法 (2024)
    • 其超参数和训练步数与既定方案 (2025; 2025) 相同
    • 不同运行(runs)之间唯一变化的因素是初始化 :模仿学习 (IL)、隐式世界建模 (IWM) 或 Self-Reflection (SR)
  • 图 3 的结果显示了一个清晰的模式:
    • 从 Early Experience 开始总是能产生更高的 RL 后性能上限
      • 在某些情况下,性能差距在 RL 训练期间增大(例如,ALFWorld);
      • 在其他情况下,差距缩小但从未逆转
    • 即使应用相同步数的奖励优化,IL 起点也很少能达到 Early Experience 起点的最终性能
    • 为了完善实验(completeness),论文还直接从原始预训练模型运行 GRPO,没有任何监督阶段
      • 这在所有任务中表现最差,并显示出不稳定的训练动态,突显了强初始化的必要性
    • 带有详细指标的完整结果可以在附录 B 中找到
  • Takeaway
    • Early Experience 充当了人类数据时代和经验时代之间的 中期训练桥梁 (mid-training bridge)
    • Early Experience 产生的策略在没有奖励的情况下已经表现强劲,并且放大了后续 RL 的收益
    • 在相同的 RL 方案下,Early Experience 起点实现了更高的最终性能
    • 这些结果表明,一旦 RL 基础设施在新的环境中可用,Early Experience 可以立即解锁进一步的收益,而无需从头开始重新训练

Discussion

Comparison to Baselines

  • 论文将 Early Experience 与两种替代方案进行比较,这些方案在不执行 alternative 动作 或 观察动作引发的状态的情况下注入 额外的监督或推理信号
    • 理解:讨论这里是想介绍两种相似的方案,作为 Early Experience 的补充比较
  • 这使论文能够测试论文的增益是否可以通过简单地扩展推理时间或在训练期间添加未经实际验证的推理来匹配
    • (I) 长思维链 (Long CoT) (test-time scaling)
      • 受测试时扩展 (2024) 的启发,论文的目标是帮助特定模型在推理时进行更广泛的推理
        • 这些特定模型包括:在专家轨迹上训练的、通常缺乏推理过程的指令微调模型和纯模仿模型
      • 提示基线使用现成的指令微调模型和先前工作中的官方提示,这些提示通常产生短思维链 (2022)
      • 论文的长思维链变体通过在 Training splits 上进行更重的提示搜索,当存在标记推理结束的分隔符 Token(例如 </think>)时,截断它以鼓励继续生成,来强制在动作生成之前进行更长的推理
        • 问题:这样也可以吗?如果人家已经不想思考了,模型会输出什么奇怪的东西呢?比如很可能重复输出吧?
      • 论文报告每个环境上的最佳结果
    • (II) STaR 风格数据 (STaR-style data) (reasoning without alternative actions or resulting states,没有 alternative 动作或结果状态的推理)
      • 遵循 STaR (2022):
        • 让模型为每个状态下的专家动作生成一个原理,并仅保留预测动作与专家动作匹配的情况
        • 然后在(状态,原理,动作)元组((state, rationale, action) tuples)上进行微调,如公式 \(\ref{eq:self_refl}\) 所示
      • 注意:没有使用 alternative 动作及其结果状态(因为这些原理在实际结果中仍然是未经实际验证的)
      • 其他超参数:
        • 搜索用于原理合成的提示词变体并保留最强的配置
        • 优化步骤的数量与论文的自反思方法相同
  • 表 4 显示,两种 Early Experience 方法在任务和模型大小上都实现了最大的增益
    • 对于长思维链 ,更重的提示搜索和推理长度控制可以适度地改善经过模仿训练的提示基线 ,但在更困难的设置中,增益迅速消失
    • 一旦仅在缺乏固有原理的专家轨迹上进行微调,模型就失去了维持连贯长形式推理的能力,因此尽管在思维-动作边界处进行了截断,扩展的思维链常常漂移或崩溃为无效/偏离策略的动作
    • 对于 STaR 风格数据,生成的动作与专家动作之间的匹配率很低,留下的可用训练数据很少
    • 保留的原理是未经实际验证的,从未在环境中测试过,并且经常幻觉工具或事实,因此对它们进行微调甚至可能降低性能
    • 相比之下, Early Experience 直接将策略自身的非专家 rollout 转换为来自观察到的下一状态的经实际验证的监督,产生了这些替代方案无法匹配的稳健改进

Impact of Amount of Human Data

  • 为了检查性能如何随专家监督的数量而变化,论文在保持总训练预算固定的情况下,改变用于启动 Early Experience 的 Demonstrations 数量
  • 图 4 (a) 显示,在每个数据水平上, Early Experience 都保持对模仿学习的一致领先
    • 在 WebShop 上,仅使用 \(1/8\) 的 Demonstrations 就已经超过了在全量数据集上训练的模仿学习;
    • 在 ALFWorld 上,使用 \(1/2\) 的 Demonstrations 也保持了同样的优势
  • IWM 和 SR 都随着更多专家数据而改进,但相对于模仿学习的优势仍然很大,这强调了 Early Experience 提供了超越仅靠 Demonstrations 所能提供的额外监督信号

Impact of Branching Factor

  • 为了研究分支因子对论文方法的影响,论文还对分支因子 \(K\)(在生成 Early Experience 时每个专家状态 roll out 的 alternative 动作数量)进行了消融
  • 图 4 (b) 显示,随着 \(K\) 的增加,IWM 稳步改进,这与学习更丰富的转移规律相一致
  • SR 在中小 \(K\) 值时改进,并且在非常大的 \(K\) 值时可能非单调:
    • 比较许多 alternative 动作偶尔会包括其他导致成功的动作,减少了与专家的对比,并且当前模型在单个上下文中推理许多 alternative 动作和结果的能力有限
  • 总的来说,两种变体在大部分时间都有所改进,IWM 倾向于更大的 \(K\),而 SR 在适中的 \(K\)(例如 2–4)下效果最好

Model Scaling

  • 论文研究了 Early Experience 的益处是否随着模型缩放而持续
  • 在 WebArena 上,论文比较了 \(\bigcirc\) Llama-3.2-3B、\(\bigcirc\) Llama-3.1-8B 和 \(\bigcirc\) Llama-3.3-70B
  • 由于计算资源有限,70B 模型的微调对所有方法都使用参数高效的 LoRA (2022),保持相同的秩和更新步数;对于 IWM,在第二阶段继续使用相同的适配器,使得总可调参数和计算量与模仿学习相匹配
    • 问题:Meta 缺少计算资源?
  • 图 5 显示, Early Experience 在每个规模上都优于模仿学习,即使对于 70B 模型,差距仍然存在
    • 绝对性能随规模提升,而 Early Experience 检查点 consistently 占据顶部曲线,表明其提供的监督是对模型规模的补充而非替代
    • 即使仅使用 LoRA 更新,IWM 和 SR 都带来了稳定的增益,证明该方法在受限计算预算下仍然有效
    • 论文在附录 B 的表 10 中观察到 Qwen 模型的类似趋势

补充:Related Work

Training Paradigms for Language Agents

  • SFT
    • 大多数语言智能体 (2022; 2023; 2024; 2025) 使用监督微调在专家轨迹上进行训练,在强化学习文献中也称为模仿学习或行为克隆,特别是在复杂设置中,例如网络 (2024) 或操作系统 (2024)
    • 这些轨迹可能是人工标注的 (2022; 2023),也可能是由遵循精心设计的人类工作流程的更强语言模型合成的 (2024; 2025)
    • 尽管合成 Demonstrations 增加了覆盖范围,但它们只提供了增量收益,因为底层的监督信号仍然是静态的
    • 监督微调提供了密集的、无奖励的监督信号,但仍然受限于高质量 Demonstrations 的成本 (2025),并且当智能体面对新状态时显得脆弱 (2025; 2023)
  • RL
    • 强化学习通过试错来训练智能体,优化长期奖励 (1998)
    • 尽管它在控制、棋盘游戏和 Atari (2013; 2016; 2020; 2020) 中取得了令人印象深刻的结果,但在语言智能体设置中有效应用强化学习仍然很困难 (2025;)
    • 当前的研究仍处于探索阶段:
      • 许多研究依赖于由更大的教师模型产生的近似奖励 (2025;),或者依赖于精心策划的奖励函数 (2025) 和手动调整的训练方案 (2025) 来保持稳定性
    • 支持的基础设施也尚未成熟;
      • 大多数现实世界的语言智能体环境缺乏可靠的模拟器、标准的重置机制和可扩展的评估平台 (2025;),使得语言智能体的大规模强化学习训练成本高昂且脆弱
    • 总之,这些局限性表明,语言智能体的可扩展强化学习尚未成熟,这促使需要一个范式来桥接当前基于模仿的训练和未来完全由经验驱动的学习

Supervision from Exploration

  • 强化学习中的传统探索-利用策略收集轨迹,随后通过奖励反馈进行优化
  • 诸如 Hindsight Experience Replay (2017) 之类的方法通过将已实现的结果改造为目标来稠密化稀疏奖励,但仍然需要许多语言智能体环境中不可用的可验证奖励函数
  • 论文的设置以不同的方式使用探索:交互轨迹成为直接的监督信号,完全消除了对奖励或手动重新标注的需求

World Models

  • 传统上的世界模型 (1991; 2018; 2020, 2021) 是指:在观察到的状态转移上进行训练,以预测未来状态和奖励,允许基于模型的强化学习减少样本复杂度并支持推测性规划
  • 最近的工作通过使用大语言模型作为世界模型 (2025; 2023) 将此思想扩展到语言智能体 ,这通过语言介导的模拟提高了下游性能
    • 尽管不同时代的世界模型具有不同的状态表征,但这些系统中的大多数仍然将世界模型视为一个 独立的 模拟器,呼应了经典的控制流程
    • 相比之下,论文将交互轨迹本身视为智能体策略的辅助预测任务,在精神上类似于中期训练 (2025)
    • 通过训练策略来预测其自身的未来状态,模型内化了粗略的环境动态,而无需独立的模拟器
    • 这种 隐式(implicit) 世界模型将智能体锚定在其操作上下文中,提供了轻量级的热身以便更快地适应,并避免了显式模拟器所需的规划开销

Self-Reflection

  • Self-Reflection (2023;) 最初是作为一种提示技术引入的,允许大语言模型通过多轮自我对话 (2024) 或精心设计的提示词变体 (2023) 来修改其答案 ,而无需更新模型参数
  • 后续工作在有奖励的轨迹上总结经验教训(例如,短期情景记忆 (2025))到提示中,以指导未来的推理
    • 但后来的研究 (2024; 2023) 表明,这类推理时方法在无法获得外部反馈(例如奖励)时常常失败
  • 另一条研究线使用大语言模型为正确答案生成原理,将这些原理视为训练目标以引导推理 (2022; 2023)
    • 论文将这种反思的观点扩展到 缺乏显式奖励(explicit rewards are absent) 的智能体设置中
    • 论文的方法训练智能体反思其自身的次优行动及由此产生的轨迹,然后使用反思出的原理作为训练信号来改进决策制定

附录 B:Implementation details

  • 在本节中,论文为每个环境提供实现细节
  • 对于每个环境,论文呈现包含所有可用指标的表格
  • 此外,论文还展示了由 Llama-3.1-8B 合成的具体训练示例(例如,用于 Self-Reflection 的数据)

B.1 ALFWorld

  • 论文遵循 ALFWorld (2021) 的默认 split,使用 Verl-Agent (2025) 框架下的 TextWorld (2019) 设置
    • 论文从 ALFWorld 的专家轨迹中提取了 21,031 个状态-动作对来构成 \(\mathcal{D}_{\text{expert} }\)
    • 鉴于数据集中任务可解性的完整性,这些专家轨迹是最优的
  • 对于隐式世界建模,论文使用 \(\mathcal{D}_{\text{rollout} }\) 来增强 \(\mathcal{D}_{\text{expert} }\)
    • 在每个状态,论文从可行动作列表中(排除专家动作)均匀地、无放回地采样 8 个非专家动作
    • 包含专家动作,总计为隐式世界建模产生 \(21,031 \times 9 = 189,279\) 个三元组
  • 对于 Self-Reflection ,论文通过提示模型解释其自身决策来构建数据
    • 对于每个状态,论文使用相同的策略模型(温度设为 1.0)来提出最多 3 个 alternative 动作
      • 对提出的动作进行规范化处理,并仅保留唯一动作
    • 如果提出的动作不在该状态的可行动作空间内,将其丢弃,并改为从剩余未选中的可行动作中均匀随机采样
    • 最终的提示要求模型根据当前状态和可用工具,证明为什么专家动作优于采样得到的 alternative 动作
  • 在训练期间,论文使用批大小为 16,学习率为 \(1\mathrm{e}{-5}\),并使用 LlamaFactory (2024b) 训练 2 个 Epoch
    • 对于强化学习训练,论文采用 Verl-Agent 中的默认超参数 ,并在其论文(理解:应该是 ALFWorld 论文)报告的相同 split 上进行评估
    • 对于评估,论文将最大提示长度设置为 4096,最大响应长度设置为 1024,温度设置为 0.4
  • 完整结果见表 5

B.2 WebShop

  • 根据 WebShop (2022) 官方发布的人类演示数据,论文提取了 1,571 条人类轨迹,并将其转换为 Verl-Agent (2025) 格式,得到了 15,464 个状态-动作对,构成了用于模仿学习的 \(\mathcal{D}_{\text{expert} }\)
  • 对于隐式世界建模,数据包含两个部分
    • 第一部分直接来源于 \(\mathcal{D}_{\text{expert} }\),通过将每个步骤重新格式化为世界建模格式,其中输入包含历史上下文和当前步骤采取的动作,目标是执行该动作后下一个状态的离线文本摘要(平均长度 345 个字符)
    • 第二部分是通过用非专家动作增强每个专家状态获得的:
      • 让相同的策略在温度 {0.5, 0.8, 0.9} 下提出动作,并额外为每个状态均匀随机采样最多五个可行动作
      • 然后将增强的样本转换为与第一部分相同的世界建模格式:
        • 对于每个非专家动作,论文在 WebShop 环境中执行它以获得后续观察结果,并推导出下一个状态的离线文本摘要
      • 所有候选动作都经过规范化和去重处理
      • 将这些与专家动作合并后,论文得到了 122,954 个三元组用于隐式世界建模
  • 对于 Self-Reflection ,论文构建的提示包括专家动作以及 3 个 alternative 动作 ,并要求模型根据当前状态和可行动作证明为什么专家动作更优
    • 由于原始专家轨迹中的某些动作是次优的 ,论文应用了一个简单的质量过滤器 ,仅保留那些任务能在少于 15 步内完成的轨迹中的动作 ,从而得到了 6,235 个反思示例
      • 问题:仅保留那些任务能在少于 15 步内完成的轨迹中的动作 与 某些动作是次优的 有什么关系?
    • 对于每个这样的状态,alternative 动作的抽取方式与世界建模中相同,即混合模型提出的动作(使用上述温度)和均匀采样的可行动作;
    • 经过规范化和去重后,论文保留 3 个不同的 alternative 动作
    • 论文有意保留多样化的 alternative 动作集合,包括可行但无帮助的动作、空响应以及偶尔的无效动作,以帮助模型学习更清晰的决策边界
  • 在训练期间,论文使用批大小为 4,学习率为 \(1\mathrm{e}{-5}\),并使用 LlamaFactory (2024b) 进行训练
    • 对于强化学习训练,论文采用 Verl-Agent 中的默认超参数,并在其论文报告的相同 split 上进行评估
  • 完整结果见表 6

B.3 BFCLv3

  • 论文遵循 BFCLv3 (2025) 基准测试的默认多轮函数调用 split ,该 split 将任务分类为Base、Long-Context、Miss Function 和Miss Parameters
    • Base 包含基础但多样的多轮交互 ,其中所有必要信息 ,包括用户请求、先前轮次的执行结果和探索性函数输出,都可用于完成任务而无歧义
    • Long-Context 通过引入大量无关数据(例如,数百个文件或数千条记录)来评估模型在冗长、信息密集的环境中保持准确性的能力 ,从而测试其在认知负荷下提取基本细节的能力
    • Miss Function 评估模型能否识别出没有可用函数可以满足用户请求的情况;
      • 当该问题被识别出来时,将在后续轮次中提供缺失的函数 ,并要求模型适应新可用的能力(理解:即函数)
    • Miss Parameters 检查模型是否能够检测到用户请求中缺少基本参数且无法从系统状态推断的情况,提示其请求澄清而不是做出无根据的假设
  • 由于默认的 BFCLv3 基准测试不提供训练集 split ,为了构建训练集,论文专门使用Base 类别中的样本
    • 论文随机选择其中 75% 的样本(125 条轨迹)作为用于模仿学习的专家轨迹 \(\mathcal{D}_{\text{expert} }\)
      • 每条轨迹包含多个步骤和交互,论文将其进一步拆分为单独的步骤以提高训练效率
  • 对于隐式世界建模,数据包含两个部分
    • 第一部分直接来源于 \(\mathcal{D}_{\text{expert} }\),通过将每条轨迹重新格式化为世界建模格式,其中给定历史上下文和上一步的动作,模型预测下一个状态
      • 这产生了 1,264 个训练样本
    • 第二部分是通过增强生成的:
      • 对于专家轨迹中的每个状态,论文让目标模型除了专家动作外再采样 10 个 alternative 动作 ,按照与 ALFWorld 相同的过程 ,产生了 11,904 个样本
  • 对于 Self-Reflection,论文通过提示模型解释其决策来构建训练数据,强调在当前状态下,包括先前定义的工具集在内,为什么专家动作优于其他可用动作
    • 在过滤掉一小部分生成的结论动作与专家动作不匹配的低质量样本后,论文获得了 1,200 个训练样本
  • 论文使用 LlamaFactory (2024b),以批大小 16、学习率 \(1\mathrm{e}{-5}\) 进行训练
    • 为了推理效率,论文采用 vLLM 基础设施
  • 完整结果见表 7

B.4 Tau-Bench

  • 论文使用 Tau-Bench 中的零售任务(retail task)进行实验,在 Tau-Bench 中,零售任务分为训练集和评估集,分别包含 495 和 115 个任务
  • 论文采用一个高性能的指令调优 LLaMA 系列模型在训练集上收集专家轨迹
    • 对于每个任务,推理温度设置为 1.0,并生成四条轨迹
      • 选择最终奖励为 1 的轨迹作为专家轨迹;
      • 如果存在多条这样的轨迹,则随机选择一条;
      • 如果没有轨迹达到奖励 1,则丢弃该任务
    • 此过程为 452 个任务生成了专家轨迹,总共得到 5,239 个(观察,动作)(〈observation, action〉)对
  • 对于世界模型数据,论文使用目标模型为专家轨迹中的每个观察提出五个动作候选
    • 为了避免重复的工具调用并促进探索 ,论文从每个专家观察对应的工具集中移除专家动作中使用的工具,允许模型从剩余工具中进行选择
    • 然后,在环境中执行所选动作以获得下一个观察
      • 每个生成的(专家观察,动作,下一个观察)三元组都包含在世界模型的训练数据集中
  • 对于 Self-Reflection 数据,对于每个(专家观察,专家动作)对,论文从相应的五个世界模型数据点中选择三个 alternative 动作,并将其呈现给模型本身进行反思,提示其解释选择专家动作背后的原理
    • 论文过滤掉一小部分低质量的反思样本,最终得到总共 5,233 个训练实例
  • 论文采用 LLamaFactory (2024b) 作为训练代码库
    • 对于模仿学习,论文以 1e-5 的学习率训练 6 个 Epoch
    • 对于隐式世界模型学习,论文以 5e-6 的学习率训练 1 个 Epoch
    • 对于 Self-Reflection ,论文以 1e-5 的学习率进行 6 个 Epoch 的 SFT
    • 在所有训练配置中,批大小固定为 16
  • 由于 Tau-Bench 不包含更细粒度的指标,论文在表 2 中报告了完整表格

B.5 SearchQA

  • 专家轨迹收集 论文从 MuSiQue 训练数据集中选择了所有的 3 跳和 4 跳任务,以及随机抽样的 1,438 个 2 跳任务,以适应需要多步推理来解决复杂问题的场景
    • 最终,论文总共有 7,000 个任务
    • 由于训练数据缺乏细粒度的推理轨迹,例如 Jin 等人 (2025) 所使用的思考-搜索-答案结构,论文使用 Search-R1 模型来生成专家数据
      • 具体来说,论文将温度设置为 1.0,并为每个任务生成 5 条轨迹,仅保留最终答案与真实答案匹配的轨迹
      • 为了减少冗余,论文每个任务最多保留 2 条正确轨迹。此过程产生了 2,082 条轨迹,包含总共 7,691 个状态-动作对用于模仿学习
  • 世界建模数据构建 与 Jin 等人 (2025) 的观察一致,论文发现直接预测检索到的文档内容会产生次优性能,因为许多 Token 与搜索查询不直接相关
    • 为了解决这个问题,论文首先指导模型总结检索到的文档,然后让模型预测这些摘要而不是全文
    • 对于专家轨迹中的每个状态,论文让模型在温度为 1.0 的情况下生成 30 个 alternative 动作,使其能够从自身的 Early Experience 中实质性地内化环境动态
    • 如果生成的动作无效,即查询没有包含在 \(<\)search\(><\)/search\(>\) 标签内,论文返回反馈:”格式错误!如果需要外部知识,你必须将搜索查询包含在 \(<\)search\(><\)/search\(>\) 标签内。”
  • Self-Reflection 数据构建 为了构建 Self-Reflection 训练数据集,论文为每个状态随机采样 2 个 alternative 动作
    • 对于每个实例,提示模型基于当前状态、专家动作、 alternative 动作以及与这些动作相关的检索文档,生成解释为什么专家动作优于 alternative 动作的细粒度推理
    • 此过程产生了 7,691 个包含详细推理过程的训练数据
  • 训练细节 论文采用 LLamaFactory (2024b) 作为代码库,并使用 ZeRO-3 在 4 个 H100 GPU 上进行全参数调优
    • 对于模仿学习和 Self-Reflection ,论文以 \(1\times 10^{-5}\) 的学习率、8192 个 Token 的上下文窗口、每个 GPU 批大小为 2 进行 3 个 Epoch 的训练,同时将梯度累积步数设置为 16
    • 对于隐式世界模型学习,论文利用来自专家轨迹的世界模型数据,使其与模仿学习数据集达到 1:1 的比例,并在相同设置下进行训练
    • 对于强化学习,论文采用 Search-R1 代码库并在 8 个 H100 GPU 上进行训练
      • 所有设置与 Jin 等人 (2025) 保持一致,除了论文使用 F1 分数作为奖励,将最大检索交互次数设置为 6,配置上下文窗口为 12,280 个 Token ,并指定最大输出长度为 2,048 个 Token
      • 对于训练数据,论文使用 MuSiQue 数据集中的所有训练任务
  • 完整结果见表 8

B.6 ScienceWorld

  • 论文遵循 ScienceWorld (2022) 的默认 split ,使用 Verl-Agent (2025) 框架下的 AgentGym (2024) 设置
    • 从 ScienceWorld 的专家轨迹中,论文提取了 14,506 个状态-动作对来构成 \(\mathcal{D}_{\text{expert} }\)
    • 鉴于数据集中任务可解性的完整性,这些专家轨迹是最优的
  • 对于隐式世界建模,论文使用 \(\mathcal{D}_{\text{tollout} }\) 来增强 \(\mathcal{D}_{\text{expert} }\)
    • 在每个状态,论文从可行动作列表中(排除专家动作)均匀地、无放回地采样 3 个非专家动作,并包含专家动作用于隐式世界建模
  • 对于 Self-Reflection ,论文通过提示模型解释其自身决策来构建数据
    • 对于每个状态,论文使用相同的策略模型(温度设为 1.0)来提出最多 3 个 alternative 动作(对于 Llama-3.1-8B-Instruct 则为 2 个 alternative 动作)
    • 论文对提出的动作进行规范化处理,并仅保留唯一的动作
      • 如果提出的动作不在该状态的可行动作空间内,论文将其丢弃,并改为从剩余未选中的可行动作中均匀随机采样
    • 最终的提示要求模型根据当前状态和可用工具,证明为什么专家动作优于采样得到的 alternative 动作
  • 对于所有的训练和评估,论文使用 one-shot example
    • 在训练期间,论文使用批大小为 32,学习率为 \(5\mathrm{e}{-6}\),并使用 LlamaFactory (2024b) 训练 1 个 Epoch
    • 对于评估,论文将最大提示长度设置为 4096,最大响应长度设置为 1024,温度设置为 0.4
  • 由于 ScienceWorld 不包含更细粒度的指标,论文在表 2 中报告了完整表格

B.7 TravelPlanner

  • 论文将 TravelPlanner (2024a) 基准测试适配为一个基于 gym 的环境 ,用于训练语言智能体
    • 原始基准测试包含 1,225 个查询,分为训练集(45 个查询)、验证集(180 个查询)和测试集
    • 论文使用涵盖不同难度级别(基于旅行持续时间:3、5 或 7 天)和约束复杂性(简单、中等、困难)的多样化规划场景的 45 个训练轨迹
      • 简单 查询主要是针对单人的预算约束
      • 中等 查询引入了额外的约束,如美食类型、房间类型或房间规则,旅行者人数在 2 到 8 人之间变化
      • 困难 查询包括交通偏好以及所有中等级别的约束,包含三个随机选择的困难约束。论文在包含 180 个查询的验证集上进行评估
  • 环境实现 论文将 TravelPlanner 实现为一个具有离散动作空间和字典观察空间的 gym 环境
    • 状态表示包括以结构化文本格式格式化的当前规划进度:
      • 查询描述、预算跟踪(初始/已花费/剩余)以及每天显示交通、餐饮、景点和住宿字段的当前计划状态
    • 动作是 JSON 对象,包含动作类型(例如,SET TRANSPORTATION, SET MEAL, SET ACCOMMODATION)、天数、字段名称、选定值和成本等字段
      • 动作空间根据参考信息中的可用数据动态生成所有有效动作,包括城市间的航班、具有美食类型和价格的餐厅、景点以及具有房间规则和最低住宿夜数要求的住宿
    • 环境实时跟踪预算支出,验证约束条件,并通过状态机维护规划进度,该状态机按顺序推进每个字段
  • 专家轨迹收集 论文使用训练集中的 45 条带标注轨迹作为专家演示 \(\mathcal{D}_{\text{expert} }\)
    • 每条轨迹包含一个完整的多日旅行计划,其中包含交通、住宿、餐饮和景点的真实动作
    • 论文使用 SFTConverter 将这些轨迹分解为 1,395 个独立的状态-动作对,该转换器将专家计划条目映射到有效的 gym 动作,同时处理城市名称变化并根据环境约束进行验证
  • 隐式世界建模 对于世界建模数据,论文生成两种类型的训练样本
    • 首先,将专家轨迹重新格式化为状态转换格式 ,模型学习在给定当前状态和动作的情况下预测下一个状态
    • 其次,论文通过执行专家轨迹中每个状态下所有可用的有效动作(而不仅仅是采样)来执行 exhaustive augmentation,收集全面的状态转换以最大化环境动态的覆盖范围
      • 理解:这里的 exhaustive augmentation 指 穷尽式数据增强,访问了所有的有效动作
    • 此过程生成了超过 70,000 个状态转换样本,为学习环境动态(包括预算更新、约束评估和计划进展)提供了丰富的监督信息
  • Self-Reflection 论文通过提示 Llama-3.1-8B-Instruct 生成思维链推理来解释为什么专家动作优于 alternative 动作,从而构建 Self-Reflection 数据
    • 对于 1,395 个状态-动作对中的每一个,论文探索最多 30 个替代的有效动作,并生成考虑多个约束的推理:预算限制、住宿的最低住宿夜数、餐厅多样性要求以及往返完成情况
    • 推理生成使用温度 0.9 和 8 路张量并行性来产生自然的解释,同时保持逻辑一致性
    • 论文不应用额外的过滤,因为推理生成过程已经验证了约束满足情况
    • 问题:这里为什么要使用 Llama-3.1-8B-Instruct 而不是目标模型?
  • 训练细节 论文使用 LlamaFactory ,在 8 个 H100 GPU 上使用 DeepSpeed ZeRO-3 进行全参数微调来训练模型
    • 对于模仿学习和隐式世界建模,论文以 \(1\mathrm{e}{-5}\) 的学习率和余弦调度器训练 5 个 Epoch
    • 对于 Self-Reflection ,论文将最大生成长度扩展到 8K Token 以容纳详细的推理
    • 所有模型使用 32K 上下文窗口,每个 GPU 批大小为 16
    • 对于评估,论文使用 vLLM,在 8 个 GPU 上进行张量并行,并使用贪婪解码以确保可重现性
  • 完整结果见表 9

B.8 WebArena

  • 鉴于 WebArena (2024) 中的完整评估集冗长且包含许多类似任务
    • 论文遵循先前的工作 (2024; 2025a) ,在 WebArena-Lite (2024) 上评估论文训练好的智能体,这是一个从原始的 812 个任务中手动挑选出的更高效、更平衡的 165 个高质量、具有挑战性的任务的子集
    • WebArena 中剩余的 647 个任务(不包括评估集中的任务)用于智能体训练
  • 为了获取 WebArena 中的专家演示,论文从公开的 WebArena 排行榜上表现最佳的智能体中提取成功的轨迹
    • 具体来说,论文选择那些在其观察中包含可访问性树信息的智能体,例如 IBM CUGA (2025), ScribeAgent (2024), Learn-by-Interact (2025) 和 AgentOccam (2024)
    • 在过滤掉不成功的轨迹后,论文获得了 554 条成功的轨迹和 7,044 个状态-动作对,构成了 \(\mathcal{D}_{\text{expert} }\)
  • 对于隐式世界建模 ,为了从专家轨迹中分支出来进行隐式世界建模 ,论文增强 \(\mathcal{D}_{\text{expert} }\) 以形成 \(\mathcal{D}_{\text{rollout} }\)
    • 对于 \(\mathcal{D}_{\text{expert} }\) 中的每个状态,论文让目标模型(待训练)使用自由形式生成提出 5 个非专家动作,排除任何与专家动作相同的动作
    • 对于每个 resulting next state,论文应用一个额外的处理步骤:使用相同的模型,论文生成下一个状态观察的简洁摘要,该摘要以任务为条件,替换原始观察以减少噪声并强调与任务相关的信息。然后,论文将专家动作与采样的动作一起包含进来,创建形式为(当前状态,动作,摘要化的下一个状态)的三元组,最终为每个模型总共产生 \(7,044 \times 6 = 42,264\) 个三元组
  • 对于 Self-Reflection ,论文通过提示模型解释在当前状态下为什么专家动作优于采样的 alternative 动作来构建 \(\mathcal{D}_{\text{SR} }\)
    • 论文使用来自 \(\mathcal{D}_{\text{rollout} }\) 的相同 5 个 alternative 动作,规范化动作字符串以避免重复,并用随机采样的有效动作替换任何无效动作(例如,引用不存在的 UI 元素)
    • 最终的提示词包括当前状态、可行动作和专家动作,并要求模型在任务进度、约束满足和效率方面证明专家选择的最优性
    • 论文过滤掉那些解释错误地支持非专家动作的低质量生成内容,留下 3,190 个高质量的 Self-Reflection 示例
  • 所有模型均以 1e-5 的学习率和余弦调度器训练 2 个 Epoch
  • 论文在 WebArena-Lite 上的完整数据报告在表 10 中

NLP——技术报告解读-DeepSeek-V3.2

注:本文包含 AI 辅助创作

  • 参考链接:
    • 原始论文(已过期):DeepSeek-V3.2: Pushing the Frontier of Open Large Language Models, DeepSeek, 20251202
    • 原始论文(arXiv):DeepSeek-V3.2: Pushing the Frontier of Open Large Language Models, DeepSeek, 20251202
    • 参考博客:DeepSeek-V3.2 技术报告深度解析:架构演进、RL 扩展与 Agent 合成数据
    • 对 Unbiased KL Estimate 的理解:DeepSeek-V3.2中无偏 KL估计(Unbiased KL Estimate)的一些想法 - Keith Jiang的文章 - 知乎

Paper Summary

  • DeepSeek-V3.2:在高效计算与卓越推理和智能体性能之间取得平衡的模型
  • DeepSeek-V3.2 关键技术:
    • (1) DeepSeek 稀疏注意力 (DeepSeek Sparse Attention, DSA): 论文引入了 DSA,这是一种高效的注意力机制,能在保持长上下文场景下模型性能的同时,显著降低计算复杂度
    • (2) 可扩展的强化学习框架 (Scalable Reinforcement Learning Framework): 通过实施一个鲁棒的强化学习协议并扩展后训练计算量,DeepSeek-V3.2 的性能与 GPT-5 相当
      • DeepSeek-V3.2-Speciale(DeepSeek-V3.2 的高计算量变体) 超越了 GPT-5,并且其推理能力与 Gemini-3.0-Pro 持平,在 2025 年国际数学奥林匹克 (International Mathematical Olympiad, IMO) 和国际信息学奥林匹克 (International Olympiad in Informatics, IOI) 中均取得了金牌表现
    • (3) 大规模智能体任务合成流程 (Large-Scale Agentic Task Synthesis Pipeline): 为了将推理能力整合到工具使用场景中,论文开发了一种新颖的合成流程,系统地大规模生成训练数据。这种方法促进了可扩展的智能体后训练,在复杂、交互式环境中显著提升了模型的泛化能力和遵循指令的鲁棒性
  • 图 1:DeepSeek-V3.2 及其同类模型的基准测试
    • 对于 HMMT 2025,论文报告的是二月份的比赛结果,与基线一致
    • 对于 HLE,论文报告的是纯文本子集

Introduction and Discussion

  • 推理模型的发布标志着 LLM 演进中的一个关键转折点,在可验证领域的整体性能的显著飞跃
  • 自这一里程碑以来,LLM 的能力迅速发展;但在过去几个月中出现了明显的分化
    • 虽然开源社区持续取得进展,但闭源专有模型 (Anthropic; DeepMind; OpenAI, 2025) 的性能提升轨迹以明显更快的速度在加速
    • 闭源和开源模型之间的性能差距不仅没有缩小,反而似乎在扩大,专有系统在复杂任务中表现出日益卓越的能力
  • 作者分析确定了限制开源模型在复杂任务中能力的三个关键不足
    • 在架构上,主要依赖普通注意力 (vanilla attention) (2017) 机制严重限制了长序列的效率
      • 这种低效性对可扩展部署和有效后训练都构成了重大障碍
    • 在资源分配方面,开源模型在后训练阶段的计算投入不足,限制了其在困难任务上的表现
    • 在 AI 智能体 (AI agents) 的背景下,与专有模型相比,开源模型在泛化能力和指令遵循能力方面表现出明显的滞后 (EvalSys, 2025; 2025; 2025),这阻碍了其在实际部署中的有效性
  • 为了解决这些关键限制,论文做了如下改进:
    • 第一:引入 DSA,一种旨在显著降低计算复杂度的高效注意力机制
      • 该架构有效解决了效率瓶颈,即使在长上下文场景下也能保持模型性能
    • 第二:开发了一种稳定且可扩展的 RL 协议,允许在后训练阶段进行显著的计算扩展
      • 该框架分配的后训练计算预算超过了预训练成本的 \(10%\),从而解锁了高级能力
    • 第三,提出了一种新颖的流程,以促进工具使用场景中可泛化的推理
      • 首先,实施一个冷启动 (cold-start) 阶段,利用 DeepSeek-V3 (DeepSeek-AI, 2024) 的方法论将推理和工具使用统一在单个轨迹内
      • 随后,论文推进到大规模智能体任务合成,生成了超过 1,800 个不同的环境和 85,000 个复杂的 Prompt
      • 这种广泛的合成数据驱动了 RL 过程,显著增强了模型在智能体上下文中的泛化能力和指令遵循能力
  • 小结:
    • DeepSeek-V3.2 在多个推理基准测试中与 Kimi-k2-thinking 和 GPT-5 取得了相近的性能
    • DeepSeek-V3.2 显著提升了开源模型的智能体能力,在之前工作(EvalSys,2025; 2025; 2025)引入的长尾智能体任务上表现出卓越的熟练度
    • DeepSeek-V3.2 成为智能体场景中一个极具成本效益的替代方案,在显著降低成本的同时,大大缩小了开源模型与前沿专有模型之间的性能差距
    • 特别地:为了推动开源模型在推理领域的前沿,论文放宽了长度约束以开发 DeepSeek-V3.2-Speciale
      • DeepSeek-V3.2-Speciale 达到了与领先闭源系统 Gemini-3.0-Pro (DeepMind) 相当的性能
      • 在 IOI 2025、ICPC World Final 2025、IMO 2025 和 CMO 2025 中均表现出金牌水平的性能
    • 注:论文评估了 CMO 2025 的英文版。IMO 2025 和 CMO 2025 的问题以及推理代码可在 github.com/deepseek-ai/DeepSeek-Math-V2 找到

DeepSeek-V3.2 Architecture

DeepSeek Sparse Attention

  • DeepSeek-V3.2 的架构与 DeepSeek-V3.2-Exp 完全相同
  • 与 DeepSeek-V3.1 的最后一个版本 DeepSeek-V3.1-Terminus 相比,DeepSeek-V3.2 唯一的架构修改是通过持续训练(Continuous Training)引入了 DeepSeek 稀疏注意力 (DeepSeek Sparse Attention, DSA)
  • DSA 原型 (Prototype of DSA)
    • DSA 的原型主要由两个部分组成:一个 Lightning Indexer 和一个细粒度 Token 选择机制 (fine-grained token selection mechanism)
  • Lightning Indexer
    • 计算查询 Token \(\mathbf{h}_{t}\in\mathbb{R}^{d}\) 与前一个 Token \(\mathbf{h}_{s}\in\mathbb{R}^{d}\) 之间的索引分数 \(I_{t,s}\),确定哪些 Token 将被查询 Token 选择:
      $$I_{t,s}=\sum_{j=1}^{H^{l} }w_{t,j}^{I}\cdot\text{ReLU}\left(\mathbf{q}_{t,j}^{I} \cdot\mathbf{k}_{s}^{I}\right), \tag{1}$$
      • \(H^{l}\) 表示 Indexer 头 (indexer heads) 的数量;
      • \(\mathbf{q}_{t,j}^{I}\in\mathbb{R}^{d^{l} }\) 和 \(w_{t,j}^{I}\in\mathbb{R}\) 来源于查询 Token \(\mathbf{h}_{t}\);
      • \(\mathbf{k}_{s}^{I}\in\mathbb{R}^{d^{l} }\) 来源于前一个 Token \(\mathbf{h}_{s}\)
    • 出于吞吐量考虑,论文选择 ReLU 作为激活函数
    • 鉴于 Lightning Indexer 具有少量头部并且可以在 FPS 中实现,其计算效率非常显著
  • 细粒度 Token 选择机制 (fine-grained token selection mechanism)
    • 给定每个查询 Token \(\mathbf{h}_{t}\) 的索引分数 \(\{I_{t,s}\}\),fine-grained token selection mechanism 仅检索与最高 k 个索引分数对应的键值条目 \(\{\mathbf{c}_{s}\}\)
    • 然后,通过在查询 Token \(\mathbf{h}_{t}\) 和稀疏选择的键值条目 \(\{\mathbf{c}_{s}\}\) 之间应用注意力机制来计算注意力输出 \(\mathbf{u}_{t}\):
      $$\mathbf{u}_{t}=\text{Attn}(\mathbf{h}_{t},\left\{\mathbf{c}_{s}\mid I_{t,s}\in \text{Top-k}(I_{t,:})\right\}). \tag{2}$$
  • 在 MLA 下实例化 DSA (Instantiate DSA Under MLA)
    • 出于从 DeepSeek-V3.1-Terminus 进行持续训练的考虑,论文为 DeepSeek-V3.2 基于 MLA (DeepSeek-AI, 2024) 实例化了 DSA
    • 在 kernel 层面,为了提高计算效率,每个键值条目必须在多个查询之间共享 (2025)
    • 基于 MLA1 的 MQA (Multi-Query Attention) 模式 (Shazeer, 2019) 实现了 DSA,其中每个潜在向量 (MLA 的键值条目) 将在查询 Token 的所有查询头之间共享
    • 基于 MLA 的 DSA 架构如图 2 所示
    • 详情见:DeepSeek-V3.2 的开源实现以明确指定细节 和 论文附录
Continued Pre-Training
  • 从一个上下文长度已扩展到 128K 的 DeepSeek-V3.1-Terminus base checkpoint 开始,进行持续预训练,随后进行后训练(最终得到 DeepSeek-V3.2)
  • DeepSeek-V3.2 的持续预训练包括两个训练阶段
    • 对于这两个阶段,训练数据的分布与用于 DeepSeek-V3.1-Terminus 的 128K 长上下文扩展数据完全一致
  • 密集预热阶段 (Dense Warm-up Stage) : 使用一个简短的预热阶段来初始化 Lightning Indexer (预热)
    • 在此阶段,论文保持密集注意力,并冻结除 Lightning Indexer 外的所有模型参数
    • 为了使 Indexer 输出与主要注意力分布对齐,对于第 \(t\) 个查询 Token
      • 先通过对所有注意力头求和来聚合主要注意力分数
      • 然后,沿序列维度对该和进行 L1 归一化以产生目标分布 \(p_{t,:}\in\mathbb{R}^{t}\)
    • 基于 \(p_{t,:}\),论文将 KL 散度损失设置为 Indexer 的训练目标:
      $$\mathcal{L}^{l}=\sum_{t}\mathbf{D}_{\text{KL} }\big{(}p_{t,:}\big{|}\text{Softmax }(I_{t,:})\big{)}. \tag{3}$$
    • 对于预热,使用 \(10^{-3}\) 的学习率
    • 只对 Indexer 训练 \(1000\) 步,每步包含 \(16\) 个 128K Token 的序列,总计 2.1B Token
  • 稀疏训练阶段 (Sparse Training Stage) : Indexer 预热之后,引入细粒度 Token 选择机制,并优化所有模型参数以使模型适应 DSA 的稀疏模式
    • 在此阶段,论文仍然保持 Indexer 输出与主要注意力分布的对齐,但仅考虑被选择的 Token 集合 \(\mathcal{S}_{t}=\{s|I_{t,s}\in\text{Top-k}(I_{t,:})\}\):
      $$\mathcal{L}^{l}=\sum_{t}\mathbf{D}_{\text{KL} }\big{(}p_{t,\mathcal{S}_{t} }\big{|}\text{Softmax}(I_{t,\mathcal{S}_{t} })\big{)}. \tag{4}$$
  • 特别注意:作者将 Indexer 输入从计算图中分离 (detach) 出来进行单独优化
    • Indexer 的训练信号仅来自 \(\mathcal{L}^{l}\),而主要模型的优化仅根据语言建模损失进行
    • 在这个稀疏训练阶段,论文使用 \(7.3\times 10^{-6}\) 的学习率,并为每个查询 Token 选择 \(2048\) 个键值 Token
    • 对主要模型和 Indexer 都训练了 \(15000\) 步,每步包含 \(480\) 个 128K Token 的序列,总计 9437 亿 Token
  • 图 2: DeepSeek-V3.2 的注意力架构,其中 DSA 在 MLA 下实例化
    • 绿色部分说明了 DSA 如何根据 Indexer 选择 top-k 的键值条目

Post-Training

  • 持续预训练(continued pre-training)后再执行后训练
  • DeepSeek-V3.2 的后训练也采用与稀疏持续预训练阶段相同的方式使用稀疏注意力
  • DeepSeek-V3.2 保持与 DeepSeek-V3.2-Exp 相同的后训练流程,其中包括专家蒸馏和混合强化学习训练
  • 专家蒸馏(Specialist Distillation)
    • 对于每项任务,首先开发一个专门针对该特定领域的专用模型
      • 所有专家模型都从同一个预训练的 DeepSeek-V3.2 基础 Checkpoint 进行微调
    • 除了写作任务和通用问答外,论文的框架还涵盖六个专业领域:
      • 数学、编程、通用逻辑推理、通用智能体任务、智能体编码和智能体搜索
      • 所有这些领域都同时支持 Thinking 模式和非 Thinking 模式
    • 每个专家都通过大规模 RL 计算进行训练
    • 使用不同的模型来生成长链 Thinking 推理( Thinking 模式)和直接响应生成(非 Thinking 模式)的训练数据
      • 专家模型用来为最终 Checkpoint 生成特定领域的数据
      • 实验结果表明,在蒸馏数据上训练的模型达到的性能水平仅略低于领域特定专家,并且通过后续的 RL 训练可以有效地消除性能差距
  • 混合 RL 训练(Mixed RL Training)
    • 对于 DeepSeek-V3.2,论文仍然采用 GRPO (DeepSeek-AI, 2025; 2024) 作为 RL 训练算法
    • 与 DeepSeek-V3.2-Exp 一样,将推理、智能体和对齐训练合并到一个 RL 阶段
    • 这种方法有效地平衡了不同领域的性能,同时避免了通常与多阶段训练范式相关的灾难性遗忘问题
    • 对于推理和智能体任务,论文采用基于规则的结果奖励、长度惩罚和语言一致性奖励
    • 对于通用任务,论文采用生成式奖励模型,其中每个 Prompt 都有其自己的评估准则(Rubrics RM?)

      For general tasks, we employ a generative reward model where each prompt has its own rubrics for evaluation

  • DeepSeek-V3.2 与 DeepSeek-V3.2-Speciale
    • DeepSeek-V3.2 整合了从专家蒸馏出的推理、智能体和对齐数据,并经过数千步的持续 RL 训练以到达最终 Checkpoint
    • 为了研究扩展 Thinking 的潜力,开发了一个实验性变体,DeepSeek-V3.2-Speciale
      • 该模型仅在 RL 期间长度惩罚降低的情况下,专门在推理数据上进行训练
      • 作者还整合了来自 DeepSeekMath-V2 (2025) 的数据集和奖励方法,以增强数学证明方面的能力
  • 作者重点强调:在第 3.1 节中介绍如何创建一个稳定的方案来扩大 RL 计算规模,以及在第 3.2 节中介绍如何将 Thinking 整合到智能体任务中的努力
  • 图 3:DeepSeek-V3.1-Terminus 和 DeepSeek-V3.2 在 H800 集群上的推理成本

Scaling GRPO

  • 首先回顾 GRPO 的目标
  • GRPO 通过最大化以下关于从旧策略 \(\pi_{\text{old} }\) 采样得到的一组响应 \(\{o_{1},\cdots,o_{G}\}\) 的目标函数来优化策略模型 \(\pi_{\theta}\),给定每个问题 \(q\):
    $$
    \mathcal{J}_{\text{GRPO} }(\theta) =\mathbb{E}_{q\sim P(Q),\{o_i\}_{i=1}^{G}\sim\pi_{\text{old} }(\cdot|q)}\Bigg[\frac{1}{G}\sum_{i=1}^{G}\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}
    \min \left(r_{i,t}(\theta)\hat{A}_{i,t},\text{clip}\left(r_{i,t}(\theta),1-\varepsilon,1+\varepsilon\right)\hat{A}_{i,t}\right)-\beta\mathbb{D}_{\text{KL} }\left(\pi_{\theta}(o_{i,t})\parallel\pi_{\text{ref} }(o_{i,t})\right)\Bigg],
    $$
    • \(r_{i,t}(\theta)\) 是当前策略与旧策略之间的重要性采样比率:
      $$
      r_{i,t}(\theta)=\frac{\pi_{\theta}(o_{i,t}|q,o_{i,<t})}{\pi_{\text{old} }(o_{i,t}|q,o_{i,<t})}
      $$
    • \(\varepsilon\) 和 \(\beta\) 是分别控制剪切范围和 KL 惩罚强度的超参数
    • \(\hat{A}_{i,t}\) 是 \(o_{i,t}\) 的优势,通过对组内的结果奖励进行归一化来估计
      • 使用一组奖励模型为组中的每个输出 \(o_i\) 评一个结果奖励 \(R_i\),分别得到 \(G\) 个奖励 \(R=\{R_1,\cdots,R_G\}\)
      • \(o_{i,t}\) 的优势通过从输出 \(o_i\) 的奖励中减去组的平均奖励来计算,即
        $$ \hat{A}_{i,t}=R_i-\text{mean}(R)$$
        • 特别注意:这里作者没有除以分母!
  • 论文接下来介绍了基于 GRPO 算法的额外更新策略,这些策略可以稳定 RL 的扩展
无偏 KL 估计(Unbiased KL Estimate):有趣的做法
  • 给定 \(o_{i,t}\) 是从旧策略 \(\pi_{\text{old} }(\cdot|q,o_{i,< t})\) 中采样的,这里校正 k3 估计器 (Schulman, 2020) 以使用当前策略 \(\pi_{\theta}\) 和旧策略 \(\pi_{\text{old} }\) 之间的重要性采样比率来获得无偏 KL 估计
    $$
    \mathbb{D}_{\text{KL} }\big(\pi_{\theta}(o_{i,t})\parallel\pi_{\text{ref} }(o_{i,t})\big)=\frac{\pi_{\theta}(o_{i,t}|q,o_{i,<t})}{\pi_{\text{old} }(o_{i,t}|q,o_{i,<t})}\left(\frac{\pi_{\text{ref} }(o_{i,t}|q,o_{i,<t})}{\pi_{\theta}(o_{i,t}|q,o_{i,<t})}-\log\frac{\pi_{\text{ref} }(o_{i,t}|q,o_{i,<t})}{\pi_{\theta}(o_{i,t}|q,o_{i,<t})}-1\right).
    $$
  • 作为此调整的直接结果,该 KL 估计器的梯度变得无偏,从而消除了系统性估计误差,促进了稳定的收敛
  • 这与原始的 k3 估计器形成鲜明对比,特别是当采样到的 Token 在当前策略下的概率远低于参考策略时,即 \(\pi_{\theta}\ll\pi_{\text{ref} }\)
    • 在这种情况下,k3 估计器的梯度会分配不成比例的大且无界的权重来最大化这些 Token 的似然,从而导致噪声梯度更新,这些更新累积起来会降低后续迭代中的样本质量并导致不稳定的训练动态
  • 在实践中,论文发现不同领域受益于不同强度的 KL 正则化
  • 对于某些领域,例如数学 ,应用相对较弱的 KL 惩罚甚至完全省略它都可以获得改进的性能
  • 详细推到证明见附录
Off-Policy Sequence Masking
  • 为了提高 RL 系统的效率,通常生成大量的 rollout 数据,随后将其分割成多个小批次用于若干次梯度更新步骤
    • 但这种做法本质上引入了离策略行为
  • 此外,用于高效数据生成的推理框架通常经过高度优化,其实现细节可能与训练框架不同
    • 这种训练-推理的不一致性进一步加剧了离策略的程度
  • 为了稳定训练并提高对离策略更新的容忍度,论文掩码那些引入显著策略分歧的负序列,其衡量标准是数据采样策略 \(\pi_{\text{old} }\) 与当前策略 \(\pi_{\theta}\) 之间的 KL 散度
  • 论文在 GRPO 损失中引入一个二元掩码 \(M\):
    $$
    \mathcal{J}_{\text{GRPO} }(\theta)=\mathbb{E}_{q\sim P(Q),\{o_i\}_{i=1}^{G}\sim\pi_{\text{old} }(\cdot|q)}\Bigg[\frac{1}{G}\sum_{i=1}^{G}\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}
    \min \left(r_{i,t}(\theta)\hat{A}_{i,t},\text{clip}\left(r_{i,t}(\theta),1-\varepsilon,1+\varepsilon\right)\hat{A}_{i,t}\right)M_{i,t}-\beta\mathbb{D}_{\text{KL} }\left(\pi_{\theta}(o_{i,t})\parallel\pi_{\text{ref} }(o_{i,t})\right)\Bigg],
    $$
  • 其中
    $$
    M_{i,t}=\begin{cases}
    0 & \hat{A}_{i,t}<0,\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}\log\frac{\pi_{\text{old} }(o_{i,t}|q,o_{i,<t})}{\pi_{\theta}(o_{i,t}|q,o_{i,<t})}>\delta\
    1 & \text{otherwise},
    \end{cases}
    $$
  • \(\delta\) 是一个控制策略分歧阈值的超参数
  • 注意:这里的 \(\pi_{\text{old} }\) 表示推理框架直接返回的采样概率,因此旧策略与当前策略之间的 KL 散度考虑了上述两种离策略来源
  • 同样值得注意的是,论文只掩码具有负优势的序列
  • 直观地说,模型从自身错误中学习受益最大,而高度离策略的负样本可能是有害的,可能误导或破坏优化过程的稳定性
  • 论文通过经验观察到,这种离策略序列掩码操作改善了在某些原本会表现出不稳定性的训练场景中的稳定性
  • 理解:
    • 这个做法很常见,主要是当 \(A < 0\) 时,原始 PPO 的 Clip 机制无法限制 \(\frac{\pi_\theta}{\pi_{\theta_\text{old}}}\) 很大的情况
Keep Routing
  • MoE 模型通过在推理期间仅激活专家模块的子集来提高计算效率
  • 但推理和训练框架之间的差异,加上策略更新,可能导致即使对于相同的输入,在推理和训练期间也产生不一致的专家路由
    • 这种不一致性会引起活跃参数子空间的突然变化,从而破坏优化的稳定性并加剧离策略问题
  • 缓解这个问题的方案:
    • 作者保留了在推理框架中采样期间使用的专家路由路径 ,并在训练期间强制执行相同的路由路径 ,确保优化相同的专家参数
    • 作者发现这种保持路由操作对于 MoE 模型的 RL 训练稳定性至关重要,并且自 DeepSeek-V3-0324 以来已在论文 RL 训练流程中采用
Keep Sampling Mask
  • Top-p 和 top-k 采样是广泛使用的采样策略,用于提高 LLM 生成的响应质量
  • 在 RL 训练中采用这些策略也是有益的,因为它避免了采样极低概率的 Token(理解:这就避免了使用这些 Token 用作优化目标)
  • 这种截断保持了样本质量,但它引入了 \(\pi_{\text{old} }\) 和 \(\pi_{\theta}\) 之间动作空间的不匹配
    • 这违反了重要性采样的原则并使训练不稳定
  • 解决这个问题的方案:
    • 作者在从 \(\pi_{\text{old} }\) 采样期间保留截断掩码,并在训练期间将它们应用于 \(\pi_{\theta}\),确保两种策略共享相同的动作子空间
  • 根据经验,作者发现将 top-p 采样与保持采样掩码策略结合使用可以有效保持 RL 训练期间的语言一致性

Thinking in Tool-Use

Thinking Context Management
  • DeepSeek-R1 已经证明,融入 Thinking 过程可以显著增强模型解决复杂问题的能力
    • 基于这一见解,作者的目标是将 Thinking 能力整合到工具调用场景中
  • 作者观察到,复制 DeepSeek-R1 的策略会导致显著的 Token 效率低下
    • 注:DeepSeek-R1 的策略是在第二轮消息到达时丢弃推理内容
    • 这种方法迫使模型在每次后续工具调用时为整个问题冗余地重新推理
  • 为了缓解这个问题,作者开发了如图 4 所示的、为工具调用场景严格定制的上下文管理:
    • 仅当对话中引入新的用户消息时,才会丢弃历史推理内容
      • 如果仅追加与工具相关的消息(例如,工具输出),则推理内容在整个交互过程中保留
    • 当推理痕迹被移除时,工具调用及其结果的历史记录仍保留在上下文中
  • 特别需要注意:某些智能体框架,例如 Roo Code 或 Terminus,通过用户消息模拟工具交互
    • 由于上述上下文管理规则,这些框架可能无法完全受益于论文增强的推理持久性
    • 因此,作者建议在此类架构中使用非 Thinking 模型以获得最佳性能
  • 图 4:工具调用场景中的 Thinking 保留机制
Cold-Start
  • 鉴于已有推理数据(非智能体)和非推理智能体数据的可用性,整合这两种能力的一个直接策略是通过精心设计的 Prompting
  • 论文假设模型具备足够的能力来准确遵循明确的指令,从而能够在推理过程中无缝整合工具执行
  • 为了演示冷启动机制的运作(operation),论文选择性地采样训练数据,如附录表 6-8 所示
    • 需要注意的是,不同的任务 Prompt 与不同的系统 Prompt 相关联
  • 表 6-8 展示了一个对应于竞赛编程(competitive programming) Prompt 的示例
    • 表 6 展示了论文推理数据的一个示例,其中使用系统 Prompt 明确要求模型在最终答案之前进行推理,并使用特殊标签 <think></think> 来标记推理路径
    • 表 7 展示了非推理智能体数据的 Prompt ,其中系统 Prompt 包含工具调用的指导
    • 表 8 展示了论文设计的系统 Prompt ,用于指导模型在其推理过程中整合多个工具调用
  • 通过这种方式,尽管工具使用模式中的推理可能缺乏鲁棒性 ,但模型偶尔能够生成期望的轨迹 ,从而为后续的强化学习阶段提供基础
Large-Scale Agentic Tasks
  • 多样化的 RL 任务对于增强模型的鲁棒性至关重要
  • 对于搜索、代码工程和代码解释等任务,论文使用现实世界的工具,包括实际的网络搜索 API、编码工具和 Jupyter Notebooks
    • 虽然这些 RL 环境是真实的,但所使用的 Prompt 要么从互联网来源提取,要么是合成生成的,而不是从真实的用户交互中获取
  • 对于其他任务,环境和 Prompt 都是合成的
  • 论文使用的智能体任务如表 1 所述
    • 表 1:不同智能体任务的描述,包括任务数量、环境类型(真实或合成)和 Prompt 来源(提取或合成)
Search Agent
  • 论文采用基于 DeepSeek-V3.2 的多智能体管道来生成多样化、高质量的训练数据
    • 从大规模网络语料库中跨不同领域采样信息丰富的长尾实体
    • (一个)问题构建智能体 使用可配置深度和广度参数的搜索工具探索每个实体,将发现的信息整合成问答对
    • 具有异构配置(不同 Checkpoint 、系统 Prompt 等)的 (多个)答案生成智能体 为每个提出的 QA 对生成不同的候选响应
    • 具有搜索能力的 一个验证智能体 通过多次轮询验证所有答案,只保留真实答案正确且所有候选答案均可验证为错误的样本
    • 这些数据涵盖多种语言、领域和难度级别
  • 为了补充这些可验证的样本并更好地反映现实世界的使用情况
    • 第一:用来自现有有帮助 RL 数据集的过滤实例来增强数据集,对于这些数据集,搜索工具提供了 measurable benefits
    • 第二:开发跨多个质量维度的详细评估准则(rubrics),并采用生成式奖励模型根据这些准则对响应进行评分
    • 这种混合方法使得能够同时针对事实可靠性和实际帮助性进行优化
Code Agent
  • 论文通过从 GitHub 挖掘数百万个 issue-Pull Request (PR) pairs,为软件问题解决构建了大规模、可执行的环境
  • 该数据集使用启发式规则和 LLM-based 判断进行了严格过滤,以确保高质量,要求每个条目包含合理的问题描述、相关的 Gold Patch 以及用于验证的测试补丁
  • 论文使用由 DeepSeek-V3.2 驱动的自动化环境设置智能体来为这些 pairs 构建可执行环境
    • 该智能体处理包安装、依赖项解决和测试执行
    • 测试结果以标准的 JUnit 格式输出,确保跨编程语言和测试框架的一致解析
  • 只有当应用 Gold Patch 后,满足下面的条件,才认为环境成功构建
    • non-zero count of false-to-positive(F2P)test cases(表明问题已修复)
      • 即 F2P 数量不为 0:即至少存在一个测试用例曾经失败的,使用 Gold Patch 后成功了
    • zero count of pass-to-fail(P2F)test cases(表明没有 regressions)
      • P2F 数量为 0:即没有测试用例曾经成功,使用 Gold Patch 后,失败了
  • 使用此管道,论文成功构建了数万个可重现的问题解决环境,涵盖多种编程语言,包括 Python、Java、JavaScript、TypeScript、C、C++、Go 和 PHP
Code Interpreter Agent
  • 利用 Jupyter Notebook 作为代码解释器来解决复杂的推理任务
  • 作者策划了一组涵盖数学、逻辑和数据科学的多样化问题,每个问题都需要模型利用代码执行能力来得出 Solution
通用智能体(General Agent)【这里的流程还需要再明确】
  • 为了在 RL 中扩大智能体环境和任务规模,作者用了一个自动环境合成智能体,它合成了 1827 个面向任务的环境

    • 这些任务难以解决但易于验证
    • 合成工作流程主要包括环境和工具集构建、任务合成以及 Solution 生成
  • 具体来说,工作流程如下

    • 1)给定一个任务类别(例如,规划旅行行程)和一个配备 bash 和搜索工具的沙盒,智能体首先使用这些工具从互联网生成或检索相关数据,并将它们存储在沙盒数据库中
    • 2)智能体合成一组特定于任务的工具 ,每个工具都实现为一个函数
    • 3)为了创建既具有挑战性又可自动验证的任务 ,智能体做如下工作:
      • 首先:基于当前数据库 propose 一个简单任务,同时抽取这个任务的 Python 实现 Solution Function 和 Verification function
        • 对 Solution function 的要求:
          • 第一:这里的 Solution function 仅限于调用工具函数或执行逻辑计算,不能调用其他函数或直接访问数据库 ,确保只能通过工具接口(interface)解决问题
          • 第二:这个 Solution function 产生的结果必须由 Verification function 验证
        • 如果以上 Solution function 验证未通过,智能体将修改 Solution function 或 Verification function ,直到它产生的 Solution function 输出通过 Verification function 验证
      • 然后:智能体迭代地增加任务难度 ,并更新相应的 Solution function 和 Verification function
        • 在此迭代过程中,如果当前工具集不足以解决任务,智能体将扩展工具集
          • 问题:扩展的依据是什么?何时扩展?
      • 问题:是针对同一个问题,逐步提升任务难度?还是针对不同难度的问题,先解决简单问题,再解决复杂问题?
  • 遵循此工作流程,获得了数千个 <环境, 工具, 任务, 验证器>(<environment, tools, task, verifier>) 元组

    • 理解:这里的 <environment, tools, task, verifier> 是匹配对齐的,在这个环境 envirnoment 下,用这些工具 tools 能解决的任务 task 和 可以验证该 任务是否成功的验证器 verifier
  • 然后使用 DeepSeek-V3.2 在该数据集上执行 RL,并仅保留 pass@100 非 0 的实例,最终得到 1827 个环境及其相应的任务(共 4417 个)

  • 下面展示了一个合成的行程规划示例

  • 示例说明:此示例强调,虽然为满足所有约束的行程计划搜索大型组合空间具有挑战性,但检查给定的候选 Solution 是否满足这些约束则相对简单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    **合成任务示例:行程规划(An Example of Synthesized Task: Trip Planning)**
    我正在计划从杭州开始的三天旅行,需要帮助创建 2025 年 10 月 1 日至 10 月 3 日的行程。
    一些重要要求:在整个旅行中,我不想重复任何城市、酒店、景点或餐厅。
    另外,请确保你推荐的每家酒店、餐厅和景点实际上都位于我当天将要入住的城市。
    关于第二天还有一件事——我正在试图精明地控制预算。如果我最终预订了每晚 800 元人民币或更贵的豪华酒店,那么我需要更加谨慎地控制其他开支:
    我在两家餐厅(午餐和晚餐)的总消费应保持在 350 元人民币以下,两家餐厅的评分至少应为 4.0 星,并且下午景点的门票需要低于 120 元人民币。
    如果第 2 天的酒店属于中高端范围(500-800 元人民币),那么我有更多的灵活性——我只需要确保我选择的至少一家餐厅评分在 4.0 或更高,并且景点门票应低于 180 元人民币。
    对于更经济实惠的酒店(200-500 元人民币范围),我只需要确保至少一家餐厅的评分在 3.2 或以上。你能帮我制定这个行程吗?

    **提交结果格式(Submit Result Format)**
    ```json
    [
    {"time": "2025-10-01", "city": "city_name", "hotel": "hotel_name", "afternoon_restaurant": "restaurant_name", "afternoon_attraction": "attraction_name", "evening_restaurant": "restaurant_name"},
    {"time": "2025-10-02", "city": "city_name", "hotel": "hotel_name", "afternoon_restaurant": "restaurant_name", "afternoon_attraction": "attraction_name", "evening_restaurant": "restaurant_name"},
    {"time": "2025-10-03", "city": "city_name", "hotel": "hotel_name", "afternoon_restaurant": "restaurant_name", "afternoon_attraction": "attraction_name", "evening_restaurant": "restaurant_name"}
    ]

    行程规划工具集(Tool Set for Trip Planning)

    函数名称 描述
    get_all_attractions_by_city(city) 获取给定城市的所有景点
    get_all_cities() 从数据库获取所有城市
    get_all_hotels_by_city(city) 获取给定城市的所有酒店
    get_all_restaurants_by_city(city) 获取给定城市的所有餐厅
    get_city_by_attraction(attraction) 获取给定景点名称的城市
    get_city_by_hotel(hotel) 获取给定酒店名称的城市
    get_city_by_restaurant(restaurant) 获取给定餐厅名称的城市
    get_city_transport(city) 获取给定城市的所有市内交通选项
    get_infos_by_attraction(info_keywords, attraction) 获取给定景点的指定信息
    get_infos_by_city(info_keywords, city) 获取给定城市的指定信息
    get_infos_by_hotel(info_keywords, hotel) 获取给定酒店的指定信息
    get_infos_by_restaurant(info_keywords, restaurant) 获取给定餐厅的指定信息
    get_inter_city_transport(from_city, to_city) 获取给定城市对之间的所有交通方式
    get_weather_by_city_date(city, date) 获取给定城市-日期对的天气
    submit_result(answer_text) 提交最终答案内容

Evaluation

Main Results

  • 作者在多个 Benchmark 上进行了评估,包括:
    • MMLU-Pro (2024)
    • GPQA Diamond (2023)
    • Human Last Exam (HLE) Text-only (2025)
    • LiveCodeBench (2024.08-2025.04)
    • Codeforces
    • Aider-Polyglot
    • AIME 2025
    • HMMT Feb 2025
    • HMMT Nov 2025 (2025)
    • IMOAnswerBench (2025)
    • Terminal Bench 2.0
    • SWE-Verified (OpenAI, 2024b)
    • SWE Multilingual (2025)
    • BrowseComp (2025)
    • BrowseCompZh (2025)
    • \(\tau^{2}\)-bench (2025)
    • MCP-Universe (2025)
    • MCP-Mark (EvalSys, 2025)
    • Tool-Decathlon (2025)
  • 评估说明及结果:
    • 工具使用基准使用标准函数调用格式进行评估,其中模型配置为思考模式
    • MCP-Universe (2025) 和 MCP-Mark (EvalSys, 2025),使用内部环境评估所有模型
      • 因为搜索和 playwright 环境可能与官方设置略有不同
    • 论文中,将温度设置为 1.0,上下文窗口设置为 128K tokens
    • 对于数学相关任务,如 AIME, HMMT, IMOAnswerBench 和 HLE(理解:其实 HLE 中不全是数学):
      • 论文使用以下模板进行评估:"{question}\n Please reason step by step, and put your final answer within \boxed{}"
        • 理解:这是一个业内目前常用的 Thinking 模板
      • 注:对于 HLE,论文还使用官方模板评估了 DeepSeek-V3.2-Thinking,得分为 23.9
  • 在推理任务上(reasoning tasks):
    • DeepSeek-V3.2 与 GPT-5-high 表现相当,略逊于 Gemini-3.0-Pro
    • 与 K2-Thinking 相比,DeepSeek-V3.2 以显著更少的输出 token 获得了相似的分数,如表 3 所示
    • 这些性能提升可归因于分配给 RL 训练的计算资源增加
      • 在最近几个月,作者观察到性能的持续改进与 RL 训练预算的延长相关,该预算已超过预训练成本的 \(10%\)
      • 作者假设额外的计算预算分配可以进一步增强推理能力
      • 论文呈现的 DeepSeek-V3.2 性能受到长度约束奖励模型的限制;在移除该限制后,论文观察到模型性能的进一步提升,详见第 4.2 节
  • 在代码智能体任务中(code agent evaluations):
    • DeepSeek-V3.2 在 SWE-bench Verified 和 Terminal Bench 2.0 上均显著优于开源 LLM
      • 展示了 DeepSeek-V3.2 在现实世界编码工作流程中的潜力
    • 关于 Terminal Bench 2.0 的特别说明
      • (如前所述)作者为 “思考模式(thinking mode)” 设计的上下文管理策略目前与 Terminus 不兼容;
      • 因此,报告的 46.4 分是使用 Claude Code 框架实现的
      • 作者也使用 Terminus 在非思考模式(non-thinking mode)下评估了 DeepSeek-V3.2,得分为 39.3
    • 对于 SWE-bench Verified,主要得分是使用 DeepSeek 的内部框架获得的
      • 在其他设置(包括 Claude Code 和 RooCode 框架,以及非思考模式)下的鲁棒性测试产生了一致的结果,范围在 72 到 74 之间
  • 对于搜索智能体评估(search agent evaluation)
    • 论文使用标准的商业搜索 API 评估论文的模型
    • 由于 DeepSeek-V3.2 最大仅支持 128K 的上下文长度,大约 \(20%\) 以上的测试用例超过此限制
      • 为了解决这个问题,作者采用了一种上下文管理方法来获得最终分数
      • 注:不使用上下文管理的分数是 51.4
    • 更多细节在第 4.4 节提供
  • 在工具使用基准上(tool-use benchmarks):
    • DeepSeek-V3.2 显著缩小了 open-source 与 closed-source LLM 之间的性能差距,但仍低于 frontier 模型
    • 对于 \(\tau^{2}\)-bench
      • 作者使用模型本身作为 User Agent,获得的最终类别分数为 63.8 (Airline), 81.1 (Retail), and 96.2 (Telecom)
    • 对于 MCP 基准
      • 作者使用函数调用格式,并将工具输出放在标记为 ‘tool’ 角色的消息中,而不是 ‘user’ 角色
      • 在论文的测试中,作者观察到 DeepSeek-V3.2 经常进行冗余的自我验证,生成了过长的轨迹
        • 这种倾向通常导致上下文长度超过 128K 的限制,特别是在诸如 MCP-Mark GitHub 和 Playwright 评估等任务中
          • 因此,这种现象阻碍了 DeepSeek-V3.2 的最终性能
        • 但集成上下文管理策略可以进一步提高性能
          • 论文将此确定为未来工作的方向和对用户的实用考虑
        • 即使 DeepSeek-V3.2 存在此问题,它仍然显著优于现有的开源模型
      • Notably,由于这些基准中使用的环境和工具集在 RL 训练期间未遇到过 ,观察到的改进证明了 DeepSeek-V3.2 将其推理策略泛化到领域外智能体场景的能力
        • 非思考模型在智能体场景中的评估见附录表 9

Results of DeepSeek-V3.2-Speciale

  • 表 3 表明,DeepSeek-V3.2-Speciale 通过利用增加的推理 token 获得了卓越的性能,在多个基准上超越了 SOTA Gemini-3.0-Pro
  • Remarkably,如表 4 所示
    • DeepSeek-V3.2-Speciale 这个通用模型在 2025 年国际信息学奥林匹克竞赛(IOI)和 ICPC 世界总决赛(ICPC WF)中达到了金牌级别的性能,而无需针对性的训练
    • Furthermore,通过结合 Shao 等人 (2025) 的技术,DeepSeek-V3.2-Speciale 模型在复杂的证明任务中表现出色,达到了 2025 年国际数学奥林匹克竞赛(IMO)和中国数学奥林匹克竞赛(CMO)的金牌门槛\(^5\)
    • 详细的评估协议在附录 D 中提供
  • However,DeepSeek-V3.2-Speciale 的 token 效率仍然显著低于 Gemini-3.0-Pro
    • 为了降低部署成本和延迟,作者在官方 DeepSeek-V3.2 的训练中施加了更严格的 token 约束,旨在优化性能与成本之间的权衡
    • 作者认为 token 效率仍然是未来研究的一个关键领域

Synthesis Agentic Tasks

  • 在本节中,作者进行消融实验来研究合成智能体任务的效果
  • 论文关注两个问题
    • 第一:合成任务对强化学习来说是否足够具有挑战性?
    • 第二:这些合成任务的泛化能力如何,即它们能否迁移到不同的下游任务或现实世界环境?
  • 为了回答第一个问题,作者从通用合成智能体任务中随机抽取 50 个实例,并评估用于合成的模型和 frontier closed-source LLM
  • 如表 5 所示,DeepSeek-V3.2-Exp 的准确率仅为 12%,而 frontier closed-source 模型的准确率最多为 62%
    • 这些结果表明,合成数据包含了对 DeepSeek-V3.2-Exp 和 frontier closed-source 模型都具有挑战性的智能体任务
  • 为了研究合成数据上的 RL 能否泛化到不同的任务或现实世界环境
    • 作者对 DeepSeek-V3.2 的 SFT Checkpoint(记为 DeepSeek-V3.2-SFT)应用 RL
  • 为了排除长 Thinking 链和其他 RL 数据的影响
    • 作者仅在非思考模式下对合成智能体任务进行 RL
  • 作者将上述模型与 DeepSeek-V3.2-SFT 和 DeepSeek-V3.2-Exp 进行比较
    • 其中 DeepSeek-V3.2-Exp 仅在搜索和代码环境中进行了 RL 训练(即不包含 合成数据)
    • DeepSeek-V3.2-SFT 则未经过任何 RL 训练
  • 如图 5 所示,在合成数据上进行大规模 RL 在 Tau2Bench、MCP-Mark 和 MCP-Universe 基准上相比 DeepSeek-V3.2-SFT 带来了显著的改进
    • 相比之下,将 RL 限制在代码和搜索场景并未改善这些基准上的性能,进一步凸显了合成数据的潜力

Context Management of Search Agent

  • 即使使用扩展的上下文窗口(如 128k),智能体工作流,特别是在基于搜索的场景中,也经常会遇到最大长度限制,从而过早地截断推理过程
    • 这个瓶颈抑制了测试时计算潜力的充分发挥
  • 为了解决这个问题,当 token 使用量超过上下文窗口长度的 80% 时,作者引入了上下文管理,采用简单的策略在测试时扩展 token 预算
  • 这些策略包括:
    • (1) 总结 (Summary) :总结溢出的轨迹并重新启动 rollout;
    • (2) 丢弃-75% (Discard-75%) :丢弃轨迹中前 75% 的工具调用历史以释放空间;
    • (3) 全部丢弃 (Discard-all) :通过丢弃之前所有工具调用历史来重置上下文(类似于新的上下文工具 Anthropic (2025a))
  • 为了比较,论文还实现了一个并行扩展基线:
    • 并行最少步骤 (Parallel-fewest-step) :采样 N 个独立的轨迹并选择步骤最少的轨迹
  • 论文在 BrowseComp 基准 (2025) 上评估这些策略
  • 如图 6 所示:
    • 在不同的计算预算下,上下文管理通过允许模型扩展测试时计算、提供更多空间来执行额外的执行步骤,从而带来显著的性能提升
    • Summary 将平均步骤从 140 扩展到 364,将性能从 53.4 提高到 60.2;但其整体效率相对较低
    • 尽管 Discard-all 很简单,但它在效率和可扩展性方面都表现良好,达到了 67.6 分,与并行扩展相当,同时使用的步骤显著更少
  • In summary:
    • 测试时计算可以通过上下文管理串行扩展,也可以并行扩展,两者都能有效扩展模型的问题解决能力
    • 但不同的策略表现出不同的效率和可扩展性
      • Thus,在对模型性能进行基准测试时,考虑实际的计算成本至关重要
      • Meanwhile,寻找串行和并行扩展的最佳组合以最大化效率和可扩展性,仍然是未来工作的一个关键方向

Conclusion, Limitation, and Future Work

  • 论文介绍了 DeepSeek-V3.2,有效弥合计算效率与高级推理能力之间差距
  • DeepSeek-V3.2 使用 DSA 解决了关键的计算复杂性,同时没有牺牲长上下文性能
  • (通过增加计算预算)DeepSeek-V3.2 在推理基准上实现了与 GPT-5 相当的性能
  • 论文的大规模智能体任务合成 Pipeline 的集成显著提高了工具使用熟练度,为具有开放 LLM 的鲁棒和可泛化的人工智能智能体开启了新的可能性
  • 高计算变体 DeepSeek-V3.2-Speciale,通过在 IMO 和 IOI 中获得的金牌成就得到了验证,为开放 LLM 树立了一个里程碑
  • 尽管取得了这些成就,与诸如 Gemini-3.0-Pro 这样的 frontier closed-source 模型相比,作者承认存在某些局限性
    • 第一:由于总训练 FLOPs 较少,DeepSeek-V3.2 的世界知识的广度仍然落后于领先的专有模型
      • 论文计划在未来的迭代中通过扩大预训练计算来解决这一知识差距
    • 第二:token 效率仍然是一个挑战;
      • DeepSeek-V3.2 通常需要更长的生成轨迹(即更多 token)来匹配像 Gemini-3.0-Pro 这样的模型的输出质量
      • 未来的工作将侧重于优化模型推理链的智能密度以提高效率
    • 第三,解决复杂任务的能力仍然不如前沿模型,作者将进一步改进论文的基础模型和后训练方案

附录 A: MLA 的 MHA 与 MQA 模式

  • 图 7:MLA 的 MHA 和 MQA 模式示意图
    • 对于 DeepSeek-V3.1-Terminus,训练和前填充时使用 MHA 模式,解码时使用 MQA 模式
    • 图 7 展示了 MLA 的两个方面(MHA 和 MQA 模式)以及它们之间的转换

附录 B:冷启动模板

  • 表 6: 推理数据系统 Prompt 示例。系统 Prompt 要求模型在 <think></think> 标签中输出推理过程
  • 表 7:[工具描述] 和 [工具调用格式] 将被替换为具体的工具和论文设计的工具调用格式
  • 表 8:模型在 Thinking 过程中执行工具调用

附录 C:non-thinking mode DeepSeek-V3.2 智能体能力评估

  • 表 9:DeepSeek-V3.2 非思考模式与思考模式对比
    • 表中的终端测试台分数使用 Claude Code 框架评估
    • 使用 Terminus 框架的非思考模式终端测试台 2.0 分数为 39.3
  • 非思考模式的性能略逊于思考模式,但仍然具有竞争力

附录 D:IOI、ICPC 世界总决赛、IMO 及 CMO 的评估方法

  • 对于所有竞赛:
    • 模型的最大生成长度设置为 128k
    • 不使用任何工具或互联网访问,测试严格遵守竞赛的时间和尝试限制
  • 对于 IOI 评估
    • 作者根据官方竞赛规则设计了提交策略,规则允许每道题最多提交 50 次,并根据在所有子任务中获得的最高分对每次提交进行评分
    • 具体来说:
      • 首先为每道题采样 500 个候选 Solution,然后应用一个多阶段过滤流程
      • 在初始阶段,剔除未能通过提供的样例测试用例或超出长度限制的无效提交
      • 随后,使用 DeepSeek-V3.2-Exp 模型来识别并剔除那些模型明确表示无法或拒绝解决问题的样本
      • 从剩余的有效候选方案中,论文选择具有最长 Thinking 轨迹的 50 个样本进行最终提交
  • 对于 ICPC 评估
    • 作者采用了相同的过滤方法,但初始采样规模较小
    • 论文为每道题生成 32 个候选 Solution ,并应用相同的过滤标准来选择提交
  • 在 IMO 和 CMO 任务中
    • 作者采用 generate-verify-refine 的循环
    • 模型迭代地改进其 Solution ,直到获得完美的自我评估或达到最大修订上限,此过程与 Shao 等人 (2025) 的方法相同

附录:Unbiased KL Estimate 的推导

  • 部分推导逻辑也可以参考博客:DeepSeek-V3.2中无偏 KL估计(Unbiased KL Estimate)的一些想法 - Keith Jiang的文章 - 知乎
  • 本节核心目标是说明为何 DeepSeek-V3.2 在策略梯度中将 KL 散度项乘以重要性权重(importance weight),从而实现对 KL 梯度的无偏估计
    • 注1:在绝对的 On-policy 的更新中,其实 \(\pi_\theta = \pi_{\theta_\text{old}}\),这个重要性权重值为 1,加不加都行
    • 注2:本节中主要是针对 Off-policy 更新的步骤中,需要对 GRPO 的 KL 散度添加重要性权重校准

Background :带 KL 约束的强化学习目标

  • 考虑 LLM 强化学习中的一般目标函数:
    $$
    J_{\text{RL} }(\theta; x) = \mathbb{E}_{y \sim \pi_\theta(\cdot|x)} \left[ r(x, y) \right] - \beta \cdot D_{\mathrm{KL} }\left[ \pi_\theta(\cdot|x) \parallel \pi_{\theta_0}(\cdot|x) \right]
    $$
  • 其中:
    • \(x\) 是输入(如 prompt)
    • \(y = (y_1, \dots, y_T)\) 是模型生成的 token 序列
    • \(r(x, y)\) 是 reward
    • \(\pi_{\theta_0}\) 是参考策略(通常为初始策略或 SFT 模型)
    • \(\beta\) 是 KL 正则化系数

自回归模型下的 KL 散度展开

  • 由于语言模型是自回归的,有:
    $$
    \pi_\theta(y|x) = \prod_{t=1}^T \pi_\theta(y_t|x, y_{ < t})
    $$
  • 因此 KL 散度可写为:
    $$
    \begin{align}
    D_{\mathrm{KL} }[\pi_\theta(y|x) \parallel \pi_{\theta_0}(y|x)]
    &= \mathbb{E}_{y \sim \pi_\theta(\cdot|x)} \left[ \sum_{t=1}^T \log \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_0}(y_t|x, y_{ < t})} \right] \\
    &= \sum_{t=1}^T \mathbb{E}_{y \sim \pi_\theta(\cdot|x)} \left[ \log \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_0}(y_t|x, y_{ < t})} \right]
    \end{align}
    $$
    • 注:上式最后一步通过 交换期望与求和顺序 得到
  • 接下来我们先关注第 \(t\) 项
    • 注意到内部只依赖于 \(y_{\le t}\),而期望是对整个序列 \(y\) 的,所以可以利用全概率公式(联合概率密度分解成 \(< t\) 的部分和 \(t\) 本身),于是可以将期望分解为:
      $$
      \mathbb{E}_{y \sim \pi_\theta(\cdot|x)}\left[ \log \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_0}(y_t|x, y_{ < t})} \right]
      = \mathbb{E}_{y_{ < t} \sim \pi_\theta(\cdot|x)} \left[ \mathbb{E}_{y_t \sim \pi_\theta(\cdot|x, y_{ < t})} \left[ \log \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_0}(y_t|x, y_{ < t})} \right] \right]
      $$
    • 上面中括号里面的内容可以转换成 KL 散度的形式:
      $$
      \mathbb{E}_{y_t \sim \pi_\theta(\cdot|x, y_{ < t})} \left[ \log \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_0}(y_t|x, y_{ < t})} \right] = D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\theta_0}(\cdot|x, y_{ < t}) \big)
      $$
    • 于是第 \(t\) 项变为:
      $$
      \text{Term}_t = \mathbb{E}_{y_{ < t} \sim \pi_\theta(\cdot|x)} \left[ D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\theta_0}(\cdot|x, y_{ < t}) \big) \right]
      $$
  • 最终得到:
    $$
    \begin{align}
    D_{\mathrm{KL} }[\pi_\theta(y|x) \parallel \pi_{\theta_0}(y|x)]
    &= \sum_{t=1}^T \mathbb{E}_{y_{ < t} \sim \pi_\theta(\cdot|x)} \left[ D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\theta_0}(\cdot|x, y_{ < t}) \big) \right] \\
    &= \mathbb{E}_{y_{ < t} \sim \color{red}{\pi_\theta}(\cdot|x)} \left[ \sum_{t=1}^T D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\theta_0}(\cdot|x, y_{ < t}) \big) \right]
    \end{align}
    $$
    • 注:上面最后一步是交换期望与求和顺序得到的

将 KL 项放入采样期望内(关键步骤)

  • 回顾原 RL 目标为:
    $$
    J_{\text{RL} }(\theta;x) = \mathbb{E}_{y\sim\pi_\theta}[r(x,y)] - \beta \cdot \mathbb{E}_{y\sim\pi_\theta} \left[ \sum_{t=1}^T D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\text{ref} }(\cdot|x, y_{ < t}) \big) \right]
    $$
    • 注:这里对 \( D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\text{ref} }(\cdot|x, y_{ < t}) \big)\) 求期望的做法已经在前面推导过
  • 将奖励和 KL 散度合并为单个期望得到最原始的 RL 目标应该是:
    $$
    J_{\text{RL} }(\theta;x) = \mathbb{E}_{y\sim\pi_\theta} \left[ r(x,y) - \beta \sum_{t=1}^T D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\text{ref} }(\cdot|x, y_{ < t}) \big) \right]
    $$
  • 在实际训练中(如 PPO、GRPO),我们无法直接从当前策略 \(\pi_\theta\) 采样(因为参数正在更新),而是从旧策略 \(\pi_{\theta_{\text{old} } }\) 采样轨迹 \(\{o_i\}_{i=1}^G\)
    • 此时,目标函数一般需通过重要性采样重写,对于任意函数 \(f(y)\),有重要性采样如下:
      $$
      \mathbb{E}_{y \sim \pi_\theta(\cdot|x)}[f(y)]
      = \mathbb{E}_{y \sim \pi_{\theta_{\text{old} } }(\cdot|x)} \left[ \frac{\pi_\theta(y|x)}{\pi_{\theta_{\text{old} } }(y|x)} f(y) \right]
      $$
  • 现在用 \(\pi_{\theta_{\text{old} } }\) 采样,对 \(J_{\text{RL} }(\theta;x)\) 中的期望估计应用重要性采样有:
    $$
    \begin{align}
    J_{\text{RL} }(\theta;x)
    &= \mathbb{E}_{y\sim\pi_{\theta_{\text{old} } } } \left[ \frac{\pi_\theta(y|x)}{\pi_{\theta_{\text{old} } }(y|x)} \left( r(x,y) - \beta \sum_{t=1}^T D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\text{ref} }(\cdot|x, y_{ < t}) \big) \right) \right]
    \end{align}
    $$
    • 特别注意:这里的 KL 本身依赖于 \(\pi_\theta\)(这一点容易遗忘),重要性权重也依赖 \(\pi_\theta\)
    • 这一步在这里看起来推导很顺利,但是其实非常关键,这里直接回答了之前的一些问题,有了这一步之后,如博客 The critical implementation detail of KL loss in GRPO, Hongyu Zang 中提出的问题就不存在了
  • 至此,可以看出:
    • 当 \(y \sim \pi_{\theta_\text{old}}\) 采样时,重要性权重需要同时对奖励 \(r(x,y)\) 和 KL 散度 \(\sum_{t=1}^T D_{\mathrm{KL} }\big( \pi_\theta(\cdot|x, y_{ < t}) \parallel \pi_{\text{ref} }(\cdot|x, y_{ < t}) \big)\) 进行修正才对
    • 注:之前的实现一般仅对奖励使用重要性权重修正, 而忽略了 KL 散度

Token-level 分别加权的讨论

  • 上述的结果还是按照序列粒度评估的,实际上单独考虑 KL 散度时(不考虑奖励时),其实可以按照 Token-level 来考量
  • 对自回归模型,重要性权重可分解为 token-level 的形式:
    $$
    \frac{\pi_\theta(y|x)}{\pi_{\theta_{\text{old} } }(y|x)} = \prod_{t=1}^T \frac{\pi_\theta(y_t|x, y_{ < t})}{\pi_{\theta_{\text{old} } }(y_t|x, y_{ < t})}
    $$
    • 注意:这里是序列级别加权的,即整个序列看成是一个整体,即 期望里面的 KL 散度先算出来,再统一乘以外面的 Sequence-level 重要性权重
  • 在 RLHF 中, PPO/GRPO 实践时,常采用 token-level importance weight,即 每一步单独加权(而非整句相同重要性权重)
    • 注:数学上,其实这里的 Token-level 重要性权重本是不能拆开的,必须乘起来才能做到在数学上等价于序列级别的奖励和 KL 整体目标
    • 这种从 Sequence-level 到 Token-level 的转换,是为了降低方差,同时 Token-level 的方式可以看做 Sequence-level 重要性采样的一阶近似,更多讨论见论文和本人其他讨论博客:(GSPO)Group Sequence Policy Optimization, 20250728, Qwen(本人解读博客:NLP——LLM对齐微调-GSPO) 和 (MiniRL)Stabilizing Reinforcement Learning with LLMs: Formulation and Practices, 20251201, Qwen(本人解读博客:NLP——LLM对齐微调-MiniRL

补充分析:k3 估计下的 Token-Level 无偏 KL 估计(DeepSeek-V3.2 的做法)

  • 跟上述讨论一样,DeepSeek-V3.2 将 KL 项按照 token 分解,并对每个 token 的 KL 分别使用对应的重要性权重
  • 回忆 k3 估计(一种 KL 的无偏估计器):
    $$
    \begin{align}
    D_{\mathrm{KL} }[\pi_\theta \parallel \pi_{\text{ref} }] &\approx \frac{\pi_{\text{ref} }(a)}{\pi_\theta(a)} - \log \frac{\pi_{\text{ref} }(a)}{\pi_\theta(a)} - 1 \\
    &= \text{k3}
    \end{align}
    $$
    • 补充 k3 本身的性质:对以上 k3 估计求 \(a \sim \pi_\theta\) 下的期望,满足
      $$ \mathbb{E}_{a \sim \pi_\theta}[\text{k3}] = D_{\mathrm{KL} }[\pi_\theta \parallel \pi_{\text{ref} }]$$
  • 但在 GRPO 中,样本是从 \(\pi_{\theta_{\text{old} } }\) 采的,所以要估计(使用重要性采样):
    $$
    \mathbb{E}_{a \sim \pi_\theta} [\text{k3}] = \mathbb{E}_{a \sim \pi_{\theta_{\text{old} } } } \left[ \frac{\pi_\theta(a)}{\pi_{\theta_{\text{old} } }(a)} \text{k3} \right]
    $$
    • 注:若直接用 \(\pi_{\theta_{\text{old} } }\) 采样而不加权,则估计有偏;
  • 真正的无偏估计应为:
    $$
    \begin{align}
    \widehat{D}_{\mathrm{KL} }^{\text{unbiased} }
    &= \frac{\pi_\theta(a)}{\pi_{\theta_{\text{old} } }(a)} \left( \frac{\pi_{\text{ref} }(a)}{\pi_\theta(a)} - \log \frac{\pi_{\text{ref} }(a)}{\pi_\theta(a)} - 1 \right) \\
    &= \frac{\pi_{\text{ref} }(a)}{\pi_{\theta_{\text{old} } }(a)} - \frac{\pi_\theta(a)}{\pi_{\theta_{\text{old} } }(a)} \log \frac{\pi_{\text{ref} }(a)}{\pi_\theta(a)} - \frac{\pi_\theta(a)}{\pi_{\theta_{\text{old} } }(a)}
    \end{align}
    $$
  • DeepSeek 论文中公式与上面等价(DeepSeek 中直接使用了 Token-level 的加权形式),其形式保留原始 k3 形式并乘以重要性权重:
    $$
    D_{\mathrm{KL} }[\pi_\theta \parallel \pi_{\text{ref} }]
    \approx \frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{\text{old} } }(o_{i,t} | q, o_{i,<t})} \left(\frac{\pi_{\text{ref} }(o_{i,t} | q, o_{i,<t})}{\pi_\theta(o_{i,t} | q, o_{i,<t})} - \log \frac{\pi_{\text{ref} }(o_{i,t} | q, o_{i,<t})}{\pi_\theta(o_{i,t} | q, o_{i,<t})} - 1 \right)
    $$
    • 这就是 DeepSeek-V3.2 文章中提到的 Unbiased KL Estimate
    • 这里的约等于应该是有两层含义:
      • k3 估计是无偏的,但是仍然是一种估计,而不是等于
      • Sequence-level 重要性加权 KL 到 Token-level 重要性加权 KL 的近似
个人思考:无偏性反向证明
  • 上面是正向推导形式,为了方便理解,我们其实也可以反向证明无偏性
  • 记重要性权重为:
    $$
    r_{i,t} = \frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{\text{old} } }(o_{i,t} | q, o_{i,<t})}
    $$
  • 则有:
    $$
    \mathcal{L}_{\text{KL} }^{\text{unbiased} }
    = r_{i,t} \left( \frac{\pi_{\text{ref} } }{\pi_\theta} - \log \frac{\pi_{\text{ref} } }{\pi_\theta} - 1 \right)
    $$
  • 其期望满足(下面第一步的转换是将期望概率乘进去消掉重要性权重的分母,然后将分子作为概率提出来作为期望):
    $$
    \begin{align}
    \mathbb{E}_{o_{i,t} \sim \pi_{\theta_{\text{old} } } } \left[ \mathcal{L}_{\text{KL} }^{\text{unbiased} } \right]
    &= \mathbb{E}_{o_{i,t} \sim \pi_\theta} \left[ \frac{\pi_{\text{ref} } }{\pi_\theta} - \log \frac{\pi_{\text{ref} } }{\pi_\theta} - 1 \right] \\
    &= \mathbb{E}_{o_{i,t} \sim \pi_\theta} \left[ \text{k3} \right] \\
    &= D_{\mathrm{KL} }[\pi_\theta \parallel \pi_{\text{ref} }] \\
    \end{align}
    $$
    • 因此,DeepSeek-V3.2 文章中提到的 Unbiased KL Estimate 估计形式是无偏的

一些思考

  • DeepSeek-V3.2 的 Unbiased KL Estimate 的核心思想是:
    • 将 KL 散度项视为 reward 的一部分,并对其应用与 policy gradient 相同的重要性采样权重,从而保证 KL 梯度的无偏性
  • 最终,在 GRPO 目标函数中,KL 项变为:
    $$
    -\beta \cdot \frac{1}{G} \sum_{i=1}^G \frac{1}{ o_i } \sum_{t=1}^{ o_i }
    \underbrace{\color{red}{\frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{\text{old} } }(o_{i,t} | q, o_{i,<t})}} \left(\frac{\pi_{\text{ref} }(o_{i,t} | q, o_{i,<t})}{\pi_\theta(o_{i,t} | q, o_{i,<t})} - \log \frac{\pi_{\text{ref} }(o_{i,t} | q, o_{i,<t})}{\pi_\theta(o_{i,t} | q, o_{i,<t})} - 1\right)}_{\text{Unbiased KL Estimate} }
    $$
    • 这使得整个目标函数的梯度在使用旧策略采样时仍保持对真实 KL 的无偏估计,提升了训练稳定性与效果
    • 注:再次强调,在绝对的 On-policy 的更新中,其实 \(\pi_\theta = \pi_{\theta_\text{old}}\),这个重要性权重可以忽略,类似说明其他博客也有提到
    • 这种做法比之前的一些丢弃 KL 散度的方法更好,但是否比改变形式的方法更好?
  • 其他补充:其实之前的博客也讨论过类似的问题:The critical implementation detail of KL loss in GRPO, Hongyu Zang
    • 博客中还提出了一些解决方案,其中一个方案(方案三)就跟 DeepSeek-V3.2 的方案思想类似
      • 博客中的方案三也是对 KL 散度使用 \(\frac{\pi_{\theta}}{\pi_{\theta_\text{old}}}\) 来进行修正
      • 但博客中提到的方案三是直接将 KL 添加到 Reward 中(类似传统 RLHF 中的做法一样),而 DeepSeek-V3.2 的 Unbiased KL Estimate 仍然是独立的一个 KL Loss
      • 博客相当于 DeepSeek-V3.2 工作的一半,提出了本文前面 “将 KL 项放入采样期望内” 的这一步,没有进一步推导回到独立的 KL Loss

NLP——ScaleRL

注:本文包含 AI 辅助创作

  • 参考链接:
    • 原始论文:(ScaleRL)The Art of Scaling Reinforcement Learning Compute for LLMs, Meta, 20251015
    • 代码地址:github.com/OpenLMLab/MOSS-RLHF

Paper Summary

  • 核心总结(本文的核心贡献是 Meta 团队丰富的认知):
    • 论文缩放方法论的一个重要见解是:可以系统地使用较小规模的消融来预测更大规模的性能,这使论文能够创建最终的可扩展 Recipe
    • 根据论文的消融实验, Off-policy 算法、损失函数和模型精度是最重要的决策
      • 其他每个决策单独影响不大,但正如论文从留一法实验中看到的,当它们全部组合时,仍然具有一些累积影响(在效率方面)
    • 渐近性能与效率 (Asymptotic performance vs. efficiency)
      • 论文发现更好的选项同时提高了效率和渐近性能,但情况并非总是如此(例如,对于 FP32,图 4(b)),当从基线方法开始进行”正向”消融时,论文首先且最主要地选择渐近性能
      • 当从 ScaleRL Recipe 进行”反向”留一法消融时,论文发现每个决策对渐近性能的影响非常小,但算法的每个组件似乎都有助于提高效率
        • 这表明变化的累积效应是相当鲁棒的
    • Generalization:虽然对泛化的全面描述超出了论文工作的范围,但论文确实观察到分布内验证与下游泛化性能之间的相关性
      • 有一些算法选择似乎更有助于泛化,作者指出了:
        • 更大的批次大小(章节 A.14)
        • 减少截断(章节 A.15)
        • 更长的生成长度(第 5 节,图 9)
        • 更大的模型规模(第 5 节,图 1)
    • 多任务强化学习 (Multi-task RL)
  • 背景 & 问题:
    • RL 已成为训练 LLMs 的核心技术,然而 RL 领域缺乏与预训练阶段相当的预测性 Scaling 方法论
    • 计算预算迅速增长,但对于如何评估算法改进以 Scaling RL 计算,目前尚无原则性的理解(principled understanding)
  • 论文工作:
    • 论文进行了首次大规模系统性研究,总计超过 400,000 GPU hous ,定义了一个原则性框架,用于分析和预测 LLM 中的 RL Scaling
  • 论文为 RL 训练拟合了 S 形计算-性能曲线(sigmoidal compute-performance curves),并广泛消融了一系列常见的设计选择,以分析它们对渐近性能和计算效率的影响
  • 论文观察到:
    • (1) 并非所有 Recipe (recipes)都能产生相似的渐近性能;
    • (2) 诸如损失聚合、归一化、课程学习以及 Off-policy 算法等细节主要调节计算效率,而不会显著改变渐近性能;

      Details such as loss aggregation, normalization, curriculum, and off-policy algorithm primarily modulate compute efficiency without materially shifting the asymptote

    • (3) 稳定、可扩展的 Recipe 遵循可预测的 Scaling 轨迹,使得能够从小规模运行中进行外推
  • 结合这些见解,论文提出了一个最佳实践(best-practice) Recipe ScaleRL ,并通过成功地将单个 RL 运行扩展到 100,000 GPU hous 并预测其验证性能,证明了其有效性
  • 论文的工作既提供了一个用于分析 RL Scaling 的科学框架,也提供了一个实用的 Recipe ,使 RL 训练更接近预训练中长期实现的预测性

Introduction and Discussion

  • Scaling RL 计算正成为推进 LLMs 发展的关键范式
    • 预训练奠定了模型的基础;但随后的 RL 训练阶段释放了当今许多最重要的 LLM 能力,从 test-time thinking (OpenAI, 2024; DeepSeek, 2025) 到智能体能力 (Kimi, 2025a)
    • 例如 Deepseek-RL-Zero 使用了 100,000 H800 GPU hous 进行 RL 训练,占其预训练计算的 3.75% (DeepSeek, 2025)
    • RL 计算的这种急剧增长在前沿 LLM 的各代产品中被放大,从 o1 到 o3 增加了超过 \(10\times\) (OpenAI, 2025),从 Grok-3 到 Grok-4 也有类似的飞跃 (xAI Team, 2025)
  • 尽管用于 LLM 的 RL 计算已经大规模扩展,但我们对如何扩展 RL 的理解并未跟上;其方法论仍然更像艺术而非科学
    • 最近的 RL 突破主要由针对新颖算法的孤立研究 (例如,DAPO, (2025)) 和特定模型的训练报告所驱动,例如 MiniMax 等 (2025) 和 Magistral (2025)
    • 且这些研究提供了针对特定背景的临时解决方案,但并未说明如何开发能够随计算规模扩展的 RL 方法
  • 这种 Scaling 方法论的缺乏阻碍了研究进展:
    • 由于没有可靠的方法先验地识别有前景的 RL 候选方案,进展与大规模实验绑定,这使得大多数学术界团体被边缘化
  • 这项工作通过借鉴预训练中成熟的概念 Scaling Laws ,为 RL Scaling 的科学奠定了基础
    • 虽然预训练已经收敛到能够可预测地随计算规模扩展的算法 Recipe (2020; 2022; Owen, 2024),但 RL 领域缺乏明确的标准
    • RL 从业者面临着令人眼花缭乱的设计选择,使得如何扩展以及扩展什么这些基本问题悬而未决
    • 为了解决这些问题,论文建立了一个使用类 S 形饱和曲线来预测 RL 性能的框架,该曲线描述了在同分布验证集上的期望奖励 (\(R_{C}\)) 与训练计算量 (\(C\)) 之间的关系:
      $$\boxed{ \overbrace{R_{C}-R_{0} }^{ \text{Reward Gain} } = \overbrace {(A-R_{0})}^{ \text{Asymptotic Reward Gain} } \times \frac{1}{\underbrace{1+(C_{\rm mid}/C)^{B} }_{ \text{Compute Efficiency} } } } \quad \quad \text{(fixed model and traning data)} \tag{1}$$
    • \(0\leq A\leq 1\) 代表渐近通过率
    • \(B>0\) 是决定计算效率的缩放指数
    • \(C_{\rm mid}\) 设定了 RL 性能曲线的中点
    • 注:\((A-R_{0})\) 可以理解为 渐近的奖励增益(Asymptotic Reward Gain), \(A\) 为渐近奖励(Asymptotic Reward)
    • 理解:
      • \(A-R_0\) 是表示一个系数,越大时,整体收益 \(R_C\) 越大
      • \(C\) 是一个越大,\(C_{\rm mid}/C\) 变小,\(1+(C_{\rm mid}/C)^B\) 变小,\(\frac{1}{1+(C_{\rm mid}/C)^B}\) 变大,整体曲线如图 3 所示
  • 图 3 提供了这些参数的示意图解释
  • 公式 (1) 中的框架使研究人员能够从低计算量运行外推性能到高计算预算,从而能够在无需承担将每个实验都运行到其计算极限的成本的情况下,评估 RL 方法的可扩展性
  • 在这个框架的指导下,论文开发了 ScaleRL ,这是一个能够可预测地随计算规模扩展的 RL Recipe
    • 在一个大规模的100,000 GPU hous 训练运行中,论文展示了 ScaleRL 的性能与论文的框架预测的扩展曲线紧密匹配(图 1)
    • 仅从训练的初始阶段外推的扩展曲线与最终观察到的性能紧密匹配,证实了论文的框架在极端计算规模下的预测能力
  • ScaleRL 的设计基于一项全面的 RL Scaling 实证研究,该研究跨越了超过 400,000 GPU hous(在 Nvidia GB200 GPU 上)
  • 这项研究在 8B 模型参数规模上探索了众多设计选择,其中单个运行使用高达 16,000 GPU hous,使其比在论文最大训练运行规模上进行实验便宜 6 倍
  • 这项调查得出了三个关键原则:
    • RL 性能上限并非普适(RL Performance Ceilings are Not Universal) :当我们为不同方法扩展训练计算量时,它们会遇到不同的可达到性能上限 (\(A\))
      • 这个限制可以通过诸如损失类型和批次大小等选择来改变
    • 拥抱苦涩教训(Embracing the Bitter Lesson) :在小计算预算下表现优越的方法,在外推到大规模计算区域时可能更差(图 2)
      • 仍然可以通过使用论文的框架(公式 (1))从早期训练动态中估计缩放参数 (\(A\), \(B\)) 来识别可扩展的方法
    • 重新评估常见智慧 :通常被认为能提高峰值性能的干预措施(例如,损失聚合、数据课程、长度惩罚、优势归一化)主要调整计算效率 (\(B\)),而不会显著改变性能上限
  • 基于这些见解,ScaleRL 通过整合现有方法而非发明新方法来实现可预测的扩展
    • 具体来说,ScaleRL 结合了异步 Pipeline-RL 设置(第 3.1 节)、强制长度中断、截断重要性采样 RL 损失 (CISPO from MiniMax-M1)、提示级损失平均、批次级优势归一化、logits 处的 FP32 精度、零方差过滤和 No-Positive-Resampling
    • 以上每个组件的贡献都在消耗 16,000 GPU hous 每次运行的留一法消融实验中得到了验证
    • ScaleRL 实现可预测地扩展,且建立了新的SOTA(图 2)
      • 与已建立的 RL Recipe 相比,它实现了更高的渐近性能和计算效率
    • ScaleRL 在跨多个训练轴增加计算量时保持了可预测的扩展性(第 5 节)
      • 包括 \(2.5\times\) 更大的批次大小、长达 32,768 个 Token 的生成长度、使用数学和代码的多任务 RL 以及更大的混合专家模型 (Llama-4 17B\(\times\)16);
      • 其益处持续迁移到下游任务
  • 总的来说,这项工作建立了一种严谨的方法论,用于成本效益地预测新 RL 算法的可扩展性

Preliminaries & Setup

  • 论文使用 LLM 进行强化学习,其中提示 \(x\) 从数据分布 \(D\) 中采样
  • 论文的设置遵循在 GPU 上的 Generator-Trainer 分离:
    • Generator GPU 使用优化的推理内核进行高通量 rollout 生成
    • Trainer GPU(其余的 GPU)运行训练后端 (FSDP) 并更新参数
  • 论文分别用 \(\pi^{\theta}_{\text{gen} }\) 和 \(\pi^{\theta}_{\text{train} }\) 表示 Generator 和训练后端上具有参数 \(\theta\) 的模型
  • 对于每个提示, Generator GPU 上的旧策略 \(\pi^{\theta_\text{old} }_\text{gen}\) 产生候选补全,然后被分配标量奖励
  • 策略优化通过最大化一个裁剪的 Surrogate Objective 进行,对 \(x\sim D\) 和来自 \(\pi^{\theta_\text{old} }_\text{gen}\) 的 rollout 取期望

Training Regimen(安排,规划)

  • 所有实验均在用于推理的 RL 领域进行,其中模型产生一个用特殊 Token(<think> … </think>)包围的思考轨迹和一个最终解决方案
  • 除非另有说明,训练使用 16,384 个 Token 的序列长度:
    • 12,288 用于思考,2,048 用于解决方案,另外 2,048 用于输入提示
  • 论文采用 12,288 的思考预算以加快迭代速度,并在第 5 节展示 ScaleRL 外推在使用更大思考预算 (32,768) 进行训练时仍保持预测性
  • 对于数学 RL 实验,论文使用 Polaris-53K 数据集 (2025),批次大小为 768(48 个提示,每个提示 16 次生成)
  • 在论文的设置中,扩展 RL 计算对应于在训练提示上运行多个周期
  • 关于训练的更多细节,包括 SFT 和超参数,见附录 A.3

Base RL Algorithm

  • 作为论文在第 3 节的起点,论文从一个“基础”算法开始
    • 该算法类似于没有 KL 正则化项的 GRPO (2024),与大规模训练报告一致 (Magistral, 2025; MiniMax, 2025)
    • 论文包含了非对称 DAPO 裁剪 (2025),它作为避免熵崩溃和保持输出多样性的默认方法被广泛采用
  • 对于给定的提示 \(x\),旧策略 \(\pi_{\text{gen} }(\theta_{\text{old} })\) 生成 \(G\) 个候选补全 \(\{y_{i}\}_{i=1}^{G}\),每个被分配一个标量奖励 \(r_{i}\)。论文计算优势 \(\hat{A}_{i}\) 并使用组归一化优势:
    $$\hat{A}_{i}=r_{i}-\text{mean}(\{r_{j}\}_{j=1}^{G}),\quad\hat{A}_{i}^{G}=\hat{A}_ {i}/(\text{std}(\{r_{j}\}_{j=1}^{G})+\epsilon).$$
    • 每个长度为 \(|y_{i}|\) 的补全 \(y_{i}\) 在 Token-level 的重要性采样 (IS) 比率 \(\rho_{i,t}(\theta)\) 上做出贡献,具有非对称的上限和下限裁剪阈值,类似于 DAPO (2025):
      $$\rho_{i,t}(\theta):=\frac{\pi^{\theta}_\text{train}(y_{i,t}\mid x,y_{i,<t})}{\pi^{ \theta_{\text{old} } }_\text{gen }(y_{i,t}\mid x,y_{i,<t})}=\frac{\pi^ {\theta}_\text{train}(y_{i,t})}{\pi^{\theta_{\text{old} } }_\text{gen }(y_{ i,t})};\quad\text{clip}_{\text{asym} }(\rho,\epsilon^{-},\epsilon^{+}):=\text{ clip}(\rho,1-\epsilon^{-},1+\epsilon^{+}). \tag{2}$$
    • 论文在 Sample-level 聚合损失,即在跨样本平均之前,先平均每个样本的 Token 损失
    • Surrogate Objective 为:
      $$\mathcal{J}(\theta)=\mathbb{E}_{x\sim D,\atop\{y_{i}\}_{i=1}^{G}\sim\pi^{ \theta_{\text{old} } }_\text{gen }(\cdot|x)}\left[\frac{1}{G}\sum_{i=1}^{G}\frac{1 }{|y_{i}|}\sum_{t=1}^{|y_{i}|}\min\Bigl{(}\rho_{i,t}(\theta)\hat{A}_{i}^{G}, \text{clip}_{\text{asym} }(\rho_{i,t}(\theta),\epsilon^{-},\epsilon^{+})\hat{A}_ {i}^{G}\Bigr{)}\right]. \tag{3}$$
  • 控制生成长度 (Controlling Generation Lengths)
    • 为了防止训练过程中推理输出长度爆炸性增长,这有害于训练稳定性和效率,论文使用中断 (GLM-V Team, 2025; 2025),通过附加一个思考结束短语(例如,“</think>”)来强制停止过长的生成,示意 LLM 终止其推理并产生最终答案
    • 论文将在后面的第 4 节重新讨论这个选择,并将其与惩罚长生成的长度惩罚进行比较 (2025; Kimi Team, 2025b)

Predictive compute-scaling and fitting curves

  • 与通常使用幂律拟合预测曲线的预训练不同,论文使用 S 形函数(公式 (1))来模拟通过率与 \(\log(compute)\) 的关系
    • 论文这样做是因为论文经验发现 S 形拟合比幂律拟合更鲁棒和稳定,论文将在附录 A.4 中进一步讨论
    • 论文的选择与先前使用类 S 形幂律来捕捉有界指标(如准确率)的工作一致 (2024; 2022)
  • 与预训练研究类似 (2025b; 2025),论文发现排除非常早期的低计算区域(low-compute regime)会产生更稳定的拟合,之后训练遵循可预测的轨迹
    • 除非另有说明,论文所有的缩放拟合都在约 1.5k GPU hous 之后开始
    • 拟合过程的进一步细节在附录 A.5 中提供,论文曲线拟合的鲁棒性在附录 A.7 中讨论
    • 问题:这里是指拟合 S 形曲线时,排除早期的训练结果,理解是因为此时模型没有得到良好的训练,不排除会受波动影响较大
  • 解释缩放曲线 (Interpreting scaling curves)
    • 直观地说,S 形曲线捕捉了饱和回报:
      • 在低计算区域增长缓慢,在高效缩放的中段急剧加速,然后在计算量高时饱和
    • 论文还在图 3 中提供了 S 形曲线参数 \(A,B,\text{ 和 }C_{mid}\) 的示意图解释
      • 可以看到,\(B,C_{\text{mid} }\) 主要影响运行的效率,\(A\) 表示在大型计算规模下的渐近性能
    • 关于这些参数的进一步讨论在附录 A.8 中提供
  • 在留出验证集上的缩放曲线 (Scaling curve on held-out validation)
    • 与预训练实践一致 (2022; 2025),论文在同分布验证数据上测量预测性能
    • 由于训练运行跨越多个 Epochs,论文从 Polaris-53k 数据集中随机留出 \(1,000\) 个提示用于验证,并使用其余部分进行训练
    • 缩放曲线拟合在验证点上,这些点每 100 个训练步骤测量一次平均通过率,在 \(1,000\) 个留出提示上每个提示有 16 次生成

An Empirical Study of RL Scaling

  • 论文使用一个 8B 参数的稠密模型在可验证的数学问题上进行 RL 实验
  • 使用第 2 节中描述的设置,论文研究了几个设计轴在其可预测的计算缩放行为方面,即渐近性能 (asymptotic performance, \(A\)) 和计算效率 (compute efficiency, \(B\)),如图 3 所示
  • 论文将实验结构分为三个阶段
    • 首先,在 3.5k 到 4k GPU hous 的基线之上消融设计选择,因为一些实验选择在此规模之外会变得不稳定(附录 A.15)
      • 每当一个设计改变被证明是稳定的,论文就将其训练更长时间
    • 然后,将最佳选择组合成 ScaleRL ,并在第 4 节进行 16k GPU hous 的留一法 (LOO) 实验
      • 在这里,论文通过在前 8k GPU hous 上拟合并外推运行的剩余部分来评估可预测性
    • 最后,为了证明使用 ScaleRL 的可预测缩放,论文在第 5 节还考虑了具有更大批次大小、混合专家模型、多任务(数学和代码)和更长序列长度的训练设置

Asynchronous RL Setup

  • 论文首先研究异步 Off-policy RL 设置 (2024) 的选择,因为它控制着训练稳定性和效率,通常独立于所有其他设计选择
  • 论文考虑两种 Off-policy 学习方法:PPO-off-policy-\(k\) 和 PipelineRL-\(k\)
  • PPO-off-policy-\(k\) 是异步 RL 的默认方法,先前已被 Qwen3 (2025) 和 ProRL (2025a) 使用
    • 在这种设置中,旧策略 \(\pi_{\theta^{\text{old} }_{\text{gen} } }^{op}\) 为一批 \(B\) 个提示生成推理轨迹
    • 每次梯度更新处理一个包含 \(\hat{B}\) 个提示的小批次,导致每个批次有 \(k=B/\hat{B}\) 次梯度更新
    • 在论文的实验中,论文固定 \(\hat{B}=48\) 个提示(每个提示 16 次生成),并通过设置 \(B=k\times 48\) 来改变 \(k\in \{1,8\}\)
  • PipelineRL-\(k\) 是来自 Piche 等 (2025) 的一种新方法,并被 Magistral (2025) 使用
    • 在 PipelineRL-\(k\) 中, Generator 以流式方式持续产生推理轨迹
    • 每当 Trainer 完成一次策略更新时,新参数立即推送到 Generator , Generator 继续使用更新后的权重但使用来自旧策略的陈旧 KV 缓存进行生成
    • 一旦生成完整的轨迹批次,它就被传递给 Trainer 进行下一次更新
    • 在论文的设置中,论文引入了一个参数 \(k\):如果 Trainer 比 Generator 提前 \(k\) 步,它们就会等待
  • 论文在图 4(a) 中比较了这些方法
    • PipelineRL 和 PPO-off-policy 实现了相似的渐近性能 \(A\),但 PipelineRL 显著提高了计算效率 \(B\);从而更快地达到上限 \(A\)
      • 因为 PipelineRL 减少了训练过程中的空闲时间
    • 这种选择以更少的 Token 产生可靠的收益,使得在较低计算预算下进行更大范围的扫描成为可能
    • 论文还改变了 PipelineRL 的最大 Off-policy 程度,并发现 \(k=8\) 是最优的,如图 4(b) 所示,论文将在附录 A.11 中进一步讨论

Algorithmic Choices

  • 基于以上结果,论文采用 PipelineRL-8 作为论文更新后的基线。然后论文研究了六个额外的算法轴:
    • (a) 损失聚合, loss aggregation
    • (b) 优势归一化,advantage normalization
    • (c) 精度修正,precision fixes
    • (d) 数据课程,data curriculum
    • (e) 批次定义,batch definition
    • (f) 损失类型,loss type
  • 在第 4 节,论文将最佳选项组合成一个统一的 Recipe ,称为 ScaleRL (Scale-able RL),并在 16,000 GPU hous 的更大规模上进行留一法实验

Loss type

  • 论文将非对称 DAPO 损失(公式 8)与两个最近提出的替代方案进行比较:GSPO (Qwen, 2025a) 和 CISPO (MiniMax, 2025; 2025)
  • GSPO 在序列级别应用重要性采样,而不是 GRPO 的 Token-level 公式。具体来说,GSPO 将 Token-level 的 IS 比率(公式 2)改变为序列级别的比率:
    $$ \rho_{i}(\theta)=\frac{ {\pi_\text{train}(y_{i}|x,\theta)} }{ {\pi_{gen}(y_{i}|x,\theta_{\text{old} })} }$$
  • CISPO 简单地将截断 IS 与普通策略梯度 (Ionides, 2008) 结合起来,其中 \(\mathbf{sg}\) 是停止梯度函数:
    $$\mathcal{J}_{\text{CISPO} }(\theta)=\underset{\begin{subarray}{c}x\sim D,\ (y_{t})_{t=1}^{G}\sim\pi_{gen}(\cdot|x,\theta_{\text{old} })\end{subarray} }{\mathbb {E} }\left[\frac{1}{T}\sum_{t=1}^{G}\sum_{t=1}^{\lvert y_{t}\rvert}\mathbf{sg}(\min(\rho_{i,t},\epsilon_{\max}))\hat{A}_{i}\log \left(\pi_\text{train}(y_{i,t}|x,y_{i<t},\theta)\right)\right] \tag{4}$$
  • 图 5(a) 显示 GSPO 和 CISPO 都显著优于 DAPO,大幅提高了渐近通过率 \(A\)
  • CISPO 表现出延长的近线性奖励增长,并且在训练后期略优于 GSPO,因此论文选择 CISPO 作为论文的最佳损失类型
  • 关于 Off-policy 损失类型及其超参数鲁棒性的进一步讨论在第 4 节和附录 A.17 中详述

FP32 Precision for LLM logits

  • Generator 和 Trainer 依赖不同的内核进行推理和训练,导致它们的 Token 概率存在小的数值不匹配 (ThinkingMachine Defeating nondeterminism in LLM inference, 2025)
    • RL 训练对此类差异高度敏感,因为它们直接影响 Surrogate Objective 中的 IS 比率
  • MiniMax (2025) 发现这些不匹配在语言模型头(language model head)尤其明显,并通过在 Generator 和 Trainer 的 Head 使用 FP32 计算来缓解这个问题
    • 如图 5(b) 所示,精度修正将渐近性能 \(A\) 从 \(0.52\) 显著提高到 \(0.61\)
    • 鉴于这个明显的好处,论文将 FP32 精度修正包含在论文的 ScaleRL Recipe 中

Loss Aggregation

  • 论文评估了三种聚合 RL 损失的策略:
    • (a) 样本平均(Sample average) ,每个 rollout 贡献相等(如 GRPO,附录 A.2)
    • (b) 提示平均(Prompt average) ,每个提示贡献相等(如 DAPO,附录 A.2)
    • (c) Token 平均(Token average) ,批次中的所有 Token 损失直接平均,没有中间分组
  • 比较结果见附录 A.9(图 14(a))
  • 论文发现 Prompt average 实现了最高的渐近性能,因此在 ScaleRL 中使用此选择

Advantage Normalization

  • 论文比较了三种优势归一化的变体:
    • (a) 提示级别(Prompt level) ,优势通过同一提示的 rollout 奖励的标准差进行归一化(如 GRPO,附录 A.2)
    • (b) 批次级别(Batch level) ,优势通过批次中所有生成的标准差进行归一化,如 Reinforce++ (2025a); Magistral (2025) 所用
    • (c) 无归一化(No normalization) ,优势计算为原始奖励减去提示生成的平均奖励,没有方差缩放(如 Dr. GRPO (2025c) 所提出)
  • 比较图见附录 A.9(图 14(b)),观察到所有三种方法产生相似的性能
  • 因此论文采用 Batch level 归一化,因为它在理论上合理且略好
  • 这个选择在第 4 节的更大规模留一法实验中也得到了进一步证实

Zero-Variance Filtering

  • 在每个批次中,一些提示在其所有生成中产生相同的奖励
    • 这些“零方差”提示具有零优势,因此贡献零策略梯度
    • 默认基线在损失计算中包含这些提示,但尚不清楚是否应将它们包含在有效批次中
  • 为了测试这一点,论文将默认设置与有效批次(effective batch)方法进行比较
    • 在 effective batch approach 中,只有具有非零方差的提示被包含在损失计算中(如 Seed (2025) 所做)
  • 请注意:零方差过滤不同于 DAPO (2025) 中的动态采样
    • 零方差过滤仅仅是丢弃 Prompt ,而 DAPO 是重新采样更多提示直到批次满员(until the batch is full)
    • 论文在图 6(a) 中显示使用有效批次在渐近性能上表现更好;论文将其纳入论文的 ScaleRL Recipe

Adaptive Prompt Filtering

  • 已经提出了许多用于 RL 训练的数据课程策略以提高样本效率 (2025; 2025b; 2025b)
  • 这里论文评估一个简单的变体,由 (2025) 引入,其关键观察是
    • 一旦一个提示对策略变得过于简单,它通常会持续保持简单
    • 由于这样的提示消耗一些计算但不再贡献有用的梯度信号(第 3.2 节),最好将它们从未来的训练中排除
  • 论文通过维护一个通过率历史记录并永久移除任何通过率 \(\geq 0.9\) 的提示在后续周期中来实现这一点(论文称之为 No-Positive-Resampling)
  • 在图 6(b) 中,论文将此课程与默认设置(所有提示在整个训练过程中均匀重新采样)进行比较
    • 论文看到课程提高了可扩展性和渐近奖励 \(A\)

ScaleRL: 有效且可预测地扩展强化学习计算 (ScaleRL: Scaling RL Compute Effectively & Predictably)

  • 根据上述研究的设计维度,论文将性能最佳的设置整合到一个单一的 Recipe 中,论文称之为 ScaleRL (Scale-able RL)
  • ScaleRL 是一种异步强化学习 Recipe ,它使用下面的配置:
    • 具有 8 步 Off-policy 性的 PipelineRL
    • 基于中断的长度控制进行截断(interruption-based length control for truncation)
      • 注:后文有提到,对于强制中断,论文使用思考结束短语:”Okay, time is up. Let me stop thinking and formulate a final answer now. </think>“
    • FP32 计算用于逻辑单元
    • 优化 \(\mathcal{J}_{\texttt{ScaleRL} }(\theta)\) 损失
  • \(\mathcal{J}_{\texttt{ScaleRL} }(\theta)\) 损失结合了:
    • Prompt-level 损失聚合
    • Batch-level 优势归一化
      • 注意:是按照批次做 Advantage 归一化的,不是 GRPO 方法,而是类似 REINFORCE++ 方法
      • 补充:REINFORCE++ 的方法:
        • 记录历史平均奖励作为基线,判断模型是否在进步
        • 使用历史奖励的均值和方差做归一化,类似 Batch Normalization)
    • 截断重要性采样(truncated importance-sampling)REINFORCE 损失 (CISPO)
    • 零方差过滤(zero-variance filtering)
    • 无正例重采样(no-positive resampling)
      $$\begin{split}\mathcal{J}_{\texttt{ScaleRL} }(\theta)=& \underset{x\sim D,\atop\{y_{i}\}_{i=1}^{G},\sim\pi^{data}_{g\in h}( \cdot|x)}{\mathbb{E} }\left[\frac{1}{\sum_{g=1}^{G}|y_{g}|}\sum_{i=1}^{G}\sum_{t=1 }^{|y_{i}|}\mathsf{sg}(\min(\rho_{i,t},\epsilon))\hat{A}^{\text{norm} }_{i}\log \pi^{ {\theta} }_\text{train}(y_{i,t})\right],\\ \rho_{i,t}=&\frac{\pi^{ {\theta} }_\text{train}(y_{i,t})}{\pi^{ {\theta}_{add} }_{g\in h}(y_{i,t})},\hat{A}^{\text{norm} }_{i}=\hat{A}_{i}/\hat{A}_{\text{std} },0<\text{mean}(\{r_{j}\}_{j=1}^{G})<1,\text{pass_rate} (x)<0.9,\end{split}$$
    • 其中 \(\mathsf{sg}\) 是停止梯度函数
    • \(\hat{A}_{\text{std} }\) 是一个批次中所有优势 \(\hat{A}_{i}\) 的标准差
    • pass_rate\((x)\) 表示提示 \(x\) 的历史通过率

留一法消融实验 (Leave-One-Out (LOO) Ablations)

  • 为了验证这些选择在组合后仍然是最优的,论文进行了留一法 (LOO) 实验:
    • 从 ScaleRL 开始,论文每次将一个维度恢复到其在第 2 节中的基线对应项
    • 这确保了每个设计决策即使在其他所有决策都存在的情况下也能做出积极贡献
  • 图 7 报告了这些实验,每个实验扩展到 16k GPU hous
  • 在所有维度上,ScaleRL 始终是最有效的配置,在渐近奖励或计算效率上略微优于 LOO 变体(参见图 7 表格的最后一列)
    • 由于大多数 LOO 变体达到相似的渐近通过率,论文将 sigmoid 拟合转换为幂律拟合,以通过斜率 \(B\) 突出效率差异(细节见图 7)
    • 具体来说,论文平均所有运行的渐近奖励 \(A\),用这个固定的 \(A\) 重新拟合曲线,然后在图 7 中比较斜率(衡量效率)
    • 相应的未转换的通过率与计算曲线在附录 A.2 中提供

Error margin(误差范围)in fitting scaling curves

  • 由于强化学习训练已知具有高方差 (2021),论文使用三个独立的 ScaleRL 运行(图 8a)来估计拟合缩放系数的变异性
    • 观察到的渐近奖励和效率参数的方差作为论文的经验误差范围,用于确定两个不同运行的计算效率或渐近性能的变化是否具有统计意义 (2024)

Extrapolating Scaling Curves

  • 在论文所有的 LOO 实验以及独立的 ScaleRL 运行中,论文拟合了高达 8000 GPU hous 的 sigmoid 曲线,并外推到 16000 GPU hous ,观察到预测曲线与训练点和扩展点都紧密对齐
    • 这证明了 ScaleRL 和其他稳定、可扩展的 Recipe 在大规模强化学习训练下的稳定性和可预测性

Are the design choices worth it?

  • 在第 3.2 节中,某些设计选择改变了渐近性能,例如损失类型(图 5a)和 FP32 精度(图 5b)
  • 但在论文使用 ScaleRL 的 LOO 实验中(图 7),这些组件单独来看似乎不那么关键(图中最后一列)
  • 这就提出了一个问题:某些设计选择是否可以安全地保留其”默认”值
    • 作者认为上述问题的答案是否定的
    • 即使一个选择在组合 Recipe 中显得多余,它仍然可以提供稳定性或鲁棒性,这在其他情况下可能变得至关重要
      • 问题:如何理解显得多余又能提供稳定性或鲁棒性,是指不使用这些指标时,不同随机种子下表现差异大吗?还是说在不同的 模型规模或者数据集上表现差异大?
    • 例如,虽然 FP32 精度修复在使用 ScaleRL 训练的密集 8B 模型上差异不大(图 7),但它在 GRPO/DAPO 风格的损失中通过减轻数值不稳定性带来了巨大收益
      • 这表明它的好处超出了论文研究的特定 ScaleRL 配置
      • 为了进一步测试这一点,论文在 Scout 17Bx16 MoE 上进行了留一法实验,观察到 FP32 精度提高了整体可扩展性(图 8b)
    • 损失类型也出现了类似的情况
      • 在图 7 中,恢复到 DAPO 在 ScaleRL 内产生了与 CISPO 相似的渐近性能
      • 但如论文在附录 A.17 中讨论的那样,CISPO 对 IS 裁剪参数 \(\epsilon_{\text{max} }\) 的选择明显更鲁棒,降低了训练对超参数调整的敏感性
      • 而且它在 LOO 实验中比 DAPO 更高效(\(B=2.01\) 对比 \(B=1.77\))
      • 这证明了即使一个经过仔细调整的 DAPO 变体在渐近性能上可能相似,也倾向于选择 CISPO 是合理的
  • 总之,即使个别设计选择在组合 Recipe 中显得多余,它们通常也能以跨模型和设置泛化的方式增强训练稳定性、鲁棒性或效率
    • ScaleRL 保留这些组件不仅仅是为了在特定配置中获得边际收益,而是因为它们解决了在强化学习体系中反复出现的不稳定性和方差来源
  • 注:本节的主要目标是说明,很多改进点看似在论文特定场景下没有收益,但在更通用的其他场景(随机种子,数据集,模型等)下,可能会有收益,为了保证方法的稳定性,建议加上一些确定性的改进点

Predictable Scaling Returns Across RL Compute Axes(跨强化学习计算轴的可预测缩放回报)

  • 给定固定或增长的计算预算,哪个缩放旋钮(上下文长度、批次大小、每个提示的生成次数和模型大小)能带来最可靠的性能增益,并且论文多早可以预测到这种回报?
  • 论文通过以下方式回答这个问题:
    • (i) 在每种设置的训练早期(精确地说,是目标预算的一半)拟合方程 (1) 中的饱和幂律;
    • (ii) 外推到目标预算;
    • (iii) 扩展训练以验证预测
  • 在下面所有的轴线上,论文观察到清晰、可预测的拟合,其外推曲线与扩展轨迹对齐,反映了论文在 100,000 GPU hous 运行(图 1)和图 2 中的跨 Recipe 比较中看到的行为

模型规模(Model scale (MoE))

  • ScaleRL 在更大模型上是否仍然保持可预测性和稳定性?(注:即论文的 Scaling Law 是否能泛化到其他模型上)
  • 使用 ScaleRL 训练 17B\(\times\)16 Llama-4 Scout MoE 表现出与 8B 模型相同的可预测缩放行为 ,具有低截断率且没有不稳定性问题(附录 A.15, A.17)
    • 图 1 显示了训练曲线
  • 扩展点与拟合曲线对齐,支持了论文 Recipe 对模型规模的不变性
  • 更大的 17B\(\times\)16 MoE 表现出比 8B 密集模型高得多的渐近强化学习性能,仅使用其 1/6 的强化学习训练计算量就超越了 8B 的性能

Generation length(context budget,即上下文预算)

  • 将生成长度从 14k 增加到 32k 个 Token 会减缓早期进展(更低的 \(B\) 和更高的 \(C_{mid}\)),但会持续提升了拟合的渐近线 (A)
    • 提供足够的计算量后,可以产生更高的最终性能(图 9)
  • 这验证了长上下文强化学习是一个提升性能上限的旋钮,而不仅仅是效率权衡
  • 从拟合中做出的外推正确地预测了当训练扩展时更高的 32k Token 轨迹

Global batch size(prompts,即提示数)

  • 较小的批次运行在下游基准测试中显示出早期停滞(即使分布内验证性能持续提高)
  • 较大的批次可靠地改善了渐近线,并避免了论文在较小批次运行中观察到的下游停滞
  • 图 10a 在中尺度上显示了相同的定性模式:
    • 小批次可能在早期表现更好,但随着计算量的增长会被超越
    • 在论文图 1 中最大的数学运行中,将批次大小增加到 2048 个提示既稳定了训练,又产生了一个可以从高达 50k GPU hous 外推到最终 100k 点的拟合

每个提示的生成次数(固定总批次)(Generations per prompt (fixed total batch))

  • 对于固定的总批次,是分配更多提示还是每个提示分配更多生成次数更好?
    • 扫描每个提示的生成次数 8,16,24,32 并调整提示数以保持总批次固定,得到的拟合缩放曲线基本不变(附录 A.13)
    • 这表明在中等批次下,这种分配对于 A 和 B 都是次要选择
  • 在更大批次(例如,2k+)下可能会出现更明显的差异,论文将其留待未来工作

Related Work

  • 论文在本节中详细介绍了与论文研究最相关的两项工作
  • ProRL (2025a) 证明,在大型语言模型上进行长时间的强化学习微调(约 2000 个优化步骤,批次大小 64),使用混合推理任务进行 16K GPU hous ,可以发现超越模型基础能力的新解决方案策略
    • 这种更长的训练方案在 1.5B 模型上带来了显著收益,在某些基准测试中媲美更大模型的性能
    • ProRL 的贡献在于特定的稳定性启发式方法(KL 正则化、策略重置、熵控制等),以实现 1.5B 模型的高性能
  • Alibaba Group 等 (2025c), Part I: Tricks or Traps? A Deep Dive into RL for LLM Reasoning 提供了一个互补的视角
    • 在 Qwen-3 4B/8B (2025) 上的一致条件下消融了各种设计选择,并提出了一种极简组合 LitePPO
      • LitePPO 在较小规模的模型和计算量上优于更复杂的方法,如 GRPO (2024) 和 DAPO (2025)
    • 这产生了有价值的算法见解,但重点是比较实证发现,而不是缩放行为
  • 这些工作都没有研究这些方法的”缩放(scaling)”特性
    • 事实上,主要的比较是在下游评估上进行的,这可能不是研究可预测缩放的正确指标
    • 正如在预训练和论文这里的工作中所做的那样,论文研究分布内留出验证集上的性能
  • 与上述提到的相关工作相比,论文的工作开发并验证了一个具有预测拟合的计算-性能框架,同时在更大的计算预算(例如,比 ProRL 大 6 倍)和模型规模上运行
  • 论文的研究结果产生了一个近乎 SOTA 强化学习 Recipe ,可以可预测地扩展到超过 100,000 GPU hous 而没有任何稳定性问题
  • 其余相关工作推迟到附录 A.1

Discussion & Conclusion

  • 在这项工作中,论文研究了用于大型语言模型强化学习的各种技术的缩放特性,以寻求一个可预测、可扩展的 Recipe
  • 基于此使命,论文推导出一种为验证集准确率拟合预测性缩放曲线的方法,使论文能够量化强化学习方法的渐近性能和计算效率
  • 使用这种方法论,论文的主要贡献是仔细进行了一系列消融实验,涉及构成强化学习 Recipe 的若干算法选项
    • 对于每次消融,论文尽可能选择具有更高渐近性能的选项,否则选择效率更高的选项
  • 结合这些选择产生了 ScaleRL Recipe ,它在论文的实验中比所有现有 Recipe 缩放得更好
  • 以下几点观察值得注意:
    • 计算缩放外推 (Compute scaling extrapolation)
      • 论文缩放方法论的一个重要见解是,我们可以系统地使用较小规模的消融来预测更大规模的性能
      • 这使论文能够创建最终的可扩展 Recipe
    • 最重要的决策 (Most important decisions)
      • 根据论文的消融实验, Off-policy 算法、损失函数和模型精度是最重要的决策
      • 其他每个决策单独影响不大,但正如论文从留一法实验中看到的,当它们全部组合时,仍然具有一些累积影响(在效率方面)
    • 渐近性能与效率 (Asymptotic performance vs. efficiency)
      • 对于论文许多消融实验,论文发现更好的选项同时提高了效率和渐近性能,但情况并非总是如此(例如,对于 FP32,图 4(b))
        • 当从基线方法开始进行”正向”消融时,论文首先且最主要地选择渐近性能
      • 有趣的是,当从 ScaleRL Recipe 进行”反向”留一法消融时,论文发现每个决策对渐近性能的影响非常小,但算法的每个组件似乎都有助于提高效率
        • 这表明变化的累积效应是相当鲁棒的
    • 泛化 (Generalization)
      • 虽然论文报告了下游评估的迁移情况,但论文的主要重点是研究预测性缩放,这是通过在训练提示的留出数据集上的分布内性能曲线来表征的 (2022;2025)
        • 这仍然留下了大型语言模型从训练分布到留出测试集的泛化能力如何的问题
      • 虽然对泛化的全面描述超出了论文工作的范围,但论文确实观察到分布内验证与下游泛化性能之间的相关性
      • 但有一些算法选择似乎更有助于泛化,论文在此想指出,包括:
        • 更大的批次大小(章节 A.14)
        • 减少截断(章节 A.15)
        • 更长的生成长度(第 5 节,图 9)
        • 更大的模型规模(第 5 节,图 1)
    • 多任务强化学习 (Multi-task RL)
      • 虽然论文的实验主要集中在数学领域,但论文也在多任务强化学习训练下评估了 ScaleRL
      • 如图 11 所示,在数学和代码上联合训练为每个领域产生了清晰、平行的幂律趋势,扩展的运行保持与外推曲线对齐
      • 虽然论文的初步结果是有希望的,但彻底研究具有不同训练数据混合的多任务强化学习的计算缩放可预测性将是很有趣的

Future work

  • 一个自然的下一步是为强化学习在预训练计算、模型大小和强化学习训练数据方面推导预测性的”Scaling Laws”
  • 未来的研究还可以包括其他强化学习计算缩放的轴(Axes),例如结合结构化或密集奖励 (2025b;2024) 和更计算密集的生成验证器 (2025a),以找到强化学习训练的最佳计算分配
  • 最后,这里介绍的方法论框架可以应用于研究其他后训练机制的缩放行为,包括多轮强化学习、智能体交互和长形式推理
  • 强化学习中有许多设计选择,因此作者认为论文的 ScaleRL Recipe 并非故事的终点
    • 作者希望论文对可扩展强化学习的关注以及预测可扩展性的方法能够激励未来的工作,进一步推动大型语言模型强化学习的前沿
    • 为了使未来的研究能够拟合计算-性能强化学习缩放曲线,论文在 www.devvrit.com/scalerl_curve_fitting 发布了一个最小代码库

附录 A:Appendix

A.1 Extended Related Work

  • 近期涌现的一波工作将强化学习应用于提升大语言模型的推理能力;这些工作通常能在具有挑战性的任务上取得 SOTA 结果 (2024; 2025; 2025; 2025)
    • OpenAI 的 o1 系列模型证实了大规模强化学习能显著增强长程推理能力,但并未发布这些模型训练方式的任何细节
    • Deepseek R1(以及 R1-Zero)(2025) 提供了首个关于主要通过强化学习训练高性能长思维链模型的全面研究,记录了在扩展强化学习下不依赖奖励模型 (2023) 或蒙特卡洛树搜索 (2024) 而出现的涌现行为
  • 这波推理发展浪潮中最早被广泛引用的 RLVR(可验证奖励)算法是 GRPO
    • GRPO 是一种无评论员、分组相对的策略梯度方法,采用 PPO 风格的裁剪,用分组基线替代学习的价值基线,以降低计算成本并稳定长思维链的信用分配
    • 虽然 GRPO 催化了快速进展,但后续工作记录了其局限性( Token-Level 裁剪、模型崩溃风险)并推动了不同分组或序列级别的变体 (2025; 2025; 2025; 2025)
  • DAPO 提出了解耦裁剪和动态采样策略优化
    • DAPO 在 GRPO 目标中解耦了 \(\epsilon_{\text{low} }\) 和 \(\epsilon_{\text{high} }\) 裁剪,并对 \(\epsilon_{\text{high} }\) 进行 Clip-Higher操作以避免熵崩溃
    • DAPO 在给定批次中对提示进行动态采样,以避免方差(或优势)为零的样本,这些样本对策略梯度没有贡献
    • DAPO 采用 Token-Level 损失聚合(注:GRPO 使用样本级损失平均)
    • 通过以上这些修改,DAPO 能够在避免强化学习训练中熵崩溃的同时超越原始 GRPO 基线
  • 与此同时提出的 VAPO 是一种专为长思维链设计的价值增强型 PPO,具有强大的稳定性,并优于像 GRPO 和 DAPO 这样的无价值基线
    • VAPO 结合了价值预训练和来自 VC-PPO (2025) 的解耦广义优势估计、来自 DAPO 的损失目标修改,并提出了长度自适应的 GAE,从而形成了一个开放的 Recipe VAPO,该 Recipe 已被用于训练 Seed1.5-thinking (2025) 中的大型混合专家模型
    • 类似地,其他技术报告如 Magistral (2025)、Kimi-k1.5 (2025)、Minimax-01 (2025) 详细介绍了他们强化学习训练 Recipe 的各种细节,但并未分享关于其设计选择为何优于基线的广泛实验

A.2 面向大语言模型的强化学习:GRPO 和 DAPO (RL for LLMs: GRPO and DAPO)

GRPO (2024)
  • GRPO 将 PPO (2017) 应用于具有可验证奖励的大语言模型微调
  • 对于给定的提示 \(x\),旧策略 \(\pi_{\text{gen} }(\theta_{\text{old} })\) 生成 \(G\) 个候选补全 \(\{y_i\}_{i=1}^G\),每个补全被分配一个标量奖励 \(r_i\)
  • 为了强调组内的相对质量,奖励被归一化为
    $$
    \hat{A}_i=\frac{r_i-\text{mean}(\{r_j\}_{j=1}^G)}{\text{std}(\{r_j\}_{j=1}^G)+\epsilon}.
    $$
  • 每个长度为 \(|y_i|\) 的补全 \(y_i\) 通过比率在 Token-level 上做出贡献
    $$
    \rho_{i,t}(\theta)=\frac{\pi_\text{train}(y_{i,t} \mid x,y_{i,<t},\theta)}{\pi_{gen}(y_{i,t} \mid x,y_{i,<t},\theta_{\text{old} })}.
    $$
  • GRPO 目标在补全和 Token 之间进行平均:
    $$
    \mathcal{J}_{\text{GRPO} }(\theta)=\mathbb{E}_{x\sim D,\atop\{y_i\}_{i=1}^G,\sim\pi_{\text{gen}(\cdot \mid x,\theta_{\text{old} })} }\left[\frac{1}{G}\sum_{i=1}^G\frac{1}{|y_i|}\sum_{t=1}^{|y_i|}\min\Big(\rho_{i,t}(\theta)\hat{A}_i,\ \operatorname{clip}(\rho_{i,t}(\theta),1\pm\epsilon)\hat{A}_i\Big)\right].
    $$
  • GRPO 像 PPO 一样保留了 Token-level 的策略比率,同时使用序列级别、分组归一化的优势来在稀疏奖励下稳定学习
DAPO
  • DAPO (2025) 通过两个关键修改扩展了 GRPO
  • 第一个改进点:用 非对称裁剪 替代了对称裁剪,对向上和向下的偏差使用不同的阈值:
    $$ \text{clip}_{\text{asym} }(\rho,a)=\text{clip}(\rho,,1-\epsilon^{-},1+\epsilon^{+})$$
    • 其中 \(\epsilon^{-}\) 和 \(\epsilon^{+}\) 是超参数
  • 第二个改进点:DAPO 将聚合方案更改为在 提示级别 操作
    • 对于给定的提示 \(x\sim D\),旧策略产生 \(G\) 个补全 \(\{y_i\}_{i=1}^G\),其优势为 \(\{\hat{A}_i\}\)(公式 (5))
    • 令 \(T=\sum_{i=1}^G|y_i|\) 表示所有补全的总 Token 数
    • Token-level 比率如公式 (2) 所示
  • DAPO 代理目标为
    $$
    \mathcal{J}_{\text{DAPO} }(\theta)=\mathbb{E}_{x\sim D,\atop\{y_i\}_{i=1}^G\sim\pi_{\text{gen}(-|x,\theta_{\text{old} })} }\left[\frac{1}{T}\sum_{i=1}^G\sum_{t=1}^{|y_i|}\min\Bigl(\rho_{i,t}(\theta)\hat{A}_i,\ \text{clip}_{\text{asym} }(\rho_{i,t}(\theta))\hat{A}_i\Bigr)\right].
    $$
  • 这种提示级别的归一化确保每个 Token 对提示的损失贡献相等,无论其采样补全的数量或长度如何
  • DAPO 还引入了在训练期间动态丢弃批次中方差为零的提示,并用更多提示填充批次直到批次满员(论文在此跳过该更改,因为其效果类似于拥有更大的批次大小)

A.3 Training Setup

  • 数据集
    • 对于小规模监督微调,论文使用精心策划的推理轨迹数据混合
    • 论文通过移除琐碎的提示、丢弃超过 12\(k\) 个 Token 的解决方案轨迹,并使用 AIME 2024/2025 和 MATH-500 (2021) 基准进行去污染来过滤此数据集
    • 对于强化学习阶段,论文在大多数运行中使用 Polaris-53K 数据集 (2025);
    • 对于同时包含数学和代码的运行,使用 Deepcoder 数据集 (2025)
  • 监督微调
    • 论文使用 2M Token 的批次大小、最大序列长度 12288 和学习率 \(3\times 10^{-5}\),在 32 个 H100 GPU 节点上使用 AdamW 优化器 (2019) 运行监督微调,总共大约 4 个轮次和 32B Token
  • 强化学习
    • 论文在强化学习训练期间分配 14k 的生成预算,其中 12k Token 分配给中间推理(“思考”),随后 2k Token 用于最终解决方案和答案
    • 论文在每个批次中采样 48 个提示,每个提示有 16 个生成(即每个梯度更新步骤的总批次大小为 768 个回复)
    • 奖励分别给予正确和错误的轨迹 \(\pm 1\)
    • 使用恒定学习率 \(5\times 10^{-7}\)
    • AdamW 优化器 (2019),其中 \(\epsilon=10^{-15}\),权重衰减为 0.01(AdamW 中的默认值)
      • 注:较低的 \(\epsilon\) 是为了避免梯度裁剪(epsilon 下溢)(2023)
    • 100 步的线性预热
  • 数学问题评估:
    • 论文使用自动化检查器,如 Sympy (2017) 或 Math-Verify 来评估数学问题在剥离思考轨迹(\(<\)think\(>\)\(\cdots\)\(<\)/think\(>\))后最终答案的正确性
  • 代码问题:
    • 对于涉及单元测试和期望输出的代码问题,论文使用自定义代码执行环境
  • 硬件:
    • 论文使用 80 个 Nvidia GB200 GPU 进行单次运行
      • 3.5-4K GPU hous(用于在第 3.2 节中建立不同的设计选择)
      • 16K GPU hous 用于留一法实验(第 4 节)
      • 30k-100K GPU hous 用于论文更大规模的运行(第 5 节)
    • 论文在 GPU 之间采用 Generator-Trainer 分离
      • 对于 80 个 GPU 的实验,论文将其中的 64 个设置为 Generator ,负责使用优化的推理代码库生成推理轨迹
      • 其余的 16 个 GPU 作为 Trainer ,接收生成的轨迹,执行策略更新,并定期将更新后的参数广播回 Generator

A.4 拟合什么曲线? (What curve to fit?)

  • 预训练曲线通常使用幂律方程进行拟合 (2025; 2020; 2025)
  • 在论文的情况下,这将性能建模为 \(R_C=A-D/C^B, C\geq C_0\),其中 \(D\) 是常数,\(C_0\) 标志着超出该阈值后定律成立的计算量阈值
    • 直观地说,这意味着计算的每次倍增都会带来性能的恒定比例增益
  • 但对于强化学习后训练,论文发现 S 形曲线(公式 (1))更合适,原因如下
    • 首先,对于有界指标,如准确率或奖励,S 形曲线提供了更好的预测拟合 (2024; 2022);论文观察到同样的情况,能够准确外推到更高的计算量(图 1)
    • 其次,幂律在低计算量时是无界的,并且通常只在超过阈值 \(C_0\) 后才进行拟合
      • 在强化学习中,总训练步数要少得多(例如,图 1 中只有约 75 个评估点可供拟合),丢弃早期点会进一步减少本已有限的拟合数据
    • 第三,根据经验,S 形拟合比幂律拟合更加稳健和稳定
      • 具体来说,考虑图 1 中所示的在 8B 稠密模型上进行的 100k GPU hous 运行
        • 当论文在 1.5k-50k GPU hous 之间拟合幂律曲线时,它预测的渐近性能为 \(A=1.0\),这显然是错误的(实际曲线在 0.65 附近饱和)
        • 相比之下,S 形拟合给出了 \(A=0.645\) 的准确预测
      • 此外,幂律拟合对所选拟合区间高度敏感:
        • 在 (5\(\text{k}\),50\(\text{k}\)) GPU hous 上拟合则得到 \(A=0.74\),而 S 形拟合仍然稳健,并且仍然预测 \(A=0.645\)
      • 幂律模型只有在专门在高计算量区间(例如,30k-60k GPU hous )拟合时才能恢复正确的渐近线
        • 但论文的目标是从低计算量区间预测大规模性能,而在这些区间无法获得如此长的运行
  • 考虑到这些因素,论文在整个分析中使用 S 形形式
    • S 形曲线捕捉了收益递减规律,即在低计算量区间增长缓慢,在高效缩放的中等区间急剧加速,然后在计算量高时饱和,接近有限的性能上限
  • 需要注意的一点是,在高计算量区间,S 形曲线的行为与幂律相同
    • 具体来说,我们可以对 S 形曲线进行以下近似:
      $$
      \begin{align}
      R_C &=R_0+\frac{A-R_0}{1+(C_{mid}/C)^B} \quad \text{(来自公式 (1) 的 S 形曲线)} \\
      \implies R_C &\approx R_0+(A-R_0)\left(1-\frac{C^{B}_{mid} }{C^{B} }\right) \quad \text{(对于 \(C>>C_{mid}\), 高计算量区间(high compute regime))} \\
      &=A-\frac{(A-R_0)C^{B}_{mid} }{C^{B} } \\
      &=A-\frac{D}{C^{B} }
      \end{align}
      $$
    • 其中 \(D=(A-R_0)C^{B}_{mid}\)
    • 这与本节开头提到的幂律形式相同

A.5 Fitting scaling curves

  • 论文将公式 (1) 中的 S 形定律方程拟合到论文留出验证集上的平均奖励
    • 包含从 Polaris-53k (2025) 数学数据集中留出的 1,000 个提示,每 100 个训练步骤进行一次评估,每次在留出的 1,000 个提示上采样 16 个生成
  • 直接拟合所有三个参数 \(\{A,B,C_{mid}\}\) 具有挑战性
    • 所以论文执行网格搜索,遍历 \(A\in\{0.450,0.455,0.460,\ldots,0.800\}\) 和 \(C_{mid}\in[100,40000]\)(搜索 100 个线性分隔的值),并对每个候选的 \(A,C_{mid}\) 拟合 \(B\)
      • 在此网格上最佳拟合(通过残差平方和衡量)作为最终曲线
    • 论文使用 SciPy 的 curve_fit 和默认初始化;改变初始化策略产生了相同的结果
    • 为了使未来的研究能够拟合计算性能强化学习缩放曲线,论文在 www.dewrit.com/scalerl_curve_fitting 发布了一个最小的代码库
  • 为了估计论文拟合的误差范围,论文训练了三个独立的 ScaleRL 运行,批次大小为 768,生成长度为 14k(如第 4 节所用),如图 8a 所示
    • \(A\) 的拟合值最多变化 \(\pm 0.015\),表明在渐近性能估计上 0.02 是一个合理的误差范围
    • 估计拟合值 \(B\) 的误差范围很困难,因为具有不同 \(A\) 值的不同算法可能对 \(B\) 有不同的误差范围
    • 为了比较算法的目的,我们可以安全地推断,如果两种方法达到相似的 \(A\) 值(在 0.02 范围内),那么当使用 \(A\) 值的平均值重新拟合时,具有较高 \(B\) 值的方法在可扩展效率方面至少同样好

A.6 Comparing algorithms

  • 与大规模预训练中的观察一致,损失在初始急剧下降后进入可预测的幂律衰减阶段 (2025),论文在强化学习中也观察到类似的两阶段行为
  • 平均奖励在约第一个 epoch(约 1k 步,或对于大多数运行约 1.5k GPU hous )期间快速、几乎线性地增加,之后曲线遵循 S 形定律行为(见图 15 查看“S 形”曲线)
  • 论文的 S 形定律拟合应用于训练曲线的后一部分
  • 与预训练不同,论文的主要目标不是预测固定 Recipe 的性能,而是识别哪些算法和设计选择能够可靠地扩展,并设计出具有可预测性的算法
  • 实现高度稳健的拟合通常需要具有数百或数千个评估点的非常大的运行,这在论文的设置中是不切实际的,原因有两个
    • 第一个原因:在此规模上运行所有消融实验在计算上是不可行的
    • 第二个原因:论文比较的许多强化学习算法本身无法扩展到如此极端的预算:它们通常更早饱和,甚至由于不稳定性而在计算量增加时性能下降
      • 例如,论文的基线方法(第 3.2 节)在超过约 3500 GPU hous 后变得不稳定,因为过长的生成截断超过了生成的 10%,降低了有效批次大小
      • 关于此点的更多讨论见第 A.15 节
  • 当论文在第 3.2 节中跨不同轴进行消融时,论文发现了能在更高计算量下提高稳定性的设计选择
    • 一些消融变体可以进一步扩展,例如,DAPO 中 \(\epsilon=0.26\) 的情况下约 5k GPU hous ,使用 FP32 精度修复(第 3.2 节)的情况下约 6k GPU hous ,以及 CISPO 的情况下约 7k GPU hous
    • 结合论文最佳的设计选择是一个稳定且可扩展的 Recipe ,这使论文能够以每次运行约 1600 GPU hous 的预算进行留一法实验
      问题:怎么还变少了?

A.7 Robustness of fits

  • 对于稳定且可扩展的实验,包括从第 4 节开始的所有运行,改变拟合区间(例如,包含或排除初始 1.5k GPU hous 范围)会产生类似的可预测结果
    • 例如,在 8B 稠密模型上的 100k GPU hous 运行中,在 (1.5\(\text{k}\),50\(\text{k}\)) 上拟合得到 \(B=1.70\),\(A=0.645\),而 (0,100\(\text{k}\)) 得到 \(B=1.56\),\(A=0.655\),(0,50\(\text{k}\)) 得到 \(B=1.7,A=0.645\),以及 (5\(\text{k}\),50\(\text{k}\)) 得到 \(B=1.67\),\(A=0.645\)。在这些区间内,参数值保持在预期误差范围内(第 7 节)
  • 此外,论文跳过低计算量区间,因为早期训练阶段,尤其是在第 3.2 节中不太稳定的设置中,常常由于短暂的不稳定性而过早达到平台期或偏离 S 形趋势(见附录 A.6, A.15)
    • 排除此区域可以使拟合专注于中高计算量范围,在该范围内饱和行为更清晰、更一致
  • 1.5k GPU hous 阈值是根据经验选择的启发式方法:
    • 它大约对应于第 3.2 节中大多数实验的一个 epoch
    • 较大的截止值减少了拟合点的数量,而较小的截止值常常引入噪声
    • 论文发现 1.5k GPU hous 能在拟合稳定性和样本覆盖率之间提供最佳平衡,这与在预训练缩放分析和拟合中跳过低 FLOPs 区间的做法一致 (2025)

A.8 Interpreting Sigmoidal Curves

  • 图 3 展示了一个示例拟合,说明了参数 \(A\)、\(B\) 和 \(C_{\text{mid} }\) 的影响
  • 通过额外的图示扩展了这一点:图 12a、图 12b 和图 13a 分别改变了 \(B\)、\(C_{\text{mid} }\) 和 \(A\),同时保持其他参数不变
  • \(B\) 和 \(C_{\text{mid} }\) 主要影响缩放的效率 ,而 \(A\) 决定了在大计算量下可实现的渐近性能
  • 在图 13b 中,论文看到一个两个运行的案例,其中一个效率高得多,因此显示出初期有希望的收益,但收敛到较低的渐近线,而另一个进展较慢,但由于更高的 \(A\) 最终超过了前者
  • 在实践中,缩放策略应优先考虑提高渐近上限 \(A\) 的设计选择,然后才优化效率参数,如 \(B\) 或 \(C_{\text{mid} }\)

A.9 Forward and LOO Ablations

  • 论文在图 14a-14b 中展示了第 3.2 节的额外结果
  • 图 15 中绘制了第 4 节中关于通过率与计算量的留一法实验

A.10 Controlling generation length

  • 推理强化学习中一个常见的担忧是控制爆炸性增长的生成长度,这会损害训练效率和稳定性(附录 A.15)
  • 论文考虑两种方法:
    • (a) 中断(Interruptions),用于像 GLM-4.1V (2025) 和 Qwen3 (2025) 这样的工作;
    • (b) 长度惩罚(Length penalties),用于像 DAPO (2025)、Kimi (2025)、Magistral (2025) 和 Minimax-M1 (2025) 这样的工作
中断,Interruptions
  • 通过附加一个标记性短语(例如“Okay, time is up. Let me stop thinking and formulate a final answer \(<\)/think\(>\)”)来强制停止生成,指示模型终止其推理并产生最终答案
  • 在论文的设置中,中断 Token 被随机放置在 \([10k,12k]\) Token 长度之间,以诱导对不同生成长度的泛化
Length penalties
  • 用于重塑奖励
  • 遵循 DAPO (2025),论文使用容忍区间 \(L_{\text{cache} }\) 来惩罚过长的补全:
    $$
    R_{\text{length} }(y)=clip\left(\frac{L_{\max}-|y|}{L_{\text{cache} } }-1,-1,0\right)
    $$
  • 此惩罚仅添加到正确的轨迹上,以阻止过长的生成
    • 在长度惩罚实验中,论文设置 \(L_{\max}=14\text{k}\) 个 Token 和 \(L_{\text{cache} }=2\text{k}\) 个 Token
  • 在第 4 节中,论文在 16\(\text{k}\) GPU hous 的规模上比较了长度惩罚和中断
  • 在论文的最终 ScaleRL Recipe 中用长度惩罚替换中断不能提高性能

A.11 PipelineRL

  • 使用基线设置,论文在 PipelineRL 中消融了 Off-policy 参数(图 4(b))
  • Off-policy 度为 4 和 8 的表现同样好,论文在第 3.1 节更新基线时采用 8 作为默认设置
    • 为什么 8 比 1 效果好?是因为横坐标不是 step,而是 GPU 时间吗?
  • 为什么 PipelineRL 始终优于经典的 PPO-off-policy 方法(第 3.1 节和 第 4 节)?
    • 论文将其归因于其与 On-policy 训练更紧密的对齐
    • 在 PPO-off-policy 中,生成和训练交替进行:
      • Trainer 严格处理与所选参数 \(k\) 一样 Off-policy 的批次,基于过时的 Rollout 更新进行更新
      • PipelineRL 以流式方式运行:
        • 一旦批次可用,它就传递给 Trainer ;
        • 同样,一旦模型更新就绪,它就立即共享回 Generator ,Generator 立即使用它(包括在部分生成的轨迹的延续中)
      • 这种紧密的反馈循环使训练更接近 On-policy 状态,减少了 Generator 和 Trainer 分布之间的不匹配
  • 重要的是,这种区别影响了缩放曲线的渐近性能 \(c\),而不仅仅是效率指数 \(b\)
    • 很少有轴能以这种方式移动渐近线,使得 Off-policy 算法的选择成为强化学习后训练中最关键的设计决策之一

A.12 熵曲线:缩放批次大小 (Entropy Curves: Scaling Batch Size)

  • 论文在整个训练过程中跟踪了留出验证集上的熵
    • 在所有实验中(包括批次大小、任务数量、生成长度和模型规模的变体)论文观察到熵总体一致下降
  • 一个有趣的发现是,熵可能并不总是能提供对性能的预测性洞察,正如最近一些工作如 (2025) 所提出的那样
    • 在第本节中,论文绘制了批次大小为 768 和 2048 的 ScaleRL 运行的熵
      • 2048 批次大小的运行在每个阶段都实现了更强的下游性能(图 10b),但两个运行在每一步都遵循几乎相同的熵轨迹(第 A.12 节)
        • 这突出了一个重要点,尽管熵有时被用作探索的代理指标,但仅仅保持较高的熵并不能转化为更好的泛化
      • 相反,较大的批次每一步减少了有效探索,类似于较小的批次,但仍然产生了显著更好的性能——强调了批次大小是一个重要的决定性因素
  • 总的来说,论文的发现表明,虽然熵在训练期间持续下降,但它不一定是下游性能的可靠预测指标
    • 这一观察结果强化了在旨在提高训练分布以及下游任务分布性能时,除了熵动态之外,还需要关注算法和缩放选择(例如,批次大小、 Off-policy 方法)的必要性

A.13 Scaling on multiple axes

  • 在图 17 中提供了剩余的不同轴缩放的图表(问题:如何理解这里的轴?是指不同的维度的超参)
  • 在图 18 中提供了相应的下游评估
  • 论文还在表 1 中提供了 \(A,B,C_{mid}\) 的值

A.14 Downstream performance

  • 在图 1、9、10b 和 18 中报告了一组具有代表性的下游评估曲线
  • 这些包括具有批次大小 \(\{512,768,2048\}\) 的 ScaleRL 运行、具有 32k 生成长度的长上下文训练运行、大模型(Scout)训练运行、多任务运行(数学 + 代码)以及不同每个提示生成数量(固定批次大小)的运行
  • 对于每种设置,论文绘制了性能与计算量的关系
  • 结论:对于像更大批次大小、更长生成长度和更大模型大小这样的实验,下游性能更好(与验证集曲线的顺序相似)

A.15 Truncations and training instabilities

  • 在论文的所有实验中,论文发现训练不稳定性通常与截断有关
    • 随着生成长度的增加,许多强化学习运行表现出波动的截断率,有时在训练过程中增加
  • 在批次大小 768 的情况下,论文观察到 10-15% 范围内的截断通常会破坏训练稳定性 ,性能下降且无干预就无法恢复
    • 例子包括图 2 中扩展的 GRPO 运行,其中不稳定性与上升的截断率相关,以及第 3.2 节中使用的更新基线
  • 相比之下,ScaleRL 运行更加稳定
    • 在 8B 模型上,超过 90% 的训练时间内截断率保持在 5% 以下
    • 在批次大小 2048 时,截断率略高,偶尔接近约 7%
      • 这种增加主要归因于训练期间观察到的更长的平均生成长度,这自然增加了超过预算的机会
      • 但,即使排除截断样本后,有效批次仍然很大,训练稳定性得以保持
    • 直观地说,更大的生成长度预算应有助于减少截断
    • 使用 34k 生成长度(批次 768)进行训练保持稳定(截断率短暂飙升至约 4%,但迅速降至 2% 以下)
  • 更大的模型更稳健
    • 在 Scout 运行中,截断率始终低于 2%,并且在 > 90% 的训练步数中低于 1%
    • 这可能反映了更大模型调节生成长度的固有能力以及它们更强的指令遵循能力,这使得中断信号更有效
  • 总结:论文建议实践者密切监控截断率
  • 论文的发现表明,高截断率是不稳定性的可靠警告信号 ,而更大的模型、更高的生成预算和谨慎的设计选择(如在 ScaleRL 中)可以显著降低这种风险

A.16 Comparing Prevalent Methods

  • 在图 2 中,论文将一些流行的训练 Recipe 与 ScaleRL 进行了比较,论文在此简要描述这些现有 Recipe
DeepSeek (GRPO)
  • 这个 Recipe 主要遵循 DeepSeek (2025) 的工作
  • 论文使用 GRPO 作为损失函数(第 A.2 节),其中 \(\epsilon_{min}=\epsilon_{max}=0.2\),样本平均损失聚合,以及 PPO-offpolicy-8 算法
  • 训练在 6k GPU hous 后由于截断(第 A.15 节)变得不稳定
Qwen2.5 (DAPO)
  • 这个 Recipe 遵循 DAPO (2025),包括 DAPO 损失函数(附录 A.2),其中 \(\epsilon_{min}=0.2,\epsilon_{max}=0.26\)(附录 A.17.1)
    • 这个 Recipe 使用 PPO-offpolicy-8 和提示平均损失聚合
    • 与原始 DAPO 论文 (2025) 的唯一区别是关于动态填充批次
      • DAPO 丢弃方差为零的提示,并采样更多提示直到批次满员
      • 在论文的代码库中,这效率不高
        • 因为对于 PPO-offpolicy 算法,Generator 会预先决定每个 Generator 将为 #prompts/#generators 生成 Rollout
        • 如果某个特定的 Generator 有更多方差为零的提示 ,它会采样更多的提示来完成其 #prompts/#generators 的份额
        • 这可能导致其他 Generator 停滞和整体速度减慢
      • 为了解决这个问题,论文保持一个更大的批次大小 1280(80 个提示,每个 16 个生成),并从批次中丢弃方差为零的提示
      • 论文注意到,丢弃后,有效批次仍然大于 768,即论文用于 ScaleRL 的大小
Magistral
  • 这指的是 (2025) 中使用的 Recipe
  • 这个 Recipe 包括与 DAPO 类似的 Recipe ,主要区别在于使用 PipelineRL 作为 Off-policy 算法
MiniMax
  • 这指的是 (2025) 中使用的 Recipe
  • 这个 Recipe 使用 CISPO 损失、LM 头部的 FP32 精度修复、PPO-offpolicy 算法和提示平均
  • 与 DAPO 类似,它也丢弃方差为零的提示,因此论文也给它一个更大的批次大小 1280

A.17 Loss Type - Stability and Robustness

  • GRPO/DAPO 风格的损失对裁剪比率超参数 \(\epsilon_{\text{max} }\) 的选择高度敏感;CISPO 和 GSPO 显示出远更强的稳健性
    • 例如,在附录 A.17.2 中,将 CISPO 的 \(\epsilon_{\text{max} }\) 在 \(\{4,5,8\}\) 之间变化,性能没有显著差异
  • 对于 GSPO ,原始论文 (2025) 中使用的 \(10^{-4}\) 裁剪尺度在论文的设置中效果不佳
    • 论文在更广泛的尺度上进行了消融,发现确定了正确的数量级(例如,\(4\times 10^{-3}\) 及更高)以后,性能就稳定了,并且对细粒度的变化(例如,\(\{4\times 10^{-3},5\times 10^{-3}\}\))基本不敏感
A.17.1 DAPO clipping ratios
  • 在本节中,论文分析了 DAPO 损失函数(公式 (8))中裁剪阈值 \(\epsilon_{\text{max} }\) 的作用
  • \(\epsilon_{max}\) 的超参数敏感性已在先前工作中观察到
    • 例如,GRPO 通常设置 \(\epsilon_{\text{max} }=0.2\),而 DAPO 使用 \(0.28\)
  • 除了调整敏感性之外,论文发现 \(\epsilon_{\text{max} }\) 直接改变了算法的缩放行为
    • 随着 \(\epsilon_{\text{max} }\) 增加,终端奖励 \(A\) 增加,直到达到一个最佳范围,之后 \(A\) 再次下降
  • 这是一个显著的效果:与许多仅改变收敛速度的超参数不同,\(\epsilon_{\text{max} }\) 控制着渐近误差本身
A.17.2 CISPO Clipping Ratios
  • 论文消融了 CISPO 的较高裁剪比率,将较低裁剪比率固定为 \(0\)(图 19b)
  • 在很宽的值范围内,论文发现性能差异很小,表明 CISPO 对这个超参数基本不敏感
  • 这种稳健性反映了论文对 GSPO 的发现(第 A.17.3 节),并且与 DAPO/GRPO 风格的目标形成对比,后者对裁剪阈值的精确选择高度敏感
  • 这种在超参数变化下的稳定性使 CISPO 成为大规模训练中默认使用的有力候选者
A.17.3 GSPO ablations
  • 论文消融了 GSPO 中使用的裁剪比率尺度,如图 20a 所示
  • GSPO 论文 (2025) 中给出的默认 \(10^{-4}\) 尺度对论文的 8B 模型缩放效果不是最好
  • \(10^{-3}\) 尺度的表现与其他替代方案一样好,或者更好(图 20a)
  • 给定这个尺度,论文进一步将上裁剪比率在 \(\{4\times 10^{-3},5\times 10^{-3}\}\) 之间变化,并发现 \(\{5\times 10^{-3}\}\) 产生了稍好的拟合(图 20b)
  • GSPO 对裁剪比率的选择相当稳健
    • 确定了正确的尺度以后,大多数附近的值甚至更大的尺度表现相似
    • 这种稳健性与 DAPO 风格的损失形成鲜明对比,后者对上裁剪比率的精确值高度敏感,如第 3.2 节所述
A.17.4 GSPO vs CISPO
  • 尽管具有超参数稳健性,但论文遇到了 GSPO 的稳定性问题
    • 在多次情况下,GSPO 运行在训练中期发散,导致性能突然下降
    • 对于 8B 模型,从稳定检查点重新启动可以恢复,但此策略在更大的模型(如 Scout)上失败,尽管重复重置到稳定检查点,不稳定性仍然存在
    • 虽然论文尽最大努力检查了任何实现错误,但论文没有发现
  • 总的来说,虽然所有三种损失系列在调整好的设置下都可以具有竞争力,但 CISPO 在稳定性和对超参数的稳健性方面提供了最佳平衡 ,使其成为论文推荐的选择

Python——并发模型

本文介绍Python中的并发机制,并给出一种最简洁的Python并发库


使用协程(yield语句)

  • 实现随时暂停和开始
  • 完全串行的操作,无法实现时间上的并行,这里指的是不能同时进行某个操作
  • 与Go语言的协程不同,Python的协程更像是一个“生成器”

使用线程

  • 参考threading模块实现自己的线程

使用concurrent.futures

实现线程池模型

  • 实现一般的线程池模型,代码如下,关键代码仅仅两行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import time
    from concurrent import futures

    def sleep_one_second(key):
    time.sleep(1)
    return "[%s]Done" % key

    ml = "ABCDEFGHIJ"
    with futures.ThreadPoolExecutor(10) as executor:
    res = executor.map(sleep_one_second, ml)

    print([r for r in res])
  • 上面的代码可以在一秒内执行完成,因为共有10个线程并发

  • 在实现爬虫程序时,如果需要爬取的某些数据是相对独立的,那么我们完全可以用线程池实现,而不用使用复杂的线程模块*

    实现进程池模型

  • 仅仅需要修改futures.ThreadPoolExecutor为futures.ProcessPoolExecutor即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import time
    from concurrent import futures

    def sleep_one_second(key):
    time.sleep(1)
    return "[%s]Done" % key

    ml = "ABCDEFGHIJ"
    with futures.ProcessPoolExecutor(10) as executor:
    res = executor.map(sleep_one_second, ml)

    print([r for r in res])

进程与线程内存区别

对全局变量的访问对比
  • 线程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from concurrent import futures
    global_list = []

    def test_futures(range_num):
    global_list.append(range_num)
    print global_list
    return range_num

    with futures.ThreadPoolExecutor(8) as executor:
    res = executor.map(test_futures, range(10))

    print "the final global_list: %s" % global_list
    • 上面的代码输出如下:

      [0]
      [0, [10, 2]
      , 1[0, 1, 2, , 32]
      , 3, [04, 1], 2, 3, 4
      [0, , 5]
      1, [0, 21, 2, [3, , 3, 044, , 51, , 6, , 75]
      2, [0, 1, 63, 7, , 2, 3[40, , 8, , 4, 9, 155, , 6, 2]6, , 7
      , 8, 7, 9, ]3
      8, 4, , 59, 6, ]
      7, 8, 9]
      the final global_list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      the results: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • 进程:

from concurrent import futures
global_list = []

def test_futures(range_num):
    global_list.append(range_num)
    print global_list
    return range_num

with futures.ProcessPoolExecutor(8) as executor:
    res = executor.map(test_futures, range(10))

print "the final global_list: %s" % global_list
    • 上面的代码输出如下:

      [0]
      [1]
      [2]
      [3]
      [0, 4]
      [5]
      [6]
      [7]
      [1, 8]
      [2, 9]
      the final global_list: []
      the results: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • 原因分析

    • 线程之间共享地址空间,所以所有的线程线程访问同一个全局共享变量
    • 进程之间不共享地址空间,所以不同进程访问不同共享变量
    • 在程序中Process之间不共享地址空间,但是futures.ProcessPoolExecutor(max_workers)任务分配时受限与参数max_workers的影响,所以可以预估本地机器最多开启max_workers个进程,同一进程中地址空间共享,所以会有部分任务被分配给同一进程的不同线程,从而出现部分共享变量被不同任务访问到
    • 总结:
      • futures.ThreadPoolExecutor单进程多线程中全局变量共享
      • futures.ProcessPoolExecutor多进程多线程中每个进程内部的线程全局变量共享
      • 不同进程之间即使时全局变量也不能共享

Python中进程 VS 线程

  • Python中由于全局解释器锁(GIL)的存在,同一进程中的所有线程使用同一个解释器对象,所以它们无法真正实现并行
  • 所以在想要充分利用多核的时候,需要选择使用多进程
  • 更多信息参考Process和Thread分析

Python——分布式编程之mpi4py使用


整体说明

  • 分布式系统 是由一组通过网络相互连接的独立计算节点(或计算机)组成的集合,这些节点协同工作以实现一个共同的目标,实现高效的计算和处理
  • MPI(Message Passing Interface,消息传递接口) 是一个跨语言的并行计算通信协议,也是一个应用程序接口(API)标准,允许程序在分布式内存系统中高效地交换数据
    • MPI 定义了一套标准的库函数和语义规则,允许在非共享内存环境下的多个进程(通常运行在不同的处理器或计算节点上)通过发送和接收消息进行通信和协作
  • mpi4py 库是一个构建在 MPI 之上的 Python 库 ,主要使用 Cython 编写
    • Cython 的目标是让 Python 代码具备 C 语言的高性能,它是 Python 的一个超集,既支持 Python 语法,又能调用 C 函数、定义 C 类型变量,从而优化 Python 代码的性能
  • mpi4py 库以面向对象的方式提供了在 Python 环境下调用 MPI 标准的编程接口,这些接口构建在 MPI-2 C++ 编程接口基础之上,与 C++ 的 MPI 编程接口类似
  • mpi4py 库实现了很多 MPI 标准中的接口,包括点对点通信、集合通信、阻塞/非阻塞通信、组间通信等
    • 可以在不同进程间传递任何可被 pickle 序列化的内置和用户自定义 Python 对象

安装 mpi4py

Mac 环境安装

  • 安装 Homebrew(若已安装可跳过):

    1
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • 安装 Open MPI(建议使用 Open MPI,因为它在 Mac 上通常更容易配置):

    1
    brew install open-mpi
    • 这一步安装依赖比较多,需要一些时间
    • 安装完成后,你可以通过运行 mpiexec --version 来验证 Open MPI 是否正确安装
  • 安装 mpi4py:

    1
    pip install mpi4py
    • (常见报错解法)如果你的系统中有多个 MPI 版本,或者 pip 无法找到正确的 MPI 库,你可能需要设置 MPICC 环境变量来指定 MPI 编译器。例如:

      1
      2
      export MPICC=/opt/homebrew/bin/mpicc  # 根据你的 Open MPI 安装路径调整
      pip install mpi4py
    • 在安装 mpi4py 后运行以下命令来验证安装:

      1
      python -c "import mpi4py; print(mpi4py.__version__)"

Ubuntu 环境安装(待补充)


mpi4py 的使用

mpi4py 的操作总结(通信原语)

  • mpi4py提供了并行计算所需的各种通信操作,主要分为两类:
  • 点对点通信(Point-to-Point Communication) :
    • 在两个特定进程间进行数据交换
    • 主要操作:Send/send, Recv/recv, Isend/isend, Irecv/irecv, Sendrecv/sendrecv等
  • 集体通信(Collective Communication) :
    • 涉及通信组(communicator)中的所有进程
    • 提供更高效的全局数据操作
  • 不同集体通信操作对比
    操作类型 通信模式 数据流向 结果分布 典型应用场景
    Barrier/barrier 同步 无数据传输 无 进程同步
    Bcast/bcast 一对多 根 -> 所有 所有进程相同 分发配置参数
    Scatter/scatter 一对多 根 -> 各部分 每个进程不同 数据并行分解
    Gather/gather 多对一 所有 -> 根 仅根进程有结果 结果收集
    Allgather/allgather 多对多 所有 -> 所有 所有进程相同 全局信息共享
    Alltoall/alltoall 多对多 所有↔所有 每个进程不同 矩阵转置
    Reduce/reduce 多对一 所有 -> 规约 -> 根 仅根进程有结果 全局统计计算
    Allreduce/allreduce 多对多 所有 -> 规约 -> 所有 所有进程相同 需要全局结果的并行计算
    Scan/scan 多对多 前缀累积 每个进程不同 累积计算
    Reduce_scatter 多对多 先reduce再scatter 每个进程不同
  • 在很多地方中,表述也使用类似 All-Gather, All-to-All, All-Reduce 等来表达
  • All-Gather 和 All-to-All 的区别:
    • All-Gather 和 All-to-All 都是多对多发送数据
    • 发送数据上来看:
      • All-Gather 中,从任意进程的视角看,向不同进程发送的数据是相同的;
      • All-to-All 中则向不同进程发送不同数据,默认数据的维度和 world_size 相同,每个 receive_rank 进程会得到其他进程 send_data[receive_rank] 的数据
    • 结果上来看:All-Gather 操作后,各个进程最终的数据是相同的;All-to-All 操作后,不同进程最终的数据不同

mpi4py 使用演示

  • 以下 mpi4py 示例均以小 Pythonic 风格(小写) 为例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    from mpi4py import MPI
    import numpy as np
    import time

    def main():
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    print(f"进程 {rank} 启动,共有 {size} 个进程")

    # 1. barrier - 进程同步
    comm.Barrier() # 与 comm.barrier() 等价

    # 2. bcast - 广播数据
    if rank == 0:
    broadcast_data = {"message": "这是来自 rank=0 的 broadcast 消息", "value": 123}
    else:
    broadcast_data = None
    broadcast_data = comm.bcast(broadcast_data, root=0)
    print(f"进程 {rank} 收到 bcast 数据: {broadcast_data}")

    # 3. scatter - 分发数据
    if rank == 0:
    scatter_data = [f"from-0-index-{i}" for i in range(size)]
    else:
    scatter_data = None
    data = comm.scatter(scatter_data, root=0)
    print(f"进程 {rank} 收到 scatter 数据: {data}")

    comm.Barrier()
    # 4. gather - 收集数据
    if rank == 0:
    print(f"==开始测试更复杂的原语:==")
    comm.Barrier()
    local_data = np.arange(size * rank, size * (rank + 1), dtype=np.int32)
    print(f"进程 {rank} 原始数据: {local_data}")
    gathered_data = comm.gather(local_data, root=0)
    print(f"进程 {rank} 收到 gather 数据: {gathered_data}")

    # 5. allgather - 全收集数据
    all_gathered_data = comm.allgather(local_data)
    print(f"进程 {rank} 收到 allgather 数据: {all_gathered_data}")

    # 6. alltoall - 全对全数据交换
    recv_data = comm.alltoall(local_data)
    print(f"进程 {rank} 收到 alltoall 数据: {recv_data}")

    # 7. reduce - 规约操作
    recv_data = comm.reduce(local_data, op=MPI.SUM, root=0)
    print(f"进程 {rank} 收到 reduce 数据: {recv_data}")

    # 8. allreduce - 全局规约操作
    recv_data = comm.allreduce(local_data, op=MPI.SUM)
    print(f"进程 {rank} 收到 allreduce 数据: {recv_data}")

    time.sleep(0.1)
    # 高阶,任意维度的 allreduce 操作
    comm.Barrier()
    if rank == 0:
    print(f"==测试任意维度的 allreduce 操作:==")
    comm.Barrier()
    all_reduce_local_data = np.array([rank*i for i in range(size+3)], dtype=np.int32)
    print(f"进程 {rank} 原始 all_reduce_local_data 数据: {all_reduce_local_data}")
    recv_data = comm.allreduce(all_reduce_local_data, op=MPI.SUM) # 输入可以是任意维度
    print(f"进程 {rank} 收到 allreduce 数据: {recv_data}")
    comm.Barrier()

    time.sleep(0.1)
    # 9. scan - 前缀积累,按照 rank 累积
    recv_data = comm.scan(local_data, op=MPI.SUM)
    print(f"进程 {rank} 收到 scan 数据: {recv_data}")
    comm.Barrier()

    time.sleep(0.1)
    # 增加:reduce_scatter - reduce_scatter规约操作
    if rank == 0:
    print(f"==开始 reduce_scatter 演示==")
    local_data = np.array([rank*i for i in range(size)])
    reduce_scatter_recv_data = np.array(0, local_data.dtype) # 必须将发送数据和接受数据的类型对齐,否则会出现类型不匹配的错误
    print(f"进程 {rank} local_data 原始数据: {local_data}")
    comm.Barrier()
    print(f"进程 {rank} reduce_scatter_recv_data 原始数据: {reduce_scatter_recv_data}")
    comm.Reduce_scatter(local_data, reduce_scatter_recv_data, op=MPI.SUM)
    print(f"进程 {rank} 收到 Reduce_scatter 数据: {reduce_scatter_recv_data}")
    comm.Barrier()

    time.sleep(0.1)
    # 点对点通信函数演示
    if rank == 0:
    print(f"==开始点对点通信演示==")
    # 10. send 和 recv - 阻塞式发送接收
    if rank == 0:
    dest = 1
    message = f"from {rank}, 你好,进程 1!"
    comm.send(message, dest=dest)
    print(f"进程 {rank} 发送消息到进程 {dest}")

    source = 1
    recv_msg = comm.recv(source=source)
    print(f"进程 {rank} 从进程 {source} 收到消息: {recv_msg}")

    elif rank == 1:
    source = 0
    recv_msg = comm.recv(source=source)
    print(f"进程 {rank} 从进程 {source} 收到消息: {recv_msg}")

    dest = 0
    message = f"from {rank}, 你好,进程 0!"
    comm.send(message, dest=dest)
    print(f"进程 {rank} 发送消息到进程 {dest}")

    comm.Barrier()
    # 11. isend 和 irecv - 非阻塞式发送接收
    if rank == 2:
    dest = 3
    message = "非阻塞消息"
    req = comm.isend(message, dest=dest)

    source = 3
    req_recv = comm.irecv(source=source)

    # 可以在这里执行其他计算
    req.wait() # 等待发送完成
    print(f"进程 {rank} 非阻塞发送完成")

    recv_msg = req_recv.wait() # 等待接收完成
    print(f"进程 {rank} 收到非阻塞消息: {recv_msg}")

    elif rank == 3:
    source = 2
    req_recv = comm.irecv(source=source)

    dest = 2
    message = "非阻塞回复"
    req = comm.isend(message, dest=dest)

    # 可以在这里执行其他计算
    recv_msg = req_recv.wait() # 等待接收完成
    print(f"进程 {rank} 收到非阻塞消息: {recv_msg}")

    req.wait() # 等待发送完成
    print(f"进程 {rank} 非阻塞发送完成")

    comm.Barrier()
    # 12. sendrecv - 同时发送和接收
    send_val = -rank * 100
    dest = (rank + 1) % size # 发送给下一个
    source = (rank - 1) if rank - 1 >= 0 else size - 1 # 接收自来自上一个的

    # 上面的实现是一个圆环的通信方式,节点之间消息是依次流转的
    print(f"rank={rank}, dest={dest}, source={source}")

    # 注意:一定要对齐,A.dest = B,则必须有 B.source = A,否则下面的语句会卡死(一直等待)
    recv_val = comm.sendrecv(send_val, dest=dest, source=source)
    print(f"进程 {rank} 发送 {send_val} 到进程 {dest},从进程 {source} 接收 {recv_val}")

    # 所有演示操作做完,最终同步
    comm.Barrier()
    if rank == 0:
    print("\n所有进程完成演示")

    if __name__ == "__main__":
    main()

    # 进程 0 启动,共有 4 个进程
    # 进程 2 启动,共有 4 个进程
    # 进程 3 启动,共有 4 个进程
    # 进程 1 启动,共有 4 个进程
    # 进程 0 收到 bcast 数据: {'message': '这是来自 rank=0 的 broadcast 消息', 'value': 123}
    # 进程 1 收到 bcast 数据: {'message': '这是来自 rank=0 的 broadcast 消息', 'value': 123}
    # 进程 2 收到 bcast 数据: {'message': '这是来自 rank=0 的 broadcast 消息', 'value': 123}
    # 进程 3 收到 bcast 数据: {'message': '这是来自 rank=0 的 broadcast 消息', 'value': 123}
    # 进程 1 收到 scatter 数据: from-0-index-1
    # 进程 3 收到 scatter 数据: from-0-index-3
    # 进程 0 收到 scatter 数据: from-0-index-0
    # ==开始测试更复杂的原语:==
    # 进程 2 收到 scatter 数据: from-0-index-2
    # 进程 0 原始数据: [0 1 2 3]
    # 进程 1 原始数据: [4 5 6 7]
    # 进程 3 原始数据: [12 13 14 15]
    # 进程 1 收到 gather 数据: None
    # 进程 3 收到 gather 数据: None
    # 进程 2 原始数据: [ 8 9 10 11]
    # 进程 2 收到 gather 数据: None
    # 进程 0 收到 gather 数据: [array([0, 1, 2, 3], dtype=int32), array([4, 5, 6, 7], dtype=int32), array([ 8, 9, 10, 11], dtype=int32), array([12, 13, 14, 15], dtype=int32)]
    # 进程 0 收到 allgather 数据: [array([0, 1, 2, 3], dtype=int32), array([4, 5, 6, 7], dtype=int32), array([ 8, 9, 10, 11], dtype=int32), array([12, 13, 14, 15], dtype=int32)]
    # 进程 1 收到 allgather 数据: [array([0, 1, 2, 3], dtype=int32), array([4, 5, 6, 7], dtype=int32), array([ 8, 9, 10, 11], dtype=int32), array([12, 13, 14, 15], dtype=int32)]
    # 进程 3 收到 allgather 数据: [array([0, 1, 2, 3], dtype=int32), array([4, 5, 6, 7], dtype=int32), array([ 8, 9, 10, 11], dtype=int32), array([12, 13, 14, 15], dtype=int32)]
    # 进程 2 收到 allgather 数据: [array([0, 1, 2, 3], dtype=int32), array([4, 5, 6, 7], dtype=int32), array([ 8, 9, 10, 11], dtype=int32), array([12, 13, 14, 15], dtype=int32)]
    # 进程 1 收到 alltoall 数据: [1, 5, 9, 13]
    # 进程 0 收到 alltoall 数据: [0, 4, 8, 12]
    # 进程 2 收到 alltoall 数据: [2, 6, 10, 14]
    # 进程 3 收到 alltoall 数据: [3, 7, 11, 15]
    # 进程 3 收到 reduce 数据: None
    # 进程 1 收到 reduce 数据: None
    # 进程 2 收到 reduce 数据: None
    # 进程 0 收到 reduce 数据: [24 28 32 36]
    # 进程 1 收到 allreduce 数据: [24 28 32 36]
    # 进程 0 收到 allreduce 数据: [24 28 32 36]
    # 进程 3 收到 allreduce 数据: [24 28 32 36]
    # 进程 2 收到 allreduce 数据: [24 28 32 36]
    # ==测试任意维度的 allreduce 操作:==
    # 进程 0 原始 all_reduce_local_data 数据: [0 0 0 0 0 0 0]
    # 进程 2 原始 all_reduce_local_data 数据: [ 0 2 4 6 8 10 12]
    # 进程 3 原始 all_reduce_local_data 数据: [ 0 3 6 9 12 15 18]
    # 进程 1 原始 all_reduce_local_data 数据: [0 1 2 3 4 5 6]
    # 进程 0 收到 allreduce 数据: [ 0 6 12 18 24 30 36]
    # 进程 2 收到 allreduce 数据: [ 0 6 12 18 24 30 36]
    # 进程 1 收到 allreduce 数据: [ 0 6 12 18 24 30 36]
    # 进程 3 收到 allreduce 数据: [ 0 6 12 18 24 30 36]
    # 进程 3 收到 scan 数据: [24 28 32 36]
    # 进程 0 收到 scan 数据: [0 1 2 3]
    # 进程 1 收到 scan 数据: [ 4 6 8 10]
    # 进程 2 收到 scan 数据: [12 15 18 21]
    # 进程 3 local_data 原始数据: [0 3 6 9]
    # 进程 2 local_data 原始数据: [0 2 4 6]
    # 进程 1 local_data 原始数据: [0 1 2 3]
    # ==开始 reduce_scatter 演示==
    # 进程 0 local_data 原始数据: [0 0 0 0]
    # 进程 0 reduce_scatter_recv_data 原始数据: 0
    # 进程 1 reduce_scatter_recv_data 原始数据: 0
    # 进程 2 reduce_scatter_recv_data 原始数据: 0
    # 进程 3 reduce_scatter_recv_data 原始数据: 0
    # 进程 0 收到 Reduce_scatter 数据: 0
    # 进程 3 收到 Reduce_scatter 数据: 18
    # 进程 2 收到 Reduce_scatter 数据: 12
    # 进程 1 收到 Reduce_scatter 数据: 6
    # ==开始点对点通信演示==
    # 进程 0 发送消息到进程 1
    # 进程 1 从进程 0 收到消息: from 0, 你好,进程 1!
    # 进程 1 发送消息到进程 0
    # 进程 0 从进程 1 收到消息: from 1, 你好,进程 0!
    # 进程 2 非阻塞发送完成
    # 进程 3 收到非阻塞消息: 非阻塞消息
    # 进程 3 非阻塞发送完成
    # 进程 2 收到非阻塞消息: 非阻塞回复
    # rank=2, dest=3, source=1
    # rank=3, dest=0, source=2
    # rank=0, dest=1, source=3
    # rank=1, dest=2, source=0
    # 进程 1 发送 -100 到进程 2,从进程 0 接收 0
    # 进程 0 发送 0 到进程 1,从进程 3 接收 -300
    # 进程 2 发送 -200 到进程 3,从进程 1 接收 -100
    # 进程 3 发送 -300 到进程 0,从进程 2 接收 -200
    #
    # 所有进程完成演示
  • 启动上述代码的命令为:

    1
    mpiexec -n 4 python example.py

附录:传输不同维度的数据

  • 在上述 allgather, alltoall, allreduce 等操作中,同一个进程传输给其他进程的数据不一定要维度完全相等,甚至类型也不一定要相同,只需要能够做对应的 MPI op 就可以
  • 示例(某个元素改成列表):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    from mpi4py import MPI
    import numpy as np
    import time

    from numba.cuda import local

    def main():
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    print(f"进程 {rank} 启动,共有 {size} 个进程")

    comm.Barrier()

    local_data = [
    [0, 1, 2, 3],
    [4, 5, 6, 7],
    [ 8, 9, [10,18], 11],
    [12, 13, 14, 15],
    ]
    local_data = local_data[rank]
    print(f"进程 {rank} 原始数据: {local_data}")
    comm.Barrier()
    time.sleep(0.1)

    # allgather
    all_gathered_data = comm.allgather(local_data)
    print(f"进程 {rank} 收到 allgather 数据: {all_gathered_data}")
    comm.Barrier()
    time.sleep(0.1)

    # alltoall
    recv_data = comm.alltoall(local_data)
    print(f"进程 {rank} 收到 alltoall 数据: {recv_data}")
    comm.Barrier()
    time.sleep(0.1)

    # areduce
    recv_data = comm.reduce(local_data, op=MPI.SUM, root=0)
    print(f"进程 {rank} 收到 reduce 数据: {recv_data}")
    comm.Barrier()
    time.sleep(0.1)

    # allreduce - 全局规约操作
    recv_data = comm.allreduce(local_data, op=MPI.SUM)
    print(f"进程 {rank} 收到 allreduce 数据: {recv_data}")
    comm.Barrier()
    time.sleep(0.1)

    if __name__ == "__main__":
    main()

    # 进程 2 启动,共有 4 个进程
    # 进程 3 启动,共有 4 个进程
    # 进程 1 启动,共有 4 个进程
    # 进程 0 启动,共有 4 个进程
    # 进程 0 原始数据: [0, 1, 2, 3]
    # 进程 1 原始数据: [4, 5, 6, 7]
    # 进程 3 原始数据: [12, 13, 14, 15]
    # 进程 2 原始数据: [8, 9, [10, 18], 11]
    # 进程 3 收到 allgather 数据: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, [10, 18], 11], [12, 13, 14, 15]]
    # 进程 1 收到 allgather 数据: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, [10, 18], 11], [12, 13, 14, 15]]
    # 进程 0 收到 allgather 数据: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, [10, 18], 11], [12, 13, 14, 15]]
    # 进程 2 收到 allgather 数据: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, [10, 18], 11], [12, 13, 14, 15]]
    # 进程 1 收到 alltoall 数据: [1, 5, 9, 13]
    # 进程 0 收到 alltoall 数据: [0, 4, 8, 12]
    # 进程 3 收到 alltoall 数据: [3, 7, 11, 15]
    # 进程 2 收到 alltoall 数据: [2, 6, [10, 18], 14]
    # 进程 3 收到 reduce 数据: None
    # 进程 2 收到 reduce 数据: None
    # 进程 0 收到 reduce 数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 18], 11, 12, 13, 14, 15]
    # 进程 1 收到 reduce 数据: None
    # 进程 2 收到 allreduce 数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 18], 11, 12, 13, 14, 15]
    # 进程 0 收到 allreduce 数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 18], 11, 12, 13, 14, 15]
    # 进程 1 收到 allreduce 数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 18], 11, 12, 13, 14, 15]
    # 进程 3 收到 allreduce 数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 18], 11, 12, 13, 14, 15]

附录:导入 mpi4py 包的方式

  • 必须使用:

    1
    from mpi4py import MPI
  • 不能使用:

    1
    2
    import mpi4py
    MPI = mpi4py.MPI
  • 两种写法看似相同, 实际上不一样,第二种方法报错为 AttributeError: module 'mpi4py' has no attribute 'MPI'

  • 这是因为 第二种方法 MPI 环境未初始化 ,mpi4py 要求在使用 MPI 功能前必须先初始化,而import mpi4py不会自动完成这一步

不同导入方式的差别

  • 假设有两种导入方式:

    1
    2
    3
    4
    5
    6
    # 方式一
    from packagea import A

    # 方式二
    import packagea
    A = packagea.A
  • 如果 packagea 是一个包(包含 __init__.py),但 __init__.py 中未导入或暴露 A,方式二将无法通过包名直接访问 A

  • 当 packagea 的 __init__.py 未显式导入或暴露 A 时,方式一(from packagea import A)仍能成功的原因与 Python 的导入机制和包结构有关

  • Python 在执行 from packagea import A 时,会按以下步骤查找 A:

    • 1) 检查 packagea.__init__.py :若 __init__.py 中定义或导入了 A,直接使用
    • 2) 搜索子模块 :若 __init__.py 未包含 A,Python 会在 packagea 目录下查找是否存在 A.py 或 A/__init__.py
    • 3) 递归子模块 :若仍未找到,Python 会尝试递归导入子模块中的 A(例如 packagea.module_a.A),但需显式指定路径(如 from packagea.module_a import A)

mpi4py 两种导入结果不同的原因

  • 方式一成功的原因 :当执行 from mpi4py import MPI 时:
    • 1) Python 加载 mpi4py 包,执行 __init__.py
    • 2) __init__.py 注册元路径导入器(_mpiabi._install_finder())
    • 3) Python 发现 __all__ 中包含 MPI,但 __init__.py 中未显式定义
    • 4) 触发元路径导入器,根据系统 MPI 环境选择并加载对应的 MPI.so 文件(注意名称不一定是这个,可能是根据不同系统命名的文件)
      • 注:已确认在 ~/anaconda3/envs/xxx/lib/python3.10/site-packages/mpi4py/ 路径下不存在 MPI.so 文件
      • 虽然 mpi4py 目录下没有直接名为 MPI.so 的文件,但实际存在 MPI.mpich.cpython-310-darwin.so(针对 MPICH 实现的扩展模块) 和 MPI.openmpi.cpython-310-darwin.so(针对 OpenMPI 实现的扩展模块)
      • _mpiabi._install_finder() 的作用之一是根据系统中实际安装的 MPI 库(通过环境变量或系统命令探测),选择对应的 .so 文件
    • 5) MPI 扩展模块被加载,并绑定到 mpi4py 命名空间,导入成功
  • 方式二失败的原因 :方式一(import mpi4py 后 mpi4py.MPI)失败是因为:
    • import mpi4py 仅执行 __init__.py,不会触发元路径导入器对 MPI 的查找
    • __init__.py 中没有显式导入或定义 MPI(如 from .MPI import MPI),因此 mpi4py.MPI 不存在于命名空间中

附录:传统 MPI 风格函数的使用

  • 在 mpi4py 中,函数名的大小写是有区别的,主要涉及两种不同的编程接口风格:Pythonic 风格(小写) 和 传统 MPI C/Fortran 风格(大写)
  • 总结:
    • 小写函数 :更 Pythonic,返回数据,适合动态数据,代码简洁,不需要管理缓冲区
    • 大写函数 :类似 C/Fortran MPI,需要缓冲区,适合高性能计算(避免数据拷贝)

小写函数(Pythonic 风格)

  • 返回数据 ,而不是修改传入的缓冲区(更符合 Python 习惯)

  • 通常更简洁,适合 Python 风格的编程

  • 适用于 NumPy 数组和 Python 对象(如列表、字典等)

  • 以 gather 为例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import numpy as np
    from mpi4py import MPI

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    # 使用小写 gather(返回结果,不修改传入的 recvbuf)
    gathered_data = comm.gather(data, root=0)
    if rank == 0:
    print("Gathered data:", gathered_data) # 输出:[0, 10, 20, ...]
  • 特点:

    • gather 返回一个列表 ,包含所有进程发送的数据(仅在 root 进程有效)
    • 不需要预先分配 recvbuf ,适合动态数据

大写函数(传统 MPI 风格)

  • 需要预先分配接收缓冲区(recvbuf) ,类似 C/Fortran 的 MPI 接口

  • 直接修改传入的缓冲区 ,而不是返回数据

  • 适用于高性能计算(特别是 NumPy 数组 ,避免数据拷贝)

  • 以 gather 为例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import numpy as np
    from mpi4py import MPI

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    # 每个进程准备自己的数据(NumPy 数组)
    sendbuf = np.array([rank * 10], dtype=int)

    if rank == 0:
    # 预先分配 recvbuf(大小必须匹配)
    recvbuf = np.empty(size, dtype=int)
    else:
    recvbuf = None # 非 root 进程不需要 recvbuf

    # 使用大写 Gather(修改 recvbuf)
    comm.Gather(sendbuf, recvbuf, root=0)

    if rank == 0:
    print("Gathered data:", recvbuf) # 输出:[0, 10, 20, ...]
  • Gather 需要预先分配 recvbuf (在 root 进程)

  • 适用于高性能计算(避免 Python 对象的额外开销)

类似函数总结

小写(Pythonic) 大写(传统 MPI) 用途
bcast Bcast 广播数据
scatter Scatter 分散数据
gather Gather 收集数据
allgather Allgather 全收集
reduce Reduce 规约计算
allreduce Allreduce 全规约
scan Scan 前缀计算

附录:分布式中 GPU 主要集体通信操作介绍

  • 分布式计算中常用的集体通信(Collective Communication)操作有All-Gather、All-Reduce 和 Reduce-Scatter,主要用于多进程或多设备(如GPU)之间的数据交互

All-Gather(全收集)

  • All-Gather:每个进程提供一块数据,最终所有进程收集到所有其他进程的数据,结果是一个包含所有数据的聚合
  • 输入:每个进程有一块独立数据(如 data_i)
  • 输出:所有进程得到相同的全量数据([data_0, data_1, ..., data_n])
  • 举例:进程0有 A,进程1有 B,进程2有 C -> 最终所有进程得到 [A, B, C]
  • 功能:参数广播、分布式训练中同步模型参数

All-Reduce(全规约)

  • All-Reduce:先对所有进程的数据进行规约操作(如求和、最大值等),然后将结果分发给所有进程
  • 输入:每个进程有一块数据(如 data_i)
  • 计算:对所有 data_i 执行规约(如 sum(data_0, data_1, ..., data_n))
  • 输出:所有进程得到相同的规约结果(如 sum)
  • 举例:进程0有 1,进程1有 2,进程2有 3 -> 求和后所有进程得到 6
  • 功能:梯度聚合(如分布式训练中多卡梯度的全局求和)

Reduce-Scatter(规约散播)

  • Reduce-Scatter:先对所有进程的数据进行规约操作,然后将结果按块分散到不同进程中,每个进程只获得结果的一部分
  • 输入:每个进程有一块数据(如 data_i)
  • 计算:规约所有数据(如 sum),然后将结果按进程数切分
  • 输出:进程 i 获得结果的第 i 块
  • 举例:进程0有 [1, 2],进程1有 [3, 4],进程2有 [5, 6] -> 全局求和为 [9, 12],然后进程0得到 9,进程1得到 12
  • 功能:分布式矩阵计算中分块结果的聚合

整体总结

操作 输入 计算步骤 输出 是否全量同步
All-Gather 每个进程一块数据 收集所有数据并广播 所有进程获得全量数据 是
All-Reduce 每个进程一块数据 规约所有数据并广播结果 所有进程获得相同的规约结果 是
Reduce-Scatter 每个进程一块数据 规约所有数据并按块分发 每个进程只获得结果的一部分 否

特别说明

  • All-Reduce 可以拆分为 Reduce-Scatter + All-Gather(先局部规约后全局同步)
  • 性能差异 :All-Reduce 通常比分开的两步操作更高效(优化后的算法如 Ring-AllReduce)

附录:Ring-AllReduce

  • Ring-AllReduce 是 All-Reduce 的一种高效实现算法,也写为 Ring AllReduce、Ring All-Reduce 等

以数据并行(DP)场景为例

  • 假设有 N 个 GPU,每个 GPU 上都有全部参数和一部分数据
  • 目标是保证所有 GPU 都能完成一次完整的参数更新
  • 特别注意:
    • 每个 GPU 都只有一部分数据,所以需要拿到其他 GPU 的数据才能计算梯度(仅依赖自身甚至算不出任何一个参数的梯度)
    • 有很多参数,每个 GPU 都要完成所有参数的更新

Ring AllReduce 的核心思想

  • Ring AllReduce 的核心思想是:
    • 先将所有 GPU 上的局部梯度数据按照参数分成不同的块(每个块包含一部分参数的局部梯度)
    • 把所有 GPU 组成一个逻辑上的环形结构 ,大家只和自己的“邻居”交流 ,然后通过多次传递 ,最终让所有人都得到完整的梯度结果

Ring AllReduce 工作流程(分两步走)

  • 为了方便理解,本文假设有 4 个 GPU(A, B, C, D)
分块并传递(Reduce-Scatter 阶段)
  • 这一阶段的目标是每个 GPU 负责一部分参数的梯度聚合(编码为 \(S_0, S_1, S_2, S_3\))
  • 首先,每个 GPU 把自己手里的局部梯度按照参数平均分成 N 份(每份叫一个“块”)
  • 然后,大家开始轮流传递:每个 GPU 把自己一部分的“块”传给右边的邻居,同时从左边的邻居那里接收一个“块”
  • 当收到邻居的“块”后,就把这个“块”和自己对应的“块”进行合并(比如求和)
  • 这个过程重复进行 N-1 次,直到每个人的手里都拿到了自己负责的参数对应那部分的梯度并完成聚合
  • 举个例子:
    • A 有局部梯度 \(A_0, A_1, A_2, A_3\),下标表示参数块的索引
    • B 有局部梯度 \(B_0, B_1, B_2, B_3\),下标表示参数块的索引
    • C 有局部梯度 \(C_0, C_1, C_2, C_3\),下标表示参数块的索引
    • D 有局部梯度 \(D_0, D_1, D_2, D_3\),下标表示参数块的索引
    • 假设某个 GPU 的目标是最终实现参数块 0 的梯度累加计算,即 \(S_0 = A_0+B_0+C_0+D_0\)
      • 其他 GPU 的最终目标分别是实现 1,2,3 块参数的梯度累加
  • 第一轮:
    • A 把 \(A_1\) 给 B,从 D 收到 \(D_0\)
    • B 把 \(B_2\) 给 C,从 A 收到 \(A_1\)
    • C 把 \(C_3\) 给 D,从 B 收到 \(B_2\)
    • D 把 \(D_0\) 给 A,从 C 收到 \(C_3\)
    • 然后大家各自合并收到的数据:
      • A 现在有 \(A_1, A_2, A_3\), 还有 \((A_0+D_0)\)(计算后的结果)
      • B 现在有 \(B_0, B_2, B_3\), 还有 \((B_1+A_1)\)(计算后的结果)
      • C 现在有 \(C_0, C_1, C_3\), 还有 \((C_2+B_2)\)(计算后的结果)
      • D 现在有 \(D_0, D_1, D_2\), 还有 \((D_3+C_3)\)(计算后的结果)
  • 第二轮:
    • A 把 \((A_0+D_0)\) 给 B,从 D 收到 \((D_3+C_3)\)
    • B 把 \((B_1+A_1)\) 给 C,从 A 收到 \((A_0+D_0)\)
    • C 把 \((C_2+B_2)\) 给 D,从 B 收到 \((B_1+A_1)\)
    • D 把 \((D_3+C_3)\) 给 A,从 C 收到 \((C_2+B_2)\)
    • 然后大家合并各自收到的数据:
      • A 现在有 \((A_0+D_0), A_1, A_2\), 还有 \((A_3+C_3+D_3)\)(计算后的结果)
      • …
      • D 现在有 \(D_0, D_1, (D_3+C_3)\), 还有 \((B_2+C_2+D_2)\)(计算后的结果)
  • 这个过程会进行 \(N-1\) 次(N 是参与者的数量),最终每个人手里都会有一部分“最终总和”的数据
    • 最终得到,A 手里有 \(S_2\) ,B 手里有 \(S_3\) ,C 手里有 \(S_0\),D 手里有 \(S_1\)

收集并广播(All-Gather 阶段)

  • 所有 GPU 再次开始传递,这次传递不再进行计算,而是把自己手里已经计算好的梯度,传给右边的邻居
  • 当收到邻居的数据后,就把它保存下来
  • 这个过程也重复进行,直到每个人都收到了所有梯度
  • 不是一般性,假定(注意:与上面不同,但是不影响推导和理解):
    • 现在 A 手里有 \(S_0\) ,B 有 \(S_1\) ,C 有 \(S_2\) ,D 有 \(S_3\)
  • 第一轮:
    • A 把 \(S_0\) 给 B
    • B 把 \(S_1\) 给 C
    • C 把 \(S_2\) 给 D
    • D 把 \(S_3\) 给 A
    • 然后大家各自保存收到的数据:
      • A 现在有了 \(S_0\) (自己的) 和 \(S_3\) (从 D 收到)
      • B 现在有了 \(S_1\) (自己的) 和 \(S_0\) (从 A 收到)
  • 第二轮:
    • A 把 \(S_3\) 传递给 B
    • …
    • D 把 \(S_2\) 传递给 A
  • 第三轮:
    • A 把 \(S_2\) 传递给 B,至此,B 从 A 处收到了 \(S_0, S_2, S_3\),加上自己的 \(S_1\),也就得到了完整的 \(S_0, S_1, S_2, S_3\)
    • 其他节点也一次类推
  • 这个过程同样进行 \(N-1\) 次,最终每个人都会收集到所有的 \(S_0, S_1, S_2, S_3\),从而得到了完整的总和

Ring AllReduce 的优点

  • 高效利用带宽 :去中心化设计是的它不会让某个节点成为瓶颈
    • 比如像传统的“参数服务器”模式,所有数据都传给一个中心服务器,而 Ring AllReduce 是让所有节点都参与数据传输和计算,充分利用了网络的带宽
  • 良好的可扩展性 :即使参与的设备数量很多,它的通信效率也能保持相对稳定
    • 非常适合大规模的分布式训练(比如训练大型深度学习模型)
  • 降低延迟 :通过分块和流水线式的传输,它能有效地减少数据同步的等待时间
  • 特别说明:每个 GPU 只能和自己邻居交流这个约束,看似是限制,实际是非常巧妙地设计,是的数据通道建立一次即可,且传输是连续的

通信量对比

  • Ring All-Reduce 是 All-Reduce 的一种高效实现方式,在通信量方面相比传统的All-Reduce有显著优势。
  • 假设存在 \(N\) 个设备(如GPU),每个设备的数据大小为 \(\Phi\)
  • 传统 All-Reduce 的原始版本中,每个GPU需要发送 \((N - 1)\Phi\) 个数据,\(N\) 个 GPU 的总通信量为
    $$N(N - 1)\Phi$$
    • 其通信量与GPU数量呈(N^2) 复杂度
  • Ring All-Reduce 将每个 GPU 存储的数据顺序切分为 \(N\) 块,每块的数据量是 \(\frac{\Phi}{N}\)
    • Ring All-Reduce 包含 Reduce-Scatter 和 All-Gather 两个步骤,每个步骤都需要 \(N - 1\) 次通信,每次通信的数据量为 \(\frac{\Phi}{N}\)
    • 所以每个 GPU 的通信数据量为
      $$\frac{2(N - 1)\Phi}{N} \approx 2\Phi$$
  • 与传统 All-Reduce 相比,Ring All-Reduce 的每个 GPU 通信量显著减少,且通信量与设备数量 \(N\) 无关,只受限于逻辑环中最慢的两个 GPU 的连接

Math——一些常见概率分布


二项分布(Binomial Distribution)

  • 二项分布 :是 \(p\) 次独立重复试验中成功的次数的离散概率分布,其中每次试验只有两种可能结果(成功或失败),成功概率为 \(p\) ,失败概率为 \(1-p\) ,其概率公式为:
    $$P(X = k)=C_{n}^{k}p^{k}(1 - p)^{n - k}$$
    • 其中 \(X\) 表示成功的次数, \(k\) 是具体的成功次数, \(C_{n}^{k}\) 是组合数
  • 举例 :如抛硬币 \(n\) 次,正面朝上的次数;多次独立射击,命中目标的次数等

多项分布(Multinomial Distribution)

  • 多项分布 :是二项分布的推广,用于描述在 \(n\) 次独立试验中,每次试验有 \(k\) 种互斥且完备的结果,每种结果出现的概率分别为 \(p_{1},p_{2},\cdots,p_{k}\) ,且 \(\sum_{i = 1}^{k}p_{i}=1\) ,其概率公式为:
    $$P(X_{1}=n_{1},X_{2}=n_{2},\cdots,X_{k}=n_{k})=\frac{n!}{n_{1}!n_{2}!\cdots n_{k}!}p_{1}^{n_{1}}p_{2}^{n_{2}}\cdots p_{k}^{n_{k}}$$
    • 其中 \(X_{i}\) 表示第 \(i\) 种结果出现的次数, \(n_{i}\) 是具体的次数, \(n=\sum_{i = 1}^{k}n_{i}\)
  • 举例 :如掷骰子多次,统计每个点数出现的次数;对人群进行分类调查,统计各类人群的数量等
  • 多项分布与二项分布的区别 :二项分布是针对只有两种结果的重复试验;多项分布是二项分布的推广,用于多种结果的重复试验

分类分布(Categorical Distribution)

  • 分类分布 :也叫范畴分布,是一种离散概率分布,用于描述一个随机变量在有限个类别中的取值概率。它是多项分布在 \(n = 1\) 时的特殊情况,其概率公式为:
    $$P(X = i)=p_{i}$$
    • 其中 \(X\) 表示随机变量, \(i\) 表示类别, \(p_{i}\) 是类别 \(i\) 出现的概率, \(\sum_{i = 1}^{k}p_{i}=1\)
  • 举例 :如一次抽奖,有多种奖品,抽到每种奖品的概率;对一个物体进行分类,它属于不同类别的概率等
  • 注:强化学习中,离散动作的分布常常使用分类分布来表示(部分文献也称RL中的离散动作分布为广义伯努利分布)

广义伯努利分布(Generalized Bernoulli Distribution)

  • 广义伯努利分布 :是伯努利分布的推广,允许试验结果有多种,且每种结果的概率可以不同。它将伯努利分布从两种结果扩展到了多种结果的情,其概率公式为:
    $$P(X = x_{i})=p_{i}$$
    • \(X\) 是取值于 \({x_{1},x_{2},\cdots,x_{k}}\) 的随机变量,\(i = 1,2,\cdots,k\) ,且 \(\sum_{i = 1}^{k}p_{i}=1\)
  • 举例 :在一些多结果的单次试验场景中,如一次考试学生的成绩等级(优、良、中、差等)的概率分布
  • 注:强化学习中,离散动作的分布常常使用分类分布来表示(部分文献也称RL中的离散动作分布为广义伯努利分布)

一些总结

  • 二项分布是针对只有两种结果的重复试验(每次实验只有两种结果);
  • 多项分布是二项分布的推广,用于多种结果的重复试验(每次实验有多种结果);
  • 分类分布是多项分布在单次试验下的特殊情况;
  • 广义伯努利分布也是对伯努利分布的推广,更侧重于单次试验有多种结果的情况,与分类分布类似,但表述上更强调对伯努利分布的扩展
    • 分类分布和广义伯努利分布形式相同,代码实现上也完全相同

Math——函数空间总结

最近在看一些书籍时看到一些函数空间的定义,本科学过一些,但是由于不常用忘得差不多了,本文总结一下希尔伯特空间、欧几里得空间和巴拿赫空间等函数空间的概念,本文是对相关概念的基础理解,非专业定义

  • 参考博客:欧几里得空间与希尔伯特空间

前置说明

欧几里得空间、希尔伯特空间和巴拿赫空间属于函数空间。函数空间 = 元素 + 规则 ,即一个函数空间由 元素 与 元素所满足的规则 定义


概念说明

距离

距离 :是指在一个空间中,两个元素之间的某种度量,表示它们之间的“远近”关系。对于集合 \(X\) 中的任意两个元素 \(x,y\) ,距离函数 \(d(x,y)\) 需要满足非负性、对称性、三角不等式等性质

  • 满足三个属性可以简单理解为:
    • 大于0
    • A到B等于B到A
    • 满足三角不等式

范数

  • 范数 :是定义在向量空间上的一种函数,用于衡量向量的“长度”或“大小”。对于向量 \(x\) ,其范数 \(|x|\) 满足非负性、正齐次性、三角不等式
  • 可简单理解为某个点到0点的距离
  • 拥有范数的空间称作赋范空间

线性

  • 线性 :在数学中,线性意味着满足可加性和数乘性。对于空间 \(V\) 中的元素 \(x,y\) 以及标量 \(a,b\) ,若 \(ax + by\) 也属于 \(V\) ,则称 \(V\) 具有线性性质
  • 简单理解:若一个空间为线性空间,只要我们知道了此空间的所有基,便可以用加法与数乘表示这一空间所有的元素

内积

  • 内积 :是两个向量之间的一种运算,它将两个向量映射为一个标量。对于向量 \(x,y\) ,内积 \(\langle x,y\rangle\) 满足共轭对称性、线性性、正定性
  • 内积空间都是赋范空间
  • 有限维内积空间便是我们最熟悉的欧几里得空间

完备性

  • 完备性 :一个空间是完备的,是指该空间中的任何柯西序列都收敛于该空间中的某个元素。柯西序列是指随着序列的推进,序列中的元素之间的距离越来越小,最终趋于零
  • 柯西序列的定义和性质:
    • 柯西序列定义 :设 \((X, d)\) 是一个度量空间, \({x_n}\) 是 \(X\) 中的一个序列。如果对于任意给定的正数 \(\epsilon>0\) ,存在正整数 \(N\) ,使得当 \(m, n>N\) 时,都有 \(d(x_m, x_n)<\epsilon\) ,则称序列 \({x_n}\) 是一个柯西序列(Cauchy sequence)。直观地说,柯西序列中的元素随着序号的增大,彼此之间的距离会越来越小,最终可以任意小
    • 柯西序列性质 :
      • 有界性 :在度量空间中,柯西序列一定是有界的。即存在一个正数 \(M\) 和一个点 \(x_0\in X\) ,使得对于所有的 \(n\) ,都有 \(d(x_n, x_0)\leq M\) 。
      • 唯一性 :在完备度量空间中,柯西序列的极限是唯一的。也就是说,如果一个柯西序列收敛,那么它只能收敛到一个点
  • 对完备性的简单理解:对集合中的元素取极限不超出此空间便称其具有完备性

整体总结

  • 线性完备内积空间称作希尔伯特空间
  • 线性完备赋范空间称作巴拿赫空间
  • 有限维线性内积空间称作欧几里得空间,欧几里得空间是一种特殊的(有限维度)的希尔伯特空间

Math——有限总体校正


整体说明

  • 为了从总体 规模为 \( N \) 的有限样本中需要抽取的样本单位数量,用于在满足特定精度要求的前提下开展抽样调查或统计分析
  • 统计学中称满足特定精度的最小需要的样本总数为 有限总体校正(Finite Population Correction, FPC)
  • 最小需要的样本总数常常用 \( n \)

有限总体校正的定义

  • 有限总体校正(Finite Population Correction, FPC)样本量计算公式:
    $$ n = \frac{N \cdot Z^2 \cdot \sigma^2}{E^2 \cdot (N-1) + Z^2 \cdot \sigma^2} $$
    • 上述公式适用于总体规模 \( N \) 有限(而非无限大)的场景(例如从1000人的班级中抽样,而非从“所有中国人”中抽样)
  • 各参数含义如下:
    • \( n \) :目标样本量 ,最终需要抽取的样本数量,公式计算结果
    • \( N \) :总体规模 ,研究对象的总数量,如某学校的总学生数、某企业的总员工数
    • \( Z \) :Z值 ,对应指定置信水平的标准正态分布分位数,如95%置信水平对应的 \( Z \approx 1.96 \),99%置信水平对应的 \( Z \approx 2.58 \)
    • \( \sigma^2 \) :总体方差 ,总体中研究变量的离散程度,若总体方差未知,通常用历史数据或预调查的样本方差 \( s^2 \) 替代
    • \( E \) :边际误差(允许误差) ,抽样结果与总体真实值的最大允许偏差,如“调查结果误差不超过3%”,则 \( E = 0.03 \)

有限总体校正公式适用场景

  • 当总体规模 \( N \) 较大(如 \( N > 1000 \))且抽样比例(\( n/N \))较小时(通常小于5%),有限总体校正的影响可忽略,公式可简化为无限总体下的样本量公式:
    $$ n \approx \frac{Z^2 \cdot \sigma^2}{E^2} $$
  • 当总体规模 \( N \) 有限(如 \( N < 1000 \))或抽样比例较大(如超过5%)时,必须使用原公式(含有限总体校正项)计算 \( n \),否则会导致样本量估算偏大,造成资源浪费

Math——解析解和闭式解


解析解(Analytical Solution)

  • 解析解指的是通过标准的数学操作(如代数运算、积分、微分等)得到的精确表达式,该表达式可以是有限项的公式或无限级数的形式。解析解通常意味着我们能够以明确的数学形式写出问题的解答,而不需要进行数值逼近

闭式解(Closed-form Solution)

  • 闭式解是一种特殊的解析解 ,它指的是一类可以用有限数量的标准数学操作和已知函数(如指数函数、对数函数、三角函数等基本初等函数及其组合)表达的解析解。换句话说,闭式解是可以直接计算出来的,而不是需要迭代过程或者近似方法来获得的结果

解析解和闭式解的区别

  • 所有的闭式解都是解析解,但并非所有解析解都是闭式解。解析解可以包含无限级数或者其他非闭式的表达形式
  • 当我们说一个问题是可解析求解(或有解析解)时,意味着存在一个理论上精确的数学表达式作为答案;而当我们提到闭式解时,则进一步强调了这个解可以由有限次的基本数学运算得出。

控制系统——PID相关

PID相关笔记


PID相关参考

  • 一个简短的PID描述:PID控制原理,看了开头,你就会看到结尾!
    • 包含修改参数带来的系统输出变化可视化示例
  • 非常详细的讲解:从不懂到会用!PID从理论到实践~

位置式PID

  • 位置式PID在 \(k\) 时刻的直接输出为控制量 \( u(k) \),其离散形式为:
    $$
    u(k) = K_p \color{blue}{e(k)} + K_i \color{blue}{\sum_{j=0}^{k} e(j)} + K_d \color{blue}{\left[ e(k) - e(k-1) \right]}
    $$
  • 其中:
    • \( K_p, K_i, K_d \) 分别为比例、积分、微分系数;
    • \( e(k) \) 为当前时刻误差;
    • \( \sum_{j=0}^{k} e(j) \) 为历史误差累加(积分项)
  • 进阶:
    • \( K_i = K_p \frac{T}{T_i} \):积分系数(\( T_i \)为积分时间常数,\( T \)为采样时间)
    • \( K_d = K_p \frac{T_d}{T} \):微分系数(\( T_d \)为微分时间常数)

增量式PID

  • 增量式PID的输出是控制量的增量
    $$ \Delta u(k) = u(k) - u(k-1) $$
  • 类似位置式PID ,增量式PID在 \(k\) 时刻的 \(u(k)\) 可定义为如下:
    $$
    \begin{align}
    u(k) &= u(k-1) + \color{red}{\Delta u(k)} \\
    u(k) &= u(k-1) + (K_p + K_i + K_d) \color{red}{e(k)} - (K_p + 2K_d) \color{red}{e(k-1)} + K_d \color{red}{e(k-2)} \\
    u(k) &= u(k-1) + A \color{red}{e(k)} + B \color{red}{e(k-1)} + C \color{red}{e(k-2)}
    \end{align}
    $$
  • 注:一般提到增量式PID ,我们一般认为输出是 控制量的增量 \(\Delta u(k)\)

位置式PID到增量式PID的推导

  • 位置式PID和增量式PID完全等价,只是形式不同,通过对位置式PID做一阶差分 ,即可得到增量式PID
  • 位置式在 \( k-1 \) 时刻的输出 \( u(k-1) \) 为:
    $$
    u(k-1) = K_p e(k-1) + K_i \sum_{j=0}^{k-1} e(j) + K_d \left[ e(k-1) - e(k-2) \right]
    $$
  • 将 \( u(k) \) 和 \( u(k-1) \) 相减等到增量 \( \Delta u(k) = u(k) - u(k-1) \):
    $$
    \Delta u(k) = K_p \left[ e(k) - e(k-1) \right] + K_i e(k) + K_d \left[ e(k) - 2e(k-1) + e(k-2) \right]
    $$
  • 整理后得到增量式PID公式:
    $$
    \Delta u(k) = (K_p + K_i + K_d) e(k) - (K_p + 2K_d) e(k-1) + K_d e(k-2)
    $$

增量式PID到位置式PID的推导

  • 已知增量式PID的参数为A、B、C,其增量输出公式为:
    $$\Delta u(k) = A \color{red}{e(k)} + B \color{red}{e(k-1)} + C \color{red}{e(k-2)}$$
  • 通过对比位置式PID的差分形式,可以推导出位置式PID参数(Kp、Ki、Kd)与增量式参数的关系如下:
  • 位置式PID的输出为:
    $$u(k) = K_p \color{blue}{e(k)} + K_i \color{blue}{\sum_{j=0}^{k} e(j)} + K_d \color{blue}{\left[ e(k) - e(k-1) \right]}$$
  • 增量式PID的输出是位置式的差分:
    $$\Delta u(k) = u(k) - u(k-1).$$
    • 将位置式公式代入差分表达式并整理,得到:
      $$\Delta u(k) = \left(K_p + K_i + K_d\right)e(k) + \left(-K_p - 2K_d\right)e(k-1) + K_d e(k-2).$$
  • 对比系数 ,得到方程组:
    $$
    \begin{align}
    A &= K_p + K_i + K_d,\\
    B &= -K_p - 2K_d,\\
    C &= K_d
    \end{align}
    $$
  • 解方程组得位置式PID的参数为:
    $$
    \begin{align}
    \color{red}{K_p} &= -B - 2C,\\
    \color{red}{K_i} &= A + B + C,\\
    \color{red}{K_d} &= C
    \end{align}
    $$

增量式PID和位置式PID简单对比

特性 位置式PID 增量式PID
输出形式 绝对控制量(如阀门开度) 控制增量(如步进脉冲)
积分处理 显式累加误差,易饱和 隐式累加,天然抗饱和
计算复杂度 需存储所有误差,计算量大 仅需最近几次误差,计算量小
等效性 通过差分可转化为增量式 通过累加可转化为位置式

附录:现实场景中的一些trick

常用形式一:使用了 \( \lambda(k-1) \)的位置式PID

  • 适用场景:在一些场景中,控制变量 \( \lambda \) 需要平滑调整 ,而非完全重新计算(比如oCPX出价中)
  • 常用位置式PID来输出某个变量的增量(直接计算全量 \( \lambda(k) \) 可能导致相邻时间片的出价跳跃,而基于前一时刻的 \( \lambda(k-1) \) 进行增量调整,可以保证控制量的连续性),工程师可能会将位置式PID改写为以下形式:
    $$
    \begin{align}
    \lambda(k) &= \lambda(k-1) + \color{red}{\Delta \lambda(k)} \\
    \lambda(k) &= \lambda(k-1) + \color{red}{u(k)} \\
    \lambda(k) &= \lambda(k-1) + \color{red}{\left[ K_p e(k) + K_i \sum e(k) + K_d (e(k)-e(k-1)) \right]} \\
    \end{align}
    $$
    • 理解:这是一个位置式PID ,其中 \(\lambda\) 与PID无关,属于被控对象的一部分,其中PID输出为该变量的增量:
      $$ u(k) = \color{red}{\Delta \lambda(k)} = \color{red}{\left[ K_p e(k) + K_i \sum e(k) + K_d (e(k)-e(k-1)) \right]} $$
    • 问题:当 \(e(t)\) 为0时,由于积分项的存在,\(\color{red}{\Delta \lambda(k)}\) 可能不为0,\(u(k)\) 还会持续变化,这个是否符合预期?这个问题的简单理解如下:
      • 对于系统需要 \(u(k)\) 持续增加的场景,比如系统是一个压力越来越大的弹簧,\(u(k)\) 是施加的反向力,需要逐步增大,则这种情况天然适配这种设计,持续增加的 \(u(k)\) 能与系统逐步增加的压力抵消,保持稳态
      • 对于系统不需要 \(u(k)\) 持续增加的场景,假设 \(\color{red}{\Delta \lambda(k)} > 0\),则 \(u(k)\) 会继续增大,超调以后,积分项会逐步减少,同时 \(e(t) \neq 0\),也会开始减小 \(\color{red}{\Delta \lambda(k)} \),逐步地,\(\color{red}{\Delta \lambda(k)} = 0\),然后逐步变成负值,直到 \(e(t)\) 再次为0时,此时的积分项比上一轮更小了,\(\color{red}{\Delta \lambda(k)}\) 也更小了,甚至为负,也就是说,对于积分项逐步地应该也会收敛到0
  • 注:由于\(\lambda(k-1)\)中其实包含了累计误差的信息,可以进一步不考虑积分项(微分项一般不用考虑,这里顺便消除了),甚至可以简化为下面的公式形式:
    $$\lambda(k) = \lambda(k-1) + \color{blue}{K_p} \color{red}{e(k)}$$
    • 这种形式的优点:一定程度上,\(\lambda(k-1)\)中其实包含了累计误差的信息,可以在不包含 \(K_i\)的情况下实现类似积分项效果,存储和更新 \( \lambda(k-1) \) 比维护全局积分项 \( \sum e(k) \) 更简单(后者需持久化历史状态)
    • 此时也可以用增量式PID来理解这种公式,本文下面会聊到增量式PID下这种形式的含义

附录:增量式PID的实际使用简化

  • 增量式PID可能简化为只保留 \(e_t\) 相关的项,即:
    $$u(k) = u(k-1) + \color{blue}{A} \color{red}{e(k)}$$
  • 对照增量式PID的公式:
    $$
    \begin{align}
    u(k) &= u(k-1) + \color{red}{\Delta u(k)} \\
    u(k) &= u(k-1) + (K_p + K_i + K_d) \color{red}{e(k)} - (K_p + 2K_d) \color{red}{e(k-1)} + K_d \color{red}{e(k-2)} \\
    u(k) &= u(k-1) + A \color{red}{e(k)} + B \color{red}{e(k-1)} + C \color{red}{e(k-2)}
    \end{align}
    $$
  • 可以看出此时相当于没有 \(C = K_d = 0\),结合 \(B = - (K_p + 2K_d) = 0\),进一步有 \(K_p = 0\),最终可得:
    $$ \color{blue}{A} = K_i $$
  • 也就是说,此时相当于只包含 \(K_i\) 项的位置式PID
    • 进一步理解:其实只包含 \(K_i\) 项的位置式PID ,本质上可以等价于包含 \(K_i,K_p\) 项的位置式PID(但需要 \(K_i,K_p\) 系数服从某种关系)

附录:oCPX下PID的理想设计方式

  • oCPX的真正目标 :oCPX的最终目标是保整个投放周期内的ROI满足约束
  • 应该如何设计误差项 \(e(t)\)?
    • 如果 \(e(t)\) 表示时间片 \(t\) 的达成情况 ,则其值是根据时间片 \(t\) 内的消耗和收入计算出来的,则难以真正满足全天的ROI达成;此外,实际场景中,单个时间片的数据可能会非常稀疏 ,特别是oCPX的场景计算ROI需要用到订单数据,中小广告主的订单数据往往是非常稀疏的
      • 存在稀疏的情况。解决思路:一个思路改进是可以考虑用预估值去代替真实值,从而缓解稀疏问题
      • 难以达成全站ROI目标。解决思路:在原有PID基础上,引入累计偏差补偿项 \(\gamma \cdot \text{Global}_\text{Error}\),确保全天ROI收敛
    • 如果 \(e(t)\) 表示截止到时间片 \(t\) 的达成情况 ,值是根据投放周期开始到 \(t\) 时间片的消耗和收入计算出来的,则 \(e(t)\) 直接表达了截止到时间片 \(t\) 的ROI达成情况,这种设计下 \(e(t)=0\) 时说明全天刚好达成
      • 可以缓解稀疏问题
      • 更贴近oCPX产品的目标
    • 结论:
      • 订单稠密的场景可以考虑使用时间片 \(t\) 的达成情况 ,再增加引入累计偏差补偿项 \(\gamma \cdot \text{Global}_\text{Error}\),确保全天ROI收敛
      • 订单稀疏的场景使用截止到时间片 \(t\) 的达成情况 ,可以缓解稀疏问题
  • 对于无法获取分时间特征(无法计算位置式PID的积分项),且无法存储上一时间片的PID输出(无法用增量式PID)的情况,如何设计PID?
    • 一个思路是使用截止到时间片 \(t\) 的达成情况 ,且仅使用 \(K_p\) 参数,这样至少目标是达成全天的ROI目标,这种方法可能导致商家存在稳态误差(因为没有积分项)
  • 其他优化点:
    • 可以对 \(e(t)\) 做一个量纲映射,比如除以目标ROI以保证误差在指定范围内(特别是对于保CPS的场景,不同商家的CPS甚至不在统一量纲,想用相同的 \(K_p,K_i,K_d\) 参数来控制所有商家是困难的):
      $$ e(t) = \frac{真实ROI-目标ROI}{\color{red}{目标ROI}}$$
    • 初期数据量较少时不要调控,因为数据还不够准确,初期就开始调控可能导致商家初期出价波动较大
    • 可以统计过去一天或多天的PID输出作为下一天的初始出价 K 值,使得PID更容易达成,也让商家初期的消耗更符合ROI目标

附录:PID的其他优化

积分限幅

  • 现象:当因为不可抗力影响系统时,误差积分会一直增加,为了防止不可抗力消失的瞬间出现问题,可以给误差积分增加一个限制幅度(最大值)
  • 举例:无人机中这个现象可以看做一段时间内是有人压着无人机不许升高;在智能算力场景可以看做是非高峰期间,无论PID如何调整,TP999都到不了目标值
  • 解法:对误差积分项加一个上限,称为“积分限幅”

积分分离

  • 现象:目标有修改时,误差会突然增加,短时间内误差非常大,容易出现超调
  • 解法:对误差做一个条件判断,如果瞬间出现较大误差(比如超过一个阈值),可以让KI项的系数为0(注意不是清空KI项),只使用Kp项来调节;直到误差重新回到阈值以下,KI再生效

Kp上调下调差异化

  • 在一些场景上,如果对超成本和欠成本有倾向,可以通过设置上调和下调不同Kp来实现,比如,对于厌恶超成本的场景,可以适当增大下调系数,提升上调系数
1…303132…63
Joe Zhou

Joe Zhou

Stay Hungry. Stay Foolish.

630 posts
53 tags
GitHub E-Mail
© 2026 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4