最近在折腾本地部署Qwen2.5 7B(int4量化版),用的vllm框架,服务器是两张RTX 4090(24G),设置了max_num_seqs=64和gpu_memory_utilization=0.9。刚开始跑几个请求还挺正常,但连续处理几十个prompt之后,显存就慢慢涨到46G然后直接OOM了。查了vllm的文档说是有动态显存管理的,但感觉没生效。我试过调低max_num_batched_tokens到2048,也没用。是不是我哪里设置不对?还是7B模型本身在长文本多并发下就是容易爆显存?求大佬们指点一下排查思路或者有没有其他轻量部署方案推荐。
用vllm部署Qwen2.5 7B,显存一直涨到OOM,是代码有问题吗?
全部回复
共 159 条我之前也踩过类似的坑,vllm的显存管理对PagedAttention的块大小挺敏感的,你试试把--max-num-seqs降下来同时把--max-num-batched-tokens调回默认,很多时候是并发和token预算互相挤占导致的。另外你确认一下是否真的加载了int4,有时候quantization参数没传对,模型会悄悄回退到fp16,显存翻倍直接就爆了。如果还想省心,可以看看sglang或者llama.cpp的server模式,对小显存场景更友好,不过并发能力会弱一些。最后建议你用nvidia-smi盯一下是不是碎片化增长,如果看到的是阶梯式跳涨而不是线性,那大概率是预分配策略的问题。
我之前跑Mixtral也遇到过类似情况,后来发现是vllm的prefix caching跟长prompt叠加时,显存碎片化特别严重,你试试把--enable-prefix-caching关掉,或者干脆把gpu_memory_utilization降到0.8看看,给KV cache留点余量。另外你确认下是不是真的加载了int4,有时候transformers版本不对会偷偷回退到fp16,那显存翻倍很正常。如果还不行,可以换sglang试试,它对连续请求的显存回收更激进,我这边同配置能多扛两倍请求不炸。
说实话我之前也踩过类似的坑,vllm那个动态显存管理不是完全自动的,它主要管的是KV cache,但int4量化模型的权重和激活值还是会占不少显存。你gpu_memory_utilization设0.9其实已经很高了,但两张卡之间还有通信开销,而且max_num_seqs=64对于7B来说可能偏大,每个seq的KV cache累积起来很吓人。建议先试试把max_num_seqs降到16或者32,同时把block_size调小一点,比如16,这样显存碎片化会好很多。另外你确认一下是不是真的加载了int4版本,有时候hf的量化权重加载方式不对会退回fp16,那24G单卡根本扛不住。还有个排查技巧,就是跑的时候用nvidia-smi盯一下每张卡的显存增长曲线,看是匀速涨还是突然跳变,匀速涨大概率是KV cache没释放,跳变可能是请求长度不均导致临时分配。如果实在不行,可以换AWQ或者GPTQ量化配合exllama后端,那个对显存控制更精细。不过要我说,7B模型双卡24G跑长文本多并发本来就是极限操作,建议加个--enable-prefix-caching,对重复prompt能省不少显存。
我之前也踩过这个坑,vllm那个动态显存管理对int4量化支持其实没那么好,尤其长上下文时预分配和KV cache会互相挤。你试试把gpu_memory_utilization降到0.8,同时显式设一下max_model_len,别让它默认拉满。另外两张卡最好用tensor-parallel=2,单卡24G跑7B int4其实有点紧,数据并行反而容易碎片化。要是还不行,换个思路用llama.cpp或者SGLang,小批量场景下更稳,显存曲线平缓很多。
这问题我上周刚踩过,vllm那个动态显存管理对int4量化支持其实不太友好,建议先看下是不是PagedAttention的block没被释放。另外你gpu_memory_utilization设0.9太高了,加上双卡本身通信也要占用显存,试试降到0.7再配个--swap-space 8,把部分tensor换到内存里。我之前用AWQ量化版跑qwen2.5 7b,连续压测300个请求没爆,你可以换个量化格式对比下。
感觉不是代码问题,是vllm默认的preemption策略在长上下文下会疯狂缓存历史token,你试试加个--enable-prefix-caching或者把max_model_len调低到4096看看。另外两张4090跑7b有点尴尬,单卡其实就能塞下int4,不如直接--tensor-parallel-size 1,另一张卡专门跑别的任务,避免跨卡通信带来的隐性显存占用。
我之前也遇到过,最后发现是max_num_seqs设太大导致的,虽然你调了batched_tokens但seqs还是64,等于每个seq都预留了最大长度的显存。建议改成8-16,配合--max-batch-tokens 1024,吞吐会降一点但稳定很多。另外试试用flashinfer后端替代默认的paged attention,对量化模型的内存
之前跑qwen2.5 7b也踩过这坑,int4其实没省多少显存,关键还是kv cache在长上下文下疯涨,试下把max_model_len调小点,比如4096,同时把gpu_memory_utilization降到0.85留点余量。另外vllm的prefix caching要开着,不然多prompt重复前缀也会吃显存。如果还不行,可以换sglang试试,感觉它的显存控制更激进一些。
我之前也踩过类似的坑,vllm那个动态显存管理对int4量化模型的支持其实没那么完美,尤其是连续请求时KV cache的分配策略可能没完全释放。你试试把gpu_memory_utilization降到0.75以下,给显存留出更多余量,同时把max_num_seqs调成32,看看峰值会不会降下来。另外排查一下是不是prompt长度差异太大导致的碎片化,vllm对变长序列的显存预分配挺保守的,可以试着用--swap-space参数开一点CPU offload,虽然会慢但至少不崩。我之前用AWQ量化版+lorra部署遇到过类似问题,后来发现是tokenizer的padding策略没对齐,换个safetensors原版模型反而稳了。实在不行可以换llama.cpp的server模式,虽然吞吐低一些,但显存占用是硬上限,不会无限涨。最后建议你监控一下nvidia-smi里的碎片内存,如果看到很多小块空闲但不连续,那就是典型的分配碎片问题,重启服务通常能缓解一时。
我之前也遇到过类似情况,后来发现是vllm的prefix caching没关,长文本重复前缀会疯狂占显存。你可以试试加--disable-prefix-caching,或者把gpu_memory_utilization降到0.8给KV cache留点余量。另外int4量化其实对显存压力不大,问题多半出在并发请求的token总数上,试试把max_num_seqs调到32,同时限制单条prompt长度,应该能缓解。如果还不行,换SGLang跑一下对比看看,说不定是vllm版本bug。
int4其实省不了多少显存,峰值还是会炸,试试把gpu_memory_utilization降到0.7看看。
vllm的显存管理对长上下文不友好,建议换sglang或者直接上量化过的AWQ版本试试。
量化版还开0.9显存利用率,4090双卡跑7B确实容易卡在kv cache上,建议先降到0.7试试。
你这个现象挺典型的,vllm的paged attention只管理KV cache,但int4量化后权重本身不吃显存,涨到OOM多半是长文本下中间激活值或prefill阶段峰值没控制住。建议先开--enable-chunked-prefill试试,或者把gpu_memory_utilization降到0.8,给CUDA context留点余量,另外确认下是不是max_model_len设太大导致每个seq都预留了完整空间。我之前跑7B单卡24G,设max_model_len=8192同时压max_num_seqs到32就没再爆过,你可以对比下这个基准。
说实话我第一反应不是你代码的问题,vllm那个动态显存机制主要是针对KV cache的,但int4量化后权重占得少了,KV cache反而可能成为大头,尤其你max_num_seqs拉到64,每个seq的上下文稍微长一点,KV cache就跟滚雪球一样。我之前用7B模型也遇到过类似情况,后来发现是prompt里带了特别长的system prompt或者历史对话,你留意下是不是某些请求的输入长度特别夸张?可以试着在日志里把每个请求的token数打出来看看分布。
另外gpu_memory_utilization=0.9这个值其实有点激进,双卡情况下vllm默认是均匀分配显存的,但你设了0.9意味着每张卡要预留21.6G,留给动态分配的空间就很小了。我建议改成0.7或者0.75试试,给碎片化内存留点缓冲。还有个小技巧,把max_num_seqs降到32,同时开启--enable-prefix-caching,能显著减少重复前缀的cache占用,我自己实测有效。
如果调完还是涨,那就得怀疑是不是某个请求触发了模型重新加载或者量化反量化的问题,可以在vllm里开--disable-log-requests看下请求日志,甚至用nvidia-smi定时采样下显存看是哪个tensor在涨。实在不行就换TGI或者直接上llama.cpp的server模式,虽然吞吐低点但显存控制稳得多。
说到这个我前阵子也踩过类似的坑,vllm那个动态显存管理其实是有前提的,它默认会为每个seq预留完整的max_model_len空间,你虽然设了max_num_seqs=64,但Qwen2.5 7B的max_model_len默认是32768,这算下来预分配就非常夸张了,显存直接按最坏情况吃满。建议你先看看实际请求的平均token长度,然后显式设一下max_model_len,比如改成4096或8192,这样vllm的paged attention才能真正按需分配,不然它宁可留着buffer也不会释放。另外int4量化的话,用awq或gptq格式配合vllm的量化参数加载,别直接用bitsandbytes那种动态反量化,性能差且显存容易波动。还有个思路是你试试把gpu_memory_utilization降到0.7,留出更多给KV cache的碎片整理,有时0.9太高反而触发频繁的swap。我自己的经验是把max_num_seqs降到32,加上--enforce-eager禁用cudagraph,虽然吞吐掉一点但稳定很多。如果还不行,可以换个方案用llama.cpp的server模式,配合--n-gpu-layers全量offload,那个显存控制是严格按物理上限来的,不会突然暴涨。你查一下是不是prompt里有特别长的system prompt或者历史消息没截断,这个影响比并发数还大。
int4量化后显存还涨这么多,八成是vllm的prefix cache没关,试试--disable-prefix-caching。
我之前也遇到过类似情况,后来发现是vllm的prefix caching在作怪,长文本重复前缀会疯狂吃显存,你试试把enable_prefix_caching关掉,或者把max_num_seqs调到32看看。另外int4量化虽然省显存,但7B在4090上连续推理时KV cache增长很猛,0.9的利用率其实挺危险的,建议改成0.85留点余量。还有个思路是换成AWQ量化试试,实测比GPTQ在vllm下更稳。
遇到过类似的,int4量化其实省的是权重显存,但KV cache和中间激活值才是大头,你这并发量下动态管理不太来得及回收。建议先关掉max_num_seqs的限制,或者干脆设成1跑长文本试试,看是不是并发导致峰值叠加。另外vllm的gpu_memory_utilization是预留池子,不代表不会超,你可以观察下nvidia-smi里是持续增长还是到某个点才爆,前者可能是显存泄漏,后者就是单纯的峰值问题。要是排查麻烦,换llama.cpp的server模式跑同量化模型,显存控制稳得多,就是吞吐低点。
同样配置遇到过,问题大概率不在max_num_seqs,而是vllm的prefix caching和continuous batching在长对话场景下会累积KV cache碎片,试试把enable_prefix_caching关掉,然后显存利用降到0.85留点余量。另外int4量化版本身吃显存就比fp16少,但7B模型在4090上并发32个左右就接近极限了,你这64个有点激进,可以先砍到16观察下显存曲线。实在不行换llama.cpp的server模式,虽然吞吐低点但内存控制稳很多,我这边跑同样负载就没爆过。
这问题我上周刚踩过,大概率不是代码问题,是vllm的显存管理在int4量化下有点坑。你设了gpu_memory_utilization=0.9,但vllm会预分配KV cache,加上动态调度并不像文档说的那么智能,连续请求时如果序列长度波动大,它不会及时释放旧block,就会慢慢涨上去。建议直接试试把max_num_seqs降到16或者32,同时把gpu_memory_utilization调到0.75,先给PyTorch留出余量,看能不能压住。另外,7B int4在24G双卡上确实有点尴尬,长文本下每个序列的KV cache开销不小,如果prompt平均超过2k tokens,这配置本身就容易爆。排查的话,可以开vllm的--enable-memory-profiling参数看看实际峰值分配,或者用nvidia-smi盯一下是不是只有单卡在涨,双卡负载不均也可能导致一张卡先炸。真要轻量方案,试试llama.cpp的server模式,配合flash attention吃显存省很多,或者用exllamav2的flash-attn实现,7B int4单卡16G就能跑得稳,多并发就上AWQ量化加progressive rollout,比你硬调vllm参数省心。
我之前也踩过类似的坑,vllm那个显存管理对int4量化支持得没那么好,你试试把gpu_memory_utilization降到0.75,然后别用max_num_seqs,改成默认值,同时把--enforce-eager加上,能省不少缓存。另外长文本场景下7B的KV cache膨胀得很快,建议直接限制max_model_len到4096,基本能稳。如果还不行就换llama.cpp或者sglang,对量化模型更友好,部署起来也省心。
我之前用vllm跑别的模型也踩过类似的坑,后来发现动态显存管理其实对连续请求的释放没那么及时,尤其是你这种多并发长文本场景,paged attention的page块会越积越多,感觉像是泄漏但其实不是,只是碎片化或者触发了预分配。你gpu_memory_utilization设0.9已经很高了,两张卡共享的话,vllm是按单卡算的,你其实等于要它每张卡都吃满90%,但模型权重加KV cache本身就会预留不少,建议你试试把utilization调到0.75左右,给碎片化留点缓冲。另外max_num_seqs=64对7B来说太激进了,我一般16就够,你可以观察下是不是并发太高导致KV cache膨胀,int4量化后反而显存分配更碎。排查的话,先开vllm的--enable-memory-monitoring看下峰值和空闲分布,或者用nvidia-smi循环记录一下,看是不是某个特定长度的prompt触发跳变。如果实在搞不定,换llama.cpp或者SGLang试试,后者对显存控制更细粒度,但吞吐会低一点。