解讀DeepseekV3
我見過的最省的GPT4o,Claude,Gemini2級別的模型,而且是國內唯一有機會上桌的,其實海外目前和這三家有資格掰手腕的也只有它自己,可以負責任的說其他的模型不配上桌吃菜(Gemini上個月都沒資格)。
其實性能好就不說了,DeepseekR1就還不錯,國內講道理是第一家做inference timing scaling law的模型,阿里是第二家,其他的就不太值得談論了,其實國外也只有GPT和Google有資格,沒想到年底還能出個DeepseekV3,在傳統scaling law這邊還能玩出花活兒,實屬不易。
FP8混合精度訓練框架,并首次驗證其在超大規模模型上的有效性。
它模型下載下來看起來還能行啊,也就不到700G,那正常671B的參數,根本不可能這么點顯存占用,應該1.4T左右,這是因為它原生就FP8出的,這大概是我知道的第一個原生之直接出FP8的模型,Meta說很早就用FP8訓練了,那Llama3啥的也默認都BF16的,有些特定的模型FP8 GPTQ/AWQ過,像它這么激進的應該是第一個。
省錢
只有2.664M GPU小時的經濟成本,完成了對14.8萬億tokens的DeepSeek-V3預訓練,預訓練后的進一步階段僅需要0.1M GPU小時,因為FP8嗎,自然就省算力,也省顯存,還省通信,要不也不能就這么2048張卡就打發了,預訓練階段,DeepSeek-V3在每萬億tokens上的訓練僅需180K H800 GPU小時,即以2048 H800 GPUs集群僅需3.7天的時間。就能訓1萬億的token。因此。預訓練在不到兩個月內完成,總體使用GPU時間為2664K小時。加上上下文擴展需要的119K GPU小時以及后續訓練需要的5K GPU小時,總計2788K GPU小時,約合$5.576M。如果算上其他精細調整部分,總成本尚不足$5.576M,看到這心里真的在滴血啊,比起動輒幾百億人民幣都聽不出來個響的公司,它簡直是白蓮花了。(當然它家本身不缺錢,做成現在這種各種優化能力,也是之前多少錢砸出來的經驗)省錢因為FP8這是主要理由,但是光靠FP8是不夠的,我們一會接著講。
code math很不錯
這個肯定是蒸餾級別的高級模型的數據了,這個沒什么可避諱的,Google的gemni2還蒸餾了Athropic的Claude3.5, 現在這也正常,蒸餾出來只是一方面,關鍵得訓到Parameter里才是硬道理,而且為了增加V3的性能,Deepseek團隊,還蒸餾了自己的R1的reason能力作為語料和隱式COT給V3灌進去。(主要是后訓練階段)。
MLA (多頭潛注意力,Multi-HeadLatentAttention)
這個也是老活兒了,DeepseekV2里就有,但是真的好用,啥叫多頭潛注意力呢?
現規定幾個變量啊
- d: 嵌入維度(Embedding dimension),表示詞向量的維度。
- nh: 注意力頭的數量(Number of attention heads)。
- dh: 每個注意力頭的維度(Dimension per head)。
- ht: 第t個token在某個注意力層的輸入(Attention input for the t-th token)。
MLA 的核心思路就是:
- 先對 token 的特征進行一個“低秩”或“小維度”的壓縮(稱為 latent vector),再通過少量的變換將它還原/擴展到各頭所需要的 Key、Value 空間。
- 一部分必要的信息(如旋轉位置編碼 RoPE)的矩陣則保持單獨處理,讓網絡依然能保留時序、位置信息。
我們看看它怎么搞的啊。首先定義一個矩陣潛注意力W^{DKV}。
你就理解成一個下投影的矩陣,維度是 d x d_c,d_c是非常小的。
原始是啥呢?原始肯定是dh*nh啊,也就是每個頭的hidden_size,也可以說embedding size,這倆玩意等價的然后*多少個頭,也就是等于d。
dh*nh其實可以理解近似為hidden_size,也就是d,因為你多個頭就直接對接了模型的寬度么,那你這倆至少得4096吧(咱哪怕以llama來計算)。
然后我們搞下面這么個式子,也就是把你的第t個token在某個hidden_layer的輸出你經過我剛才說的下投影矩陣給一壓縮,那就變得非常小了。
c_t^{KV} = W^{DKV} h_t
h_t原始維度是啥?是d啊,比如4096,我經過一個d*dc的下投影矩陣。
d矩陣乘于d*d_c, 一出來就變d_c維的向量c_t^{KV} 了,比如d_c是400,那就小10倍,就是這么個壓縮。
c_t^{KV} 是一個低維度的向量,是壓縮后的 keys 和 values 的 latent 向量。d_c 表示壓縮后的維度,遠小于 d_h * n_h,所以你kv對就小了唄,因為小了,所以占顯存也少了,推理的時候kv_cache也少,推的也快,這下看懂了吧!
當然你肯定還得逆向把你壓縮的回復到原來的維度,那就乘一個上矩陣,要不也推不了么,可以簡單認為存的時候存這玩意c_t^{KV} (不占空間),用的時候還得矩陣乘一個上矩陣來還原,這塊就不解釋了。
rope也一樣,要被算出來一個key,最后rope的key和壓縮的key,一起合成一個key,因為要帶著位置編碼,這快我也不細講了,看明白我剛才講的,可以自己去看論文,邏輯是一樣的,微信公眾號寫數學公式太遭罪了,好累,能少寫就少寫點。
剛才講的是對于推理的時候優化,訓練的時候把Q也順便給優化了,道理和剛才的kv一樣,就并不贅述了。
路由專家和共享專家結合的MOE
路由專家 (Routed Experts) 和共享專家 (Shared Experts) 在 DeepSeekMoE 架構中扮演著不同的角色,它們的主要區別在于如何被激活和利用。
路由專家 (Routed Experts):
- 選擇性激活: 路由專家是按需激活的。對于每個輸入的 token,只有一部分路由專家會被選中并參與計算。這個選擇過程由一個門控機制 (gating mechanism) 決定,例如 DeepSeekMoE 中使用的基于親和度分數的 Top-K 選擇。
- 專精化: 每個路由專家都被設計為擅長處理特定類型的輸入或學習特定的特征。通過選擇性激活,模型能夠將不同的輸入路由到最合適的專家進行處理,從而實現專精化處理。
- 稀疏性: 由于只有一部分路由專家被激活,所以計算是稀疏的,可以提高模型的效率。
- 負載均衡: 門控機制的目標之一是實現專家之間的負載均衡,確保不同的專家在不同的輸入上被激活,避免某些專家過載。
DeepSeekMoE 使用 稀疏門控 (sparse gating) 的機制來選擇激活哪些路由專家。只有與當前 token 最匹配(親和度分數最高)的個路由專家才會被激活并產生非零的Kr門控值。其他路由專家的門控值為 0,意味著它們不參與當前 token 的處理。
共享專家 (Shared Experts):
- 全局參與: 共享專家始終參與所有輸入的處理。無論輸入是什么,所有共享專家都會貢獻它們的力量。
- 通用知識: 共享專家旨在學習對所有輸入都有用的通用知識或基礎特征。它們可以捕捉到數據中普遍存在的模式。
- 促進泛化: 由于共享專家對所有輸入都有貢獻,它們有助于模型學習更魯棒和泛化的表示,減少過擬合的風險。
- 提高穩定性: 共享專家可以為模型的預測提供一個更穩定的基礎,尤其是在路由機制不夠完美或者某些輸入不適合任何特定的路由專家時。
那你拿到的最終的outputs是啥呢?
就是路由專家和共享專家的值乘以他們的權重,然后加權,所以輸入也相當是一個有重點,有泛化的輸出。
Auxiliary-Loss-Free Load Balancing(輔助損失無關的負載均衡)
這個設計很巧妙,MOE專家就多對把,那多服務節點系統無論是什么都跑不出要做負載均衡,MOE也一樣,純輪訓肯定是開玩笑。
傳統怎么做的呢?
依賴于輔助損失 以避免不平衡的負載。然而,過大的輔助損失會損害模型性能,輔助損失是什么呢?
訓練機器學習模型時,除了主要的損失函數(用于衡量模型在主要任務上的性能)之外,額外引入的損失函數。 你可以把它理解為一個次要的、額外的優化目標。
在MOE領域輔助損失主要干這些事:
- 衡量負載不均衡程度: 輔助損失通常會定義一個指標來衡量當前專家負載的均衡程度。常見的指標包括:
- 專家被選擇的頻率差異: 計算每個專家被路由到的輸入數量,并衡量這些數量之間的差異。差異越大,不均衡程度越高。
- 每個專家的平均負載: 衡量每個專家處理的輸入的復雜度或計算量,并確保這些平均負載相對均勻。
- 作為懲罰項添加到總損失中: 將衡量到的負載不均衡程度轉化為一個損失值,并將其添加到模型的主要任務損失中。這樣,在訓練過程中,模型不僅要努力完成主要任務,還要努力減少負載不均衡帶來的額外損失。
- 鼓勵更均勻的路由決策: 通過反向傳播,負載均衡輔助損失會影響模型中門控網絡的參數。門控網絡負責決定將哪些輸入路由到哪些專家。輔助損失會促使門控網絡學習更均勻的路由策略,避免過度集中到某些專家。
傳統都是這么做的,但是如上文我們提到的,你怎么定義輔助損失?如果定義的有問題,會影響模型
Deepseek就不用輔助損失了,那么怎么實現的呢?
偏差項: 為每個路由專家引入一個偏差項,將其添加到相應的親緣度得分中,以確定最終選擇的專家。
動態調整偏差項: 在訓練過程中,模型會持續監控每個專家的負載情況。如果某個專家過載,則降低其偏差項;如果某個專家負載不足,則增加其偏差項。
消除輔助損失: 通過這種動態調整偏差項的方法,DeepSeek-V3 能夠在不使用輔助損失函數的情況下保持專家負載均衡,從而最大程度地減少了對模型性能的負面影響。
在無輔助損失的前提下呢,它又擴展了一下Complementary Sequence-Wise Auxiliary Loss(補充性的序列級輔助損失)。
盡管 DeepSeek-V3 主要依靠無輔助損失策略來實現負載均衡,但為了防止任何單個序列中出現極端不平衡的情況,它還使用了一種補充性的序列級平衡損失。該損失函數鼓勵每個序列上的專家負載均衡,并使用一個極小的平衡因子來確保其對模型性能的影響最小化。
節點受限路由:
為了進一步降低訓練成本,DeepSeek-V3 還采用了節點受限路由機制,限制每個令牌最多只能發送到四個節點進行處理。這種機制有效地減少了跨節點通信的開銷,并使模型能夠實現更高的訓練效率。
更高的訓練效率: 通過采用更細粒度的專家和節點受限路由,DeepSeek-V3 能夠更高效地利用計算資源,并降低訓練成本。
你們以前玩過hadoop,不有就近計算么,和那玩意差不多,就是降低通信導致的計算代償,也沒啥好解釋的。
另外就是MTP了,也是今天講的最后一個吧!
這張圖展示了 DeepSeek-V3 中使用的 Multi-Token Prediction (MTP) 的實現方式。我們可以把它分解開來理解:
核心思想:
MTP 的核心思想是在訓練過程中,模型不僅預測下一個 token (像傳統的語言模型一樣),還同時預測序列中后續的幾個 token。這可以為模型提供更豐富的訓練信號,幫助它更好地理解上下文和長距離依賴關系。
圖中的組成部分:
Input Tokens (輸入 Tokens): 圖的底部顯示了輸入到模型中的 token 序列,例如 t?, t?, t?, t?。
Target Tokens (目標 Tokens): 圖的頂部顯示了模型需要預測的目標 token 序列。注意,不同的模塊對應的目標 token 是不同的。
Main Model (主模型): 這部分代表了模型的核心結構,通常是一個 Transformer 模型的堆疊。
(Next Token Prediction) (下一個 Token 預測): 說明主模型的任務是預測序列中的下一個 token。
Embedding Layer (嵌入層): 將輸入的 token 轉化為向量表示。
Transformer Block × L (Transformer 模塊 × L): L 代表 Transformer 模塊的層數,是模型進行上下文理解和特征提取的核心部分。
Output Head (輸出頭): 將 Transformer 模塊的輸出轉化為預測下一個 token 的概率分布。
Cross-Entropy Loss (交叉熵損失): 計算主模型預測結果與實際下一個 token 之間的損失,這是訓練主模型的標準損失函數。
MTP Module 1 (MTP 模塊 1): 這是第一個 MTP 模塊。
(Next2 Token Prediction) (下第二個 Token 預測): 說明這個模塊的任務是預測輸入序列中下第二個 token。例如,當輸入為 t?, t?, t?, t? 時,它預測 t?。
Embedding Layer (嵌入層): 與主模型共享 (Shared) 嵌入層,這可以節省參數并學習通用的 token 表示。
Transformer Block (Transformer 模塊): 與主模型類似,用于處理輸入并提取特征。
Linear Projection (線性投影) 和 RMSNorm (RMS 歸一化): 這些是 Transformer 模塊內部的常見組件,用于調整維度和穩定訓練。這沒啥可講的。
Concatenation (拼接): 這里將 Embedding Layer 的輸出與 Transformer Block 的輸出拼接起來,為預測提供更豐富的上下文信息。
Output Head (輸出頭): 將 Transformer 模塊的輸出轉化為預測下第二個 token 的概率分布。
它輸出那肯定也是交叉熵損失,計算 MTP 模塊 1 預測結果與實際下第二個 token 之間的損失。
MTP Module 2 (MTP 模塊 2): 這是第二個 MTP 模塊。(Next3 Token Prediction) (下第三個 Token 預測): 說明這個模塊的任務是預測輸入序列中下第三個 token。例如,當輸入為 t?, t?, t?, t? 時,它預測 t?。
結構與 MTP Module 1 類似: 它也共享嵌入層,并包含 Transformer Block、線性投影、RMS 歸一化和輸出頭,不講了和前面一樣。
以此類推可以有更多的 MTP 模塊,每個模塊預測序列中更遠的后續 token。
Shared (共享): 虛線箭頭標明了不同模塊之間共享的組件,例如嵌入層。
工作流程和意義:
輸入: 一個 token 序列被輸入到模型中。
主模型預測: 主模型基于輸入預測下一個 token。
MTP 模塊預測: 同時,不同的 MTP 模塊基于稍微偏移的輸入分別預測下第二個、下第三個以及更遠的 token。
損失計算: 每個模塊都計算其預測結果與實際目標 token 之間的交叉熵損失。
聯合訓練: 所有模塊(主模型和 MTP 模塊)的損失會被聯合起來進行反向傳播,更新模型的參數。
MTP 的優勢:
更豐富的訓練信號: 模型不僅學習預測下一個 token,還學習預測更遠的未來 token,這有助于模型理解更長期的依賴關系和上下文信息。(上下文感知能力的提升)
潛在的加速收斂: 通過提供額外的預測任務,模型可能更快地學習到有效的表征。
提高生成質量: 學習預測多個未來 token 可能有助于生成更連貫和有意義的文本,這個對續寫任務是很有用的,當然有人測試,它文科任務一般,估計是語料的問題。對code也同樣有用,尤其是多行代碼(它的code不錯)
剩下什么強化PP流水線降低Bubble時間啥的我就不講了,大家自己下去看看論文吧
最后補一下訓練方式,準確說是4階段:
2階段預訓練,第一階段32k;
第二階段補到128k,擴展上下文;
SFT和RLHF的后訓練;
訓練方式中規中矩,傳統scaling law打法。
本文轉載自??熵減AI??,作者:周博洋
