动态shape推理导致显存不足设置max_seq_len上限的Llama.cpp配置

文章导读
动态 shape 推理时,prompt 长度和生成长度都可能变动。如果 llama.cpp 在推理过程中出现 out of memory,通常不是单条输入固定超长,而是没有对上下文窗口设置上限,导致 KV cache 和中间激活按动态增长去分配。设置 max_seq_len 上限,是把上下文长度截断在可控范围,从而在推理前预留固定显存预算。但上限值不能拍脑袋,需要结合模型大小、batch size
📋 目录
  1. 先分清显存消耗来自哪里
  2. 设置 max_seq_len 的配置方式
  3. 判断 max_seq_len 该设多少
  4. 验证配置是否生效
  5. 容易忽略的边界
A A

动态 shape 推理时,prompt 长度和生成长度都可能变动。如果 llama.cpp 在推理过程中出现 out of memory,通常不是单条输入固定超长,而是没有对上下文窗口设置上限,导致 KV cache 和中间激活按动态增长去分配。设置 max_seq_len 上限,是把上下文长度截断在可控范围,从而在推理前预留固定显存预算。但上限值不能拍脑袋,需要结合模型大小、batch size、GPU 空闲显存一起估算。

显存不足如果发生在生成阶段且随上下文递增,优先限制 max_seq_len。建议先设置 1024 或 2048 跑通,用启动日志确认 KV cache 实际占用,再逐步上调;同时限制 batch 和并行序列数。max_seq_len 只约束单序列上下文长度,prefill 阶段的大 prompt 依然可能触发 OOM,需要配合 batch 参数控制。

先分清显存消耗来自哪里

模型权重、KV cache 和 prefill 中间的激活张量都会占用显存。动态 shape 主要影响后两者:序列越长,KV cache 越大;prompt 越长,prefill 阶段临时张量也越大。启动时如果只看到“llama_tensor”或“failed to allocate”一类的错误,不一定只是 KV cache 的问题。

  • 如果 OOM 日志在 decode 阶段,且上下文接近上限,优先降低 -c`--max-seq-len`
  • 如果 OOM 出现在第一批 prompt 处理时,说明 prefill 的 batch 太大,需要限制 -b
  • 如果模型权重本身放不下,设置 max_seq_len 无法解决,需要换更小的量化版本。

设置 max_seq_len 的配置方式

llama.cpp 的主程序和内置 server 通常用 -c`--ctx-size` 指定上下文窗口,某些新版本也接受 `--max-seq-len`。不同版本参数名不完全一致,先执行 llama-server `--help` 确认。以下是最常见的写法:

llama-server -m /path/to/model.gguf -c 2048 -n 512 `--n-gpu-layers` 99

-c 2048 就是 max_seq_len 上限,表示单条序列最多保留 2048 个 token 的上下文。-n 512 限制生成步数,来自输入真正占用的 KV cache 不会超过 -c。为了减小动态增长带来的波动,还可以限制 batch 和并行数:

llama-server -m /path/to/model.gguf -c 2048 -b 512 -ub 512 `--parallel` 1

-b 是 prompt 处理 batch,-ub 是生成时 batch,`--parallel` 是并发序列数。对于单用户场景,先设成 1 和 512,比只限制上下文更稳。

判断 max_seq_len 该设多少

最直观的方法是看启动日志。llama.cpp 在加载模型后会打印 KV cache 大小。例如:

llama-server -m /path/to/model.gguf -c 1024 `--verbose`

日志里会给出类似 KV cache size 的行。如果 1024 上下文显示的缓存占用已经接近剩余显存,就不要继续上调。另一种方式是先用很小的值跑通,再在显存有余量时逐步增加。不要只凭模型总参数量估算,量化类型和层数都会影响 KV cache 的系数。

如果使用多路并发,还需要把 KV cache size × parallel 算进去。比如 `--parallel` 4 时,四条序列各占一份上下文缓存。

验证配置是否生效

启动后在日志里找 KV cache 占用,再用一个接近上限的长 prompt 测试。如果 prompt 长度低于 -c,但显存仍然上涨,说明 prefill 激活张量是主因,不能靠 max_seq_len 解决;这时需要把 -b 调小,或对输入做分块处理。

在 server 模式中,可以通过 /props 接口查看当前上下文窗口配置。发送 prompt 时若超过上限,llama.cpp 会截断到 -c 的长度,不会继续增长。

容易忽略的边界

  • -c 限制的是上下文长度,不是“总 token 数”。每条并发序列都会占用一份。
  • gpu offload 层数 `--n-gpu-layers` 越多,KV cache 和激活可能也更多放在 GPU 上;如果在 CPU 和 GPU 间分配,显存峰值会比全 GPU 低,但速度变慢。
  • 如果 OOM 出现在运行时,可以先用 `--no-mmap` 或减少 offload 层数做交叉验证,以区分是权重加载问题还是 KV cache 超限。
  • 设置 max_seq_len 会截断超长输入,影响长文档处理效果。若业务要求完整阅读长文档,应先考虑分块摘要,而不是把上下文无限调大。