~/blog/dgx-spark-deepseek-v4-flash-architecture

DeepSeek-V4-Flash on DGX Spark · part 6

[地端 LLM] 284B 塞得進 128GB、長 context 還跑得動:DeepSeek-V4-Flash 打的是 KV cache,不是參數量

cat --toc

TL;DR

一顆 284B 能在單顆 128GB GB10 上跑得動,關鍵不是權重小(Q2 還是 ~80.8GiB),是 DeepSeek-V4-Flash 打從架構就衝著 KV cache 來——長 context 真正會爆的是它。混合式壓縮 attention(SWA + CSA + HCA)加上 top-512 稀疏 indexer,把 64K 的 KV 壓到只剩 871MiB、每步只讀幾百列。所以你沒辦法再靠量化 KV 省記憶體——它本來就是 FP8、又小。參數量從來不是敵人,KV cache 才是。

白話版:284B 塞得進小盒子,靠的不是模型小,是它不整疊重讀

想像你桌上有一疊會議記錄,而且每開一次會就加厚一頁。這疊記錄,就是模型的 KV cache——它是「這段對話到目前為止」的即時記憶。一般模型每次要接你的話,都得從第一頁翻到最後一頁;紀錄越厚,翻得越久。你聊越久,它就養越肥,慢也慢在這裡。真正把一顆大模型擠出小電腦的,通常不是模型本身多大,是這疊越長越厚的記錄。

DeepSeek-V4-Flash 就是設計來讓這疊記錄又薄又好翻。它做兩件事:一,把記錄壓成摘要卡——有些層每 4 頁壓成一張,有些層更狠,128 頁壓成一張;二,要接話時不整疊翻,只抽出最相關的幾百張卡來看。結果是 64K token(大概幾萬字)的記錄,壓到不到 1GB,而且每次只翻幾百張。這就是為什麼一顆 2840 億參數的模型,在一台照帳面根本養不起它的電腦上,長對話還跑得順。


前言

跑地端大模型,大家第一個問的都是同一句:2840 億參數,128GB 塞得下嗎?老實說塞得有點勉強——但這其實是這題最無聊的一半。真正會把你擠出這台盒子的,不是權重,是 KV cache(這段對話到目前為止的即時記憶)。你講越久它養越肥,一般架構下養到最後,就是它把你踢出去。

這是 DeepSeek-V4-Flash on DGX Spark 系列 Part 6。前面幾篇都很操作面:Part 1 讓 284B 跑上單顆 GB10、Part 2 挑每天用的設定、Part 3 論證 Q2 權重還是強過塞得下的小模型、Part 4 追一個月後才冒出來的 KV evict 風暴。這篇是撐在底下的架構篇——把前面那些「為什麼有效」講清楚。細節我對著 DeepSeek-V4 架構論文 (arXiv 2606.19348) 跟 ds4 的實作核過。

一句話的主軸:長 context 下,地端 LLM 的敵人不是參數量,是 KV cache 的佔用——而 DeepSeek-V4-Flash 這顆模型,打從架構就是衝著 KV cache 來的。

284B 每步只動用 13B:算力早就稀疏,這篇講第二種稀疏——記憶體

先釘幾個數字。DeepSeek-V4-Flash 總參數 284B,每個 token 實際動用 ~13B——一顆 MoE,256 個 routed expert、top-6 加一個 shared、43 層、hidden 4096。所以它在算力這邊本來就稀疏:284B 裡每步只有 13B 在做事。

這種稀疏大家比較熟。這篇要講的是第二種、比較隱形的——記憶體這邊的稀疏。前一種決定你「每吐一個字要算多少」,後一種決定你「拖著多大一坨對話記憶在跑」。長 context 用久了咬你的,是後面這個。

兩件事分開做:壓縮你「存」的,只讀你「需要」的

DeepSeek 打 KV 是兩個獨立的動作,別混在一起看:

  • (A) 壓縮你「存」下來的東西——每個 token 留在 cache 裡的,不是原封不動的 key/value,是壓過的版本。
  • (B) 每次接話,只讀你真正需要的那一小片——不是把整段 context 都拉出來重算。

一個縮的是佔用,一個縮的是每步的讀取量。下面分開拆。

(A) 壓縮你存的:混合式 attention,64K 的 KV 只剩 871MiB

第一件事,是一套交錯安排的混合式 attention:不同層用不同壓法——頭兩層 SWA 只留個小滑動窗、不壓,其餘層存進 cache 的都是「壓縮過」的東西(程式碼裡叫 attn_comp_kv,512 寬)。每層壓多少不是寫死的,是從 config 的 deepseek4.attention.compress_ratios 讀出來的一張排程表。

這表看最右欄——同一顆模型,不同層存的密度差到 32 倍:

做法壓縮率
0–1SWA(sliding window,只看回頭固定一段)不壓
偶數層 2–42CSA(Compressed Sparse Attention)4(每 4 個 token 壓成 1)
奇數層 3–41HCA(Heavily Compressed Attention,密集地讀、不做 top-k)128(每 128 個 token 壓成 1)

HCA 那層壓到 128 倍,所以 64K 下整層只剩 ~512 個壓縮 entry,少到它乾脆全讀、不必再挑。加總起來,64K 的 KV 大概是 871MiB(這是 logical / CPU 端的數字;CUDA graph 實際會多留一點、~1.2GiB 給常駐的 prefill cache)。同樣 64K 換一般 full attention,KV 會到幾十 GB。就這一個數字,把「284B 怎麼塞得下」整題重新框了:在我實際會跑的 context 長度下,KV 跟 ~80.8GiB 的權重比是零頭,不是反過來。

混合式 attention:層 0–1 用 SWA、偶數層 CSA 壓 4 倍、奇數層 HCA 壓 128 倍,加上 top-k indexer 把 284B 的 KV 壓進 128GB

(B) 只讀你需要的:lightning indexer 挑的是壓過的 entry,一步只讀幾百列

第二件事縮的是另一種成本:你每個 decode step 要多少。這就是 lightning indexer——DeepSeek Sparse Attention(DSA,原生的 top-k 稀疏 attention)裡「挑選」的那一半。它只在 CSA 層做:一個輕量 indexer(用自己一組 128 維的 key,index_comp_kv)幫壓縮過的 entry 評分,只留分數最高的 top-512(參數 n_indexer_top_k=512,Pro 變體用 1024)。CPU 算出一個 bool mask(comp_allowed),GPU 就直接把選中的 row id 丟進 indexed kernel。

這裡有個算術我第一版草稿寫錯了,得講對:indexer 挑的是「壓縮過的 entry」,不是原始 token。 64K 下,CSA 層已經把 context 壓縮 4 倍 → 剩 ~16K 個壓縮 entry;top-512 大約只佔其中 3%(再加 SWA 那 128 個 window)。HCA 層根本不用 top-k——已經壓 128 倍、整層只有 ~512 個,全讀也才幾百個。所以每個 decode step 只讀「幾百個壓縮列」,不是 64K。

而且 context 越長,這招越賺:top-k 的額度固定是 512,context 一直長,佔比只會越來越小。一般讓長 context 很痛的原因——字越多、要回頭讀的越多——正好就是這招要壓下來的。

疊起來:284B 長 context 好用,是因為 KV 小到不用怕

兩件事合起來,「284B 長 context 怎麼在 128GB GB10 上還好用」這題就自己解開了。權重是固定成本(Q2 下 ~80.8GiB),一次付清。KV 很小(64K 下 ~871MiB),而且一次只讀幾百列。盒子有空間,decode 每吐一個字也不用拖著整段 context 重讀——這就是一顆 284B,在一台照帳面根本養不起它的硬體上,長 context 還跑得順的原因。

為什麼你沒辦法靠量化 KV 再省記憶體

這件事我在 Part 2 花過真功夫,定案了:KV 這邊沒辦法靠量化省記憶體,而且量了也省不到。 兩個原因,還互相加強。

一,壓過的 KV 本來就是降精度存的。論文在 RoPE 維度存 BF16、其餘非 RoPE 維度存 FP8(E4M3,每 64 個一組,配一個 2 的次方 scale)——非 RoPE 那部分已經是 8-bit,不是等你去壓的 f16。

二,ds4 的 CUDA attention path 根本不吃 f16 的壓縮 KV cache——你設 comp_kv_f16 它就直接跳出,這條路沒開。就算開了,能省的也只是 871MiB 的一小塊。

DeepSeek 在設計架構時就先把 KV 壓完了,所以那個常見的「量化 KV 塞更多 context」的招式,在這裡是既被擋住、又沒意義。(這剛好是 Part 3 權重故事的鏡像:權重狠狠壓,KV 別碰。)

埋伏筆:原生 indexer 跟 dense attention 重疊 93–96%,外掛擠不出東西

對 top-512 這種稀疏 attention,最直覺的問題是:代價呢?你只讀幾百列,會不會漏掉真正重要的那些 token?

我自己量了一輪——先講清楚,這是我的量測,不是論文的數字:原生 indexer 挑的位置,跟真正 dense attention 會 attend 的,重疊到 93–96%(我看的那幾層:L10 0.930 / L12 0.957 / L20 0.956)。它挑的幾乎就是 full attention 會加重的那些位置,而且只用一小部分的讀取量。

推論很直接:在 V4-Flash 上「外掛」一套稀疏 KV 方案沒用。 模型本身內建的已經夠好,你能再榨的,只剩它沒吃滿的那 4–7%——一個外部啟發式規則,不太可能為了這一小片,穩定壓過一個訓練進去的 indexer。數字下一篇(Part 7)放。

我的量測:原生 indexer 挑的位置跟真 dense attention 重疊 93–96%,近最優

收穫

最花時間的地方

不在讀懂這顆模型——SWA / CSA / HCA / indexer 每個概念都很單純。真正花時間的,是把「參數量才是記憶體問題」這個直覺戒掉。我一開始上這台盒子,滿腦子都在幫 80GB 級的權重抓預算,把 context 當次要煩惱在處理。架構把這件事整個顛倒:權重是一次付清、固定的一大塊,而那個本來會無限長大的——KV——才是 DeepSeek 工程掉、壓成零頭的部分。我花在「擠 KV 挪空間」的每一小時,都花在這題早就解掉的那一半上。

可搬走的診斷方法

在固定硬體上估一顆長 context 模型,把兩個數字分開算:權重佔用(固定、可量化),跟你真實 context 長度下的 KV 佔用(隨 token 漲、看架構)。一般 attention 模型,咬你的是第二個;像 V4-Flash 這種混合式壓縮 + top-k 的模型,第二個早就被拆掉引信。還有一個很具體的信號:如果一顆模型的 KV 本來就 FP8 存、它的 runtime 又不肯跑 f16 KV,那就是架構在告訴你 KV 這邊的工作在上游做完了——別再去那裡找量化的便宜,力氣拿去重用 prefill 比較實在(那是 Part 4)。

通用原則

長 context 下,決定一顆地端模型好不好用的佔用,是 KV cache,不是參數量。 一顆衝著 KV 蓋的模型——壓你存的、只讀重要的那一小片——會在一台照參數量看根本養不起它的硬體上,塞得下、又跑得快。看權重數字之前,先看 KV 這條路。

結論

濃縮版的濃縮版:

  1. 284B 長 context 塞得進 128GB GB10,是因為 KV 小,不是權重小。 ~80.8GiB 的 Q2 權重,64K 下 ~871MiB 的 KV。
  2. 混合式 attention 壓你存的: SWA(層 0–1 不壓)、CSA(偶數層 2–42 壓 4 倍)、HCA(奇數層 3–41 壓 128 倍),每層壓多少照 config 的 compress_ratios
  3. lightning indexer 挑的是壓過的 entry: 64K 下 ~16K 個 entry 裡只留 top-512(~3%),一步只讀幾百列,context 越長越賺。
  4. 別想量化 KV: 非 RoPE 維度本來就 FP8,ds4 的 CUDA path 還拒絕 f16 的壓縮 KV。省不到,力氣拿去重用 prefill。
  5. 想外掛稀疏 KV 方案的,先看原生 indexer: 跟 dense 重疊 93–96%,你能再榨的空間只有 4–7%。

說穿了,大家報的都是參數量,但決定這東西用一個月後還好不好用的,是 KV cache。V4-Flash 就是繞著這個區別蓋的——看懂這條路,這系列後面幾篇讀起來會不一樣。


本系列其他篇:Part 1 — 第一次跑 Q2 就以為模型變笨,真兇是 parser 不認 DSML · Part 2 — 把 15 tok/s 的 284B 當每天的 agent 大腦 · Part 3 — 權重就是正義:284B 砍到 2-bit 還是強 · Part 4 — 養了一個月,agent 悄悄不再快取:evict 風暴 · Part 5 — 推測解碼要看工作型態:agent +9%、散文 −4% · DeepSeek-V4 架構論文 (arXiv 2606.19348)

常見問題

DeepSeek-V4-Flash 是 284B,為什麼長 context 還塞得進 128GB?
因為長 context 真正會漲的是 KV cache(對話記憶),不是權重,而 V4-Flash 天生就在把 KV 壓小。它用一套混合式 attention:除了頭兩層 SWA 只留一個小滑動窗,其餘每層存的都是壓過的 cache,所以 64K token 的 KV 只有 ~871MiB,跟 ~80.8GiB 的 Q2 權重比根本是零頭。換一般 full attention,同樣長度的 KV 會到幾十 GB,養到最後把你擠出這台盒子的是它、不是權重。權重是一次付清的固定成本;KV 才是那個會無限長大的東西,而 DeepSeek 從架構上就把它壓下去了。
DeepSeek-V4-Flash 的 lightning indexer 是什麼?
它是 DeepSeek Sparse Attention(DSA)裡「挑選」的那一半,只在 CSA 層做。一個輕量 indexer(用自己一組 128 維的 key)幫壓縮過的 entry 評分,只留分數最高的 top-512(參數 n_indexer_top_k=512,Pro 變體用 1024)。關鍵是它挑的是「壓過的 entry」不是原始 token:64K 下 CSA 層已經把 context 壓縮 4 倍、剩 ~16K 個壓縮 entry,top-512 大約只佔其中 3%。所以每個 decode step 只讀幾百個壓縮列,而且 context 越長它越划算。
DeepSeek-V4-Flash 的 KV cache 能再量化省記憶體嗎?
不行,而且省不到什麼。壓過的 KV 本來就是降精度存的——論文在 RoPE 維度存 BF16、其餘非 RoPE 維度存 FP8(E4M3,每 64 個一組配一個 2 的次方 scale),那部分已經是 8-bit。ds4 的 CUDA attention path 又根本不吃 f16 的壓縮 KV,你設 comp_kv_f16 它就直接跳出,這條路沒開。就算開了,能省的也只是 871MiB 的一小塊。KV 這邊的記憶體工作架構早就幫你做完了,力氣拿去重用 prefill 比較實在。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。