最近在把我们微调过的Qwen2.5-7B部署到内网服务器上,用vLLM跑的,开了gptq量化。理论上7B模型int4量化后显存占用应该在5-6G左右,但实际部署后nvidia-smi一看,单卡A10直接吃了14G,吞吐也只有200 tokens/s不到。我已经设置了max_model_len=4096,也开了continuous batching,但感觉没起到什么作用。怀疑是不是上下文预填充阶段太吃显存,还是量化版本选错了?求有经验的大佬指点一下,或者有没有什么工具能定位显存到底被什么占住了?提前感谢。
部署7B大模型到生产环境,显存占用比预想高很多怎么办?
全部回复
共 90 条说实话你这个数字我一看就觉得不太对劲,A10是24G显存吧,14G占用对于int4的7B来说确实虚高太多了。我之前跑过类似的模型,同样用vLLM,开gptq后大概也就6-7G左右,所以你怀疑预填充阶段吃显存是有道理的——context长度4096下,KV cache的峰值往往被低估了,尤其是并发请求多的时候,vLLM默认会预分配一部分显存给KV cache,这个在启动日志里能看到具体预留值。
另一个可能就是量化版本没选对,gptq的group size和desc_act设置会直接影响显存占用,如果用的是老版本或者没校准好的权重,实际跑起来反而会比fp16还吃显存。你可以先用transformers直接加载模型跑个简单推理,对比一下峰值显存,排除vLLM的调度开销。
至于定位工具,我建议你开一下vLLM的--gpu-memory-utilization参数,手动限制到0.7左右,然后观察nvidia-smi的波动,再配合nsys或者py-spy看下算子级别显存分配,基本能看出是embedding表、attention还是ffn占了大头。不过我更好奇的是你吞吐量怎么这么低,200 tokens/s对于7B int4来说有点离谱,哪怕A10算力弱也不至于,你检查过是不是并发数设太低或者request调度没生效?
我之前也踩过类似的坑,7B int4理论值和实际差很多很正常,vLLM的KV cache加上预填充峰值会吃掉一大块,而且A10的显存带宽跑7B也就这水平了,200 tokens/s不算离谱。你可以先看看vLLM的日志里有没有提示KV cache分配了多少,或者用nvidia-smi盯一下推理过程中的显存曲线,大概率是prefill阶段撑起来的。另外确认下GPTQ的group size是不是128,有些量化版本反而会变慢变占显存,换AWQ或者把max_model_len降到2048试试,吞吐可能反而上来。
用nvidia-smi看显存不准,vllm会预分配缓存,试试vllm serve --gpu-memory-utilization 0.9看日志里kv cache占了多大。
vLLM的显存占用大头其实在KV cache和预填充的临时激活值,int4只压缩了权重,这两块还是按fp16算的。你max_model_len设4096的话,7B模型KV cache大概就要吃掉2-3G,加上CUDA context和碎片,14G挺正常的。建议先用vllm的--gpu-memory-utilization调低到0.8看看,或者开--enable-prefix-caching试试,预填充阶段的显存峰值会明显降下来。另外200 tokens/s对A10来说其实不算慢,你对比下同配置下fp16的吞吐,如果差距不大那就是量化没吃满算力。
同款问题踩过坑,你这14G其实大概率不是模型权重吃的,vLLM的KV cache和预填充阶段的临时张量才是大头。A10只有24G显存,max_model_len设4096但实际并发请求一多,KV cache会按最大可能序列长度预分配,你试试把--max-num-seqs调低到4或者8,同时开--enable-prefix-caching,能省不少。另外GPTQ量化版本确实有坑,7B的int4理论4G左右,但vLLM对GPTQ支持比较激进,反量化算子会额外占显存,建议换AWQ试试,同样4bit但内存占用更稳。定位显存可以用vllm的--print-exception-info加nvidia-smi的--query-gpu=memory.used,memory.total配合--loop看时间曲线,或者直接跑个profiling工具,比如torch.profiler,能看出是哪个算子爆的。200 tokens/s对A10来说偏低,但连续批处理没生效的话很可能是你max_num_batched_tokens没调,默认256,调成2048试试,吞吐能翻倍。最后怀疑一下是不是微调后的模型层数或者注意力头配置变了,导致量化后实际参数没对齐,这个用vllm的--quantization gptq --model-id加载时检查下日志里的shape信息。
你这情况我遇到过类似的,7B量化后理论显存和实际占用差距大很正常,vLLM的KV cache和CUDA context开销很吃显存,尤其max_model_len设4096时KV cache会预分配一大块。建议先用vllm的--gpu-memory-utilization参数限制显存使用率,再配合nvidia-smi看下具体分块,另外检查下gptq版本是不是和vLLM兼容,我之前换过awq后占用直接降了3G。
你这个数字不太对劲,7B int4跑4096上下文按说峰值也就8-9G,14G明显是权重没真正加载成4bit。建议先确认下GPTQ的group_size和vLLM的quantization参数是不是匹配,另外A10跑7B吞吐200也不该这么低,看看是不是没走对Tensor Parallel或者CPU offload了。想定位显存的话,可以开vLLM的--enable-chunked-prefill再配合nvidia-smi看峰值,或者用pytorch的memory profiler抓一下,不过我猜大概率是预填充阶段KV cache涨得太猛,试试把max_num_seqs调小点。
vLLM的KV cache默认会吃满剩余显存,你试试限制下gpu_memory_utilization,或者用nvidia-smi看下是不是预填充峰值。
14G有点离谱了,先看下是不是vLLM默认把KV cache吃满了,调低gpu_memory_utilization试试。
你试试用vllm --print-memory-profile看下KV cache和activation占了多少,我之前遇到过类似情况,其实是预分配显存里有一大块是给paged attention的buffer了。另外7B的GPTQ权重本身没这么夸张,但A10上跑fp16的KV cache加临时张量很容易吃满,建议把gpu_memory_utilization调到0.85以下,再对比下不量化时的峰值。还有你那个吞吐200可能受限于max_model_len,可以试试把preemption mode改成recompute看看。
说实话你这情况我太熟了,之前部署13B的时候也踩过一模一样的坑。先别急着怀疑量化文件,vLLM默认会为每个序列预留完整的KV cache空间,哪怕你max_model_len设了4096,但并发序列多起来,显存是按峰值预留的,不是实际使用量动态分配的。A10只有24G,你单卡吃14G其实有很大一部分是KV cache和中间激活值在作怪,这不单纯是模型权重的问题。
你可以先用vllm的--gpu-memory-utilization参数把显存利用率压到0.85左右,然后配合--max-num-seqs调小并发数,比如设为8或16,看看显存会不会降下来。另外,gptq量化对7B模型来说,权重确实能压到4bit,但Qwen2.5的架构里attention部分有些算子未必完全走量化,这部分还是会以fp16跑,占的显存比你想的多。
想定位具体是啥在吃显存,可以开vLLM的--log-stats参数,它会在日志里打印KV cache的分配情况和显存峰值分布,比nvidia-smi直观得多。还有个笨办法,你把max_model_len降到1024试跑一下,如果显存瞬间掉到7-8G,那基本就确认是KV cache的问题了。
至于吞吐200 tokens/s,说实话对这个模型和单卡组合不算离谱,但如果你开的是离线批量推理,建议把--enable-prefix-caching打开,尤其是微调过的模型,重复提示词多的时候能明显提速。最后提醒一句,检查一下你用的gptq版本是不是适配vLLM当前版本,版本不匹配会导致量化权重没有被正确加载,显存直接按fp16算,那就真是白忙活了。
我之前也踩过类似的坑,vLLM默认会把KV cache预分配很大,你max_model_len设了4096但实际显存里可能还留了冗余,建议查下gpu_memory_utilization参数,默认是0.9,A10 24G的话确实会一下吃掉20G左右。另外GPTQ的int4实际显存占用比理论值高很正常,因为中间激活值和临时张量也会占用,尤其预填充阶段峰值很高。你可以用vllm的--profile或者直接开NVIDIA的nsight看看具体哪块占的,我之前发现是paged attention的block数没调,改成手动设置--kv-cache-dtype和--block-size之后好很多。吞吐200不到有点低了,检查下是不是没开--enable-prefix-caching,还有微调后的模型如果加了Lora adapter也会额外吃显存。
vLLM的显存占用本来就不是单纯看模型权重的,KV cache和activation才是大头,尤其你把max_model_len设成4096,A10上每个序列的KV cache能占到接近1G,并发一多直接爆。你可以先用vllm的--gpu-memory-utilization参数把显存利用率压到0.85左右,再配合--max-num-seqs限制并发数,看看能不能降下来。另外gptq量化在vLLM里对7B模型提升其实有限,不如直接上AWQ或者GPTQ-Marlin,推理速度能快不少。吞吐200 tokens/s对于7B int4来说确实偏低,怀疑你用的量化版本没有走vLLM的优化内核,去检查下是不是装了老版本的auto-gptq依赖。定位显存占用的话,可以开vLLM的--log-stats参数,它会打印KV cache和模型权重的详细分配,或者用nvidia-smi dmon实时看显存波动。我之前也遇到过类似情况,最后发现是prefill阶段中间激活没释放干净,把--enforce-eager打开能缓解一些。
建议先用vllm的--gpu-memory-utilization和--max-num-seqs调一下,A10跑7B int4按理说不会爆这么多,检查下是不是实际加载的还是fp16权重,gptq的量化权重有时会被vllm忽略掉。另外nvidia-smi显示的进程显存包含了CUDA context和KV cache的预分配,可以用vllm serve --kv-cache-dtype fp8试试,或者开--enable-chunked-prefill看能不能压下来。我上次也遇到过类似问题,最后发现是模型配置里rope_scaling没生效导致预填充异常吃显存。
我之前也踩过类似的坑,vLLM的显存大头其实在KV cache和预填充的临时激活值上,你max_model_len=4096配合batch size稍大一点,这部分很容易飙到8G以上,gptq省下的权重内存全被吃回去了。建议先关掉continuous batching,把gpu_memory_utilization调低到0.7试试,再观察一下nvidia-smi里是哪个进程的显存在涨。另外可以开下vLLM的--log-stats参数,它会打印KV cache和预填充的详细分配情况,比瞎猜靠谱多了。顺便问下,你用的是AutoGPTQ还是GPTQModel的量化版本?不同库的kernel对显存优化差别挺大的。
说个可能的原因,你看到的14G大概率是峰值显存,vLLM在预填充阶段会把整段prompt的KV cache都塞进去,4096长度加上7B的注意力头数,这部分开销很容易被低估。建议先用vllm的--gpu-memory-utilization参数把显存上限调低到0.7试试,另外确认下GPTQ的group size是不是128,如果用了更小粒度量化,显存会明显膨胀。我之前遇到过类似情况,最后是换成了AWQ才把占用压下来,吞吐也稳了。你可以先跑个不带量化的原始模型对比下baseline,再逐步排查是不是某个组件吃掉了多余显存。
你贴的这个数字我太熟了,之前跑7B int4也翻过车。vLLM的KV cache默认会预分配不少,加上continuous batching开起来后显存是动态疯涨的,建议先用vllm-cli或者--gpu-memory-utilization把上限卡到0.85试试,再查下是不是gptq的group size没用对。另外你那个200 tokens/s如果是单并发下的预填充速度,那其实还算正常,想定位具体占用可以用nvidia-smi dmon看每块内存的分配过程,或者直接抓vLLM的日志看KV cache给配了多少。
vLLM的显存占用大头其实在KV cache和预填充的中间激活,int4只压缩了权重,这两块还是按原始精度算的。你max_model_len设4096的话,7B模型KV cache大概就要吃2-3G,再加上CUDA context和碎片,14G挺正常的。建议先用vllm的--gpu-memory-utilization调低到0.7试试,再配合--max-num-seqs限制并发数。真想看显存分布就开VLLM_LOG_LEVEL=DEBUG,或者用nsys抓一下kernel,能明显看到预填充阶段峰值。
另外200 tokens/s对于A10来说偏低了,检查下是不是gptq的group_size设太小,或者--quantization参数没对齐,有时候模型文件是awq但你用了gptq的配置也会这样。我之前遇到过类似情况,换回fp16跑反而吞吐更高,量化省下的显存全被缓存吃回去了。
我之前也踩过这坑,vLLM的显存大头其实在KV cache和预分配池上,单看模型权重会严重低估。你可以先看一眼vllm serve启动日志里KV cache预留了多少G,用--gpu-memory-utilization调低到0.7试试,顺便把--max-num-seqs限制到32左右,通常能压下来不少。另外确认下GPTQ是真正生效了,有时候HuggingFace权重没对应量化配置,vLLM会静默回退到FP16,14G这个数字更像是没量化的状态。实在不行就用nvidia-smi dmon -d 1盯着显存变化曲线,看是峰值在预填充还是生成阶段。
这问题我太熟了,之前部署13B的时候也踩过一模一样的坑。你看到nvidia-smi显示14G其实不全是模型权重,vLLM默认会给每个请求预留很大的KV cache空间,加上预填充阶段会把整段prompt一次性算完,显存峰值直接就飙上去了。我建议你先用vllm的--gpu-memory-utilization参数把显存利用率调到0.85左右,再开--enable-prefix-caching,这样至少能压掉几个G。另外确认一下你用的gptq是不是真正跑在4bit上,有时候量化配置没生效,实际还是bf16在跑,那14G就说得通了。我之前用过一个叫vllm-smi的脚本,能打印出每个tensor的显存占用,比看nvidia-smi直观多了,你可以去GitHub翻翻。吞吐200 tokens/s对7B来说确实偏低,如果max_model_len只是4K,但并发请求多,continuous batching没完全生效的话,可以试试把--max-num-seqs调大一点,比如32或者64,让vLLM有更多机会做batch。还有个小细节,A10的显存带宽就那样,别太指望量化能带来吞吐翻倍,它主要是省显存,速度提升有限。你可以先把预填充和decode阶段分开测一下,看看瓶颈到底在哪,这个用vLLM的--print-trace能看出来。