TGI 部署 Llama 3 时遇到 CUDA out of memory,先不用急着换小号模型或上量化,多数情况下是显存分块预分配策略设置得太激进。TGI 在服务启动时就会为 KV cache 预留连续显存,并把批量请求的 token 预算作为分配上限。当一批请求的输入输出长度总和超过预算时,CUDA 申请不到足够的显存块,就会直接抛 OutOfMemoryError。
调显存分块预分配参数时,核心是限制批处理 token 总量和预填充阶段的单次计算量。优先调整 `--max-batch-total-tokens` 与 `--max-batch-prefill-tokens`,用 `--cuda-memory-fraction` 限定进程显存上限。适用场景是并发较多、上下文较长导致的运行期 OOM;加载期 OOM 或单卡容量不足时,必须先换策略。
1. 先区分 OOM 发生在加载阶段还是运行阶段
加载阶段 OOM 通常发生在模型权重装载时,此时调分块参数无效,需要换更大的 GPU、启用量化或减少并行度。运行阶段 OOM 才与批处理和 KV cache 预分配相关,常见日志中会有显存申请大小,可以通过申请大小与 batch token 总量的对应关系来确认。
2. 收紧批处理和 prefill 的 token 预算
TGI 启动参数中,`--max-batch-total-tokens` 决定一个批次最多容纳的输入与输出 token 总和,`--max-batch-prefill-tokens` 控制预填充阶段单次计算的 token 数。两条参数直接影响显存分块预分配的大小。先用一个偏保守的组合启动,再逐步调高,是最稳妥的路径。
text-generation-launcher `--model-id` meta-llama/Llama-3-8B-Instruct `--max-batch-total-tokens` 8192 `--max-batch-prefill-tokens` 2048 `--max-total-tokens` 4096这里 `--max-total-tokens` 是单条请求的输入加输出上限,用来防止单条长请求顶满整个批次。三个参数组合使用,相当于给 TGI 的显存预分配设置了多道保险。执行后先验证服务能起来,再逐步调高 `--max-batch-total-tokens`,直到接近目标负载。
3. 为进程设置 CUDA 显存上限
`--cuda-memory-fraction` 用来限制 TGI 占用每张 GPU 显存的比例,默认是 1.0。如果宿主机器上还有其他进程,建议设到 0.8 或 0.9,避免系统进入严重 swap。但设得太低会连模型权重都装不下,所以要先确认权重占用和 KV cache 预算之和小于目标显存。
以 8B 模型 FP16 部署为例,权重通常占用十几 GB,如果单卡是 24GB,余量能留给 KV cache 的并不宽裕。可以先设置 `--cuda-memory-fraction` 0.9,再根据实际显存占用调整。不同环境差异较大,需要结合当前显卡型号和并发量确认。
4. 调整后的验证与取舍
- 先以保守参数启动,确认服务没有被 OOM 打断。
- 用接近线上实际的输入长度和并发数发送请求,观察显存占用和错误日志。
- 如果仍出现 OOM,优先降低
`--max-batch-total-tokens`,其次降低`--max-batch-prefill-tokens`。 - 显存占用稳定且有余量时,再逐步调高参数,每次只调一个变量。
- 不要用系统 swap 作为长期调节手段,swap 只是延迟崩溃,会掩盖真实显存瓶颈。
调低 token 预算的直接代价是单批次吞吐下降。这是显存与并发能力的正常取舍,不需要强行压到极限。量化、换更大显存、使用多卡都是不同方向的解决办法,但如果问题出在分块预分配策略上,调整上述参数通常能先让服务稳定跑起来。