KV 缓存 Q8 换 f16 + MTP,双 P40 老卡跑 Qwen 27B 冲到 48 tok/s
TL;DR:如果使用 MTP 和 ngrams,将 KV 缓存切换到 f16 可能会显著提升速度。
我有一个自建的“AI 巨型集群”,由两块 P40、一块廉价中国主板和一颗 Xeon CPU 组成(整机成本约 1100 美元,包括 GPU 的水冷)。在 Qwen 3.8 27B Dense 上使用张量并行时,我通常只能获得最高 15 tk/s 的速度,但我怀疑它还能更快。所以,我最终请 Codex 帮忙再榨出一些性能。
免责声明:我根本不是程序员。我只是一个普通 PC 用户,整体经验还算丰富,但绝对算不上开发者。
最近我一直在运行 Qwen 3.8 27B Q8。在 Codex 建议的各种调整下,我可以在短上下文中达到最高 32 tk/s——但在 130K+ 的长上下文中,速度仍然回落到平均 12-15 tk/s。我最初使用 Q8 作为缓存(我以为它更小所以更快),但后来我想,为什么不试试 F16 缓存呢?我试了,结果发现 F16 在 MTP 接受率上远优于 Q8。这需要微调其他参数,但确实显著提升了性能。
由于我不擅长解释这些技术细节,我让 Codex 来总结。抱歉,这些内容有点 AI 味!😄
双 Tesla P40 / Qwen3.8-27B Q8 基准测试
硬件:2x Tesla P40(每块 24 GiB),Xeon E5-2680 v4(14C/28T),64 GiB 内存。NVIDIA 驱动 580.173.02。
软件:llama.cpp 构建 5d9e5ac30(构建号 10388),CUDA + 本地构建的 NCCL。模型:Qwen3.8-27B-Cold-Fusion-GAIN-V1.1-NM-DAU-NEO-MAX-NEO-MTP-Q8_0.gguf(28.15 GiB,llama-bench 报告 27.32B 参数)。
标准 llama-bench
三次重复,F16 KV,全部层 offload,张量并行切分到两块 P40:
llama-bench -m MODEL -ngl 99 -sm tensor -ts 1/1 -dev CUDA0/CUDA1 -mg 0 \
-fa on -b 2048 -ub 512 -ctk f16 -ctv f16 -p 512,2048,8192 -n 128,512 -r 3
| 测试 | Tokens/s |
|---|---|
| pp512 | 444.38 +/- 0.15 |
| pp2048 | 432.38 +/- 0.10 |
| pp8192 | 409.99 +/- 0.50 |
| tg128 | 16.12 +/- 0.02 |
| tg512 | 16.12 +/- 0.01 |
pp 和 tg 是 llama-bench 的原始测量值;不包括分词或采样。该工具调用不使用推测解码或视觉功能。
实际服务器配置
日常使用的引擎是独立的 p40.cpp:F16 KV 缓存,单个 220,160 token 槽位,张量切分 1:1,Flash Attention,使用 ngram-simple 的 MTP 推测解码(draft-mtp),最大 draft 6,Qwen 推理强度 medium,并加载了 F16 视觉投影模型。
| 场景 | 结果 |
|---|---|
| 合成短 128-token 解码,MTP=6 + ngram-simple | 最高 48.00 tok/s |
| 使用中观察到的典型短交互解码(代码任务) | 最高 46 tok/s |
| 使用中观察到的长上下文交互解码 | 约 20 tok/s |
| 加载视觉功能的 63,900-token 服务器 prefill | 258.33 tok/s |
| 相同 63,900-token 前缀,更换后缀 | LCP f_keep=1.000;仅 4 个 prompt token 在 542.53 ms 内重新计算 |
前缀结果是内置的 LCP 缓存,而不是 --cache-reuse。后者是 KV 位移,在多模态投影模型加载时会被 llama.cpp 禁用。
作为对比,在采用这个 p40.cpp/NCCL 配置之前,同一台机器在长上下文下通常约为 15 tok/s。约 20 tok/s 这个数字是实际服务器观测结果,不是 llama-bench 的基准行。
所以……看来祖母级 GPU 还是有点余力的!😄
P.S. 我的“生产”配置:
-ngl all \
-sm tensor \
-ts 1,1 \
-mg 0 \
-fa on \
-c 220160 \
--fit off \
-np 1 \
-cb \
--spec-type draft-mtp,ngram-simple \
--spec-draft-n-max 6 \
--jinja \
--chat-template-file /models/qwen/chat_template.jinja \
--cache-reuse 256 \
--mmproj /models/qwen/mmproj-F16.gguf \
--chat-template-kwargs '{"reasoning_effort":"medium"}' \
--reasoning on \
--reasoning-preserve \
--repeat-penalty 1.0 \
--presence-penalty 0.5 \
--min-p 0.0 \
--top-k 20 \
--top-p 0.95 \
--temp 1
―― 高票评论(帖子共 15 条讨论)――
[+7] u/Long_comment_san:“祖母集群”……我想我从此会永远记住这个说法了,笑死
[+6] u/seamonn:你从哪里搞到这种自带 Nvidia GPU 的祖母?
[+2] u/cezarducatti:我可以在 3.8 Q4 XL 上证实这一点;我只把 K 缓存换成 f16,就提高了 MTP 速度,尤其是在编写可预测的代码时。
[+1] u/jacek2023:我现在在波兰看到一块 Nvidia Tesla P40 24GB 卖 1700 波兰兹罗提。那价格只有 3090 的一半。
[+1] u/nobleglEn9:对于那套硬件来说,结果很扎实。我有一件事很好奇,你试过 q8 和 f16 之间的中间量化缓存吗,还是只是二元对比?
[+1] u/OnlineParacosm:我喜欢这个地方,因为昨天有个家伙花了可能 8 万美元配了一台机器用来做一个 Vite 包装器;而你却在战壕里,用我曾祖父的 GPU 咬牙忍受糟糕的解码和 prefill。