最近在用vLLM部署一个13B的模型到公司服务器上,单卡A100 80G跑起来倒是还行,但并发一上来就显存溢出,报OOM错误。我试了GPTQ量化到4bit,精度有点下降但还能忍,结果显存占用还是跑满。问了同事,有人推荐用Flash Attention,有人建议上多卡张量并行,但我搞不清楚这些方案到底怎么落地。有没有大佬分享一下实际部署中压显存的成熟套路?或者有没有什么简单的trick能先顶住小流量?感谢!
部署开源大模型到生产环境,显存总不够用怎么办?
全部回复
共 161 条显存不够先砍max batch size,再把KV cache用PagedAttention跑起来,小流量能顶一阵。
Flash Attention先加上,能把KV cache省不少,vLLM里直接开就行,小流量能顶一阵。
建议直接上张量并行,两张A100跑13B很稳,GPTQ降精度不如换AWQ,效果和速度都更均衡。
vLLM的PagedAttention其实已经帮你省了不少显存了,OOM大概率是KV cache被占满而不是权重本身。你GPTQ到4bit后显存还跑满,建议先看下是不是max_num_seqs和gpu_memory_utilization这两个参数没调好,把利用率卡到0.9,同时限制一下单请求的最大长度,很多OOM是长上下文撑爆的。Flash Attention主要省的是计算时的中间激活值,对显存峰值有帮助,但如果你已经用vLLM,它内部应该已经集成了相关优化,自己再去套可能反而冲突。多卡张量并行是最直接的解法,但你需要确认代码里model parallelism的切分方式,如果只是简单用device_map="auto"那等于没切,得用accelerate或者手动把线性层权重按TP规则切分。想先顶小流量的话,有个土办法是把并发请求排队,用vLLM的--max-num-seqs调小,比如设置成4,这样每个batch的峰值显存会降很多,代价是吞吐量下降。另外可以试试AWQ或者SmoothQuant,实测比GPTQ在相同bit下显存占用能再低几个百分点,而且推理速度更快。最后建议你开--enable-prefix-caching,如果业务里有重复系统提示词,这个能省下不少KV cache空间。
说实话你这个情况我太懂了,13B模型看着不大,但并发一上来就是另一回事。GPTQ 4bit降精度其实不是关键瓶颈,我怀疑你vLLM的KV cache没调好,默认配置会预分配大量显存,建议先看看--gpu-memory-utilization参数,把它从默认的0.9往下降,比如0.8,同时配合--max-num-seqs限制并发数,这样能立刻止血。Flash Attention确实要上,它能省不少显存,而且vLLM里直接开--enable-flash-attn就行,基本零成本,你值得先试试这个。至于多卡张量并行,那是治本的路子,但A100 80G单卡跑13B其实绰绰有余,你更可能是显存碎片化而不是真不够用,可以试试paged attention的显存管理,vLLM里已经内置了,但记得把--swap-space设小点,默认值会吃掉不少显存。我这边实际部署时还发现,输入序列长度对显存影响巨大,如果业务场景长文本多,建议用--max-model-len限制输入长度,比如4096,能省下一大截。另外一个小trick,如果只是小流量顶一下,可以把vLLM换成TGI,它资源占用更保守,虽然吞吐略低,但至少不会一上来就炸。最后,别迷信量化,4bit有时反而会让显存占用更不可控,先排查是不是显存管理逻辑的问题,再考虑升级硬件方案。
vLLM本身已经集成了Flash Attention,你如果没显式开的话可以看下日志确认下是不是默认关着的,这玩意儿对长序列的显存优化还是挺明显的,尤其是并发上去之后KV Cache那块能省不少。多卡张量并行确实是正路,但13B模型在A100 80G上单卡其实不该这么容易爆,你最好先算一下是不是max-model-len设太大了,或者gpu-memory-utilization没调好,默认值有时候会留太多冗余。我这边之前部署33B的时候试过把max-num-seqs调小一点,配合continuous batching,小流量下体验会好很多,至少不会一上来就OOM。GPTQ 4bit还是占满显存的话,你检查下是不是把KV Cache也量化了,或者显存碎片化严重,可以试试vLLM的--kv-cache-dtype fp8,A100上支持得还不错。另外有个土办法,如果只是临时顶流量,可以把并发请求的max-tokens限制死,避免某些极端生成长度把显存撑爆,代价就是用户体验稍微打点折扣。还有个坑是你可能没开prefix caching,如果生产里很多请求带相同系统提示词的话,这个能省不少显存和算力,vLLM里一行配置的事。最后建议你监控一下实际显存分配曲线,有时候看着是OOM,其实是显卡上别的东西占了显存没释放,不一定是模型本身的问题。
Flash Attention值得优先试,它主要省的是kv cache那块显存,你并发高的时候瓶颈多半在这,vLLM本身也支持,改一下启动参数就行。张量并行的话,如果只是单卡OOM,先别急着上,要改模型切分和通信配置,落地成本不低。临时顶小流量的话,可以把max_num_seqs调小,或者限制最大输入长度,很多请求的prompt其实没你想的那么长。另外你GPTQ已经4bit了还跑满,建议看一眼是不是vLLM的gpu_memory_utilization设太高了,留点余量给碎片。
vLLM的PagedAttention本身已经优化过KV cache了,但OOM大概率是max-num-seqs和gpu-memory-utilization没调好,先试着把利用率压到0.85以下,再把并发数限到8以内试试,小流量应该能扛住。至于Flash Attention主要是省显存带宽,对峰值显存帮助有限,不如直接上张量并行,13B模型两张A100很宽裕,GPTQ的4bit配合TP=2基本能解决。另外可以看看PREFIX CACHING开没开,开完重复请求的显存复用特别明显,我这边压了差不多30%占用。
vLLM本身已经集成了PagedAttention,跟Flash Attention不是一个层面的东西,前者管KV Cache的显存分配,后者优化注意力计算,两个能一起用。你如果已经上了vLLM,那Flash Attention带来的收益其实有限,更值得先看的是KV Cache的预留比例,vLLM里那个gpu_memory_utilization参数,默认0.9,可以调到0.95,但得留点余量给CUDA context和碎显存。说到量化,GPTQ 4bit对13B模型来说,显存大头其实还在KV Cache和激活值上,尤其并发一高,KV Cache是按序列长度线性涨的,你试下把max_num_seqs调小,比如16或者8,能显著降低峰值显存,代价是吞吐量下降。
多卡张量并行确实是最直接的路子,两张A100跑13B,每卡只要扛一半权重和一半KV Cache,但你要注意TP通信开销,vLLM里设tensor_parallel_size=2,模型并行度上去了,但如果你服务器是单机多卡,PCIE带宽够的话还好,跨机就惨了。还有个更简单的trick,如果你暂时不想动分布式,可以把max_model_len砍半,比如从4096降到2048,很多生产场景其实不需要那么长上下文,这样KV Cache直接少一半,小流量完全能顶住。
另外你提到精度下降能忍,那可以看看AWQ,比GPTQ在某些模型上保持得更好,而且vLLM直接支持,不用额外改代码。如果还不行,就得考虑投机解码或者offload部分层到CPU了,但后者延迟会涨,不适合在线服务。我这边实际跑过7B和13B,感觉最关键还是先监控一下每请求的显存曲线,确认瓶颈到底在权重还是KV Cache,别一上来就调量化。
Flash Attention确实该优先上,它能省不少显存,而且vLLM里直接开就行,基本零成本。张量并行适合你这种单机多卡场景,把13B拆到两张A100上,单卡压力小很多,但要注意通信开销,最好用NVLink。另外小流量顶住的话,可以试试把max-num-seqs调小,或者开PagedAttention,vLLM默认就有这功能,并发不高时能明显减少峰值占用。对了,你GPTQ量化后显存还满,是不是因为context长度设太大或者没开continuous batching?这俩对显存影响也很大。
Flash Attention先安排上,能省不少显存,vLLM里直接开就行,4bit配合这个基本能顶住小流量。
显存不够先砍max_len和并发数,顶上小流量再说,别一上来就上多卡,调试成本太高。
Flash Attention确实值得先试,它在不降精度的前提下能把KV cache的显存占用压下去不少,而且vLLM里直接开就行,改动很小。不过你并发上来还爆的话,光靠这个可能不够,建议把max-num-seqs调小一点,比如32甚至16,牺牲点吞吐先把服务稳住。多卡张量并行是治本的路子,但要注意通信开销,小流量阶段可以先用单卡加量化顶着,等真扛不住了再上TP。还有个土办法是开swap到CPU offload,虽然慢点但至少不OOM,适合临时救急。
跑量小的话先试试把max-num-seqs调低点,配合vLLM的continuous batching,能顶一阵子。
先试试把max-num-seqs调低点,小流量能撑住,再考虑换量化加paged attention。
Flash attention得配着paged attention一起看,vLLM本身就有这个,你确认下是不是没开对参数。多卡张量并行其实没那么玄乎,把模型切到两张A100上,world_size设成2就行,但要注意通信开销。小流量想先顶着的话,可以试试把max_num_seqs调小,或者干脆限制并发数,牺牲点吞吐换稳定。另外GPTQ 4bit在13B上掉点挺明显的,建议看看AWQ,同量化下更稳一点。
显存不够先上flash attention,能省不少,张量并行等流量真大了再弄也不迟。
vLLM本身支持paged attention,你确认下是不是把它关了,这个对显存碎片化帮助挺大的。另外建议先别急着上多卡,试试把concurrent_requests调低点,配合连续批处理,小流量场景下能顶不少。GPTQ到4bit如果还爆,检查下是不是没用上KV cache量化,vLLM里有这个选项。
试试把max-num-seqs调小,再开个prefix-caching,小流量能顶住,大并发还是得上多卡。
vLLM本身已经默认带flash attention了,所以这步基本不用额外折腾,真正吃显存的大头其实是kv cache和激活值。你GPTQ量化到4bit后显存还跑满,大概率是max_num_seqs和gpu_memory_utilization这两个参数没调好,vLLM默认会预留很多显存给cache,建议把gpu_memory_utilization调到0.9以上,同时把max_num_seqs压到32甚至16试试,小流量下能明显缓解。另外你提到张量并行,单卡80G跑13B其实没必要上多卡,除非你要同时处理超长上下文或者并发超过50,不然通信开销反而拖慢速度。如果只是临时顶一下,可以把模型输入长度限制在2048以内,再开continuous batching,vLLM对短请求的并发优化很激进,实测能扛住不少。还有个冷门trick,把模型fp16的权重转成bf16,有些卡上能省一点显存,但作用有限。最后建议你直接看下vLLM的官方文档,里面有显存计算器,算一下你当前配置的理论峰值,比瞎试参数靠谱。