iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
AI Engineering

不是模型太慢,是你沒算過這筆帳:地端 LLM 工程實戰 30 天系列 第 10

Day 10 - 546 對 504 帳面同級,為什麼 4070 Ti 實測快 41%

  • 分享至 

  • xImage
  •  

Day 10 - 546 對 504 帳面同級,為什麼 4070 Ti 實測快 41%

Day 08 開賽前我押過一注。M4 Max 的記憶體頻寬帳面 546 GB/s,4070 Ti 是 504,同一個量級,所以我猜 Mac 會小勝 8% 左右。

開獎那天,兩台跑的是同一顆 Gemma 4 12B 官方 QAT、同一個 llama.cpp release b10488、同一組 -n 128 -r 10 -fa off -ngl 99

tg128(tok/s)
T1 M4 Max 128GB · Metal 40.83 [30.2–41.7]
T2 RTX 4070 Ti · CUDA 57.72 [57.71–57.72]

中位數 [全距],取多個獨立 process,口徑同 Day 08。T1 那個寬全距來自一筆冷卻不足的 run。

4070 Ti 快 41%。我押的方向跟幅度都錯了。

今天就是要把這 41% 拆開來看。範圍先講清楚:全篇只有 bs=1 的單流 decode——一個人、單發問題、逐字生成,沒有 speculative decoding。批次一拉大規則整套換掉,那是第 3 週的事。

先看 decode 在忙什麼

那組數字還有一個形狀:同樣這兩台,prefill 差了 7 倍,decode 只差 1.4 倍。同一組硬體、兩種工作差這麼多,至少很像不是卡在同一個地方。

decode 每產一個 token,GPU 大致都得把這個 token 用得到的權重重新串流一次——矩陣不搬進來就乘不了。而一個 token 份量的矩陣乘,對現代 GPU 來說根本吃不飽。

所以單流 decode 卡的是搬運,不是計算,這種狀況叫 memory-bound。prefill 反過來:同一份權重可以攤給一整批 token 用,搬運成本被攤薄,比較偏吃算力。

https://ithelp.ithome.com.tw/upload/images/20260821/201835502cz6yIMdQy.png
圖 1:這個循環每產一個 token 就走一次。

於是有一條可以寫在便利貼上的除法:

單流 tok/s 天花板 ≈ 記憶體頻寬(GB/s)÷ 每個 step 要讀的權重(GB)

分母寫「每個 step 要讀的權重」不是囉唆:dense 做第一階估算,直接拿整份 tensor size 就夠;但 MoE 每個 token 只讀被選中的那幾個 expert 加上一直開著的權重,不能拿整顆 model size 代進去

直接算一次

那顆 Gemma 4 12B,llama-bench 印出來是 6.48 GiB,換十進位是 6.96 GB(Day 07 那條 GB/GiB 規矩的第二個用場)。

M4 Max 這台:

天花板   546 ÷ 6.96 = 78.5 tok/s
實測                   40.83 tok/s

只有天花板的 52%。同一條除法套 4070 Ti:504 ÷ 6.96 = 72.4,實測 57.72,是 80%

四個數放在同一個刻度上:

https://ithelp.ithome.com.tw/upload/images/20260821/201835505S67E39aAC.png
圖 2:左邊兩根天花板,Mac 高 8%;右邊兩根實測,4070 Ti 高 41%。

帳面 546 對 504 沒說錯,Mac 的天花板確實高一點。差在兩台把帳面換成 tok/s 的效率——真正在比的不是 546 對 504,是 546 的 52% 對 504 的 80%。這個比例我後面都叫它兌現率

把同一條除法換個寫法——實測 tg × 權重——就是 Day 08 表頭那個權重讀取等效(weight-equivalent bandwidth):M4 Max 是 284 GB/s、4070 Ti 是 402 GB/s。兩種寫法同一件事,284 ÷ 546 一樣是 52%。

這裡要小心:284 不是 profiler 量到的 DRAM 流量。真實 decode 還要讀 KV cache、activation 與中間 buffer,kernel 裡也有 cache 命中與解量化。這個數只把權重那一筆算進分子,拿來看「這套軟硬體離天花板多遠」剛好,當成硬體規格就過頭了。

換一顆模型再算一次:同一台 M4 Max 跑 Llama-3.1-8B Q4_K_M(4.92 GB),tg 58.39,得到 53%。兩顆很接近,但我不會把 52-53% 當成 M4 Max 的固定常數。

Mac 贏的是容量線,不是速度線。 至少在這組 bs=1 decode 裡是這樣——Day 07 那格 107.5 GiB 對單卡 12 GiB 是真的,速度線則要看兌現率。

你自己跑一次

前兩個數在同一份 llama-bench 輸出裡:

# ① tg128 那一列就是 tg
#    -ngl 99 對本文這幾顆足以 full offload;層數更多的要自己確認
./llama-bench -m model.gguf -n 128 -r 10 -ngl 99 -fa off

# ② 同一張表的 size 欄就是模型大小(GiB)
#    換十進位:GiB × 1024^3 ÷ 1e9

# ③ 天花板 = 帳面頻寬 ÷ 模型大小
# ④ 兌現率 = 實測 tg ÷ 天花板

size模型 tensor 的大小,不是 GGUF 檔案大小(檔案還含 metadata 與 tokenizer)。兩者差不多,但你拿 ls 的數字算會跟我對不上。

-ngl 99-fa off 是 Day 08 那六根釘子裡的兩根:沒 full offload 就不是在量這台機器的頻寬,而 -faauto 會因 backend 或 build 選到不同路徑。

一台能跑 llama-bench 的機器加一顆 7B/8B 的 Q4 就能驗;要完整重現開頭那張 T1/T2 對照,才需要 Mac 與 N 卡各一台。算出來的兌現率貼留言區,我幫你看健不健康。

那 48% 去哪了

先看一組現象。#4167 那串裡有同一台 M4 Max、同一個 commit、只換量化的三列,是全篇少數可以直接相比的資料。

https://ithelp.ithome.com.tw/upload/images/20260821/20183550Dsx2ICkrYQ.png
圖 3:同一台機器只換量化,兌現率反而是 Q4_0 最低。

這裡容易誤會:Q4_0 的絕對速度確實最快,83.06 對 F16 的 31.64。但它沒有等比例變快——權重小了 3.5 倍,速度只快 2.6 倍。

差額跑到分母去了。兌現率的分子只算權重,分母卻是整個 decode step 的時間;KV、kernel、解量化都吃這段時間。其中只要有些成本沒有跟著權重一起縮,它們在 Q4 裡的佔比自然就變大。

試著寫成式子:每 token 時間 = 權重 ÷ B + 固定成本。用 Q4_0 與 F16 解,得到 B ≈ 493 GB/s、固定成本 ≈ 4.3 ms

兩個參數配兩個點本來就一定解得出來,這步沒有資訊量。有意思的是沒有參與擬合的 Q8_0:這組參數預測 53.2 tok/s,實測 54.05,只差 1.5%。

但 B 與固定成本都只是擬合參數,並沒有真的把 kernel、解量化與 cache 的成本分開。而且這組參數不能跨模型、跨 build 直接搬——拿去預測我 2026 build 上的 Gemma 4,算出 54 tok/s,實測只有 40.8。那個「固定」只在這組資料裡固定。

長 context 還會再吃一刀:hardware-corner 的 RTX PRO 6000 資料裡,Llama 3.3 70B Q4 在 4K 是 32.0 tok/s、128K 只剩 16.6。權重一個 byte 沒變,掉的那一半來自長 context 下 attention 與 KV cache 多出來的流量與計算。

換別人的機器還準嗎

我本來想在這裡給你三條可以直接套的「有效頻寬帶」:Metal 幾成、消費卡幾成、機房卡幾成。

它們撐不住。Metal 那條我原本抓 55-65%,把我自己量到的 52% 排在外面;消費卡那條抓 65-85%,看一眼下面這張圖就知道問題在哪。

https://ithelp.ithome.com.tw/upload/images/20260821/20183550DHH4AM9pJD.png
圖 4:同一張表的五張卡,兌現率從 56% 到 84%,帳面最高的 5090 落在最下面。

這五列共用同一顆 Llama 2 7B Q4_0,也都跑 Vulkan——模型跟 backend 都是控住的。沒控住的是 commit 與各自的測試環境,那串橫跨 220 天。所以它不能拿來排卡的優劣,只說明除以自家帳面之後,兌現率也不會變成硬體常數。能換出多少 tok/s,是硬體架構、backend、kernel、driver、build 與測試環境一起決定的,這張表只固定了其中兩項。

一台機器倒推一次是一個點,點拼不出通則。

所以規劃的時候我不猜成數,直接做 sensitivity。下面這張表想回答的是:如果兌現率落在某個值,70B 會跑多快。

假設兌現率 M4 Max 546 4070 Ti 504 PRO 6000 1,792 H100 ×2 6,700
50% 6.4 21.1 78.8
60% 7.7 25.3 94.5
70% 9.0 29.5 110.3
80% 10.3 33.7 126.1

全部是 70B Q4_K_M(42.52 GB)的單流 tok/s。H100 那欄是 TP2 的合計頻寬。

4070 Ti 那欄是空的:單卡 12 GiB 裝不下 42.52 GB 的權重。沒有 full offload,這條除法就不適用——partial offload 之後瓶頸會換成 PCIe 與主記憶體,那是另一本帳。塞不塞得下要先過 Day 09 那一關,才輪得到今天這條除法。

50-80% 不是信賴區間,也不是硬體通則,就是四個 sizing 情境——我自己兩台的 52% 與 80% 剛好是頭尾。拿到自己的 tg 之後,用上一節那條除法把區間收成一個點。

這四個情境有沒有離譜?拿 T3、T4 做個 sanity check。RTX PRO 6000 帳面 1,792,天花板 42.1 tok/s;兩筆明載 Q4 的外部實測約 27 與 32 tok/s,粗估 64% 與 76%。StorageReview 另有一筆 31.7,但沒寫量化,只看速度量級,不算兌現率。

H100 那筆條件齊得多:NVIDIA NIM 官方表列 2×H100 SXM、FP8、TP2、併發 1、500 in/2000 out,52.85 tok/s。拿 NVIDIA 公開那顆 FP8 checkpoint 的 72.66 GB 當權重大小的 proxy(NIM 跑的 engine 未必等於這個檔),算出約 0.57。至少這幾筆都沒有跑到四個情境之外。

四階畫在同一張圖上

https://ithelp.ithome.com.tw/upload/images/20260821/201835500cvjb9QyTc.png
圖 5:T1 與 T2 的天花板線幾乎重疊,落點卻差了半個身位。

懶得手算的話,Day 09 那支計算機的工具 3 就是這張圖的互動版,網址在 Day 09 文末。

最後拿它量一個網路數字

dense 的 70B Q4_K_M,權重 42.52 GB。M4 Max 帳面 546 全吃滿的話:

546 ÷ 42.52 = 12.8 tok/s

在本文 bs=1、無 speculative 的前提下,這是用帳面 DRAM 頻寬算出的第一階上界。再拿我這次量到的 52% 當一個 sizing 情境,大約 6.7。

我常看到一個數字:「70B 在 M4 Max 上 20-28 tok/s」。把它換回權重讀取等效:20 tok/s 要 850 GB/s、28 tok/s 要 1,191 GB/s,而帳面只有 546。差得不是一點點,所以條件一定有東西不一樣。看到這種數字,第一件事不是相信,是先問四件事:同一顆模型嗎?同一個量化嗎?有沒有開 speculative decoding?量的到底是不是 decode?

小結

  • 單流 decode 是 memory-bound,天花板 ≈ 帳面頻寬 ÷ 每個 step 要讀的權重;實測除以天花板,就是這套軟硬體的兌現率。
  • 兩台受控實測:M4 Max 52%、4070 Ti 80%。帳面該讓 Mac 小勝 8%,實測是 4070 Ti 快 41%——Mac 贏的是容量線,不是速度線。
  • 兌現率是那一次軟硬體組合的結果,不是硬體屬性。沒實測過的機器就用 50-80% 做 sensitivity,拿到 tg 再收成一個點。

明天,Day 11:「70B 上 M4 Max:那些 20-28 tok/s 到底是怎麼來的」——今天這條除法就是明天的第一把尺。

咱們明天見。


上一篇
Day 09 - 權重塞得下 ≠ 跑得動:KV cache 公式與 GQA、MQA、MLA
下一篇
Day 11 - 70B 上 M4 Max:那些 20-28 tok/s 到底是怎麼來的
系列文
不是模型太慢,是你沒算過這筆帳:地端 LLM 工程實戰 30 天11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言