← 返回

一张 32GB 卡上摆 200K 上下文的显存账

2026-09 · 27B 量级模型 + 200K 上下文 + 投机解码,同时挤在一张消费级卡上

预算是怎么分的

卡的总量是 32607 MiB。一份 27B 的 6bit 量化权重就要吃掉约 20.6 GiB,剩下不到 11 GiB 要同时装下三样东西: KV 缓存、前向计算的中间缓冲、以及投机解码那个草稿模型自己的权重和缓冲。

占用说明
主模型权重≈ 20.6 GiBQ6_K,全常驻显存
KV 缓存 200K × 4 槽≈ 7 GiBK 与 V 都用 4bit 量化,且必须开 flash attention
草稿模型权重≈ 1.05 GiB换成 8bit 版本要多 0.87 GiB,见下文
计算中间缓冲随草稿长度增长草稿长度到 5 时这一项要再 1.08 GiB,直接分配失败
合计≈ 31.3 / 32.6 GiB余量约 1.3 GiB

四个并发槽与"统一池"

多槽是为了让几个短请求同时跑。默认情况下每槽各自一份上下文窗口,200K × 4 是绝对放不下的; 打开 KV 统一池之后,四个槽共享同一个 200K 的池子,才勉强塞得进去。

代价也很实在:一个长请求会把池子占满,别的槽只能排队。实测把一个 100K 的请求和两个短请求同时发进去, 短请求的首字延迟到了 86 秒、吞吐掉到 7 tok/s。所以"支持并发"和"适合并发"是两回事。

减少槽数确实能换出显存(4 槽降到 1 槽省了约 2 GiB),我本来以为这能解锁更长的草稿从而更快, 实测反而更慢——省下来的显存不产生吞吐,而并发能力没了。

那个把整条链路拖挂的 flag

多模态模型除了语言主干还有一块"视觉投影器"(把图像特征映射成模型能吃的向量)。它要不要进显存由一个开关控制, 而这个开关的命名极其反直觉:--no-mmproj-offload 里的 "offload" 指的是"放进 GPU", 所以加了这个 flag 意味着投影器留在 CPU 上,那块几百 MB 到一 GB 多的文件根本不计入显存账单。

我第一次读反了,于是算出来的显存预算比实际多出一大块,配出来的参数在别的机器上"应该能跑"却起不来。 现在我的做法是:凡是语义可能读反的 flag,先查一下版本自己的帮助文本,再决定信不信自己的记忆。

留在 CPU 上的代价是可以量化的——同样的方法测不同尺寸图片的编码耗时:

输入prompt token服务端预填充耗时端到端
纯文本对照60121 ms0.88 s
256×256 图126286 ms1.04 s
768×768 图6381.81 s2.74 s
1536×1536 图236612.61 s13.62 s

按文本预填充的速率算,2366 个 token 只值 1.5–2 秒,也就是说那张大图里约 11 秒是 CPU 在做视觉编码。 小图完全无所谓,大图就是另一回事了。要不要拿 0.6 GiB 显存换掉这段时间,取决于余量——而我的余量只有 1.3 GiB, 草稿模型的计算缓冲随时要用,所以最后的选择是留在 CPU,并在入口侧限制图片尺寸。

几条经验