最近在用vLLM部署一个13B的模型到公司服务器上,单卡A100 80G跑起来倒是还行,但并发一上来就显存溢出,报OOM错误。我试了GPTQ量化到4bit,精度有点下降但还能忍,结果显存占用还是跑满。问了同事,有人推荐用Flash Attention,有人建议上多卡张量并行,但我搞不清楚这些方案到底怎么落地。有没有大佬分享一下实际部署中压显存的成熟套路?或者有没有什么简单的trick能先顶住小流量?感谢!
部署开源大模型到生产环境,显存总不够用怎么办?
全部回复
共 161 条vLLM的PagedAttention本身已经帮你省了不少显存,但OOM大概率是prefill阶段和decode阶段峰值撞一起了。我建议先别急着上多卡,试试把max-num-seqs调小,比如从256降到64,同时把gpu-memory-utilization设成0.9,这俩参数改完可能立刻就不炸了。Flash Attention确实能降显存,但它主要省的是注意力计算那块,对KV cache的占用帮助有限,你13B模型如果上下文长度开得大,那才是显存大头。GPTQ 4bit之后还跑满,我猜是你并发时每个请求的max_model_len没限制,实际跑的长度远超你预设值,导致KV cache暴涨,可以试着用--max-model-len强制截断到2048或4096试试。另外如果公司有闲置的3090或4090,张量并行其实没想象中复杂,vLLM里直接加--tensor-parallel-size 2就行,但注意要保证卡间带宽是NVLink,否则通信开销可能比省下的显存更亏。还有个野路子,把模型切一半放CPU,用--cpu-offload-gb指定个10G,虽然推理会慢些,但至少能先顶住小流量不崩。最后建议你开个--enable-prefix-caching,如果大家问的问题有公共前缀,能省不少重复计算,这个功能实测对聊天场景挺管用的。
说实话你现在的瓶颈大概率不在量化上,GPTQ 4bit之后显存还跑满,我猜是KV cache在作祟。vLLM默认会预分配KV cache的显存池,并发一上来直接吃满,你可以试试设--gpu-memory-utilization 0.85或者更低,留点余量给驱动和调度。Flash Attention确实能省显存,但它主要省的是中间激活值,对长序列效果明显,你这个场景可能帮助有限,但值得加上,反正vLLM几行配置就能开。真正想压并发峰值,我觉得张量并行是正解,两张A100用TP=2跑13B,每卡显存压力能砍掉一半多,而且vLLM对TP支持很成熟,唯一要注意的是通信开销,建议上NVLink互联的机器,否则性能可能不升反降。如果你只是先顶住小流量,还有个土办法,把max-num-seqs调小,比如设成8或者16,同时限制max-model-len到2048,这样每个请求的显存占用会小很多,虽然并发吞吐会降,但至少不OOM。另外你提到精度下降能忍,那可以再看看AWQ,比GPTQ在低bit下通常更稳,显存占用差不多,但生成质量会好一点。最后别忘了监控一下碎片化问题,vLLM有--enable-prefix-caching,对重复prompt场景能省不少显存,我遇到过开了这个之后OOM频率明显降低。
vLLM本身已经集成了Flash Attention,你只要确认下版本和启动参数里有没有开对就行,它主要省的是KV Cache那部分显存,对并发提升很明显。多卡张量并行不是单纯压显存,是摊到多张卡上,但你的场景是单卡不够用,不如先试试把max-model-len调小点,比如限制到2048,很多OOM其实是生成长度撑爆的。另外4bit GPTQ配vLLM有个坑,就是量化后的权重会重新反量化到FP16计算,显存省了但峰值没降多少,可以试试AWQ或者把--gpu-memory-utilization设成0.9,留点buffer给调度器。小流量应急的话,最简单的trick是开--enable-prefix-caching,重复问题前缀能共享KV,实测能顶住不少并发。
Flash Attention确实该上,主要是把attention的中间态省掉了,效果等同于白捡显存,但解决不了根本问题。你这种情况我建议直接上张量并行,两张A100哪怕用TP2也能把单卡压力砍半,vLLM里设个tensor-parallel-size=2就行,基本无损。小流量临时顶着的话,把max-num-seqs调小,比如8或4,再把gpu-memory-utilization设到0.9,能扛一阵子。另外GPTQ你试了但显存还是满,检查下是不是没开--quantization gptq,或者加载时没带量化参数,有时候是vLLM版本兼容问题导致回落到fp16了。
vLLM本身已经集成了Flash Attention,你如果用的是最新版本其实默认就开着,这个主要是优化attention计算的显存占用和速度,对长序列场景收益明显,但OOM问题可能不完全是它的锅。我建议你先用vLLM的metrics看下实际KV cache占用和请求排队情况,很多时候OOM是因为max_num_seqs或者max_model_len设置得太激进了,调小这两个参数能立刻缓解。至于多卡张量并行,13B模型用两卡A100其实很划算,但注意张量并行会引入通信开销,并发不高的时候可能还更慢,你可以用tensor_parallel_size=2先试试,同时把gpu_memory_utilization从默认的0.9降到0.85左右,给碎片留点余地。另外Q4 GPTQ在13B上精度损失其实可控,但你要是跑的是代码生成或者数学推理,建议换AWQ,实际表现更稳。还有个土办法比较适合顶小流量,就是开vLLM的continuous batching配合手动限制并发数,比如max_num_seqs=8,宁可排队也别让显存爆,用户体验反而更平滑。最后检查下是不是有显存碎片,PyTorch 2.1以上版本用expandable_segments这个环境变量,有时候能多挤出几个G。
看到你这个情况,我第一反应是咱俩踩过同一个坑。A100 80G看着不小,但vLLM在并发上来后,KV cache的膨胀速度是真的吓人,尤其13B这级别,OOM太正常了。你试了GPTQ但显存还是跑满,我猜大概率是max_num_seqs或者max_model_len没配合调低,这两个参数比量化本身更管用,你先试试把max_model_len砍到2048,并发限制在8以内,小流量能立刻稳住。
Flash Attention确实该上,但指望它单方面压显存不太现实,它主要省的是计算和内存带宽,对峰值显存帮助有限,反而是PagedAttention(vLLM自带)的KV cache管理更值得调,比如调大gpu_memory_utilization到0.9,给预留留点余量。多卡张量并行是正经出路,但13B用2卡A100就够了,注意拆层时负载均衡,另外记得开--tensor-parallel-size 2,然后每卡显存占用会降一半左右。
不过我更想问一句,你精度下降能忍到什么程度?如果业务不太敏感,试试AWQ或GPTQ的2bit量化,配合KV cache量化(vLLM支持--kv-cache-dtype fp8),这组合拳能把显存再压下来一截,虽然推理速度会慢点。还有个野路子,把输入序列长度上限卡死,超长请求直接报错或截断,生产环境宁缺毋滥,别让单个长文本把显存全吃了。
之前跑7B也踩过这坑,vLLM的gpu_memory_utilization参数可以先调到0.9试试,给KV cache留点余量,小流量能稳住。Flash Attention确实能省不少显存,主要是把注意力计算重排了,vLLM里直接开就行,代码改动很小。多卡张量并行的话,得注意把模型切分好,A100 80G两张卡跑13B其实挺宽裕,但通信开销要看你的nvlink带宽,别并行后反而变慢。还有个土办法,把max_num_seqs调小点,比如16或者32,牺牲点吞吐换稳定性,先撑过上线再说。
Flash Attention确实得先安排上,它主要省的是KV cache那块的显存,13B模型并发高的时候收益特别明显,基本是零成本改动。张量并行的话得看你们服务器有没有多卡互联,NVLink带宽够的话可以上TP=2,但要注意把vLLM的tensor_parallel_size参数配上,不然光改模型并行数没用。另外你GPTQ已经4bit了还爆,可以查下是不是max_num_seqs和gpu_memory_utilization没调,这俩参数对显存占用影响特别大,把利用率从0.9降到0.7能腾出不少缓冲空间。小流量想先顶着的话,可以试试把concurrent_requests_limit调到16以下,再配合continuous batching,基本能撑住。
Flash Attention先安排上吧,能把KV cache的显存占用砍掉一大截,配合vLLM的PagedAttention其实对并发场景特别友好。另外张量并行不是银弹,13B模型上2卡就能明显感觉到通信开销,不如先试试把max_num_seqs和max_model_len调小,限制一下单请求的token长度,小流量阶段能顶不少。GPTQ都4bit了还爆,大概率是推理时KV cache没量化,可以查下有没有开KV cache量化。
vLLM的OOM很多时候是prefill阶段峰值显存炸的,不是单纯量化能解决的。建议先看看是不是max_num_seqs设太大,调到64甚至32能立竿见影,代价是吞吐掉一点。Flash Attention确实能省不少显存,但vLLM里其实已经内置了,你可能没开对版本或者没启用。另外张量并行的话,上2卡就能把每张卡的峰值压一半,但通信开销得实测下,13B模型两卡性价比最高。小流量应急可以试试把swap空间开大点,让部分KV cache落到内存,虽然慢点但至少不崩。
vLLM的PagedAttention其实已经帮你把KV Cache的碎片化问题解决了一部分,但OOM大概率还是因为预留给KV Cache的显存池设得太大,或者max_num_seqs没调好。你可以先试试把gpu_memory_utilization从0.9降到0.7,然后观察一下vLLM的日志里GPU KV Cache usage到底占了多少,如果一直很低但还OOM,那问题可能出在别的地方。
Flash Attention确实能省显存,但它是通过不保存完整注意力矩阵来省,对13B模型来说提升可能没你想象中那么夸张,主要收益还是在长序列场景。真正立竿见影的做法是开多卡张量并行,两张A100跑13B的话,每张卡的显存压力直接减半,而且TP=2的通信开销对13B这种规模来说完全能接受,推理速度反而可能更快。
另外GPTQ 4bit之后显存还是满,我猜可能是你序列长度设得太长了,比如max_model_len设成8192甚至更多,这会把KV Cache直接撑爆。先砍到2048看看,如果业务允许的话,这招比量化还管用。
还有个小trick,如果只是临时顶小流量,可以试试把并发数限制一下,比如给vLLM设置--max-num-seqs 8,同时配合--enable-prefix-caching,重复用户请求的公共前缀能复用KV Cache,能省不少。不过长期来看,建议你还是用量化+张量并行的组合,4bit配合TP=2,13B模型在80G卡上能跑到很宽的余量。
最后想问下,你部署的是对话模型还是RAG场景?如果是RAG,可以尝试把embedding模型单独拆出去,别跟生成模型抢显存。
说实话你这个问题我上个月刚踩过一遍,13B上A100单卡跑vLLM,并发一高就炸太正常了,本质是KV cache在吃显存,不是模型权重占大头。我后来把max_num_seqs调小到32,同时把max_model_len限制到4096,瞬间就稳了,小流量下完全够用,你可以先试试这个,零成本见效最快。
GPTQ 4bit你用了但还爆,我怀疑是vLLM的量化内核没走对,得确认下是不是用的GPTQ_Marlin后端,普通GPTQ在vLLM里显存优化不明显。Flash Attention确实能省不少,尤其长上下文场景,vLLM 0.4以上版本直接自带,你只要保证CUDA版本够新,然后启动参数加个--enable-flash-attn就行,不用改代码。
多卡张量并行如果你有两张卡,其实是最省心的,但注意要开--tensor-parallel-size 2,而且数据并行和流水线并行的显存分摊逻辑不一样,别搞混。另外有个冷门trick,把--gpu-memory-utilization从默认0.9调到0.85,留点余量给碎片,OOM概率会低很多。
还有个思路你可以试试,如果业务能容忍,把输入长度限制在1024以内,KV cache能砍掉一半。最后提醒下,别迷信量化,4bit在13B上精度损失可能比你想的严重,尤其代码生成类任务,建议你跑个评测集对比下再决定。我现在是双卡TP2加4bit,峰值显存只占60%,并发300没问题,你可以参考下这个组合。
vLLM的PagedAttention其实已经帮你省了不少显存,但13B模型在80G上并发一高就OOM,大概率是max-num-seqs和gpu-memory-utilization没调好,这两个参数比什么量化都来得快。我这边之前跑13B是用两张A100做张量并行,单卡负载直接砍半,并发能拉上去三倍不止,但代价是通信开销,如果你们服务器是PCIe互联的话延迟会明显。Flash Attention确实能省显存,但它主要是优化推理时的内存访问模式,对峰值显存帮助有限,不如把注意力放到KV Cache的分配策略上。小流量的话有个土办法,把max-num-seqs压到8以下,同时开--enable-chunked-prefill,能缓解不少,但吞吐会掉。另外GPTQ 4bit精度损失对生成任务影响不大,但如果你用的是AWQ,校准数据集选得好反而比GPTQ更稳。你试试把--kv-cache-dtype改成fp8,Ampere架构虽然不支持但可以开--quantization fp8模拟,能省一点是一点。最后实在不行就上量化+多卡混合,比如两张卡各跑半层,但工程复杂度会上去,建议先调参再动架构。
Flash Attention确实值得先试,它能把注意力矩阵的显存占用从O(n²)降到O(n),配合vLLM的paged attention,并发场景下改善挺明显的。另外你GPTQ都上了还是满,可以看看是不是max-model-len设太大,或者没用--gpu-memory-utilization来动态分配。小流量顶一下的话,临时把max-num-seqs调低点,配合连续批处理也能缓解。多卡张量并行是终极方案,但得注意通信开销,13B模型两张A100其实挺稳的。
其实你这个问题挺典型的,13B在A100上单卡跑推理,显存瓶颈往往不在权重本身,而在KV cache和中间激活值上。GPTQ压到4bit确实能省不少权重空间,但并发一上来,每个请求的KV cache会线性增长,这才是OOM的隐形杀手。我自己的经验是,先别急着上多卡张量并行,那个对通信开销和代码改动要求都高,小流量阶段性价比不高。你可以试试把vLLM的gpu_memory_utilization参数调低一点,比如留出30%的显存给KV cache动态分配,同时把max_num_seqs限制在16以内,这样至少能稳住几十个并发不崩。Flash Attention确实有用,它能大幅减少中间激活的内存占用,而且vLLM本身就集成了,你只要确保用的是最新版本,基本默认就开了,不用额外配置。另外,如果精度还能再让一步,AWQ量化在部分场景下比GPTQ更稳,尤其是配合vLLM的权重复用机制,有时候同样4bit能多撑20%的并发。最后一个小trick,如果是内部工具,可以把prompt长度上限从默认的2048砍到1024,这能直接砍掉一半的KV cache峰值,顶住小流量绰绰有余。等真到了要上几百并发的时候,再考虑张量并行+流水线并行的组合拳,那时候你已经有足够的数据支撑怎么切分了。
多卡张量并行其实没你想的那么复杂,vLLM里直接设tensor-parallel-size=2就行,A100 80G两张卡跑13B绰绰有余。不过你4bit量化后还爆显存,大概率是max-model-len设太高了,先砍到4096试试,一般小流量并发能顶住。Flash Attention主要省的是KV cache的显存,和量化是两码事,建议先开起来再加个--gpu-memory-utilization 0.9,基本能救急。
先试下把max-num-seqs调小,vLLM默认并发缓存吃显存挺狠的,小流量能立刻缓解。
试试把max-num-seqs调小点,再开个continuous batching,小流量能顶住,OOM概率低很多。
多卡张量并行其实不难,vLLM里设个tensor-parallel-size=2就行,显存直接翻倍,精度还无损。
试试把max-num-seqs调小点,配合continuous batching能扛住小流量,OOM基本就没了。
试过把max-num-seqs调小吗?并发高时这个参数影响很大,先压到16看看。