量化會不會加速,取決於你怎麼寫 kernel
同一份 int4 KV cache 量化,eager 版相對 SRHT 慢 12–17%,把四步融成兩顆 Metal kernel 後追平;端到端對 fp16,Gemma 短前綴快 8.2%,但 Qwen 2K 前綴只吐兩個 token。差別在四步拆開呼叫,還是融成兩顆——以及平台、前綴與架構的前提。
數字全部來自 arXiv 2605.05699v1(2026-05-07)。作者是 Illumina 的 Mohamed Amine Bergach;這是單人預印本,未同儕審查。我們沒有在 Apple M1 上獨立重跑;「我認為」的地方會標出來。
先講一個畫面
你在筆電上跑 1B 模型,context 從 256 拉到 4K,解碼變慢、KV cache(解碼時累積的 K/V 快取)越長越吃記憶體。這篇要幫你看懂兩組數字:那個「慢 17%」跟「快 8%」分別在比什麼。還有下次看 benchmark 要問哪四件事,以及什麼時候該留 fp16 退路。
上網查,答案通常是「量化」。但下一句總是「會變慢」。
有一篇論文把這句話拆開了。同一份 int4(4-bit 整數)KV cache 量化,eager 版要四次 kernel 啟動(dispatch)。在 360M 模型上,這讓延遲比 SRHT(用 Hadamard 做隨機旋轉的對照法)高 17%。把四步融成兩顆 kernel 後,SmolLM 的同一組對照變成低 1%,1.7B 低 5%;Qwen 仍慢 1%。端到端對 fp16,Gemma-3 1B 在 256 前綴低 8.2%。
但先別高興。換到 Qwen2.5-1.5B 的 2K 前綴,它只吐兩個 token 就 EOS(提前結束)。這 8% 有平台、前綴、架構的前提,後面會把邊界畫出來。
這篇要把兩個常被混在一起的問題拆開。一個是實作稅:同一個演算法,eager 版四次 dispatch、融合版兩顆 kernel。另一個是部署帳:int4 cache 對 fp16,端到端到底快多少、什麼時候會壞。
先看那個「慢 17%」
論文的方法叫 rotate-then-quantize。KV cache 裡的每個 K/V 向量,先做一個隨機旋轉,再壓成 int4;attention 讀取時,再解量化、反旋轉回來。
這裡的旋轉是 SRFT(sign-randomized FFT):先乘上一組固定的隨機正負號,再做 FFT。目的是打散離群值。模型的 K/V 向量裡,少數很大的值會把量化尺度撐大,其他值就被壓成 0;先旋轉,讓每個座標看起來接近高斯分布,均勻量化才不會被少數大值拖垮。
問題在「四步」怎麼寫。eager 版把旋轉、量化、解量化、反旋轉拆成四個 PyTorch/MPS 呼叫;每一層、每一個解碼步,就是四次 kernel dispatch。
dispatch 是什麼?就是 GPU 每啟動一顆 kernel 的排隊與搬資料成本。計算本身可能只有幾微秒,但四次啟動、四次把資料搬進搬出,加起來就變成主成本。
論文量到的代價是:SmolLM2-360M 延遲高 17%、1.7B 高 16%、Qwen2.5-1.5B 高 12%。基準是 SRHT(sign-randomized Hadamard transform),另一種隨機旋轉,不是 fp16。
為什麼拿 SRHT 當基準?因為 SRFT 和 SRHT 的量化品質在誤差內,差別只在「旋轉用 FFT 還是 Hadamard」。拿它對照,才能把「旋轉本身的成本」和「四步拆開的實作稅」分開。
論文有一句話是整段的骨架,我照原意翻:
成本在 dispatch,不在計算。底層的 rfft 和 irfft 各只要個位數微秒,但四步分開呼叫,把這個開銷乘了上去。
這就是為什麼同樣的演算法,換一個寫法會從 +17% 變成 −1%。不是量化變好了,是四次排隊變成兩次(如圖 1)。
把四步融成兩顆,還不夠
融合的做法,是把前兩步和後兩步各自塞進一顆 Metal kernel(Apple 的 GPU 程式):forward 做旋轉加量化,inverse 做解量化加反旋轉。資料在中間不用回 device memory,留在 GPU 內部的快速記憶體。
同一組對照,SmolLM 反轉,Qwen 仍慢 1%:
| 模型 | SRHT 基準 | eager Δ | 融合 SRFT(Δ) |
|---|---|---|---|
| SmolLM2-360M | 37.4 ms/tok | +17% | 37.0 ms/tok(−1%) |
| SmolLM2-1.7B | 222.2 ms/tok | +16% | 211.9 ms/tok(−5%) |
| Qwen2.5-1.5B | 84.9 ms/tok | +12% | 85.7 ms/tok(+1%) |
(Δ 相對 SRHT,百分比取整;256 token 前綴加 128 token 生成;Apple M1。不是對 fp16。)
1.7B 的差距比 360M 大。eager 的罰則在兩個模型上差不多(+17% 對 +16%)。差別在融合後:1.7B 每層的 KV 維度是 2048,360M 只有 320。融合 kernel 的固定啟動成本被更多工作攤薄,所以它從 −1% 變成 −5%。
到這裡,故事看起來很乾淨:四步變兩顆,慢 17% 變快 1%(360M)。但如果你看到這裡就下結論「量化一定快」,會漏掉下一段。
端到端對 fp16 的 −8.2%,不是只有融合。它還需要三個條件。
第一,量化配方。 4-bit 如果只用 per-token(每個 token 一個尺度),Qwen 的 ΔPPL 會炸到 +7975。作者改成 per-channel λ 加 per-group abs-max(每個 channel 一個縮放係數,每 32 個值一組取絕對值最大),把同一個數字壓到 +638.6。這個配方是在同一顆融合 kernel 裡做的。
第二,dequant-prefix cache。 解量化過的前綴先存起來,不要每一步重算;最近 16 個 token 保留 fp16,只有這個視窗滿了才失效。沒有它,Qwen 在 1024 前綴是 +2.4% 慢;有了它,才變成 −1.6% 快(表內回算;論文文字寫 −0.7%)。
第三,模型架構。 Gemma-3 1B 有 sliding-window 層:大部分層只看固定視窗、用 fp16,只有少數 full-attention 層(看完整前綴)要付 dequant 成本。所以它的優勢可以撐到 4096;Qwen 是 28 層 full-attention,成本隨前綴線性成長。
把這三件事放回去,端到端的表長這樣:
| 模型 | 前綴 | fp16 → int4(ms/tok) | 延遲差 |
|---|---|---|---|
| Gemma-3 1B | 256 | 71.2 → 65.4 | −8.2% |
| Gemma-3 1B | 1024 | 83.3 → 82.5 | −0.9% |
| Gemma-3 1B | 2048 | 129.5 → 121.3 | −6.3% |
| Gemma-3 1B | 4096 | 188.5 → 182.4 | −3.2% |
| Qwen2.5-1.5B | 256 | 90.7 → 88.3 | −2.6% |
| Qwen2.5-1.5B | 1024 | 137.1 → 134.9 | −1.6% |
(Δ 相對 fp16;Apple M1;256 token 前綴加 128 token 生成。Qwen 2048 不在表裡,原因見下一節。Qwen 1024 的 −1.6% 是用表內 137.1 → 134.9 回算;論文文字寫 −0.7%,我們以表內數字為準。)
記憶體方面,Qwen 是 3.0–3.1×;Gemma 的 19.5× 不是同層比較(full-attention 層內約 3.2×),不能直接跟 Qwen 比。
−8.2% 是 256 前綴的最佳情況。同一個模型拉到 4096,只剩 −3.2%。Qwen 拉到 1024,只剩 −1.6%。「量化快 8%」不是一個常數,是一條會隨前綴長度變化的曲線。
快之前,先看它掉了多少
速度之外,還有一本帳:品質。量化對品質的影響,通常看困惑度(perplexity,PPL)的變化;ΔPPL 是量化後減 fp16 的差。
4-bit per-token 的 ΔPPL 如下(Cosmopedia,8192 個 held-out token):
| 模型 | FP16 PPL | 不旋轉(identity) | SRHT | SRFT |
|---|---|---|---|---|
| SmolLM2-135M | 6.61 | +1.96 ± 0.15 | +0.34 ± 0.01 | +0.38 ± 0.06 |
| SmolLM2-360M | 4.87 | +0.97 ± 0.08 | +0.20 ± 0.03 | +0.21 ± 0.02 |
| SmolLM2-1.7B | 3.77 | +1.04 | +0.16 | +0.16 |
(前兩列是 3 個 seed 的平均 ± 1σ;1.7B 因為計算成本只跑 1 個 seed。6-bit 與 8-bit 在這組測試裡無損。)
旋轉不是可選項。135M 不旋轉是 +1.96,旋轉後是 +0.38;差了大約 5 倍。這也解釋了為什麼「量化會壞」和「量化只是變慢」常常是同一件事的兩面:如果你的旋轉沒做對,4-bit 的誤差會直接反映在 PPL 上。
6-bit 和 8-bit 無損,4-bit 才是取捨點。3-bit 的絕對誤差更大,但這篇沒有把 3-bit 當賣點,我也不建議讀者從 3-bit 開始。
Qwen 的 4-bit 是另一個故事。Python reference 的 per-token 是 +7975.3,Metal 的 per-token 是 +7727.9;加上 per-channel λ 加 per-group g32 之後,融合版是 +638.6。這是 12.5 倍的改善,跟 Python reference 的 +654.6 同級。
但 +638.6 仍然是 +638.6。12.5 倍的改善,不等於可以上線。 論文把這個叫做「關掉災難」;我認為,它比較像是把火從整棟房子縮到一個房間,離安全還很遠。如果你要在 Qwen 上開 4-bit,請用任務指標驗收,不要只看 PPL 的相對改善。
Gemma 的結果比較好:per-token +18.7,融合後 +3.6。Python reference 是 −5.2,差距 +8.8 來自 kernel 的 fp32 reduction 與 rounding ordering,不是演算法。這一點作者自己做了兩個 ablation 排除。
它真的會壞:Qwen 2K 只吐兩個 token
現在回到那個「先別高興」。
Qwen2.5-1.5B 在 2048 前綴,int4 只生成 2 個 token 就 EOS;fp16 是 64 個。
| 項目 | fp16 | int4 |
|---|---|---|
| 生成 token 數(2048 前綴) | 64 | 2(EOS) |
| 峰值記憶體 | 4447 MB | 5527 MB |
| 作者退路 | — | 約 1.5K 以上退回 fp16 |
原因不只一個。dequant-prefix cache 加上 int4 storage,讓峰值記憶體從 4447 拉到 5527 MB(+24%);再加上 28 層 full-attention 的量化噪聲累積,logits 被推去提前 EOS。
我認為,讓 1024 變快的那個設計,也是讓 2048 變壞的設計之一。prefix cache 把解量化成本從「前綴越長越慢」攤成固定成本,但它同時佔記憶體;在 Qwen 這種全注意力堆疊上,兩件事一起發生,就爆了。
Gemma 為什麼沒事?它的 sliding-window 層用 fp16,只有少數 full-attention 層付 dequant 成本;所以前綴拉長,成本成長得比較慢。架構不同,同一份量化 cache 的結果就不同。
如果你要在自己的模型上開這個 cache,先測 2K。不是測「能不能生成」,是測「生成出來的東西對不對、會不會提前停」。作者給的退路很明確:超過約 1.5K,就退回 fp16。
看 benchmark 要問的四件事
這篇論文最有用的地方,不是「Apple Silicon 比較快」,是它把一張 benchmark 拆成幾個要問的問題。
第一,平台。 這是 unified memory(CPU 與 GPU 共用記憶體)還是獨立 HBM(顯示卡自己的記憶體)?論文說:在獨立 HBM、dispatch 開銷高的 GPU 上,慣常的取捨會回復。也就是說,同樣的 kernel 搬過去,不一定還快。看到「量化加速」先問跑在哪。
第二,kernel。 這是 fused 還是四步分開?如果 benchmark 沒寫,數字可能被 dispatch 稅主導。你可以直接問:一層一步幾次 dispatch?
第三,前綴與架構。 256 前綴的 −8% 不是 4K 的 −3.2%;full-attention 堆疊和 sliding-window 的曲線也不一樣。要求對方給 256、1K、2K 三組數字,不要只看一張最好的圖。
第四,品質。 ΔPPL 的 baseline 與配方是什麼?+638.6 比 +7975 好,但仍然是 +638.6。per-token 和 per-channel+group 是兩種不同的東西,不能拿來互相比。
| 問題 | 為什麼要問 | 怎麼查 |
|---|---|---|
| 平台是 unified memory 還是獨立 HBM? | 取捨是否反轉的邊界 | 看硬體規格;要求分平台數字 |
| Kernel 是 fused 還是四步分開? | 相對 SRHT 可能慢 12–17% | 看 benchmark 是否寫「4 dispatches」或「fused」 |
| 前綴多長、模型是 full-attention 還是 sliding-window? | 長 context 可能失效 | 要求 256/1K/2K 三組;看架構 |
| ΔPPL 的 baseline 與量化配方是什麼? | +638.6 比 +7975 好,但仍是 +638.6 | 看 baseline、per-token 或 per-channel+group |
別過度解讀
- 單一平台:只有 Apple M1;獨立 HBM 的 GPU 沒測。
- 模型都是小模型(135M–1.7B),沒有 7B 以上。
- 單人預印本,未同儕審查;我們沒有獨立複現。
- Gemma 的 19.5× 不是同層比較;full-attention 層內約 3.2×。
- Qwen 2K 會壞;作者自己寫了 1.5K 的退路。
- 這篇不是說「融合是唯一解」;它只處理四步拆開這一種成本。
結論:問題不是「量化快不快」
量化不是一個開關,是一條工程鏈:平台、kernel、量化配方、前綴長度、模型架構,任何一個換了,答案就換了。
這篇的兩本帳,可以這樣記:
- 實作稅 是同一份方法,eager 四步對融合兩顆,差距 11–21 個百分點。
- 部署帳 是 int4 cache 對 fp16,短前綴最多 −8.2%,長前綴會縮到個位數百分比(Qwen 1024 是 −1.6%,Gemma 4096 是 −3.2%),而且可能提前 EOS。
明天可以先做一件事:用你的模型跑 256、1K、2K 三個前綴,記錄 ms/tok 和輸出品質;如果模型是 full-attention 堆疊,1.5K 以上先留 fp16 退路;2K 是測試點。
如果你要的是有人陪你把自己的模型跑過這三個前綴,我們的企業 AI 導入健檢做的就是這件事。先判斷哪些工作現在就能交給 AI,哪些還不成熟。
量化系列走到這裡,三篇的弧線是:strata 講取捨,broken-on-arrival 講配方,這篇講實作。同一個問題,從「要不要量化」走到「怎麼寫那個 kernel」。
論文:arXiv 2605.05699v1(Mohamed Amine Bergach, Illumina)。前作:125B 模型跑在 12GB 顯卡、你下載的量化模型可能是壞的。