跳到主要內容
技術

Dense、MoE、Hybrid:Transformer 的 FFN 有三種長法

DeepSeek-V3 寫著 671B 總參數、只啟動 37B;Snowflake Arctic 是 480B 總量、17B active。同樣叫 Transformer,差在哪?答案不在注意力,而在每一層的 FFN——本文拆解 Dense、MoE、與兩種 Hybrid 的結構差異。

你大概在模型卡上看過這種寫法:DeepSeek-V3「671B 總參數,啟動 37B」、Snowflake Arctic「480B total,17B active」。

第一次看到會卡一下——參數不就是參數,怎麼還分「總共有」跟「真的會算」兩種?

這個落差就是 MoE 的核心。而要講清楚它,得先知道一件事:同樣叫 Transformer,這些模型的差別幾乎都不在注意力,而在每一層裡那塊 FFN(Feed Forward Network,前饋網路)。注意力大家長得差不多,FFN 才是分岔點。

它有三種長法:全部都算的 Dense、只算一小撮的 MoE、還有把兩者縫在一起的 Hybrid。


先定位:FFN 在 Transformer 的哪裡

一個標準的 Transformer 層,骨架就兩塊:先過注意力,再過 FFN。

def layer(x):
    x = x + attention(x)   # 注意力:token 之間互相看
    x = x + ffn(x)         # FFN:每個 token 各自做一次非線性變換
    return x

注意力負責讓 token 彼此交換資訊,FFN 負責「消化」——它是逐 token 獨立運算的兩層 MLP,模型大部分的參數其實都堆在這裡。

所以當我們說 Dense、MoE、Hybrid,講的從頭到尾都是同一個問題:這塊 FFN 要怎麼擺?


Dense Transformer:每個 token 都走同一條路

最直覺的做法。整層只有一個 FFN,所有 token 不管內容是什麼,全部送進同一組權重算一遍。

def dense_layer(x):
    x = x + attention(x)
    x = x + ffn(x)         # 唯一的 FFN,全部 token 共用
    return x

好處是單純。沒有路由、沒有調度、訓練穩定,推理時也不需要決定「這個 token 該交給誰」。LLaMA 2 / 3、早期的 GPT 系列走的都是這條路。

代價在規模放大時才顯現:所有參數每一步都得參與計算。 一個 70B 的 dense 模型,處理每一個 token 都要動用全部 70B 的權重。你想讓模型更聰明,唯一辦法是把參數堆更多——但計算量是跟著一起漲的,兩者綁死。

這就是 MoE 想拆開的東西。


MoE Transformer:把 FFN 拆成一堆專家,每次只挑幾個

MoE(Mixture of Experts,專家混合)的想法很大膽:與其用一個大 FFN,不如放一排小 FFN——叫它們專家(expert)——然後每個 token 只挑其中幾個來算。

def moe_layer(x):
    x = x + attention(x)
    scores = gate(x)                 # 門控:算這個 token 對每個 expert 的適配分數
    idx = top_k(scores, k=2)         # 只挑分數最高的 2 個
    out = sum(scores[i] * expert[i](x) for i in idx)
    x = x + out                      # 其餘 expert 這一步完全沒動
    return x

關鍵在那個 gate(門控網路)。它是個小型的可學習網路,替每個 token 算出「該交給哪些 expert」,然後只啟動分數最高的 top-k 個(常見 k=1 或 2)。其他 expert 這一步的參數一動也不動。

這就是稀疏激活(sparse activation),也是開頭那個「總參數 vs 啟動參數」的來源:

  • 總參數:所有 expert 的權重加起來,決定模型的容量上限
  • 啟動參數:單個 token 實際走過的那 k 個 expert,決定每一步的計算量

兩者第一次被解耦了。DeepSeek-V3 有 256 個路由專家、每個 token 只走 8 個——換算下來,每個 token 大約只動用了 3% 的 FFN 計算量,卻能享受 671B 的參數容量。

代表作一路演進,top-k 越選越多、專家越切越細:

模型專家數每個 token 啟動總 / 啟動參數
Switch Transformer數十~數千top-1
Mixtral 8x7B8top-2約 47B / 13B
Grok-18top-2314B / 約 79B
DeepSeek-V3256 + 1 共享top-8671B / 37B

DeepSpeed-MoE 不是模型,是工具。 你可能在哪看過它被列進「代表模型」——它其實是微軟的訓練/推理框架,幫你把 MoE 跑起來的那套基礎設施,不是一個權重檔。混淆這點會在你找 checkpoint 時白忙一場。

MoE 不是免費的午餐,它把成本搬到別的地方:

門控容易偏心。 如果不管,gate 會養成只愛少數幾個 expert 的習慣,其他 expert 餓死、容量浪費掉。Switch Transformer 用一個輔助的 load-balancing loss(負載平衡損失) 懲罰分配不均;DeepSeek-V3 則乾脆拿掉輔助 loss,改用一個會隨負載動態調整的 bias 來把 token 推開。這是 MoE 訓練永遠要顧的一條線。

省了計算,沒省記憶體。 每個 token 只算 k 個 expert,FLOPs 是省了;但全部 expert 的權重還是得載進記憶體待命。所以 MoE 是拿「記憶體換計算」——它在記憶體夠、但算力或延遲吃緊的情境才划算。

分散式下通訊很貴。 expert 通常分散在不同 GPU 上,token 被路由到哪、就得把資料送過去再收回來,這個 all-to-all 通訊在大規模訓練時是真實的瓶頸。


Dense-MoE Hybrid:不是二選一,是縫在一起

知道兩端之後,中間地帶就好理解了:誰說一個模型只能全 Dense 或全 MoE?Hybrid 就是把兩者混用。但「混」有兩種完全不同的縫法,常被講成同一回事——拆開看才清楚。

縫法一:層與層之間交錯

一部分層用普通 Dense FFN,另一部分層用 MoE。最常見的安排是前幾層保持 Dense,後面才換 MoE

def model(x):
    for i, layer in enumerate(layers):
        x = x + attention(x)
        if i < n_dense:
            x = x + dense_ffn(x)   # 前幾層:穩定的稠密 FFN
        else:
            x = x + moe_ffn(x)     # 後面層:稀疏的專家路由
    return x

DeepSeek-V3 就是這樣——它最前面幾層用的是 Dense FFN,剩下的才是 MoE。直覺上,靠近輸入的低層在處理比較通用的特徵,讓全部參數一起上反而穩;高層的表徵更分化,才適合交給專家分流。

縫法二:同一層裡並聯

更進階的縫法是 Dense 跟 MoE 在同一層同時跑,結果相加。Snowflake Arctic 是教科書級的例子:它把一個約 10B 的 Dense Transformer,跟一組 residual 的 128×3.66B MoE 並聯起來,總量 480B、每個 token 啟動 17B(top-2)。

def arctic_layer(x):
    x = x + attention(x)
    x = x + dense_ffn(x) + moe_ffn(x)   # 稠密路徑與稀疏路徑並聯,結果相加
    return x

並聯不只是為了精度。Arctic 的論點是訓練效率:MoE 那條路徑要做昂貴的 all-to-all 通訊,而 Dense 路徑只要做本地計算——兩條並聯時,通訊剛好可以躲在計算背後重疊掉,把 MoE 最痛的通訊開銷藏起來。這是把架構設計拿來解工程瓶頸的漂亮案例。

其實還有第三種:層內的「常駐專家」

順帶一提,DeepSeek-V3 那個「256 + 1 共享」裡的 shared expert(共享專家),本質上也是一種 Dense-MoE 混血——只是發生在 expert 這一層。它是所有 token 都會經過的常駐 FFN,不參與路由,永遠開著;其餘 256 個才走 top-k 選擇。

道理是:有些變換對每個 token 都有用(那就用 Dense 的方式常駐),有些才需要因 token 而異(那才交給稀疏路由)。所以 DeepSeek-V3 同時用上了兩種 hybrid——層間交錯,加層內共享專家。


三者怎麼選

把上面的取捨收進一張表。注意「推論效率」這欄別誤讀:MoE 是單位啟動參數的計算效率高,不代表它整體更省——它吃的記憶體更大。

DenseMoEHybrid
參數 / 計算解耦綁死解開解開
每 token 計算量高(全參數)低(只算 k 個)
記憶體需求高(全 expert 待命)
訓練穩定性要顧負載平衡看縫法
工程複雜度高(路由、通訊)最高
代表模型LLaMA 2/3Mixtral、Grok、DeepSeek-V3Arctic、DeepSeek-V3

幾條實務上的判斷線:

想要單純、可控、好部署,選 Dense。 中小模型、或你不想碰路由與分散式通訊那一整套,Dense 永遠是穩的起點。標準的 PyTorch / HuggingFace Transformer 模組直接就能用。

想用固定算力換更大容量,選 MoE。 你有記憶體、但每個 token 的延遲和 FLOPs 有上限——這正是 MoE 的主場。別自己刻 gate 和 expert 調度,DeepSpeed-MoE、Megatron 這類框架已經把負載平衡和通訊處理好了。

Hybrid 不是「我全都要」,是用來解特定瓶頸的。 DeepSeek-V3 用層間交錯換低層的訓練穩定,Arctic 用層內並聯把 MoE 的通訊藏進 Dense 的計算——它們都是先有一個具體問題,才有那個混合策略,不是為混而混。如果你說不出自己要解的是哪個瓶頸,那大概還不需要 Hybrid。


小結

Dense、MoE、Hybrid 聽起來像三種模型,其實是同一個問題的三種答案:每一層的 FFN,要不要讓所有 token 都走同一條路?

Dense 說都走,換來單純與穩定,代價是參數和計算綁死。MoE 說只走一小撮,把容量和算力解耦,代價是記憶體、負載平衡、和分散式通訊。Hybrid 說兩種都用一點——但它的價值不在「兼具優點」,而在它總是對著一個具體的工程瓶頸下手。

所以下次再看到「671B 總參數、37B active」,你不會再卡住。你會直接想到:這是 MoE,總參數是它的容量帳,啟動參數是它的計算帳——而那中間的差距,全長在 FFN 這塊地上。