~/blog/fastllm-dflash2-dual-2080ti

改裝 2080 Ti 22G · part 20

特化的啟動器 FastLLM + DFlash2,居然可以在魔改的 2080 Ti 雙卡跑出 100+ tok/s!

cat --toc

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 慢。

改裝 2080 Ti 22G 系列 #20 封面:等距技術插畫,兩張並排的雙風扇顯示卡旁立著一道青綠色線框閘門,一整排發光小方塊穿過閘門後繼續往右上方延伸

前言

搭過尖峰時段的電梯就知道,電梯一趟的時間幾乎都花在上下樓,載一個人和載八個人差不了幾秒。一小時能送多少人,看每一趟有沒有裝滿。

顯卡吐字也是這樣。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.733.333.2
內建 MTP 8(去審查 FP8)62.153.324.0
DFlash2,262K(去審查 FP8)156.0134.953.1

最後一列是 262K context、fp4 KV 的組態。官方權重和去審查版速度差不多,完整對照在進階區。正式上線前我又關掉了 --cuda_embedding(原因在後面),複測寫程式是 153.8,開著是 154.1,差在雜訊內。TL;DR 的 153.8 就是上線那一刻量的。

三種題目的吐字速度:FastLLM 不開投機三種都約 33 tok/s,開 DFlash2 後寫程式 156.0、數學 134.9、散文 53.1,原本的 llama.cpp Q8_0 + MTP 約 66
只有寫程式和數學跑超過 100 tok/s。散文的草稿猜中得少,DFlash2 只到 53.1,比原本的 llama.cpp 那組慢。

原本的 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,裝 ftllm 0.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 站的配方原封不動跑,這四個地方會出事。每一個在進階區都有完整的錯誤訊息和量測。

  1. NCCL 沒有 sm_75。 雙卡開投機解碼就 ncclAllReduce failed: unhandled cuda error(我是開 MTP 時撞到的)。FastLLM 實際載到的是 Ubuntu 套件那顆 2.22.3,pip 帶進來的那顆也沒有 sm_75。解法是上面那行 LD_PRELOAD
  2. DFlash2 開 CUDA Graph 必炸。 cudaErrorIllegalAddress。要 FASTLLM_CUDA_GRAPH=0。FastLLM 文件教的剛好相反(sm_75 要手動設 1 打開),那句只適用不開投機。
  3. 262K 要三個設定一起改。 --kv_cache_dtype fp4(fp8 的話 draft 權重擠不進去)、不要加 --cuda_embedding(上游建議加,但它在 GPU0 佔掉 2.4GB)、--gpu_mem_ratio 0.95(0.97 長提示會炸,0.90 反而更糟)。
  4. 請求開思考時,推理會混進 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 true8.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 tokenprefill耗時暗號
22,6471,109 tok/s20 秒
91,478855 tok/s107 秒
140,022734 tok/s191 秒
199,787652 tok/s306 秒

六個長度全部答對(表裡列四個),一次都沒有重啟。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 那欄:

GSM8KMATH-500MuSRHumanEval+合計
FastLLM,不開思考49291535128
FastLLM,開思考 + effort low5030936125
llama.cpp Q8_0,開思考50301338131

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_75LD_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,144196,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 KV161.3134.755.421,956 / 21,272 MiB
262K + fp4 KV156.0134.953.121,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 availForKV1.41 GB3.96 GB
GPU1 availForKV2.49 GB5.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>結果
medium8,192length沒有答案
low1,929stop答對

整份 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.pyresult = "" 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 GB33.7977 GB/s79%
FastLLM FP8 + DFlash229 GB152.34,417 GB/s358%

第二列超過 100%,不是真的讀了那麼多,而是這個算式假設「每個字讀一次權重」,開了投機之後這個假設不成立:讀一次權重就驗 8 個位置,所以實際讀的量還不到這樣算出來的三分之一。第一列那個 79% 才算數:不開投機時,頻寬已經快用滿。

草稿 token 數:8 最快

--speculative_num_draft_tokens實際每步猜幾個寫程式數學散文
4390.285.052.3
87156.0134.953.1
12server 起不來

這個值含起點那個 token,所以設 N 實際猜 N−1 個。8 跟 DFlash2 model card 的 block size 8(每步 7 個草稿)是同一個設定。

全部組態的速度

同量法(temp 0、512 token、三發中位數):

組態寫程式數學散文
官方 FP8,不開投機33.733.333.2
去審查 FP8,不開投機32.932.632.4
官方 FP8 + MTP 859.051.323.2
去審查 FP8 + MTP 8(graph=1)61.551.223.2
去審查 FP8 + MTP 8(graph=0)62.153.324.0
官方 FP8 + DFlash2152.3136.857.6
去審查 FP8 + DFlash2,192K fp8 KV161.3134.755.4
去審查 FP8 + DFlash2,262K fp4 KV156.0134.953.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,埋在中間的暗號照樣唸得回來。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。