昨天我們把模型名字拆成六個欄位,搞清楚了 35B-A3B 到底是 35B 還是 3B。檔名最後一段 Q4_K_M.gguf 我故意留到今天,因為它值得一整篇——Day 1 那晚救回 40 秒的兩刀,其中一刀就是換一顆量化檔。
場景你一定遇過:上 Hugging Face 找某顆模型的 GGUF,跳出七八個 repo,unsloth、bartowski、lmstudio-community、ggml-org,每家都有 Q4_K_M,大小幾乎一樣。你挑了下載數最多的那個,心想反正同一個規格。
我把三家的 Llama-3.2-1B-Instruct-Q4_K_M.gguf 都抓下來,檔案大小是 807,694,464 / 807,694,368 / 807,690,688 bytes【本機實測】。最大差 3,776 bytes,0.0005%。
Q4_K_M 確實是 llama.cpp 定義的預設 recipe,這點等一下我用拆檔案證明。但同一個 recipe 不代表同樣的品質,而且差距藏在檔名不寫、model card 也常常不寫的地方。
「Q4_K_M 只是檔名,大家隨便取的」這個說法流傳很廣,但它是錯的。Q4_K_M 是 llama.cpp 的 quantization preset,llama-quantize 直接吃這個字串當量化目標,原始碼裡有對應的 LLAMA_FTYPE_MOSTLY_Q4_K_M【官方:llama.cpp tools/quantize/README.md、src/llama-quant.cpp】。
把三顆檔案拆開,看每個張量被壓成什麼型別【本機實測,腳本見文末】:
| 上傳者 | Q4_K | Q6_K | F32 | bits/weight |
|---|---|---|---|---|
| bartowski | 830.5M (67.2%) | 405.3M (32.8%) | 0.1M | 5.1779 |
| unsloth | 830.5M (67.2%) | 405.3M (32.8%) | 0.1M | 5.1779 |
| lmstudio-community | 830.5M (67.2%) | 405.3M (32.8%) | 0.1M | 5.1779 |
三家的 tensor type 組成完全一致:同樣 96 個張量是 Q4_K、同樣 17 個張量是 Q6_K,bits/weight 連小數點後四位都一樣。注意這說的是「哪個張量用哪種型別」,不是檔案內容相同——量化後的數值並不一樣,等一下就會看到差在哪。

圖 1:Q4_K_M 給的是一套預設的 tensor-type recipe。source、量化器版本、imatrix、校準資料、人工 override 都不包含在這個名字裡,品質差距就發生在這一半。
命名文法是 Q{位元數}_{變體}_{尺寸}:
Q4:主要張量的目標型別是 4-bit。是「主要」,整顆模型的平均位元數會更高。_K:K-quant,ggml 的一種 block quantization type。權重切成 block 壓縮,每個 block 有自己的 scale,連 scale 本身都再被量化過,比舊的 _0/_1 legacy 格式省得多(legacy 如今只剩 Q8_0 還常見)。_M:medium。不是「全部壓 Q4_K」,而是模型層級的 mixed-quant preset,大部分壓 Q4_K,一部分敏感張量升到更高精度。那 17 個 Q6_K 張量長這樣【本機實測】:
token_embd.weight
blk.{0,1,4,7,8,9,12,15}.attn_v.weight ← 8/16 層
blk.{0,1,4,7,8,9,12,15}.ffn_down.weight ← 8/16 層
attn_v 和 ffn_down 各一半,對得上原始 PR 的定義:「uses GGML_TYPE_Q6_K for half of the attention.wv and feed_forward.w2 tensors, else GGML_TYPE_Q4_K」【官方:PR #1684】。同一支 PR 講明的是 output.weight 在各種 quant mix 裡都保留 6-bit,所以那不是 _M 的功勞。token_embd.weight 也是 Q6_K 則是因為這顆 1B 是 tied embeddings,llama.cpp 讓 token embedding 跟著 output 張量走【官方:src/llama-quant.cpp】。
這組層號不是隨機的,是原始碼裡 use_more_bits() 挑出來的【官方:src/llama-quant.cpp】。但名單會變:同一份原始碼,Q4_K_M 遇到 70B 把 attn_v 拉到 Q5_K,遇到 8-expert MoE 拉到 Q8_0,遇到 Falcon 走另一條分支。所以它是一份依模型而異的預設 recipe,不是逐張量寫死的規格。
另一個誤解:4.83 bpw 這種「Q4_K_M 的固定位元數」不存在。我實測 Llama-3.2-1B 是 5.1779 bpw,官方文件列 Llama-3.1-8B 是 4.8944【官方:tools/quantize/README.md】。bpw 是模型乘上 preset 的結果,不是 preset 的屬性。
最後補兩個前綴。IQ 是 I-quant,codebook-based 的量化方案;UD- 是 Unsloth 自家的動態配置。兩件事要分清楚:IQ 指的是量化方案,不是「有沒有校準」;而且「IQ 同體積一定比 K-quant 好」是過度簡化,官方 Llama 3 8B 的表上,3-bit 區 iq3_S 的 KLD 只有 q3_K_S 的一半多一點,4-bit 區 iq4_NL 卻輸給體積相當的 q4_K_S【官方:tools/perplexity/README.md】。在這張表上,優勢集中在低位元區。真正跟校準綁定的只有極低位元:IQ1_S/IQ1_M/IQ2_XXS/IQ2_XS/IQ2_S/IQ3_XXS 六種,加上 Q2_K_S 裡的 Q2_K 張量,llama.cpp 硬性要求 imatrix,不給就拒絕量化【官方:src/llama-quant.cpp 的 tensor_requires_imatrix()】。
llama.cpp 引入 K-quant 的那支 PR 附了 perplexity 對照表(wikitext,越低越好),LLaMA 7B 的數字皆【官方】(來源:github.com/ggml-org/llama.cpp/pull/1684 )
| 精度 | PPL | vs F16 |
|---|---|---|
| F16 | 5.9066 | — |
| Q6_K | 5.9110 | +0.07% |
| Q5_K_M | 5.9208 | +0.24% |
| Q4_K_M | 5.9601 | +0.91% |
| Q3_K_M | 6.1503 | +4.1% |
| Q2_K | 6.7764 | +14.7% |

圖 2:在 2023 年那組原始 LLaMA 7B 實驗裡,Q4_K_M 落在很漂亮的體積/品質折衷點,這是它後來被廣泛當成起手選擇的原因之一。
Q4_K_M 的 PPL 只比 F16 高約 0.9%,體積剩三成。以相對 F16 的 PPL 增量算,Q3_K_M 約是 Q4_K_M 的 4.5 倍,Q2_K 約 16 倍【推算,由上表換算】。這是增量的倍率,不是「品質差 4.5 倍」——PPL 不是線性的品質百分比。這張表也只涵蓋 2023 年的原始 LLaMA 7B 在 wikitext 上的表現,不是所有模型的通則。
PPL 聚合的是「語料裡正確的下一個 token」拿到多少機率,它不比較整個 vocabulary 上的分佈。KL divergence 才比:拿 FP16/BF16 當參考,逐 token 看兩邊的完整輸出分佈被扭曲多少,0 代表完全相同【官方:tools/perplexity/README.md】。
社群早期最完整的一份量測(Mistral-7B,imatrix 校準,wiki.test),數字皆【第三方實測】(來源:gist.github.com/Artefact2/b5f810600771265fc1e39442288e8ec9):
| 精度 | KL 中位數 | KL q99 |
|---|---|---|
| Q6_K | 0.0032 | 0.0222 |
| Q5_K_M | 0.0043 | 0.0368 |
| Q4_K_M | 0.0075 | 0.0885 |
| Q3_K_M | 0.0171 | 0.2546 |
以中位數比,Q4_K_M 的 KL 是 Q6_K 的 2.3 倍;比到 q99(只有 1% 的 token 比這個門檻更糟),倍率拉到 4.0 倍【推算,由上表換算】。也就是 per-token KL 分佈的尾端惡化得比中位數快:多數位置差得沒那麼誇張,少數位置偏得特別遠。這也解釋了為什麼平均指標看起來接近,用起來卻偶爾出包。

圖 3:中位數是 2.3 倍,到了 q99 變成 4.0 倍。尾端的相對惡化明顯更大,平均值會騙人的地方就在這裡。
tensor 組成一模一樣,剩下的差別在 Q4_K_M 沒規定的那半邊:用什麼校準資料、從哪個 checkpoint 起手、用哪個版本的量化器。這些不寫進檔名,但有一部分寫進了 metadata【本機實測】:
| 上傳者 | imatrix | 校準 dataset | chunks |
|---|---|---|---|
| bartowski | ✅ | calibration_datav3.txt |
125 |
| unsloth | ✅ | unsloth_calibration_Llama-3.2-1B-Instruct.txt |
689 |
| lmstudio-community | ❌ | — | — |
一顆沒掛 imatrix,掛了的兩顆校準語料也完全不同——unsloth 指向的是一份以該模型命名的 calibration dataset,chunk 數是 bartowski 的 5.5 倍(檔名只能證明命名,內容有沒有真的針對這顆模型調過,metadata 看不出來)。順手也驗了本機 ollama 拉下來的 llama3.1:8b-instruct-q4_K_M、qwen3.6:35b、gemma4:26b,三顆都沒有 quantize.imatrix.* 欄位【本機實測】。
第三方的 Gemma 4 E4B 量測裡,同樣叫 Q4_K_M:bartowski 的 KL 是 0.072,lmstudio-community 是 0.207,ggml-org 是 0.208【第三方實測】(來源:localbench.substack.com,對 BF16 參考模型跑約 25 萬 token)。差了約 2.9 倍。
口徑要先講清楚:localbench 算的是 top-40 截斷 KL,我下面用 llama-perplexity 算的是完整 logits。同一份 benchmark 內比倍率可以,兩邊的絕對值不能並排比。
我也用手上這三顆自己跑了一遍,拿同一顆模型的 BF16 當參考(wikitext-2 raw test,200 chunks,約 10 萬 token)【本機實測】:
| 上傳者 | imatrix | PPL | Mean KLD | Median KLD | q99 KLD | top-1 一致率 |
|---|---|---|---|---|---|---|
| bartowski | ✅ | 14.7304 | 0.035280 | 0.023675 | 0.2346 | 90.088% |
| unsloth | ✅ | 14.7388 | 0.034736 | 0.023379 | 0.2326 | 89.898% |
| lmstudio-community | ❌ | 14.6904 | 0.041873 | 0.029238 | 0.2614 | 89.239% |
看最後一列。沒掛 imatrix 的那顆,PPL 是三顆裡最低的,比 unsloth 低 0.33%,照 PPL 的讀法它「最好」。同一顆檔案的 Mean KLD 卻比 unsloth 高 20.5%,中位數高 25.1%,跟 BF16 選出同一個 top-1 token 的比率也是三顆最低【推算,由上表換算】。
**兩把尺給出相反的排名。**它們問的問題本來就不同:PPL 問「對真正的下一個 token 給了多少機率」,KL 問「離 BF16 有多遠」。目標是忠實重現原模型就看 KL,但 KL 低不保證 downstream 任務更強。
有掛 imatrix 的兩顆彼此只差 1.6%,遠小於跟第三顆的 20.5%。這與「imatrix 有幫助」一致,但那 20.5% 不能全記在 imatrix 帳上——換 uploader 就同時換了量化器版本與 source,這是觀察不是對照實驗。真正隔離出它的是官方那張 Llama 3 8B scoreboard,其他條件全固定:Q4_K_M 掛 imatrix 的 KLD 是 0.028152,不掛 0.031273,改善 11%;Q4_K_S 則是 0.031951 對 0.043136,改善 26%【官方:tools/perplexity/README.md,百分比為推算】。

圖 4:三顆檔案在檔名、大小、tensor type 組成、bpw 四個維度上完全無法區分。分得出來的是 metadata 裡的校準資訊,以及跑一次 KL 才看得到的差距。
差距至少來自四類,哪一類主導會隨模型變:
Q4_K_M 組成可能不同。llama-quantize 支援 --output-tensor-type、--token-embedding-type,以及吃 regex 的 --tensor-type【官方:tools/quantize/README.md】。上傳者可以覆寫特定張量的型別,同時仍然把檔案叫做 Q4_K_M。第 3 點值得單獨講,坊間的描述常常是錯的。imatrix(importance matrix)不是「把 bit 預算優先分給重要通道」,那是 mixed-bit / dynamic quantization 在做的事。它是拿校準語料跑前向、收集各張量的 activation 重要度統計,量化時用這些統計降低誤差【官方:tools/imatrix/README.md】,不會把 Q4_K 張量改成 Q5/Q6。我的實測正好印證:有掛跟沒掛的兩顆,tensor type 組成一模一樣。
所以選檔的順序是:量化等級決定體積/品質的主要 trade-off,同一個等級裡再去看來源、imatrix 與 recipe。反過來說「挑上傳者比挑 quant level 更重要」會踩到官方 PPL 表,Q4 到 Q2 的落差遠大於同級不同家的落差。
也別把它變成上傳者排行榜。Unsloth 的 Dynamic 2.0 是逐模型客製的 recipe,這本身就說明 recipe 是 model-specific 的,某家在 Gemma 上做得好不保證在 Qwen 上也好。判準不是名氣或下載量,是它有沒有寫清楚 source revision、quant recipe、imatrix 與校準語料。
新版 llama.cpp 的 quantize 會把校準資訊寫進 metadata,一行指令就夾得出來:
pip install gguf
gguf-dump --no-tensors model-Q4_K_M.gguf | grep -i imatrix
# 有掛會看到:
# quantize.imatrix.file / quantize.imatrix.dataset
# quantize.imatrix.entries_count / quantize.imatrix.chunks_count
這篇的實測就是這樣跑的,兩支腳本都能重跑:verify-gguf.py 拆 tensor 組成、比對 metadata,內建的 assert 會自己驗結論還成不成立;measure-kl.sh 跑上面那張 KL 表。
有個但書:沒有這些欄位不代表沒掛,舊版工具不記錄;有欄位則是產檔工具自己宣告用過 imatrix,很強的正向證據,但 metadata 可以改,它不是不可偽造的 provenance。這個檢查拿來縮小候選,不能拿來判死刑。

圖 5:三十秒的選檔流程。先用等級圈出體積預算,再在同級裡用 metadata 分辨,最後才是自己的回歸測試。
localbench 對 Qwen3.6-35B-A3B 的分類實測裡,對後端工程師最重要的一條是:所有類別中 tool calling 對量化最敏感。即使 Q8_0,tool calling 的 KL 仍有 0.177,同一份量測裡長文件是 0.121,coding 與 science 在 0.010 以下【第三方實測】(來源同 localbench)。
合理的解釋是函式名、JSON 結構這種「一個 token 錯就全錯」的輸出,正好踩在分佈尾端。但那份 benchmark 只證明了這個類別敏感,沒證明成因。
我的做法是:一般聊天與摘要從 Q4_K_M 測起;要做 agent、tool calling、結構化輸出,記憶體允許就把 Q8_0 / Q6_K 一起納入比較。能不能往 Q5/Q4 壓,那份資料回答不了,連 Q8_0 都還有 0.177,該篇也沒給建議底線。這種界線只能用你自己的 tool-call 成功率回歸測試去壓。
從 Q4_K_M 升到 Q5_K_M 值不值?以官方 Llama-3.1-8B 的數字是 +16.5% 體積【官方 + 推算】,買到的是尾端收斂,Mistral-7B 那張表的 q99 KL 少 2.4 倍【推算,不同模型與語料,只當量級參考】。
T3/T4 那個世界(RTX PRO 6000、H100 上的高吞吐 serving)主流路線通常不是 GGUF,而是 AWQ/GPTQ 這類 checkpoint scheme、FP8,以及新硬體上的 NVFP4 與 MXFP4。有些由原廠直接提供量化 checkpoint,有些仍是部署方自己 PTQ,不能一概當成有官方背書。
vLLM 現在確實能載 GGUF,裝上 vllm-gguf-plugin 就能 vllm serve unsloth/Qwen3-0.6B-GGUF:Q4_K_M --tokenizer Qwen/Qwen3-0.6B(官方建議直接用 base model 的 tokenizer,GGUF 那份轉換慢又不穩),只是整條路線官方自己標為 "highly experimental and under-optimized"【官方:docs.vllm.ai】。所以不是「vLLM 不玩 GGUF」,而是 GGUF 主要流行在 llama.cpp 這條 local inference 生態,在 production serving 上不是主流路線。這條格式天梯我們第 19 天爬。
不用 GPU。一個 Python 環境加任何一顆下載過的 GGUF 檔就能跑 gguf-dump 驗 imatrix,三顆 1B 對照檔不到 2.4GB。想自己量 KL 要多一顆 BF16 參考檔(1B 約 2.5GB)和一個跑得動 llama.cpp 的環境。我這輪 200 chunks 三顆約十分鐘,中間產生的參考 logits 檔有 7.8GB,跑完記得刪。
Q4_K_M 是有定義的預設 recipe:同樣的 source、同樣的 llama.cpp 版本與預設參數下,tensor-type 配置可重現。三家拆開來連 bpw 的小數點後四位都一樣。_M 體現在一半的 attn_v 加一半的 ffn_down 升 Q6_K;現代 llama.cpp 會依架構與版本調整,而選層看的是張量處理序號,不是層號。gguf-dump | grep imatrix 三十秒可驗,但只能單向確認。明天,Day 06:「六顆主流地端模型:誰適合什麼場景、起手參數與雷」。今天你學會了同一顆模型該挑哪個檔,明天解決更前面的問題,一開始該挑哪顆模型:六顆你的機器跑得動的主流選手,各自的適用場景、官方建議參數,和那些文件不寫但一踩就中的雷。
咱們明天見。