改裝 2080 Ti 22G · part 10
[趣味競賽 進階 #10] 同一張 2080 Ti,一台生圖慢 3.4 倍——兇手是啟動 log 裡一行 dtype fallback
❯ cat --toc
TL;DR
兩台機器,同一張改裝 2080 Ti 22G。一台生 Z-Image 暖機 median 46.08s,實測擺著、看起來就是卡的天花板——GPU 全程 100%、模型常駐、卡也對。但我記得另一台一樣的卡只要 ~9.5s(那筆沒進知識庫)。兇手不是卡,是啟動 log 一行精度 fallback:Turing 沒有 bf16 tensor core,ComfyUI 為了保精度把權重留在 fp32,算得慢 3.4 倍。一個 --force-fp16,median 46.08→13.66s,免費、畫質沒差。誠實提醒:不省 VRAM,對影片模型也沒用。
短版:兩台同一張卡差 3.4 倍,問題根本不在卡
同一張改裝 2080 Ti 22G,插在兩台不同的機器上:一台生 Z-Image 暖機 median ~9.5s,另一台跑到 ~46s;換算掉解析度差之後還差 4-5 倍。跟晶片一點關係都沒有——差別藏在啟動 log 裡一行精度 fallback,而一個旗標就把暖機 median 從 46s 打到 13.66s。
看數據就該結案了——但我記得 forge 跑過 10 秒,而那筆沒進知識庫
先講清楚 AI 跟我看到的不是同一件事。當天早上,記錄上的結論很明確:Linux 那台實測 Z-Image 暖機 median 46.08s,就是這張 2080 Ti 的算力天花板、不是設定爛。這結論本身說得通——生圖全程 GPU 100%、模型常駐不用重新載入、卡也是對的那張;AI 手上只有這份 bench,從沒看過更快的數字,對它來說 46s 就是現實。
問題是,我記得一件記錄裡沒有的事:同一個 model,我在 forge 那台跑過,暖機後大概 10 秒就出圖。那個 session 從來沒進知識庫——所以對 AI 而言那筆不存在,只有我記得。而且我沒記錯。
forge 是台舊 Windows 機,裝的是同一張 2080 Ti。翻出它還活著的 log,白紙黑字寫著 Prompt executed in 9.49 seconds——暖機、跑 768²/8 步、穩定 1.01 s/it。慢的那台跑 1024²,像素是多了些,這條我認,但多的那點像素撐死解釋 2 倍,不到 4-5 倍。
於是問題變得很難看:兩張一模一樣的卡、同一個生成器,一台慢好幾倍。「這就是天花板」原本是數據撐得最穩的那條結論——現在它站不住了。
清三個嫌疑:OS、缺套件、attention backend——三條都走死了
我先列了三個最直覺的嫌疑,每個配一個一刀砍下去的決定性測試。
嫌疑一:OS。 Win vs Linux 是最順手的猜測,但我原本的預期是「純 Linux 應該更快才對」。一對日期就發現方向整個反了——慢的那台就是 Linux。想像中該更快的那邊反而在拖後腿,這條假設在「慢的是 Linux」那一刻就當場死了。OS 無罪。
嫌疑二:缺套件。 那也許是快的那台裝了什麼加速套件(comfy-kitchen 之類的)、慢的那台漏了?查版本——慢的那台是 0.2.20,比快的 0.2.10 還新。慢的機器版本更前面、東西一樣不缺。套件無罪。
嫌疑三:attention backend。 這條最陰。早上我其實在慢機上測過 xformers 的 A/B,結果 -0.85%(不但沒快、還更慢),我就切回原設定了。當下沒意識到的是:那場 A/B 量的,是跑在錯的那條計算路徑上的 attention。lever 沒選錯,我只是在一條本來就已經有問題的路上拉它,拉了當然沒感覺。
三條全走死,但每一條都幫我收窄範圍:不是 OS、不是套件、不是 attention kernel——問題出在「這個 model 到底怎麼跑」,不是「裝了什麼」。
破案:兩行 startup log,差在一個 dtype

破案關鍵就在 ComfyUI 啟動 log 的兩行,而我手上還留著這兩行純屬僥倖——forge 的 log 剛好還活著。那是一份 6,743 bytes 的 stderr 殘片,只涵蓋那張卡被拔走前最後 15 分鐘(22G 卡現在已經拔掉、換插了張 GTX 970,這份殘片是唯一還在的證人)。要不是它留著,這案子就斷在這了。
第一行是對齊用的指紋:Prompt executed in Ns。兩邊的冷跑、暖跑各自對齊,先確認「差是真的」,不是我某一次剛好卡到。
第二行才是破案關鍵:
- 快的那台:
weight dtype torch.float16, manual cast: torch.float16 - 慢的那台:
weight dtype torch.bfloat16, manual cast: torch.float32
同一個 checkpoint、同一張卡——快的整路跑 fp16,慢的被悄悄留在 fp32 的 manual cast。
機制其實很乾淨:Turing(sm_75)有 fp16 tensor core、但沒有 bf16 tensor core(bf16 硬體加速要 Ampere 之後才有)。ComfyUI 不是把每個 bf16 model 一律轉 fp32,而是依每個 model class 自己宣告支援的 dtype 挑計算精度;這顆 Z-Image checkpoint 在 Turing 上,預設就落在保精度的 fp32 manual cast,而 fp32 算起來比 fp16 tensor core 慢大約 3.4 倍。(這個「挑哪種精度是看 model class」的細節,正好就是為什麼等一下同一個旗標對另一顆 model 完全沒用。)
這裡藏著整篇最反直覺的一句:GPU 全程 100%,但 100% 忙 ≠ 撞到天花板。它可以 100% 地忙著算一條慢精度的路。忙,不代表滿。
解法:一個 --force-fp16,median 46.08→13.66s
修這件事只要一個旗標:--force-fp16。開下去,log 那行從 manual cast: torch.float32 變成 manual cast: None——終於肯吃 fp16 tensor core 了。
跑單變因 A/B(唯一的差就是這個旗標),1024²/8 步暖機:
- 暖機 median:46.08 → 13.66s
- sampler:5.64 → 1.59 s/it
- 3.37×,免費,輸出完整(真的 PNG、不是黑圖、沒有 NaN,畫質跟 fp32 沒差)
這個旗標我已經烙進那台天天在生圖的 ComfyUI 啟動參數,每次生圖自動帶。
再回頭看 xformers 那個 -0.85%:那是因為當初量在 fp32 這條路上。路徑修好之後再測,attention backend 幾乎不影響結果——這 3.4× 從來就不是換 kernel 換得到的——差距其實來自 kernel 上游那個 dtype 的挑法。 我早上在錯的路上拉對的 lever,難怪拉不動。
誠實提醒一:它不會省 VRAM,反而多吃 0.5G
--force-fp16 沒有省記憶體,fp16 反而多用了 0.5G(15,982 vs 15,498 MiB)。理由很無聊:bf16 跟 fp16 的權重都是 2 bytes,本來就沒空間可省;省下的那點 activation 又被 allocator 的 pool 蓋過去了。
我一直隨身帶著的那個「這個 checkpoint 省 5G」的印象,是駐機 session 舊的自報數字,一跑乾淨 bench 就被打臉。所以講清楚:它換來的是速度、不是記憶體。 想靠它「多出來的空間」去 size 下一個 model,會踩雷。
誠實提醒二:影片模型沒受益——這招有沒有用要看 model family
拿到 3.4× 我當然貪心,把同一個旗標指向影片模型試試——LTX-2(Sulphur-2,3 秒短片)。同一張卡、同樣的單變因 A/B,結果是 1.00×(140.29 → 140.93s,VRAM 一模一樣,util 也一樣)。一點都沒動。

log 解釋了為什麼:旗標確實開了,權重也確實翻成 fp16,但那行 manual cast 還是被釘死在 torch.float32——LTX-2 的 model class 沒把 fp16 列進支援清單,cast 就一直是 fp32,旗標壓不過去。Z-Image(Lumina2 家族)吃這個旗標、LTX-2 不吃。
所以這招有沒有用,是看 model family、不是卡本身的性質。Turing 上這顆影片 model 真的就只有 fp32 這一條路可走;好消息是,現在至少有一組對照,能確認那 140s 就是實測結果,不是我設定沒調好。
收穫
最花時間的不是修,是分清「數據的結論」和「我記得的事」。 修就一個旗標。當天記錄上的結論很硬:46s、三個跡象同指一個方向,對只有這份 bench 的 AI 來說完全合理。真正戳破它的不是更聰明的推理,是我記得一件知識庫沒收進去的事——forge 跑過 10 秒。教訓:當你的知識庫說「這台從來沒更好過」,別忘了它可能只是漏記了——一個反例(哪怕只在你腦裡),勝過三個鐵證如山的訊號。
真正能帶去別的專案用的除錯手法,全是無聊動作。 兩台同卡機器,把最無聊的啟動 log 對 diff,一整個答案就藏在一行裡。把 100% GPU 讀成「忙」而不是「滿」。一個假設就配一個決定性測試(OS 那條在「慢的是 Linux」那刻就結束了,不用再糾結)。還有一條最容易忽略:當你的 KB / 筆記說「這台從來沒更好過」,要信機器本地的 log、別信摘要——forge 是個非同步節點,我自己的筆記兩度堅稱它那次快跑「沒發生過」,結果離線那台機器的 log 才是權威。
⚠️ 一個 bench 踩雷點順手記下:固定 seed 重送同一張圖,ComfyUI 會 cache-hit,直接印
Prompt executed in 0.00 seconds——你以為量到暖機速度,其實整排數字都是假的。解法是餵一個 graph 會忽略、但足以讓它強制重算的 nonce,seed 跟真正的輸入都不動。
通用原則一句話: 說穿了,慢的不是這張卡,是它被逼著用一種沒有硬體加速的精度格式在算——而「GPU 100%」這個最有說服力的訊號,剛好也是最會騙人的那個。
收工前的五條 checklist
- 先 diff 兩台同卡的啟動 log。 盯
model weight dtype跟manual cast這兩行;bf16 checkpoint 跑在 pre-Ampere 卡上、又出現manual cast: torch.float32,就是 fallback。 - 別把 100% GPU 當天花板。 忙不等於最優——它可能 100% 忙在一條慢精度的路上。
- Turing 上的 bf16 checkpoint,先試
--force-fp16。 model family 吃這套的話就是 3× 級的加速;驗收看 log 那行有沒有翻成None、輸出是不是 NaN/黑圖。 - 別指望它省 VRAM。 fp16 跟 bf16 的 bytes 差不多,把它當速度優化就好、別算進省空間。
- 每個 model family 各自 A/B。 它幫了 Z-Image、對 LTX-2 完全沒用,別假設一招通吃。
同系列上一篇也是「log 把證據吃掉」的母題,只是那次死的是一個服務、不是速度:0xc0000409:當我的 AI 服務靜默暴斃,而 log 把死因吃掉了。工具本身:ComfyUI。
常見問題
- 同一張 2080 Ti,兩台機器生圖速度為什麼差 3.4 倍?
- 不是卡的差異,是 dtype。ComfyUI 不是把所有 bf16 model 一律轉 fp32,而是依每個 model class 支援的 dtype 挑計算精度。Turing(sm_75)有 fp16 tensor core、但沒有 bf16 tensor core(bf16 加速要 Ampere 之後才有);這顆 Z-Image checkpoint 在 Turing 上,預設就落在保精度的 fp32 manual cast——而 fp32 算比 fp16 tensor core 慢大約 3.4 倍。加上 `--force-fp16` 讓它改走 fp16 tensor core,同一張卡的暖機 median 就從 46.08s 掉到 13.66s。
- `--force-fp16` 會省 VRAM 嗎?
- 不會,反而多吃一點(15,982 vs 15,498 MiB)。bf16 跟 fp16 的權重都是 2 bytes,沒有省下來的空間;省掉的那點 activation 又被 allocator 的 pool 蓋掉了。它換來的是速度、不是記憶體——要拿它多出來的空間去塞下一個 model,會踩雷。
- 為什麼影片模型(LTX-2)加了同一個旗標卻沒變快?
- 因為這招有沒有用,得看 model family。LTX-2 的 model class 沒把 fp16 列進支援清單,manual cast 就一直釘在 fp32、旗標壓不過去;Z-Image(Lumina2 家族)吃這個旗標、LTX-2 不吃。同一張卡上,LTX-2 這顆影片 model 真的就只有 fp32 這條路,140s 是實測跑出來的,不是設定沒調好。
- 怎麼知道自己有沒有踩到這個坑?
- 拿兩台同卡機器的 ComfyUI 啟動 log 對 diff,盯 `model weight dtype` 跟 `manual cast` 這兩行。bf16 checkpoint 跑在 pre-Ampere 卡上、log 出現 `manual cast: torch.float32`,那就是 fallback。加 `--force-fp16` 之後那行會變 `manual cast: None`,再確認輸出不是 NaN、不是黑圖,就對了。
接著讀
- 2026-08-06[趣味競賽 進階 #11] 什麼?2080 Ti 居然跑得動 MiniMax-H3,還生得出 1080p 有聲影片
四個檔案在磁碟上 38 GiB,而卡只有 22 GiB。一張 2018 年的改裝 2080 Ti 22G(sm_75)照樣跑出 15 秒 1080p 有聲片。完整配置、實測速度與畫質,最後才是一路怎麼試出來的。
- 2026-08-20[趣味競賽 進階 #12] 為什麼你的 4-bit 模型在 2080 Ti 上快不起來?——拆開 .so 才發現這代卡只有兩種齒輪
為什麼 GGUF 量化後檔案變小,tok/s 卻沒變快?拆開 CUDA 後端 .so 才看懂:Turing(sm_75)的整數 tensor core 只有 s4×s4 跟 s8×s8 兩種同寬組合,4-bit 權重配 fp16 activation 這格在任何架構都不存在。GGUF、AWQ、Marlin 全靠反量化撐過去。
- 2026-08-28[Benchmark] 1770 億參數塞進三張二手 2080 Ti:改檔案快 3.5 倍,寫散文一點都沒快
Qwen3.8-Flash-Next(176.94B)跑在三張改裝 2080 Ti 上:128K context 拿到 23.14 tok/s,開 ngram 投機解碼後改檔案衝到 77.56。附三種量化在相同條件下的對照。
- 2026-08-23[Benchmark] 我把 2080 Ti 的 NCCL 修好了,然後發現它沒快多少
Ubuntu 的 libnccl2 跟 CUDA 13 驅動不相容,自編 NCCL 2.31.2 修好之後,prefill 的 PCIe 流量掉了 99%——而速度幾乎沒動。那個看起來很糟的 fallback,其實沒讓你付多少代價。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。