改裝 2080 Ti 22G · part 20
特化的啟動器 FastLLM + DFlash2,居然可以在魔改的 2080 Ti 雙卡跑出 100+ tok/s!
❯ cat --toc
- 前言
- FastLLM + DFlash2 是什麼:啟動器本身不快,快的是草稿
- 我量到的:寫程式 153.8、數學 134.9、散文 53.1
- 為什麼這兩張卡吃這套:FP8 權重本來就被頻寬卡住
- 怎麼跑:一個 pip、兩份權重、一個自編的 NCCL
- 會卡住你的四件事
- prefix cache:同一段開頭,第二次從 8.2 秒變 1 秒
- 262K 真的灌得進去:暗號埋到 199,787 token 都唸得回來
- 代價:散文慢兩成,能力少 3 題
- 進階:除錯與實驗紀錄
- 配方從哪來:B 站兩支影片、兩個框架
- 坑 1:NCCL 沒有 sm_75
- 坑 2:DFlash2 一定要關 CUDA Graph
- 坑 3:262K 的記憶體帳
- 坑 4:template、effort,和一個我搞錯原因的旗標
- 頻寬算法:為什麼算出來會超過 100%
- 草稿 token 數:8 最快
- 全部組態的速度
- 版本鎖定
- 還沒做的
TL;DR
兩張改裝 2080 Ti 22G,用 FastLLM(pip 套件 ftllm)跑 Qwen3.8-27B FP8,再掛 z-lab 的 DFlash2 草稿模型:寫程式 153.8 tok/s、數學 134.9、散文 53.1。262K context、看圖、prefix cache 同時開著。FastLLM 自己不開投機只有 33.7,速度是 DFlash2 給的:FP8 權重讀一次就把頻寬用掉 79%,讓草稿先猜、一次驗 8 個位置,才有 4.5 倍。散文猜中得少,比原本的 llama.cpp 慢。

前言
搭過尖峰時段的電梯就知道,電梯一趟的時間幾乎都花在上下樓,載一個人和載八個人差不了幾秒。一小時能送多少人,看每一趟有沒有裝滿。
顯卡吐字也是這樣。27B 的模型每吐一個字,就要把整份權重從 VRAM 讀一遍,那一趟跑完才輪到下一個字。投機解碼的做法是讓一個小模型先猜好幾個字,大模型讀一次權重就把這幾個位置一起驗完,猜中的全收。
B 站上有人用兩張魔改 2080 Ti 22G 跑出 150 tok/s 以上,靠的就是這招。#14 我把同一顆 Qwen3.8-27B 用 llama.cpp 攤在兩張卡上,後來調到 66 tok/s,當作這台機器的主力。這篇照著那套配方重做一次:FastLLM 加 DFlash2,寫程式跑到 153.8,已經換上去當新的主力。
FastLLM + DFlash2 是什麼:啟動器本身不快,快的是草稿
FastLLM 是一個 C++ 寫的推論框架,pip 套件叫 ftllm,裝完有一個 ftllm server 指令,開出 OpenAI 相容的 API。它在 sm_75 上跑 FP8 權重的方式是:權重用 FP8 存,運算時在 kernel 裡轉回 FP16 再算(Turing 沒有 FP8 硬體)。所以 FP8 在這裡省的是讀取量,不是算力。
DFlash2 是 z-lab 做的草稿模型,專門配 Qwen3.8-27B:5 層、3.6GB,一次猜一整塊 token,再挑出最順的一條路交給主模型驗。我用的 --speculative_num_draft_tokens 8,實際是每步猜 7 個。
兩個拆開看:
- FastLLM 自己不開投機:33.7 tok/s。 比 llama.cpp Q8_0 + MTP 的 66 慢一半。
- 加上 DFlash2:152.3 tok/s(官方 FP8 權重、寫程式)。4.5 倍全部來自草稿。
我量到的:寫程式 153.8、數學 134.9、散文 53.1
量法:真實的 chat 請求,temperature 0、每次最多 512 token,寫程式、數學、散文三種題目各打三發,取中位數,時間在用戶端量。看最後一列:
| 組態(兩張 2080 Ti,TP=2) | 寫程式 | 數學 | 散文 |
|---|---|---|---|
| 不開投機(官方 FP8) | 33.7 | 33.3 | 33.2 |
| 內建 MTP 8(去審查 FP8) | 62.1 | 53.3 | 24.0 |
| DFlash2,262K(去審查 FP8) | 156.0 | 134.9 | 53.1 |
最後一列是 262K context、fp4 KV 的組態。官方權重和去審查版速度差不多,完整對照在進階區。正式上線前我又關掉了 --cuda_embedding(原因在後面),複測寫程式是 153.8,開著是 154.1,差在雜訊內。TL;DR 的 153.8 就是上線那一刻量的。
原本的 llama.cpp 那組(Q8_0 + MTP,兩張卡)是 66 tok/s。要先講清楚:那個 66 是 140 題能力評測的吐字中位數(temperature 1.0、thinking 開著),量法跟上面三題不一樣,只能當參考。B 站上用同樣機型重現過的網友用同一套 API 打貪吃蛇題,量到 llama.cpp 58、FastLLM + DFlash 100~110,方向一樣。
所以標題的 100+ 要加主詞:寫程式和數學。
為什麼這兩張卡吃這套:FP8 權重本來就被頻寬卡住
不開投機解碼的時候,模型每吐一個字,就要把約 29GB 的權重從顯卡記憶體(VRAM)整份讀一遍。每秒吐 33.7 個字,就是每秒讀 977GB;兩張 2080 Ti 每秒頂多讀到 1232 GB,已經用掉 79%。速度卡在搬權重,顯卡的運算單元大部分時間在等資料。
開了 DFlash2,權重一樣是讀一整份,但這一趟會同時驗 8 個位置,猜中幾個就多吐幾個字。搬一趟權重的時間沒變,一趟多吐了好幾個字,吐字速度就從 33.7 跳到 152.3,就像前言那台電梯一趟多載了幾個人。(用同一個算式硬算,開 DFlash2 後的「讀取量」會超過上限,怎麼算的放在進階區。)
上一篇的 Ternary Bonsai 2 剛好是反例:三值權重只有 7.2GB,頻寬才用到 46%,卡的是解包的運算。同一家族的 DFlash2 掛上去,最好只比內建 MTP 快 3–8%,草稿猜越多越慢。
怎麼跑:一個 pip、兩份權重、一個自編的 NCCL
你需要:
- 兩張改裝 2080 Ti 22G。 我這兩張之間有 NVLink(NV2)。B 站上重現過的網友也都有 NVLink;FastLLM 官方在 5090 上是走 PCIe 跑的,所以不一定要有 NVLink,但沒 NVLink 的 2080 Ti 我沒測。
- Python 3.14 的 venv,裝
ftllm0.1.8.2。 - 主模型:orcarouter/Qwen3.8-27B-Uncensored-FP8(磁碟上約 29GB,去審查版)。官方的
Qwen/Qwen3.8-27B-FP8也行,速度差不多。 - 草稿模型:
z-lab/Qwen3.8-27B-DFlash2(3.6GB)。 - 一份有 sm_75 的 NCCL。 我用的是 #16 自編的 2.31.2。
安裝和下載:
python3.14 -m venv ~/venvs/ftllm
~/venvs/ftllm/bin/pip install ftllm==0.1.8.2
hf download orcarouter/Qwen3.8-27B-Uncensored-FP8 --local-dir /mnt/nvme1t/models/qwen38-27b-uncensored-fp8
hf download z-lab/Qwen3.8-27B-DFlash2 --local-dir /mnt/nvme1t/models/dflash2-qwen38-zlab
chat template 用 #13 那份社群修復版(froggeric,我用的是 v22.3。main 已經到 v22.5,下面那行 sed 只對 v22.3 有效,所以網址固定在 v22.3 那個 commit),只改一個地方:預設的 reasoning effort 從 medium 改成 low(原因在進階區):
mkdir -p /mnt/nvme1t/models/qwen-fastllm-low
wget -O /mnt/nvme1t/models/qwen-fastllm-low/chat_template.jinja \
https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates/resolve/492315ea6d7343bcfb32598d6a898c34e0d69ed8/chat_template.jinja
sed -i "s/is not none else 'medium' %}/is not none else 'low' %}/" \
/mnt/nvme1t/models/qwen-fastllm-low/chat_template.jinja
啟動,這就是現在上線的那一行:
export LD_PRELOAD=/home/coolthor/nccl-install/lib/libnccl.so.2 # 有 sm_75 的 NCCL
export CUDA_VISIBLE_DEVICES=0,1
export FASTLLM_CUDA_GRAPH=0 # DFlash2 一定要 0
~/venvs/ftllm/bin/ftllm server \
-p /mnt/nvme1t/models/qwen38-27b-uncensored-fp8 --model_name qwen38-27b-ud \
--tp 2 --max_batch 1 --tokens 262144 --gpu_mem_ratio 0.95 --kv_cache_dtype fp4 \
--speculative_algorithm dflash \
--speculative_draft_model_path /mnt/nvme1t/models/dflash2-qwen38-zlab \
--speculative_num_draft_tokens 8 \
--prefix_cache true \
--chat_template /mnt/nvme1t/models/qwen-fastllm-low/chat_template.jinja \
--host 0.0.0.0 --port 8082
--model_name 我沿用原本服務的模型名稱,用戶端一行都不用改。
會卡住你的四件事
照 B 站的配方原封不動跑,這四個地方會出事。每一個在進階區都有完整的錯誤訊息和量測。
- NCCL 沒有 sm_75。 雙卡開投機解碼就
ncclAllReduce failed: unhandled cuda error(我是開 MTP 時撞到的)。FastLLM 實際載到的是 Ubuntu 套件那顆 2.22.3,pip 帶進來的那顆也沒有 sm_75。解法是上面那行LD_PRELOAD。 - DFlash2 開 CUDA Graph 必炸。
cudaErrorIllegalAddress。要FASTLLM_CUDA_GRAPH=0。FastLLM 文件教的剛好相反(sm_75 要手動設 1 打開),那句只適用不開投機。 - 262K 要三個設定一起改。
--kv_cache_dtype fp4(fp8 的話 draft 權重擠不進去)、不要加--cuda_embedding(上游建議加,但它在 GPU0 佔掉 2.4GB)、--gpu_mem_ratio 0.95(0.97 長提示會炸,0.90 反而更糟)。 - 請求開思考時,推理會混進 content。 傳了
--chat_template之後,FastLLM 會關掉把 Qwen 推理內容拆到reasoning_content的功能:請求帶enable_thinking: true時,整段推理加一個孤立的</think>都在content裡,reasoning_content是空的。用戶端送enable_thinking: false就沒事,要開思考就得自己把</think>之前的部分剝掉。
prefix cache:同一段開頭,第二次從 8.2 秒變 1 秒
真的拿來用,這條比吐字速度有感多了。agent 和 RAG 的請求常常開頭一大段都一樣(系統提示、工具說明、同一份文件),只有結尾不同。
量法:8,747 token 的共同開頭,連續 6 輪換不同的結尾。
| 第一輪 | 之後的中位數 | 每輪命中 | |
|---|---|---|---|
--prefix_cache true | 8.2 秒 | 1.0~1.2 秒 | 8,192 token |
正式切換那天的驗收又量了一次:14K 的開頭,冷的 14.2 秒,熱的 2.0 秒,命中 14,336 token。DFlash2 開著,prefix cache 照樣有效。
262K 真的灌得進去:暗號埋到 199,787 token 都唸得回來
在長文件正中間埋一句「The secret access code for building 7 is MAPLE-4416.」,問它暗號是什麼:
| 實際 prompt token | prefill | 耗時 | 暗號 |
|---|---|---|---|
| 22,647 | 1,109 tok/s | 20 秒 | ✅ |
| 91,478 | 855 tok/s | 107 秒 | ✅ |
| 140,022 | 734 tok/s | 191 秒 | ✅ |
| 199,787 | 652 tok/s | 306 秒 | ✅ |
六個長度全部答對(表裡列四個),一次都沒有重啟。prefill 隨長度線性變慢,沒有突然掉下去。
兩個數字不一樣:262,144 是 KV 池的總量;單一提示的上限,log 寫的是 AddPrefill Pages limit: 1638 pages (80% of 2048),約 209K token。
看圖也還在:這份 FP8 權重內建視覺模組(vision tower),不用另外掛 mmproj。一張 448×448 的三形狀圖,它回「red circle top left / blue square top right / green triangle bottom center」,形狀、顏色、位置全對。
代價:散文慢兩成,能力少 3 題
換過來的代價有兩個,都量過:
- 散文 53.1 對 66。 這一欄輸原本的 llama.cpp。
- 能力 128/140 對 131/140。 同一份 140 題(GSM8K 50、MATH-500 30、MuSR 20、HumanEval+ 40)。128 是上線中的組態、請求不帶任何參數量的,也就是模型不開思考;llama.cpp 那組開著思考。
看最後一欄,再看 MuSR 那欄:
| GSM8K | MATH-500 | MuSR | HumanEval+ | 合計 | |
|---|---|---|---|---|---|
| FastLLM,不開思考 | 49 | 29 | 15 | 35 | 128 |
| FastLLM,開思考 + effort low | 50 | 30 | 9 | 36 | 125 |
| llama.cpp Q8_0,開思考 | 50 | 30 | 13 | 38 | 131 |
FastLLM 開不開思考,差距全在 MuSR(15 對 9),其他題庫各差一題。不開思考那輪沒有一題撞到 8192 的上限,開思考那輪有 1 題。我們自己的服務本來就送 enable_thinking: false,實際拿到的就是 128 這一組。
我平常丟給這台機器的事沒那麼難,3 題換兩倍多的寫程式速度,換了。原本的 llama.cpp 設定整份留著,兩行 systemctl 就換回去。
進階:除錯與實驗紀錄
不讀這節不影響使用。下面是每個坑的完整錯誤訊息、量法,以及試過的其他組態,給想深追的人和 AI。
配方從哪來:B 站兩支影片、兩個框架
- BV13vbK6yEhp(UP 主 _黄歪歪,2026-09-07):FastLLM 路線,
pip install ftllm,FP8 權重 + DFlash2。影片標題寫 150+ TPS,評論區有人轉述影片宣稱 FP8 平均超過 100。 - BV1Ader61ETR(UP 主 SPOTLITE,2026-09-18):置頂留言給的是 weicj/vLLM-2080Ti-Definitive,一個 vLLM 的 sm_75 分支,跟 FastLLM 無關。要 CUDA 13 + PyTorch 2.13 + Python 3.12,我這篇沒走這條。
B 站沒有字幕,影片裡的畫面我查不到;以上全部來自影片說明、評論和官方 repo。第一支影片底下有一位評論者(听我贤扯)用同樣的雙 22G + NVLink 重現過:FP8 不開投機 33.0、FP8 + DFlash B8 在固定輸出流上 191.8。我量到的不開投機是 33.7,跟他幾乎一樣,所以兩邊的環境可以比。
他的 191.8 和我的 152.3 差在量法:他用固定的合成輸出流,我用真實的 chat 請求。
坑 1:NCCL 沒有 sm_75
第一輪開 MTP 就壞:
Error: ncclAllReduce failed on device 0: unhandled cuda error
Error: ncclAllReduce failed on device 1: unhandled cuda error
吐字 19.9,比不開投機還慢,server 也跟著死掉。不開投機的 TP=2 完全正常,所以問題出在投機那條路才會走到的 AllReduce。
機器上有三顆 libnccl:Ubuntu 套件的 2.22.3、pip 裝 ftllm 時帶進來的 nvidia-nccl-cu12 2.31.2、我在 #16 自編的 2.31.2。ldd 看 FastLLM 的 libfastllm_tools.so,實際載到的是系統那顆 2.22.3。看每一顆裡面編了哪些 sm:
cuobjdump --list-elf <libnccl.so.2> | grep -oE 'sm_[0-9]+' | sort -u
只有自編那顆有 sm_75。LD_PRELOAD 指過去就好了,不用重編 FastLLM。
錯誤訊息完全沒提到架構,這是它難查的地方。別人編好的 NCCL 放到 2080 Ti 上,先當它是壞的,用上面那行驗過再說。
坑 2:DFlash2 一定要關 CUDA Graph
FASTLLM_CUDA_GRAPH=1 加上 DFlash2,server 載入完第一個請求就炸:cudaErrorIllegalAddress,連續十幾次,當場死掉。
試過沒用的:--tp 2 的不同寫法、--dtype float16、--atype float16。bf16 不是元兇,log 裡寫得很清楚:
[Qwen3.5 DFlash2] converted 18 BF16 linear weights to FP16 for the pre-Ampere mixed GEMM path
設 FASTLLM_CUDA_GRAPH=0,一次就過,吐字從 33.7 到 152.3。
FastLLM 的文件寫的是 sm_75 以下預設關 CUDA Graph、要手動設 FASTLLM_CUDA_GRAPH=1 打開。我不開投機那組是設 1 量的(33.7);DFlash2 照這句設就是壞的。內建 MTP 則是 0 或 1 都能跑,差在雜訊內(61.5 對 62.1)。
坑 3:262K 的記憶體帳
第一版用 fp8 KV,262K 在載入草稿權重時 OOM:
| KV 型別 | 262,144 | 196,608 |
|---|---|---|
| fp8_e4m3 + DFlash2 | ❌ OOM(載 dflash.layers.4.mlp.gateup_proj 時) | ✅ |
| fp8_e4m3 + 內建 MTP | ✅ |
KV 池本身有配到(KV Cache Token limit: 262144 tokens, totalPages=2048),擠不下的是草稿。
改成 fp4 KV,就不用二選一。 Qwen3.8-27B 64 層裡只有 16 層全注意力(log 的 tokenGrowingLayers=16 也這樣寫),每個 token 的 KV 是 16 層 × 2 × 4 個頭 × 256 維 = 32,768 個元素。262K 時 fp8 佔 8 GiB(每卡 4),fp4 佔 4 GiB(每卡 2),每張卡省 2 GiB。速度幾乎不變:
| 組態 | 寫程式 | 數學 | 散文 | 峰值 VRAM(GPU0 / GPU1) |
|---|---|---|---|---|
| 192K + fp8 KV | 161.3 | 134.7 | 55.4 | 21,956 / 21,272 MiB |
| 262K + fp4 KV | 156.0 | 134.9 | 53.1 | 21,652 / 20,540 MiB |
但那時的 262K 只是帳面上的數字。 FastLLM 啟動時的 AutoWarmup log 把帳算出來了:
GPU 0: availForKV=1.41 GB
GPU 1: availForKV=2.49 GB
KV Cache Token limit: 262144 (totalPages=2048, pageLen=128), localKVPerPage=1.18 MB
KV 池每張卡要 2,048 頁 × 1.18 MB = 2.36 GB,GPU0 只給得出 1.41 GB,超額大約 1 GB。頁是用到才配,短提示不會出事,真的灌到底就會炸在 GPU0,實際撐得住的大約 156K。GPU0 比較緊,因為 DFlash2 的草稿只跑在第一張卡上(FastLLM 已知的限制)。
關掉 --cuda_embedding 就解決了。 詞表 248,320 × 隱藏層 5,120 的 embedding 用 FP16 常駐,大約 2.4GB,而且壓在 GPU0。關掉之後:
| 開著 | 關掉 | |
|---|---|---|
| GPU0 availForKV | 1.41 GB | 3.96 GB |
| GPU1 availForKV | 2.49 GB | 5.04 GB |
兩張卡都有 1.6GB 以上的餘裕,寫程式 153.8 對 154.1。FastLLM 的報告建議 DFlash2 要開 --cuda_embedding,在這兩張卡上不對。
--gpu_mem_ratio 是 0.95。 0.97 的時候長提示會炸:
CUDA error when allocating 12 MB on device 0! gpuFree: 2 MB / 22000 MB
cublas error in ChunkGatedDeltaRule batched matmul
只剩 2 MB。降到 0.95,同一組 8,747 token 的測試 6/6 全過。直覺會想再降一點留更多餘裕,但 0.90 反而更糟:它把保留給暫時配置的量從 1.15 GB 拉到 2.31 GB,availForKV 掉到 0.26 GB。這個比例調的是「給模型用的比例」,不是「留多少給暫時配置」。
坑 4:template、effort,和一個我搞錯原因的旗標
第一次用模型內建的 template 跑,跑到第 93 題時,已經出現的 13 題 MuSR 全部 finish_reason=length,content 是空字串,推理最長寫到 36,628 字元。同一題 llama.cpp 那組 1,259 token 就答完、答對。權重是同一份,所以問題出在伺服器這頭。
第一層:template。 模型內建的 chat_template.jinja(9KB)其實能調 effort,但預設是 xhigh,請求沒指定就想最久。換成 froggeric v22.3(26KB,預設 medium)後 GSM8K 49 → 50,但 MuSR 還是 1/20,20 題裡 19 題撞上限。
第二層:froggeric 的 medium 什麼都沒注入。 那份 template 只有 xhigh 和 low 會加提示文字,medium 分支是空的,模型沒有任何「簡短一點」的約束,一路寫到 8192 token 都沒吐出 </think>。讀它的推理,其實已經算對了,結尾卡在「Need final. Ensure final includes boxed. Let's compose final answer:」的迴圈。
請求裡帶 chat_template_kwargs: {"enable_thinking": true, "reasoning_effort": "low"},同一題對照:
| effort | 輸出 token | 結束原因 | 有 </think> | 結果 |
|---|---|---|---|---|
| medium | 8,192 | length | ❌ | 沒有答案 |
| low | 1,929 | stop | ✅ | 答對 |
整份 140 題:想到上限從 23 題掉到 1 題,MuSR 1/20 → 9/20,總分從 110/133(medium 那輪只跑到 133 題)變成 125/140。
我也試過自己在 medium 分支補一句「Keep your thinking under about 2000 words」,MuSR 拉到 12/20,但 MATH-500 和 HumanEval+ 各掉一點,想到上限的從 1 題變 5 題,總分一樣 125。改 effort 是全域的,單一題庫的進步不能直接加到總分上。沒採用。
--think 其實什麼都沒改。 我一度以為 --think true 害模型思考收不了尾:改成 false 之後抽驗 MuSR 從 9/20 跳到 16/20,我就把「用 --think false」寫成了設定建議。回頭讀原始碼才發現原因搞錯了:
--think預設就是"false"(ftllm/util.py),寫--think false跟不寫一樣,後來我就從 unit 裡拿掉了。- 它只在回傳給用戶端的文字前面補一個
<think>\n(openai_server/fastllm_completion.py裡result = "" if emit_reasoning_content else ("<think>\n" if think else "")),不會回到模型的輸入,不可能改變模型答什麼。 - 那次 16/20 的抽驗,請求裡沒帶
chat_template_kwargs,模型是在不思考模式下答的;9/20 那組開著思考、effort low。變的是請求,不是旗標。後來照同樣的方式(不帶參數)把 140 題跑完:128/140,MuSR 15/20。
讓 </think> 混進 content 的,是 --chat_template。 傳了自訂 template,FastLLM 會把 force_chat_template 設成 true(llm.py),而 Qwen 的推理內容拆分在 force 時直接關掉(_is_qwen3_5_reasoning_response)。所以請求開思考時,推理全在 content 裡、中間夾一個 </think>;不開思考就沒事。我自己寫的兩個服務(一個多模型彙整、一個 RAG)都送 enable_thinking: false,拿到的是乾淨答案;開著思考的 Pi agent 看到的那個 </think> 就是這樣來的。
頻寬算法:為什麼算出來會超過 100%
算式是吐字速度 × 權重大小(約 29GB,用磁碟上的大小粗估),除以兩張 2080 Ti 的理論頻寬 1232 GB/s:
| 組態 | 權重 | 吐字 | 讀取量 | 佔峰值 |
|---|---|---|---|---|
| FastLLM FP8,不開投機 | 29 GB | 33.7 | 977 GB/s | 79% |
| FastLLM FP8 + DFlash2 | 29 GB | 152.3 | 4,417 GB/s | 358% |
第二列超過 100%,不是真的讀了那麼多,而是這個算式假設「每個字讀一次權重」,開了投機之後這個假設不成立:讀一次權重就驗 8 個位置,所以實際讀的量還不到這樣算出來的三分之一。第一列那個 79% 才算數:不開投機時,頻寬已經快用滿。
草稿 token 數:8 最快
--speculative_num_draft_tokens | 實際每步猜幾個 | 寫程式 | 數學 | 散文 |
|---|---|---|---|---|
| 4 | 3 | 90.2 | 85.0 | 52.3 |
| 8 | 7 | 156.0 | 134.9 | 53.1 |
| 12 | server 起不來 |
這個值含起點那個 token,所以設 N 實際猜 N−1 個。8 跟 DFlash2 model card 的 block size 8(每步 7 個草稿)是同一個設定。
全部組態的速度
同量法(temp 0、512 token、三發中位數):
| 組態 | 寫程式 | 數學 | 散文 |
|---|---|---|---|
| 官方 FP8,不開投機 | 33.7 | 33.3 | 33.2 |
| 去審查 FP8,不開投機 | 32.9 | 32.6 | 32.4 |
| 官方 FP8 + MTP 8 | 59.0 | 51.3 | 23.2 |
| 去審查 FP8 + MTP 8(graph=1) | 61.5 | 51.2 | 23.2 |
| 去審查 FP8 + MTP 8(graph=0) | 62.1 | 53.3 | 24.0 |
| 官方 FP8 + DFlash2 | 152.3 | 136.8 | 57.6 |
| 去審查 FP8 + DFlash2,192K fp8 KV | 161.3 | 134.7 | 55.4 |
| 去審查 FP8 + DFlash2,262K fp4 KV | 156.0 | 134.9 | 53.1 |
去審查版不會比較慢。內建 MTP 在散文上只有 24,比不開投機還慢;DFlash2 散文也只到 55 上下。散文的下一個字最難猜,草稿猜中得少。
版本鎖定
這套能跑,靠的是一組跟版本綁死的行為:--chat_template 會關掉推理內容拆分、DFlash2 必須關 CUDA Graph、NCCL 要 LD_PRELOAD、關 --cuda_embedding 才有 262K。任何一個 pip install -U 都可能讓它默默壞掉。
所以我把整份環境鎖起來:requirements.lock(76 個套件)、76 個 wheel(含 ftllm-0.1.8.2 本體)、整個 venv 的 tarball、unit 檔、chat template、自編 NCCL,再加一支 verify.sh 掛在 systemd 的 ExecStartPre,每次啟動前比對 10 項指紋(ftllm 版本、Python、libfastllm_tools.so 的雜湊、unit 檔、template、NCCL、模型與草稿的 config 和權重大小)。有任何一項變了就拒絕啟動,並列出是哪一項。
驗過兩件事:tarball 裡的 .so 雜湊跟正在跑的那份一致;用 pip install --no-index 只從本地 wheel 重建,出來的 .so 雜湊一字不差。就算 PyPI 撤掉 0.1.8.2,也重建得出同一顆。
還沒做的
- DFlash2 的接受率:FastLLM 的 usage 欄位沒有吐草稿統計。
- NVFP4 路線:B 站評論者量到 NVFP4 + DFlash B8 246.9(固定輸出流),權重我沒下載。
- GPU0 和 GPU1 的用量不對稱(DFlash2 只在 GPU0),現在不是瓶頸,要再往上推 context 就會再遇到。
同系列:#19 Ternary Bonsai 2 塞進一張 2080 Ti · #16 NCCL 修好了 · #14 兩張改裝 2080 Ti 玩 tensor parallel · #13 換一個 template 免費快 15%
常見問題
- FastLLM 在 2080 Ti 上比 llama.cpp 快嗎?
- 不開投機的話不會。FastLLM 跑 Qwen3.8-27B FP8 不開投機只有 33.7 tok/s,比我們 llama.cpp Q8_0 + MTP 的 66 慢一半。速度來自 DFlash2 草稿模型:開了之後寫程式 153.8、數學 134.9。散文只有 53.1,那一欄反而輸 llama.cpp。
- FastLLM 開 DFlash2 在 2080 Ti 上一直 cudaErrorIllegalAddress 怎麼辦?
- 設 `FASTLLM_CUDA_GRAPH=0`。DFlash2 配 CUDA Graph 在 sm_75 上一定會炸,換 `--dtype float16` 或 `--atype float16` 都救不了。FastLLM 文件說 sm_75 要手動設 1 打開 CUDA Graph,那句只適用不開投機;開 DFlash2 照著設就是壞的。
- FastLLM 用雙卡一跑就 ncclAllReduce unhandled cuda error?
- 那是 NCCL 沒有 sm_75 的 kernel。pip 裝 ftllm 時帶進來的 NCCL 和 Ubuntu 套件的 2.22.3 都不含 sm_75。自己編一份帶 sm_75 的 NCCL,用 `LD_PRELOAD` 指過去就好。先用 `ldd` 看 FastLLM 實際載到哪一顆,再用 `cuobjdump --list-elf` 看那顆裡面有哪些 sm。
- 兩張 2080 Ti 22G 跑 FastLLM + DFlash2 可以開 262K context 嗎?
- 可以,要 `--kv_cache_dtype fp4`、關掉 `--cuda_embedding`、`--gpu_mem_ratio 0.95`。262144 是 KV 池的總量,單一提示實際上限約 209K。我們灌到 199,787 token,埋在中間的暗號照樣唸得回來。
接著讀
- 2026-08-21[Benchmark] 換一個檔案、改一個數字,2080 Ti 上的 27B 免費快 15%
Qwen3.8-27B 在 2080 Ti 的免費加速實測:修復版 chat template 讓 KV 快取命中 94.5%,MTP 草稿深度 2 開到 4 讓 decode 從 41.6 到 47.6 tok/s。附完整驗證方法。
- 2026-09-21什麼!?Qwen3.8 27B 居然被壓到 5.9GB,跑起來能力居然有無損模型的 98.2%
PrismML 的 Ternary Bonsai 2 把 Qwen3.8-27B 壓成三值權重,官方說 5.9GB 保留 FP16 的 98.2% 能力。我在一張改裝 2080 Ti 22G 上跑同一組權重的 7.2GB 版:140 題拿 130,兩張卡跑 Q8_0 是 131。附編譯、啟動指令,以及為什麼最小那包反而最慢。
- 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-22[Benchmark] 兩張改裝 2080 Ti 玩 tensor parallel,Qwen3.8-27B 衝到 59.6 tok/s
兩張改裝 2080 Ti 22G 用 llama.cpp 的 tensor parallel 接上 Qwen3.8-27B,配 MTP 投機解碼從單卡 37.1 tok/s 衝到雙卡 59.632 tok/s,還能開到 262K context。內含現在正式在跑的組態、三個上游踩坑,和雙 5060 Ti 社群數字的對照。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。