字節DAPO算法:改進DeepSeek的GRPO算法-解鎖大規模LLM強化學習的新篇章(代碼實現)

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=1G?oi?1?i=1G?t=1oi??min(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<{oi?is_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,t?q,oi,<t?)πθ?(oi,t?q,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?)Ri??mean({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?(Lmax??Lcache?)?y?,?1,?yLmax??Lcache?Lmax??Lcache?<yLmax?Lmax?<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<{oi?is_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)\}| {oi?is_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?)Ri??mean({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 {oi?is_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<{oi?is_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<{oi?is_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?(Lmax??Lcache?)?y?,?1,?yLmax??Lcache?Lmax??Lcache?<yLmax?Lmax?<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}} Lmax??Lcache? ):安全長度閾值(例如16,384 tokens),低于此長度不施加懲罰。

分段解釋與懲罰邏輯

  1. 第一段:( ∣ y ∣ ≤ L max ? ? L cache |y| \leq L_{\max} - L_{\text{cache}} yLmax??Lcache? )

    • 懲罰值:( R length ( y ) = 0 R_{\text{length}}(y) = 0 Rlength?(y)=0 )
    • 含義:當序列長度在安全范圍內(不超過 ( L max ? ? L cache L_{\max} - L_{\text{cache}} Lmax??Lcache? )),不施加任何懲罰。
    • 例子:若 ( 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 Lmax??Lcache?=16,384 )。長度≤16,384的序列無懲罰。
    • 目的:鼓勵模型生成較短但完整的推理序列,避免因長度限制而過早懲罰合理輸出。
  2. 第二段:( L max ? ? L cache < ∣ y ∣ ≤ L max ? L_{\max} - L_{\text{cache}} < |y| \leq L_{\max} Lmax??Lcache?<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?(Lmax??Lcache?)?y? )
    • 含義:在緩沖區范圍內(16,384 < ( ∣ y ∣ |y| y ) ≤ 20,480),施加一個線性遞減的懲罰,范圍從0到-1。
      • 當 ( ∣ y ∣ |y| y ) 剛超過 ( L max ? ? L cache L_{\max} - L_{\text{cache}} Lmax??Lcache? )(如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,384?18,432?=4,096?2,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,384?20,480?=4,096?4,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}] [Lmax??Lcache?,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)? ?G1?i=1G?oi?1?t=1oi??min(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,t?q,oi,<t?)πθ?(oi,t?q,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|} oi?1?t=1oi?? ) 先對每個樣本的 token 損失取平均,得到樣本 ( o i o_i oi? ) 的平均損失。
  • 外層求和 ( 1 G ∑ i = 1 G \frac{1}{G} \sum_{i=1}^G G1?i=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=1G?oi?1?i=1G?t=1oi??min(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=1G?oi? ) 是所有樣本 token 的總數。
  • 雙重求和 ( ∑ i = 1 G ∑ t = 1 ∣ o i ∣ \sum_{i=1}^G \sum_{t=1}^{|o_i|} i=1G?t=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?=G1?i=1G? ?oi?1?t=1oi??Li,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} oi?1?t=1oi??Li,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=1G?oi?1?i=1G?t=1oi??Li,t?

  • 直接對所有 ( N = ∑ i = 1 G ∣ o i ∣ N = \sum_{i=1}^G |o_i| N=i=1G?oi? ) 個 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.pswp.cn/pingmian/73209.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73209.shtml
英文地址,請注明出處:http://en.pswp.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; 二叉…

AbMole新生大鼠腦類器官培養Protocol

近日&#xff0c;希臘亞里士多德大學塞薩洛尼基分校的研究團隊在《神經科學方法》&#xff08;Journal of Neuroscience Methods&#xff09;期刊上發表了一項引人注目的研究&#xff0c;他們開發了一種基于新生大鼠腦組織的新型類器官培養協議&#xff0c;并展望其在阿爾茨海默…

物理環境與安全

物理安全的重要性 信息系統安全戰略的一個重要組成部分物理安全面臨問題 環境風險不確定性人類活動的不可預知性 典型的物理安全問題 自然災害環境因素設備安全、介質安全、傳輸安全 場地選擇 區域&#xff1a;避開自然災害高發區環境&#xff1a;原理可能的危險因素抗震&…

手動離線安裝NextCloud插件

1、下載離線插件安裝包 進入NextCloud官方插件商城&#xff1a;https://apps.nextcloud.com/ 選擇自己需要的插件軟件 選擇NextCloud對應版本的插件安裝包 2、解壓安裝 進入的到NextCloud安裝目錄的apps目錄 cd /var/www/html/apps 將下載的xxx.tar.gz復制到apps目錄中解…

算力100問?第93問:算力資源為何更分散了?

目錄 1、政策驅動與地方投資的盲目性 2、美國芯片斷供與國產替代的陣痛 3、政企市場對私有云的偏好 4、技術標準與供需結構的失衡 5、產業生態與市場機制的滯后 6、破局路徑與未來展望 在大模型和人工智能技術快速發展的背景下,算力資源已成為數字經濟時代的核心基礎設施…

基于HTML的郵件發送狀態查詢界面設計示例

以下是一個基于HTML的郵件發送狀態查詢界面設計示例&#xff0c;結合篩選功能、狀態展示和重新發送操作&#xff0c;采用Bootstrap框架實現響應式布局&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"&…

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

目錄 題目方法&#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;結合大模型的強大…

微服務 - 中級篇

微服務 - 中級篇 一、微服務架構深化&#xff08;一&#xff09;服務拆分原則&#xff08;二&#xff09;服務通信方式 二、微服務技術選型&#xff08;一&#xff09;開發框架&#xff08;二&#xff09;容器技術 三、微服務實踐與優化&#xff08;后續會詳細分析&#xff09;…

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;來衡量測試的充分性。覆蓋率報告通常包括以下幾種…