最近在折腾本地部署,机器是4090 24G,想用VLLM跑Qwen2.5-7B-Instruct做API服务。参考了官方文档,设置了--max-model-len 4096,--gpu-memory-utilization 0.9,还用--enforce-eager关闭了CUDA graph。但启动后只要并发请求一多(大概5-6个),显存直接拉满然后OOM,日志里报的是torch.OutOfMemoryError。试过降低max-num-seqs到2,虽然不崩了,但吞吐量感觉还不如直接用transformers。我看别人说7B模型24G挺轻松的,是不是我的KV Cache配置有问题?或者该用AWQ量化版本?求有经验的大佬指点一下,先谢过了。
VLLM跑Qwen2.5-7B一直OOM,是我的显存策略有问题吗?
全部回复
共 31 条24G跑7B按理说确实够,但你可能忽略了VLLM默认会预分配大量KV Cache,gpu-memory-utilization 0.9基本把卡吃干了。试试把utilization降到0.8左右,再配合--max-num-seqs 8,别一上来就拉满。另外4090的24G里有部分被系统占了,实际可用没那么多,日志里那个OOM八成就是KV block不够分。
并发一高就OOM,多半是KV Cache没限住。试试加--max-num-batched-tokens,或者把gpu-memory-utilization降到0.85,给系统留点余量。
24G跑7B确实不该这么吃力,但4090是消费卡,VLLM默认的显存分配策略在非数据中心卡上有时会翻车。你试试把gpu-memory-utilization降到0.85左右,别拉太满,留点余量给CUDA context和临时buffer。另外max-model-len 4096对7B来说KV Cache其实不小,如果实际请求没那么长,直接砍到2048会宽裕很多。还有enforce-eager关了CUDA graph反而更费显存,这操作有点反直觉,建议去掉试试。
7B模型在24G上确实不该这么容易炸,但Qwen2.5-7B的KV Cache挺吃显存的,4096长度下并发5-6个很容易把0.9的余量吃光。你可以先把gpu-memory-utilization降到0.85左右,再试试开启--enable-prefix-caching,对API服务这种多轮场景帮助不小。另外--enforce-eager其实反而更费显存,CUDA graph能省不少,建议去掉再测。如果还是崩,把max-model-len压到2048看看是不是长度的问题。
24G跑7B确实不该这么紧,问题大概率出在KV Cache上。你算一下:Qwen2.5-7B是28层、GQA 4个KV head、head_dim 128,4096上下文下每token的KV大概就112KB左右,5-6个并发其实也就几百MB,不应该直接爆。我怀疑是gpu-memory-utilization 0.9把预分配压太满,加上enforce-eager反而让中间激活更占地方。可以试试调到0.85、去掉enforce-eager,再显式设一下max-num-batched-tokens。
你这情况其实挺典型的,4090跑7B按理说确实不该这么容易炸,问题大概率不在模型权重本身,而是KV Cache吃太多了。你设了4096的max-model-len,但没提max-num-batched-tokens,VLLM默认会按最大长度去预留KV Cache块,24G里权重占掉大概15G左右,剩下的给KV Cache和activation其实很紧张。并发一上来,每个请求的上下文叠加,KV Cache瞬间就爆了。可以试试把max-model-len降到2048先验证一下,如果立马不崩了,那就基本确认是这个方向。另外gpu-memory-utilization 0.9有点激进,留点余量给CUDA context和临时buffer会更稳,0.85甚至0.8都值得试。还有个容易忽略的点,Qwen2.5的tokenizer对中文压缩率一般,实际请求的prompt长度可能比你预期长不少,建议在服务端打个日志看看真实输入长度分布。真要追吞吐的话,可以考虑上AWQ或GPTQ量化版本,7B int4在4090上跑并发会舒服很多,精度损失做API服务基本感知不到。
4090跑7B确实不该这么吃力,你这个问题大概率不在max-model-len上,而是KV Cache的实际占用被低估了。Qwen2.5-7B是GQA架构没错,但4096上下文乘以并发数,再算上每层KV head的维度,5-6个并发叠起来其实不小。你可以先试试把gpu-memory-utilization降到0.85左右,留点余量给CUDA context和临时buffer,0.9在24G卡上经常是压着红线跑的。另外enforce-eager虽然省了graph的内存,但反而会让某些中间激活反复分配,吞吐掉得厉害,不如试试默认的CUDA graph模式,配合max-num-seqs调低一点。还有个容易忽略的点是vllm的block_size,默认16,如果你请求长度参差不齐,KV block碎片化会很严重,可以试试调成8或者开prefix caching。实在不行用AWQ或者GPTQ量化版本,7B在24G上跑fp16本来就有点紧,量化后并发能翻倍。
KV Cache这块确实容易踩坑,vLLM默认按max-model-len预分配,你设4096其实还好,但gpu-memory-utilization 0.9在4090上会留得比较紧,加上并发一上来block碎片化就容易炸。可以试试调到0.85左右,再把max-num-batched-tokens压一下,别让它一次吃太多。另外enforce-eager关了反而更省显存,但吞吐会掉,先别急着关。
24G跑7B确实不该这么紧,但VLLM默认会按gpu-memory-utilization把KV Cache预分配到接近0.9,你5-6并发一上来就容易顶到天花板。建议先把max-model-len降到2048试试,4096的KV占用翻倍很夸张。另外Qwen2.5-7B的权重加载本身就要占十几G,你--enforce-eager还会额外吃显存,不一定划算。可以换成--max-num-batched-tokens限制一下,再观察日志里KV cache block实际用了多少。
24G跑7B确实不该这么紧张,问题多半出在KV Cache没限住。你虽然设了max-model-len,但vllm默认会按gpu-memory-utilization预分配一大块给KV Cache,0.9在4090上等于把显存全押上了,并发一上来自然就爆。试下把gpu-memory-utilization降到0.85,再加个--max-num-batched-tokens限制下每步的token预算,通常能稳住。另外Qwen2.5-7B可以上FP8量化,显存能省不少,吞吐反而更好。
4090跑7B确实不该这么吃力,你试试把gpu-memory-utilization降到0.85左右,vllm预分配显存有时候会算得太激进。另外max-model-len 4096看着不大,但Qwen2.5默认GQA的KV head不多,cache其实挺占地方的,可以加个--kv-cache-dtype fp8看看。还有个坑是enforce-eager虽然省显存但会拖慢速度,不如换成限制max-num-batched-tokens更实在。