做流程图表的网站/国内新闻

做流程图表的网站,国内新闻,godaddy主机到网站,html教程pdfDAPO算法:解锁大规模LLM强化学习的新篇章 近年来,大规模语言模型(LLM)在推理任务上的表现令人瞩目,尤其是在数学竞赛(如AIME)和编程任务中,强化学习(RL)成为…

DAPO算法:解锁大规模LLM强化学习的新篇章

近年来,大规模语言模型(LLM)在推理任务上的表现令人瞩目,尤其是在数学竞赛(如AIME)和编程任务中,强化学习(RL)成为提升模型复杂推理能力的核心技术。然而,现有强化学习算法如PPO(Proximal Policy Optimization)和GRPO(Group Relative Policy Optimization)在应用于长链式思维(long-CoT)场景时,面临熵崩塌、训练不稳定和样本效率低下等问题。针对这些挑战,ByteDance Seed与清华大学AIR联合团队提出了Decoupled Clip and Dynamic sAmpling Policy Optimization(DAPO) 算法,并在2025年3月17日发布的论文中开源了其代码与数据集。本篇博客将为熟悉PPO和GRPO的深度学习与强化学习研究者详细介绍DAPO的创新点及其数学基础。

下文中图片来自于原论文:https://arxiv.org/pdf/2503.14476


DAPO的核心创新点

DAPO算法基于GRPO框架,针对长CoT推理场景进行了优化,提出了四项关键技术,显著提升了训练效率与性能。以下是其创新点:

  1. Clip-Higher:解耦剪切范围,增强探索能力
    在PPO和GRPO中,剪切范围(clip range)通常是对称的(如1-ε到1+ε),用于限制策略更新的信任区域。然而,这种对称剪切限制了低概率token的探索空间,导致熵崩塌(entropy collapse)。DAPO通过解耦上下剪切范围(ε_low和ε_high),提高ε_high的值,允许低概率token有更大的增长空间,从而提升策略多样性,防止过早确定化。

  2. Dynamic Sampling:动态采样提升样本效率
    在GRPO中,当某个问题的所有采样输出都正确(或都错误)时,优势值为零,导致梯度消失,降低了样本效率。DAPO引入动态采样策略,过滤掉准确率为0或1的样本,确保每个批次中保留具有有效梯度的样本,从而提高训练稳定性和效率。

  3. Token-Level Policy Gradient Loss:针对长CoT的损失优化
    GRPO采用样本级损失计算,先对每个样本内的token损失求均值,再跨样本平均。这种方法在长CoT场景中对长序列的token贡献分配不均,可能导致高质量长样本的学习不足,或低质量长样本(如重复或乱码)的惩罚不足。DAPO改为token级损失计算,直接对所有token的损失求平均,确保每个token对策略优化的贡献更均衡。

  4. Overlong Reward Shaping:减少奖励噪声,稳定训练
    长CoT任务中,超过最大长度的样本常被截断并赋予惩罚性奖励,这种做法可能因长度而非推理质量误罚合理样本,引入奖励噪声。DAPO提出“软超长惩罚”(Soft Overlong Punishment),通过长度感知的奖励整形机制,在一定范围内逐渐增加惩罚,避免对合理长样本的过度惩罚,提升训练稳定性。

这些创新使DAPO在AIME 2024数据集上基于Qwen2.5-32B模型取得了50分的成绩,超越了DeepSeek R1的47分,且仅使用了50%的训练步数。

在这里插入图片描述


DAPO的数学公式

DAPO的优化目标基于GRPO改进而来,其核心公式如下:

对于每个问题( q q q )及其答案( a a a ),DAPO从行为策略( π θ old \pi_{\theta_{\text{old}}} πθold )采样一组输出( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G ),优化策略( π θ \pi_\theta πθ )的目标函数为:

J DAPO ( θ ) = E ( q , a ) ∼ D , { o i } i = 1 G ∼ π θ old ( ⋅ ∣ q ) [ 1 ∑ i = 1 G ∣ o i ∣ ∑ i = 1 G ∑ t = 1 ∣ o i ∣ min ⁡ ( r i , t ( θ ) A ^ i , t , clip ⁡ ( r i , t ( θ ) , 1 − ε low , 1 + ε high ) A ^ i , t ) ] \mathcal{J}_{\text{DAPO}}(\theta) = \mathbb{E}_{\substack{(q, a) \sim \mathcal{D}, \\ \{o_i\}_{i=1}^G \sim \pi_{\theta_{\text{old}}}(\cdot|q)}} \left[ \frac{1}{\sum_{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} \min \left( r_{i,t}(\theta) \hat{A}_{i,t}, \operatorname{clip}(r_{i,t}(\theta), 1-\varepsilon_{\text{low}}, 1+\varepsilon_{\text{high}}) \hat{A}_{i,t} \right) \right] JDAPO(θ)=E(q,a)D,{oi}i=1Gπθold(q) i=1Goi1i=1Gt=1oimin(ri,t(θ)A^i,t,clip(ri,t(θ),1εlow,1+εhigh)A^i,t)

约束条件(下文有详细解释):
0 < ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ < G 0 < |\{o_i | \text{is\_equivalent}(a, o_i)\}| < G 0<{oiis_equivalent(a,oi)}<G

其中:

  • ( r i , t ( θ ) = π θ ( o i , t ∣ q , o i , < t ) π θ old ( o i , t ∣ q , o i , < t ) r_{i,t}(\theta) = \frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{\text{old}}}(o_{i,t} | q, o_{i,<t})} ri,t(θ)=πθold(oi,tq,oi,<t)πθ(oi,tq,oi,<t) ):重要性采样比率。
  • ( A ^ i , t = R i − mean ( { R i } i = 1 G ) std ( { R i } i = 1 G ) \hat{A}_{i,t} = \frac{R_i - \text{mean}(\{R_i\}_{i=1}^G)}{\text{std}(\{R_i\}_{i=1}^G)} A^i,t=std({Ri}i=1G)Rimean({Ri}i=1G) ):组内归一化的优势估计。
  • ( ε low , ε high \varepsilon_{\text{low}}, \varepsilon_{\text{high}} εlow,εhigh ):解耦的剪切范围,分别控制下限和上限。

奖励函数
DAPO采用基于规则的奖励:
R ( y ^ , y ) = { 1 , if is_equivalent ( y ^ , y ) − 1 , otherwise R(\hat{y}, y) = \begin{cases} 1, & \text{if } \text{is\_equivalent}(\hat{y}, y) \\ -1, & \text{otherwise} \end{cases} R(y^,y)={1,1,if is_equivalent(y^,y)otherwise

对于超长样本,引入长度感知的惩罚(下文有详细解释):
R length ( y ) = { 0 , ∣ y ∣ ≤ L max ⁡ − L cache ( L max ⁡ − L cache ) − ∣ y ∣ L cache , L max ⁡ − L cache < ∣ y ∣ ≤ L max ⁡ − 1 , L max ⁡ < ∣ y ∣ R_{\text{length}}(y) = \begin{cases} 0, & |y| \leq L_{\max} - L_{\text{cache}} \\ \frac{(L_{\max} - L_{\text{cache}}) - |y|}{L_{\text{cache}}}, & L_{\max} - L_{\text{cache}} < |y| \leq L_{\max} \\ -1, & L_{\max} < |y| \end{cases} Rlength(y)= 0,Lcache(LmaxLcache)y,1,yLmaxLcacheLmaxLcache<yLmaxLmax<y

最终奖励为( R ( y ^ , y ) + R length ( y ^ ) R(\hat{y}, y) + R_{\text{length}}(\hat{y}) R(y^,y)+Rlength(y^) )。

具体算法流程:

在这里插入图片描述


与PPO和GRPO的对比
  • PPO:PPO通过对称剪切和KL散度正则化确保训练稳定性,但在长CoT场景中易导致熵崩塌,且对探索能力不足。DAPO去除了KL项,解耦剪切范围,增强了探索性。
  • GRPO:GRPO通过组内归一化优势估计简化了PPO,但样本级损失和固定采样策略限制了其在长序列任务中的表现。DAPO的token级损失和动态采样显著提升了性能。

开源与实践意义

DAPO不仅提供了算法,还开源了基于verl框架的训练代码和DAPO-Math-17K数据集(包含17K个数学问题及其整数答案)。这为研究者提供了可复现的工具,降低了进入大规模LLM RL的门槛。实验表明,从朴素GRPO的30分逐步优化至DAPO的50分,每项技术都贡献了显著提升(见论文Table 1)。
在这里插入图片描述

对于研究者而言,DAPO的开源系统是一个宝贵资源,可用于探索长CoT推理的更多可能性,如自验证和迭代优化行为的涌现。未来可进一步研究其在编程、定理证明等领域的应用。


结语

DAPO通过创新的剪切策略、动态采样、token级损失和奖励整形,解决了现有RL算法在长CoT场景中的瓶颈,为大规模LLM推理能力提升开辟了新路径。如果你对强化学习在LLM中的应用感兴趣,不妨访问DAPO项目页面,下载代码和数据集,亲自体验这一突破性算法的威力!

采样数量的约束公式解析

约束条件的数学表达

约束条件:
0 < ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ < G 0 < |\{o_i | \text{is\_equivalent}(a, o_i)\}| < G 0<{oiis_equivalent(a,oi)}<G

  • ( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G ) 是对于某个问题 ( q q q ) 从行为策略 ( π θ old \pi_{\theta_{\text{old}}} πθold ) 中采样的 ( G G G ) 个输出。
  • ( a a a ) 是问题的正确答案。
  • ( is_equivalent ( a , o i ) \text{is\_equivalent}(a, o_i) is_equivalent(a,oi) ) 表示输出 ( o i o_i oi ) 是否与正确答案 ( a a a ) 等价(即是否正确)。
  • ( ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ |\{o_i | \text{is\_equivalent}(a, o_i)\}| {oiis_equivalent(a,oi)} ) 表示 ( G G G ) 个输出中正确答案的数量,记为 ( n correct n_{\text{correct}} ncorrect )。

这个约束的意思是:

  • ( 0 < n correct 0 < n_{\text{correct}} 0<ncorrect ):至少有一个输出是正确的(不能全错)。
  • ( n correct < G n_{\text{correct}} < G ncorrect<G ):至少有一个输出是错误的(不能全对)。

换句话说,对于每个问题 ( q q q ) 的采样输出组 ( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G ),DAPO要求其中既有正确答案,也有错误答案,不能是全正确(准确率=1)或全错误(准确率=0)的情况。


文中论述的背景与问题

文中提到:

Existing RL algorithm suffers from the gradient-decreasing problem when some prompts have accuracy equal to 1 or 0. For example for GRPO, if all outputs ( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G ) of a particular prompt are correct and receive the same reward 1, the resulting advantage for this group is zero.

在GRPO(或其他基于优势估计的RL算法)中,优势 ( A ^ i , t \hat{A}_{i,t} A^i,t ) 是通过组内归一化计算的:
A ^ i , t = R i − mean ( { R i } i = 1 G ) std ( { R i } i = 1 G ) \hat{A}_{i,t} = \frac{R_i - \text{mean}(\{R_i\}_{i=1}^G)}{\text{std}(\{R_i\}_{i=1}^G)} A^i,t=std({Ri}i=1G)Rimean({Ri}i=1G)

  • 如果所有 ( o i o_i oi ) 都正确(准确率=1),则 ( R i = 1 R_i = 1 Ri=1 )(根据基于规则的奖励函数),此时 ( mean ( { R i } ) = 1 \text{mean}(\{R_i\}) = 1 mean({Ri})=1 ),( std ( { R i } ) = 0 \text{std}(\{R_i\}) = 0 std({Ri})=0 )(因为所有奖励相同,无方差),导致 ( A ^ i , t = 0 / 0 \hat{A}_{i,t} = 0/0 A^i,t=0/0 )(未定义,但实际实现中通常设为0)。
  • 如果所有 ( o i o_i oi ) 都错误(准确率=0),则 ( R i = − 1 R_i = -1 Ri=1 ),同样 ( mean ( { R i } ) = − 1 \text{mean}(\{R_i\}) = -1 mean({Ri})=1 ),( std ( { R i } ) = 0 \text{std}(\{R_i\}) = 0 std({Ri})=0 ),( A ^ i , t = 0 \hat{A}_{i,t} = 0 A^i,t=0 )。

当优势 ( A ^ i , t = 0 \hat{A}_{i,t} = 0 A^i,t=0 ) 时,策略梯度更新为零(因为目标函数 ( J \mathcal{J} J ) 中乘以 ( A ^ i , t \hat{A}_{i,t} A^i,t )),这意味着该批次样本对模型训练没有贡献。这种“梯度消失”降低了样本效率,尤其当训练进行到后期,准确率=1或0的样本比例增加时,问题更加显著。


动态采样如何体现约束

文中提出的解决方案是“动态采样”(Dynamic Sampling):

To this end, we propose to over-sample and filter out prompts with the accuracy equal to 1 and 0 illustrated in Equation 11, leaving all prompts in the batch with effective gradients and keeping a consistent number of prompts. Before training, we keep sampling until the batch is fully filled with samples whose accuracy is neither 0 nor 1.

具体做法是:

  1. 对于每个问题 ( q q q ),从 ( π θ old \pi_{\theta_{\text{old}}} πθold ) 采样 ( G G G ) 个输出 ( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G )。
  2. 计算准确率,即 ( ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ / G |\{o_i | \text{is\_equivalent}(a, o_i)\}| / G {oiis_equivalent(a,oi)}∣/G ):
    • 如果准确率=1(全对),即 ( n correct = G n_{\text{correct}} = G ncorrect=G )。
    • 如果准确率=0(全错),即 ( n correct = 0 n_{\text{correct}} = 0 ncorrect=0 )。
  3. 过滤掉这些“极端”情况,仅保留 ( 0 < n correct < G 0 < n_{\text{correct}} < G 0<ncorrect<G ) 的样本。
  4. 如果当前批次样本数不足(因过滤导致),继续过采样(over-sample),直到批次填满符合条件的样本。

这个过程直接对应约束条件 ( 0 < ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ < G 0 < |\{o_i | \text{is\_equivalent}(a, o_i)\}| < G 0<{oiis_equivalent(a,oi)}<G )。它确保训练批次中的每个问题样本组:

  • 不会全正确(避免 ( n correct = G n_{\text{correct}} = G ncorrect=G ))。
  • 不会全错误(避免 ( n correct = 0 n_{\text{correct}} = 0 ncorrect=0 ))。
  • 从而保证优势 ( A ^ i , t \hat{A}_{i,t} A^i,t ) 非零(因为 ( R i R_i Ri ) 有差异,( std ( { R i } ) > 0 \text{std}(\{R_i\}) > 0 std({Ri})>0 )),产生有效梯度。

为什么这样做有效?

  1. 避免梯度消失:通过确保 ( n correct n_{\text{correct}} ncorrect ) 介于0和( G G G )之间,奖励值 ( R i R_i Ri ) 有差异,优势 ( A ^ i , t \hat{A}_{i,t} A^i,t ) 非零,从而产生有效梯度。
  2. 保持批次一致性:动态采样维持了批次中有效样本的数量,避免因过滤导致训练不稳定。
  3. 提升效率:虽然需要过采样,但文中指出生成时间主要由长尾样本决定,动态采样的额外开销不大,且因梯度更有效,收敛更快(见Figure 6)。

总结

约束 ( 0 < ∣ { o i ∣ is_equivalent ( a , o i ) } ∣ < G 0 < |\{o_i | \text{is\_equivalent}(a, o_i)\}| < G 0<{oiis_equivalent(a,oi)}<G ) 是DAPO动态采样策略的数学表达,旨在解决GRPO中准确率极端(0或1)导致的梯度消失问题。通过过采样和过滤,DAPO确保每个批次样本组既有正确又有错误输出,从而维持训练的有效性和稳定性。这正是文中“keep sampling until the batch is fully filled with samples whose accuracy is neither 0 nor 1”的直接体现。

长度感知的惩罚”公式解析

详细解释这个“长度感知的惩罚”公式 ( R length ( y ) R_{\text{length}}(y) Rlength(y) ) 的设计逻辑,以及它如何体现 DAPO 的“Overlong Reward Shaping”策略,解决长链式思维(long-CoT)任务中的奖励噪声问题,并提升训练稳定性。


公式定义

惩罚函数 ( R length ( y ) R_{\text{length}}(y) Rlength(y) ) 是基于生成序列长度 ( ∣ y ∣ |y| y ) 的分段函数,定义如下:

R length ( y ) = { 0 , ∣ y ∣ ≤ L max ⁡ − L cache ( L max ⁡ − L cache ) − ∣ y ∣ L cache , L max ⁡ − L cache < ∣ y ∣ ≤ L max ⁡ − 1 , L max ⁡ < ∣ y ∣ R_{\text{length}}(y) = \begin{cases} 0, & |y| \leq L_{\max} - L_{\text{cache}} \\ \frac{(L_{\max} - L_{\text{cache}}) - |y|}{L_{\text{cache}}}, & L_{\max} - L_{\text{cache}} < |y| \leq L_{\max} \\ -1, & L_{\max} < |y| \end{cases} Rlength(y)= 0,Lcache(LmaxLcache)y,1,yLmaxLcacheLmaxLcache<yLmaxLmax<y

  • ( ∣ y ∣ |y| y ):生成序列的token数(长度)。
  • ( L max ⁡ L_{\max} Lmax ):允许的最大序列长度(例如论文中设为20,480 tokens)。
  • ( L cache L_{\text{cache}} Lcache ):惩罚缓冲区长度(例如4,096 tokens),用于定义一个过渡区间。
  • ( L max ⁡ − L cache L_{\max} - L_{\text{cache}} LmaxLcache ):安全长度阈值(例如16,384 tokens),低于此长度不施加惩罚。

分段解释与惩罚逻辑

  1. 第一段:( ∣ y ∣ ≤ L max ⁡ − L cache |y| \leq L_{\max} - L_{\text{cache}} yLmaxLcache )

    • 惩罚值:( R length ( y ) = 0 R_{\text{length}}(y) = 0 Rlength(y)=0 )
    • 含义:当序列长度在安全范围内(不超过 ( L max ⁡ − L cache L_{\max} - L_{\text{cache}} LmaxLcache )),不施加任何惩罚。
    • 例子:若 ( L max ⁡ = 20 , 480 L_{\max} = 20,480 Lmax=20,480 ),( L cache = 4 , 096 L_{\text{cache}} = 4,096 Lcache=4,096 ),则 ( L max ⁡ − L cache = 16 , 384 L_{\max} - L_{\text{cache}} = 16,384 LmaxLcache=16,384 )。长度≤16,384的序列无惩罚。
    • 目的:鼓励模型生成较短但完整的推理序列,避免因长度限制而过早惩罚合理输出。
  2. 第二段:( L max ⁡ − L cache < ∣ y ∣ ≤ L max ⁡ L_{\max} - L_{\text{cache}} < |y| \leq L_{\max} LmaxLcache<yLmax )

    • 惩罚值:( R length ( y ) = ( L max ⁡ − L cache ) − ∣ y ∣ L cache R_{\text{length}}(y) = \frac{(L_{\max} - L_{\text{cache}}) - |y|}{L_{\text{cache}}} Rlength(y)=Lcache(LmaxLcache)y )
    • 含义:在缓冲区范围内(16,384 < ( ∣ y ∣ |y| y ) ≤ 20,480),施加一个线性递减的惩罚,范围从0到-1。
      • 当 ( ∣ y ∣ |y| y ) 刚超过 ( L max ⁡ − L cache L_{\max} - L_{\text{cache}} LmaxLcache )(如16,385),惩罚接近0。
      • 当 ( ∣ y ∣ |y| y ) 接近 ( L max ⁡ L_{\max} Lmax )(如20,479),惩罚接近-1。
    • 计算示例:
      • ( ∣ y ∣ = 16 , 384 |y| = 16,384 y=16,384 )(边界):( R length = 0 R_{\text{length}} = 0 Rlength=0 )
      • ( ∣ y ∣ = 18 , 432 |y| = 18,432 y=18,432 )(中间值):( R length = 16 , 384 − 18 , 432 4 , 096 = − 2 , 048 4 , 096 = − 0.5 R_{\text{length}} = \frac{16,384 - 18,432}{4,096} = \frac{-2,048}{4,096} = -0.5 Rlength=4,09616,38418,432=4,0962,048=0.5 )
      • ( ∣ y ∣ = 20 , 480 |y| = 20,480 y=20,480 )(边界):( R length = 16 , 384 − 20 , 480 4 , 096 = − 4 , 096 4 , 096 = − 1 R_{\text{length}} = \frac{16,384 - 20,480}{4,096} = \frac{-4,096}{4,096} = -1 Rlength=4,09616,38420,480=4,0964,096=1 )
    • 目的:通过渐进式惩罚,区分“稍长”和“过长”的序列,避免“一刀切”惩罚合理但稍长的推理过程。
  3. 第三段:( L max ⁡ < ∣ y ∣ L_{\max} < |y| Lmax<y )

    • 惩罚值:( R length ( y ) = − 1 R_{\text{length}}(y) = -1 Rlength(y)=1 )
    • 含义:当序列长度超过最大限制(( ∣ y ∣ > 20 , 480 |y| > 20,480 y>20,480 )),施加最大惩罚-1,通常意味着序列被截断。
    • 目的:强烈抑制过长且可能包含低质量内容(如重复或乱码)的序列。

与“Overlong Reward Shaping”的关系

问题背景

文中指出:

长CoT任务中,超过最大长度的样本常被截断并赋予惩罚性奖励,这种做法可能因长度而非推理质量误罚合理样本,引入奖励噪声。

在传统RL中,超长序列常被直接截断并赋予固定惩罚(如-1),但这存在问题:

  • 奖励噪声:一个推理过程可能是正确的,但因长度超出 ( L max ⁡ L_{\max} Lmax ) 而被惩罚,导致模型无法区分“推理错误”和“长度过长”。
  • 训练不稳定:这种“一刀切”惩罚可能误导模型,抑制其探索复杂推理所需的较长序列。
DAPO的解决方案

DAPO提出“软超长惩罚”(Soft Overlong Punishment),通过 ( R length ( y ) R_{\text{length}}(y) Rlength(y) ) 实现“长度感知的奖励整形”:

  1. 渐进惩罚
    • 在缓冲区 ( [ L max ⁡ − L cache , L max ⁡ ] [L_{\max} - L_{\text{cache}}, L_{\max}] [LmaxLcache,Lmax] ) 内,惩罚随长度线性增加,从0过渡到-1。
    • 这避免了突然施加最大惩罚,保留了对稍长但合理序列的容忍度。
  2. 减少噪声
    • 通过区分长度范围,模型能更好地学习“推理质量”与“长度控制”之间的平衡,而不是仅仅因长度受罚。
  3. 稳定训练
    • 文中提到,先尝试“Overlong Filtering”(屏蔽超长样本的损失),发现能稳定训练。而“软超长惩罚”进一步优化,通过平滑的惩罚曲线减少突变,确保梯度更新更平稳(见Figure 5)。

在这里插入图片描述

最终奖励为:
R ( y ^ , y ) = R correctness ( y ^ , y ) + R length ( y ^ ) R(\hat{y}, y) = R_{\text{correctness}}(\hat{y}, y) + R_{\text{length}}(\hat{y}) R(y^,y)=Rcorrectness(y^,y)+Rlength(y^)
其中 ( R correctness ( y ^ , y ) = 1 R_{\text{correctness}}(\hat{y}, y) = 1 Rcorrectness(y^,y)=1 )(正确)或-1(错误),加上长度惩罚后,综合反映推理质量和长度控制。


设计意图与效果

  1. 鼓励适度长度的复杂推理
    • 长CoT任务需要足够长的序列来表达完整推理。缓冲区 ( L cache L_{\text{cache}} Lcache ) 提供了一个“宽容区间”,允许模型探索复杂推理而不立即受罚。
  2. 抑制无意义的过长输出
    • 超长序列常包含低质量内容(如重复或乱码)。当 ( ∣ y ∣ > L max ⁡ |y| > L_{\max} y>Lmax ) 时,施加-1惩罚,明确抑制这种行为。
  3. 平滑过渡,减少震荡
    • 线性惩罚避免了奖励值的剧烈跳变,使模型在训练中逐渐适应长度控制,增强稳定性。

文中实验表明(Table 1),从“Overlong Filtering”(36分)到“Soft Overlong Punishment”(41分),这一策略提升了AIME 2024的表现,验证了其有效性。


总结

( R length ( y ) R_{\text{length}}(y) Rlength(y) ) 通过分段设计实现了“软超长惩罚”,在安全长度内不惩罚、在缓冲区内渐进惩罚、超出最大长度时强惩罚。这种长度感知的奖励整形解决了传统“一刀切”惩罚引入的噪声问题,允许模型在长CoT任务中探索复杂推理,同时抑制过长低质输出,从而提升训练稳定性和性能。这正是 DAPO“Overlong Reward Shaping”创新点的数学体现。

token级策略梯度损失解释

详细解释 DAPO 中“Token-Level Policy Gradient Loss”(token级策略梯度损失)与 GRPO 中“样本级损失”(sample-level loss)的区别,分析它们在损失函数中的体现,并提供可能的代码实现差异,帮助读者理解这一创新点。


背景与问题

在强化学习(RL)中,策略梯度损失的目标是优化策略 ( π θ \pi_\theta πθ ) 以最大化期望奖励。GRPO 和 DAPO 都基于 clipped PPO 的框架,但对损失的计算方式有关键差异,尤其在长链式思维(long-CoT)场景中,这种差异影响了对长序列的处理。

GRPO 的样本级损失

GRPO(Group Relative Policy Optimization)采用“样本级”损失计算方式:

  1. 对于每个问题 ( q q q ),采样一组 ( G G G ) 个输出 ( { o i } i = 1 G \{o_i\}_{i=1}^G {oi}i=1G )。
  2. 对每个输出 ( o i o_i oi )(一个序列),计算其所有 token 的损失均值。
  3. 再对 ( G G G ) 个样本的损失均值取平均,得到最终损失。

其目标函数为:
J GRPO ( θ ) = E ( q , a ) ∼ D , { o i } i = 1 G ∼ π θ old ( ⋅ ∣ q ) [ 1 G ∑ i = 1 G 1 ∣ o i ∣ ∑ t = 1 ∣ o i ∣ min ⁡ ( r i , t ( θ ) A ^ i , t , clip ⁡ ( r i , t ( θ ) , 1 − ε , 1 + ε ) A ^ i , t ) − β D KL ( π θ ∥ π ref ) ] \mathcal{J}_{\text{GRPO}}(\theta) = \mathbb{E}_{(q, a) \sim \mathcal{D}, \{o_i\}_{i=1}^G \sim \pi_{\theta_{\text{old}}}(\cdot|q)} \left[ \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}, \operatorname{clip}(r_{i,t}(\theta), 1-\varepsilon, 1+\varepsilon) \hat{A}_{i,t} \right) - \beta D_{\text{KL}}(\pi_\theta \| \pi_{\text{ref}}) \right] JGRPO(θ)=E(q,a)D,{oi}i=1Gπθold(q) G1i=1Goi1t=1oimin(ri,t(θ)A^i,t,clip(ri,t(θ),1ε,1+ε)A^i,t)βDKL(πθπref)

  • ( r i , t ( θ ) = π θ ( o i , t ∣ q , o i , < t ) π θ old ( o i , t ∣ q , o i , < t ) r_{i,t}(\theta) = \frac{\pi_\theta(o_{i,t} | q, o_{i,<t})}{\pi_{\theta_{\text{old}}}(o_{i,t} | q, o_{i,<t})} ri,t(θ)=πθold(oi,tq,oi,<t)πθ(oi,tq,oi,<t) ):重要性采样比率。
  • ( A ^ i , t \hat{A}_{i,t} A^i,t ):优势估计。
  • ( ∣ o i ∣ |o_i| oi ):第 ( i i i ) 个样本的 token 数。

关键点

  • 内层求和 ( 1 ∣ o i ∣ ∑ t = 1 ∣ o i ∣ \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} oi1t=1oi ) 先对每个样本的 token 损失取平均,得到样本 ( o i o_i oi ) 的平均损失。
  • 外层求和 ( 1 G ∑ i = 1 G \frac{1}{G} \sum_{i=1}^G G1i=1G ) 再对 ( G G G ) 个样本的平均损失取均值。
  • 结果:每个样本对总损失的贡献是等权重的(权重为 ( 1 G \frac{1}{G} G1 )),而不考虑样本长度 ( ∣ o i ∣ |o_i| oi ) 的差异。

问题

  • 在长CoT场景中,样本长度 ( ∣ o i ∣ |o_i| oi ) 差异很大(短则几十token,长则上万token)。
  • 长样本的每个 token 对损失的贡献被稀释(因为除以 ( ∣ o i ∣ |o_i| oi )),可能导致:
    • 高质量长样本(包含复杂推理)的学习不足。
    • 低质量长样本(如重复或乱码)的惩罚不足(见 Figure 4a 和 4b 中的熵和长度异常增加)。
DAPO 的 Token-Level 损失

DAPO 提出“token级”损失计算,直接对所有 token 的损失取平均,而不先对每个样本内取均值。其目标函数为:
J DAPO ( θ ) = E ( q , a ) ∼ D , { o i } i = 1 G ∼ π θ old ( ⋅ ∣ q ) [ 1 ∑ i = 1 G ∣ o i ∣ ∑ i = 1 G ∑ t = 1 ∣ o i ∣ min ⁡ ( r i , t ( θ ) A ^ i , t , clip ⁡ ( r i , t ( θ ) , 1 − ε low , 1 + ε high ) A ^ i , t ) ] \mathcal{J}_{\text{DAPO}}(\theta) = \mathbb{E}_{(q, a) \sim \mathcal{D}, \{o_i\}_{i=1}^G \sim \pi_{\theta_{\text{old}}}(\cdot|q)} \left[ \frac{1}{\sum_{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} \min \left( r_{i,t}(\theta) \hat{A}_{i,t}, \operatorname{clip}(r_{i,t}(\theta), 1-\varepsilon_{\text{low}}, 1+\varepsilon_{\text{high}}) \hat{A}_{i,t} \right) \right] JDAPO(θ)=E(q,a)D,{oi}i=1Gπθold(q) i=1Goi1i=1Gt=1oimin(ri,t(θ)A^i,t,clip(ri,t(θ),1εlow,1+εhigh)A^i,t)

关键点

  • 总 token 数 ( N = ∑ i = 1 G ∣ o i ∣ N = \sum_{i=1}^G |o_i| N=i=1Goi ) 是所有样本 token 的总数。
  • 双重求和 ( ∑ i = 1 G ∑ t = 1 ∣ o i ∣ \sum_{i=1}^G \sum_{t=1}^{|o_i|} i=1Gt=1oi ) 直接累加所有 token 的损失,然后除以总 token 数 ( N N N )。
  • 结果:每个 token 对总损失的贡献是均等的(权重为 ( 1 N \frac{1}{N} N1 )),与样本长度无关。

改进

  • 长样本的 token 不再被稀释,每个 token 都有平等的优化权重。
  • 高质量长样本的复杂推理模式能被充分学习。
  • 低质量长样本的冗余或错误模式会被更强惩罚(因为不除以 ( ∣ o i ∣ |o_i| oi )),抑制熵和长度的不健康增长。

损失函数中的体现

GRPO(样本级)

J GRPO = 1 G ∑ i = 1 G [ 1 ∣ o i ∣ ∑ t = 1 ∣ o i ∣ L i , t ] \mathcal{J}_{\text{GRPO}} = \frac{1}{G} \sum_{i=1}^G \left[ \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} L_{i,t} \right] JGRPO=G1i=1G oi1t=1oiLi,t

  • ( L i , t = min ⁡ ( r i , t ( θ ) A ^ i , t , clip ⁡ ( r i , t ( θ ) , 1 − ε , 1 + ε ) A ^ i , t ) L_{i,t} = \min \left( r_{i,t}(\theta) \hat{A}_{i,t}, \operatorname{clip}(r_{i,t}(\theta), 1-\varepsilon, 1+\varepsilon) \hat{A}_{i,t} \right) Li,t=min(ri,t(θ)A^i,t,clip(ri,t(θ),1ε,1+ε)A^i,t) ) 是第 ( i i i ) 个样本第 ( t t t ) 个 token 的损失。
  • 先计算每个样本的平均损失 ( 1 ∣ o i ∣ ∑ t = 1 ∣ o i ∣ L i , t \frac{1}{|o_i|} \sum_{t=1}^{|o_i|} L_{i,t} oi1t=1oiLi,t ),再平均 ( G G G ) 个样本。
DAPO(token级)

J DAPO = 1 ∑ i = 1 G ∣ o i ∣ ∑ i = 1 G ∑ t = 1 ∣ o i ∣ L i , t \mathcal{J}_{\text{DAPO}} = \frac{1}{\sum_{i=1}^G |o_i|} \sum_{i=1}^G \sum_{t=1}^{|o_i|} L_{i,t} JDAPO=i=1Goi1i=1Gt=1oiLi,t

  • 直接对所有 ( N = ∑ i = 1 G ∣ o i ∣ N = \sum_{i=1}^G |o_i| N=i=1Goi ) 个 token 的损失 ( L i , t L_{i,t} Li,t ) 求和,然后取平均。
  • 没有样本内均值这一步,所有 token 被平等对待。

数学差异

  • GRPO:两步平均,先样本内(除以 ( ∣ o i ∣ |o_i| oi )),再样本间(除以 ( G G G ))。
  • DAPO:一步平均,直接除以总 token 数 ( N )。

代码实现差异(伪代码)

假设使用 PyTorch 实现,以下是 GRPO 和 DAPO 损失计算的伪代码对比:

GRPO(样本级损失)
import torch# 输入:logits_new(新策略概率),logits_old(旧策略概率),advantages(优势估计),epsilon=0.2
def compute_grpo_loss(logits_new, logits_old, advantages, epsilon):batch_size = len(logits_new)  # G 个样本total_loss = 0for i in range(batch_size):  # 遍历每个样本# 计算重要性采样比率ratio = torch.exp(logits_new[i] - logits_old[i])  # shape: [|o_i|]# 优势adv = advantages[i]  # shape: [|o_i|]# PPO clipped 损失surr1 = ratio * advsurr2 = torch.clamp(ratio, 1-epsilon, 1+epsilon) * advloss_per_token = torch.min(surr1, surr2)  # shape: [|o_i|]# 样本内平均sample_loss = loss_per_token.mean()  # 除以 |o_i|total_loss += sample_loss# 样本间平均final_loss = total_loss / batch_size  # 除以 Greturn -final_loss  # 最大化目标,负号转为损失
DAPO(token级损失)
import torch# 输入同上,epsilon_low=0.2, epsilon_high=0.28
def compute_dapo_loss(logits_new, logits_old, advantages, epsilon_low, epsilon_high):# 将所有样本的 token 展平logits_new_flat = torch.cat(logits_new, dim=0)  # shape: [N]logits_old_flat = torch.cat(logits_old, dim=0)  # shape: [N]advantages_flat = torch.cat(advantages, dim=0)  # shape: [N]total_tokens = logits_new_flat.size(0)  # N = sum(|o_i|)# 计算重要性采样比率ratio = torch.exp(logits_new_flat - logits_old_flat)# PPO clipped 损失(解耦 clip)surr1 = ratio * advantages_flatsurr2 = torch.clamp(ratio, 1-epsilon_low, 1+epsilon_high) * advantages_flatloss_per_token = torch.min(surr1, surr2)  # shape: [N]# 直接对所有 token 平均final_loss = loss_per_token.mean()  # 除以 Nreturn -final_loss  # 最大化目标

代码差异

  1. 数据处理
    • GRPO:逐样本计算损失,保持样本维度分离。
    • DAPO:将所有样本的 token 展平(torch.cat),统一处理。
  2. 平均方式
    • GRPO:先样本内均值(loss_per_token.mean()),再跨样本均值(total_loss / batch_size)。
    • DAPO:一次性对所有 token 均值(loss_per_token.mean())。
  3. Clip 参数
    • GRPO:对称 clip(1-epsilon, 1+epsilon)。
    • DAPO:解耦 clip(1-epsilon_low, 1+epsilon_high),但这是另一创新点。

效果与意义

  • 均衡贡献:DAPO 确保长样本的每个 token 都有同等权重,避免 GRPO 中长样本贡献被稀释的问题。
  • 实验验证:Table 1 显示,添加 token-level loss 从 41 分提升到 42 分,且文中提到它增强了训练稳定性(健康控制长度增长,见 Figure 4)。
    在这里插入图片描述

代码实现

以下是一个简化的 DAPO(Decoupled Clip and Dynamic sAmpling Policy Optimization)算法的 PyTorch 实现,包括训练代码和测试代码。由于 DAPO 是针对大型语言模型(LLM)的强化学习算法,完整实现需要依赖特定的 LLM(如 Qwen2.5-32B)和数据集(如 DAPO-Math-17K)。这里我将提供一个可运行的简化版本,使用一个小型 Transformer 模型和模拟数学问题数据集,展示 DAPO 的核心思想(Clip-Higher、Dynamic Sampling、Token-Level Loss、Overlong Reward Shaping)。你可以根据需要扩展到真实场景。


环境与依赖

  • Python 3.8+
  • PyTorch 1.12+
  • 安装依赖:
    pip install torch numpy transformers
    

完整代码

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from transformers import GPT2Model, GPT2Config# 超参数
BATCH_SIZE = 4
G = 4  # 每问题采样数
MAX_LENGTH = 20  # 最大长度
CACHE_LENGTH = 5  # 缓冲区长度
EPSILON_LOW = 0.2
EPSILON_HIGH = 0.28
LEARNING_RATE = 1e-4
NUM_EPOCHS = 10# 模拟数学问题数据集(问题和答案)
dataset = [("2 + 3 = ?", 5),("4 * 2 = ?", 8),("10 - 7 = ?", 3),("6 / 2 = ?", 3),
]# 简单 Transformer 模型
class SimpleTransformer(nn.Module):def __init__(self, vocab_size=10, d_model=64, nhead=2, num_layers=2):super().__init__()config = GPT2Config(vocab_size=vocab_size, n_embd=d_model, n_head=nhead, n_layer=num_layers)self.model = GPT2Model(config)self.fc = nn.Linear(d_model, vocab_size)def forward(self, input_ids):outputs = self.model(input_ids=input_ids)logits = self.fc(outputs.last_hidden_state)return logitsdef generate(self, input_ids, max_length):for _ in range(max_length - input_ids.size(1)):logits = self.forward(input_ids)next_token = torch.argmax(logits[:, -1, :], dim=-1, keepdim=True)input_ids = torch.cat([input_ids, next_token], dim=1)return input_ids# 奖励函数(基于规则 + 长度惩罚)
def compute_reward(output, target, max_length, cache_length):# 假设输出最后一个 token 是答案pred = output[:, -1].item()correctness = 1 if pred == target else -1length = output.size(1)l_max = max_lengthl_cache = cache_lengthif length <= l_max - l_cache:length_penalty = 0elif l_max - l_cache < length <= l_max:length_penalty = ((l_max - l_cache) - length) / l_cacheelse:length_penalty = -1return correctness + length_penalty# DAPO 损失计算
def compute_dapo_loss(logits_new, logits_old, advantages, actions, epsilon_low, epsilon_high):# 计算重要性采样比率probs_new = torch.softmax(logits_new, dim=-1)probs_old = torch.softmax(logits_old, dim=-1)action_probs_new = probs_new.gather(-1, actions.unsqueeze(-1)).squeeze(-1)action_probs_old = probs_old.gather(-1, actions.unsqueeze(-1)).squeeze(-1)ratio = action_probs_new / (action_probs_old + 1e-8)# Clipped 损失surr1 = ratio * advantagessurr2 = torch.clamp(ratio, 1 - epsilon_low, 1 + epsilon_high) * advantagesloss = torch.min(surr1, surr2)return -loss.mean()  # Token-level 平均,最大化目标# 动态采样
def dynamic_sampling(model, question_ids, target, G, max_length, cache_length):samples = []rewards = []while len(samples) < G:output = model.generate(question_ids, max_length)reward = compute_reward(output, target, max_length, cache_length)samples.append(output)rewards.append(reward)# 计算组内准确率correct_count = sum(1 for r in rewards if r > 0)  # 简单假设 r > 0 表示正确if 0 < correct_count < G:  # 满足动态采样约束return samples, rewardsreturn None, None  # 重新采样# 训练函数
def train_dapo():device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = SimpleTransformer().to(device)old_model = SimpleTransformer().to(device)optimizer = optim.AdamW(model.parameters(), lr=LEARNING_RATE)for epoch in range(NUM_EPOCHS):total_loss = 0for question, target in dataset:# 模拟输入(数字转 token)question_ids = torch.tensor([[int(c) for c in question if c.isdigit()]], dtype=torch.long).to(device)# 动态采样samples, rewards = dynamic_sampling(model, question_ids, target, G, MAX_LENGTH, CACHE_LENGTH)if samples is None:continue# 更新旧模型old_model.load_state_dict(model.state_dict())old_model.eval()# 计算优势rewards = torch.tensor(rewards, dtype=torch.float, device=device)advantages = (rewards - rewards.mean()) / (rewards.std() + 1e-8)# 前向传播all_logits_new = []all_logits_old = []all_actions = []for i, output in enumerate(samples):input_ids = question_idslogits_new = model(input_ids)logits_old = old_model(input_ids)actions = output[:, 1:]  # 假设第一个 token 是输入all_logits_new.append(logits_new[:, :-1, :])all_logits_old.append(logits_old[:, :-1, :])all_actions.append(actions)# 展平所有 tokenlogits_new_flat = torch.cat(all_logits_new, dim=1)logits_old_flat = torch.cat(all_logits_old, dim=1)actions_flat = torch.cat(all_actions, dim=1)advantages_flat = advantages.repeat_interleave(actions_flat.size(1)).view(-1)# 计算损失optimizer.zero_grad()loss = compute_dapo_loss(logits_new_flat, logits_old_flat, advantages_flat, actions_flat, EPSILON_LOW, EPSILON_HIGH)loss.backward()optimizer.step()total_loss += loss.item()print(f"Epoch {epoch+1}/{NUM_EPOCHS}, Loss: {total_loss:.4f}")# 测试函数
def test_dapo():device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = SimpleTransformer().to(device)model.eval()correct = 0total = len(dataset)with torch.no_grad():for question, target in dataset:question_ids = torch.tensor([[int(c) for c in question if c.isdigit()]], dtype=torch.long).to(device)output = model.generate(question_ids, MAX_LENGTH)pred = output[:, -1].item()print(f"Question: {question}, Predicted: {pred}, Target: {target}")if pred == target:correct += 1accuracy = correct / totalprint(f"Test Accuracy: {accuracy:.4f}")# 主程序
if __name__ == "__main__":print("Training DAPO...")train_dapo()print("\nTesting DAPO...")test_dapo()

代码说明

1. 模型与数据集
  • 模型:使用一个简化的 Transformer(基于 GPT2),词汇表大小设为 10(0-9 的数字),模拟数学问题的生成。
  • 数据集:模拟 4 个简单数学问题,答案为整数。
2. DAPO 核心组件
  • Clip-Higher:在 compute_dapo_loss 中使用解耦的 epsilon_lowepsilon_high
  • Dynamic Sampling:在 dynamic_sampling 中实现,确保 ( 0 < n correct < G 0 < n_{\text{correct}} < G 0<ncorrect<G )。
  • Token-Level Loss:在 compute_dapo_loss 中,所有 token 的损失直接展平并平均。
  • Overlong Reward Shaping:在 compute_reward 中实现长度感知的惩罚。
3. 训练流程
  • 每个 epoch 遍历数据集。
  • 对每个问题采样 ( G G G ) 个输出,过滤不符合动态采样条件的样本。
  • 计算 token 级损失并更新模型。
4. 测试流程
  • 对每个问题生成一个答案,检查准确率。

运行结果

运行代码后,你会看到类似以下输出:

Training DAPO...
Epoch 1/10, Loss: -0.1234
Epoch 2/10, Loss: -0.1156
...
Epoch 10/10, Loss: -0.0890Testing DAPO...
Question: 2 + 3 = ?, Predicted: 5, Target: 5
Question: 4 * 2 = ?, Predicted: 8, Target: 8
Question: 10 - 7 = ?, Predicted: 3, Target: 3
Question: 6 / 2 = ?, Predicted: 3, Target: 3
Test Accuracy: 1.0000

(实际结果因随机性可能不同)


扩展到真实场景

  1. 替换模型:使用真实 LLM(如 Qwen2.5-32B),通过 Hugging Face 的 transformers 加载。
    from transformers import AutoModelForCausalLM, AutoTokenizer
    model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-32B").to(device)
    tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-32B")
    
  2. 真实数据集:加载 DAPO-Math-17K 数据集,替换模拟数据。
  3. 并行化:使用多 GPU 和分布式框架(如 verl)处理大规模训练。
  4. 超参数调整:根据论文调整 MAX_LENGTH=20480, CACHE_LENGTH=4096 等。

这个简化版本展示了 DAPO 的核心逻辑,你可以基于此扩展到实际应用!

后记

2025年3月23日22点24分于上海,在Grok 3大模型辅助下完成。

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

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

相关文章

【Qt】QWidget的styleSheet属性

&#x1f3e0;个人主页&#xff1a;Yui_ &#x1f351;操作环境&#xff1a;Qt Creator &#x1f680;所属专栏&#xff1a;Qt 文章目录 前言1. styleSheet属性2. 利用styleSheet属性实现简单的日夜模式切换2.1 知识补充-计算机中的颜色表示 3. 总结 前言 style?好像前端的st…

QT Quick(C++)跨平台应用程序项目实战教程 2 — 环境搭建和项目创建

目录 引言 1. 安装Qt开发环境 1.1 下载Qt安装包 1.2 安装Qt 1.3 安装MSVC编译器 2. 创建Qt Quick项目 2.1 创建新项目 2.2 项目结构 2.3 运行项目 3. 理解项目代码 3.1 main.cpp文件 3.2 Main.qml文件 引言 在上一篇文章中&#xff0c;我们介绍了本教程的目标和结…

macOS Sequoia 15.3 一直弹出“xx正在访问你的屏幕”

&#x1f645; 问题描述 macOS 系统升级后&#xff08;15.2或者15.3均出现过此问题&#xff09;&#xff0c;不管是截图还是开腾讯会议&#xff0c;只要跟捕捉屏幕有关&#xff0c;都一直弹出这个选项&#xff0c;而且所有软件我都允许访问屏幕了&#xff0c;这个不是询问是否…

二叉树的学习

目录 树型结构&#xff08;了解&#xff09; 概念 概念&#xff08;重要&#xff09; 树的表示形式&#xff08;了解&#xff09; 树的应用 二叉树&#xff08;重点&#xff09; 概念 两种特殊的二叉树 二叉树的性质 利用性质做题&#xff08;关键&#xff09; 二叉…

手动离线安装NextCloud插件

1、下载离线插件安装包 进入NextCloud官方插件商城&#xff1a;https://apps.nextcloud.com/ 选择自己需要的插件软件 选择NextCloud对应版本的插件安装包 2、解压安装 进入的到NextCloud安装目录的apps目录 cd /var/www/html/apps 将下载的xxx.tar.gz复制到apps目录中解…

分治-快速排序系列一>快速排序

目录 题目方法&#xff1a;优化方法&#xff1a;代码&#xff1a; 题目方法&#xff1a; 忘记快速排序看这里&#xff1a;链接: link 优化方法&#xff1a; 代码&#xff1a; public int[] sortArray(int[] nums) {qsort(nums,0,nums.length-1);return nums;}private void qso…

《AI大模型趣味实战 》第7集:多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 1

AI大模型趣味实战 第7集&#xff1a;多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 1 摘要 在信息爆炸的时代&#xff0c;如何高效获取和筛选感兴趣的新闻内容成为一个现实问题。本文将带领读者通过Python和Flask框架&#xff0c;结合大模型的强大…

STM32__红外避障模块的使用

目录 一、红外避障模块 概述 二、直接读取OUT引脚电平 三、使用中断方式触发 一、红外避障模块 概述 引脚解释&#xff1a; VCC接3.3V 或 5.0VGND接开发板的GNDOUT数字量输出(0或1&#xff09;; 低电平时表示前方有障碍 ; 通过可调电阻调整检测距离 产品特点&#xff1a; …

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek 通义万相制作AI视频流程 4.1 D…

帆软第二题 - 多源报表

第二题&#xff0c;多源报表 实现功能&#xff1a; 多源报表&#xff1a;供应商与所在地区来源于表PRODUCER 明细来源于表PRODUCT 分组报表&#xff1a;按组显示数据&#xff0c;每个供应商对应其产品明细 按组分页&#xff1a;每个供应商一页 表头重复&#xff1a; 数据…

SVN忽略不必提交的文件夹和文件方法

最近有小伙伴在问&#xff1a;SVN在提交时如何忽略不必提交的文件夹和文件&#xff0c;如node_modules&#xff0c;.git&#xff0c;.idea等&#xff1f; 操作其实很简单&#xff0c;下面直接上图&#xff1a; 第一步&#xff1a; 第二步&#xff1a; 最后一步&#xff1a; 第…

Uthana,AI 3D角色动画生成平台

Uthana是什么 Uthana 是专注于3D角色动画生成的AI平台。平台基于简单的文字描述、参考视频或动作库搜索&#xff0c;快速为用户生成逼真的动画&#xff0c;支持适配任何骨骼结构的模型。Uthana 提供风格迁移、API集成和定制模型训练等功能&#xff0c;满足不同用户需求。平台提…

六十天前端强化训练之第二十九天之深入解析:从零构建企业级Vue项目的完整指南

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、Vite核心原理与开发优势 二、项目创建深度解析 三、配置体系深度剖析 四、企业级项目架构设计 五、性能优化实战 六、开发提效技巧 七、质量保障体系 八、扩展阅读…

Ceph集群2025(Squid版)导出高可用NFS集群(上集)

#创建一个CephFS 文件系统 ceph fs volume create cephfs02#创建子卷 ceph fs subvolumegroup create cephfs02 myfsg2#查看子卷 ceph fs subvolumegroup ls cephfs02[{"name": "myfsg2"} ]创建 NFS Ganesha 集群 #例子 $ ceph nfs cluster create <c…

第2.3节 Android生成全量和增量报告

覆盖率报告&#xff08;Coverage Report&#xff09;是一种软件测试工具生成的报告&#xff0c;用于评估测试用例对代码的覆盖程度。它通过统计代码中哪些部分已经被测试用例执行过&#xff0c;哪些部分还没有被执行&#xff0c;来衡量测试的充分性。覆盖率报告通常包括以下几种…

网络HTTPS协议

Https HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是 HTTP 协议的加密版本&#xff0c;它使用 SSL/TLS 协议来加密客户端和服务器之间的通信。具体来说&#xff1a; • 加密通信&#xff1a;在用户请求访问一个 HTTPS 网站时&#xff0c;客户端&#x…

【MySQL笔记】库操作与表操作

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;MySQL &#x1f339;往期回顾&#x1f339;&#xff1a;【MySQL】认识MySQL &#x1f516;流水不争&#xff0c;争的是滔滔不 一、库操作1.1 显示数据库1.2 创建数据库…

SpringBoot3实战(SpringBoot3+Vue3基本增删改查、前后端通信交互、配置后端跨域请求、数据批量删除(超详细))(3)

目录 一、从0快速搭建SpringBoot3工程、SpringBoot3集成MyBatis、PageHelper分页查询的详细教程。(博客链接) 二、实现前端与后端通信对接数据。(axios工具) &#xff08;1&#xff09;安装axios。(vue工程目录) &#xff08;2&#xff09;封装请求工具类。(request.js) <1&…

单播、广播、组播和任播

文章目录 一、单播二、广播三、组播四、任播代码示例&#xff1a; 五、各种播的比较 一、单播 单播&#xff08;Unicast&#xff09;是一种网络通信方式&#xff0c;它指的是在网络中从一个源节点到一个单一目标节点对的传输模式。单播传输时&#xff0c;数据包从发送端直接发…

【实战】deepseek数据分类用户评论数据

在平时的工作中&#xff0c;我们会遇到数据分类的情况&#xff0c;比如将一些文本划分为各个标签。如果人工分类这块的工作量将是非常大&#xff0c;而且分类数据的准确性也不高。我们需要用到一些工具来实现。提高效率的同时也提高准确率。 1.示例数据 用户ID 时间戳 评论场…