最近在试着把一个7B的模型(Qwen2.5-7B)部署到公司内网服务器上,显卡是A100 40G,按理说显存绰绰有余。但实际推理时,单个请求要等好几秒才出结果,吞吐量也上不去。我试了vLLM和TGI,感觉速度提升有限,是不是我哪里没配置对?比如batch size、max tokens这些参数,或者是不是要量化一下?另外,生产环境里并发请求一多,内存占用就飙高,有没有什么成熟的工程实践?求大佬们指点一下,新手部署踩坑中……
部署7B大模型到生产环境,显存够用但推理很慢,怎么优化?
全部回复
共 162 条说实话A100 40G跑7B这个规模,瓶颈基本不在显存,vLLM和TGI都试过提升有限的话,我猜大概率是卡在prefill阶段或者并发调度上。你试试把max tokens设低一点,比如512或者256,很多时候生成长度设太大,显存预留和预分配会拖慢整体节奏。另外量化建议直接上AWQ或者GPTQ,4bit精度对7B来说损失很小,但吞吐能翻倍,特别是batch size开大的时候,显存带宽反而成了主要瓶颈。
并发一多内存飙高,这个我遇到过,得看是不是开了太多的独立CUDA context,或者每个请求都重新加载模型权重。你可以用vLLM的continuous batching,把请求动态拼batch,别让每个请求单独走完整pipeline。还有个小坑,检查一下你的GPU利用率,如果经常是20%-30%,那多半是CPU在忙着做tokenizer或者数据预处理,把预处理挪到单独的worker线程里,能明显改善。
另外你提到TGI,我建议看看它的--max-input-tokens和--max-total-tokens是不是默认开太大了,这俩参数直接影响显存分配策略。我自己的经验是,先压到模型实际需要的长度,再逐步调batch size,找到那个“GPU刚好跑满但显存不炸”的点。最后,如果生产环境允许,试试FP8或者INT8的KV cache,能省不少显存,给更大batch腾空间。
A100 40G跑7B其实算力瓶颈更可能卡在显存带宽和算子调度上,vLLM和TGI默认配置通常偏保守,你得手动调一下gpu-memory-utilization到0.9以上,然后max-num-seqs(batch size)从默认值往上拉到32甚至64试试,吞吐会有明显变化。我之前遇到过类似情况,最后发现是max-model-len设太大导致KV cache预留过多,实际请求根本用不满,把max-model-len从32K砍到8K后延迟直接降了一半,显存占用也稳了。量化的话,AWQ或GPTQ的4bit对Qwen2.5效果挺稳的,精度损失可接受,但如果你追求极致吞吐建议试下FP8,A100对FP8的支持比V100好很多。并发内存飙高有个坑是vLLM默认会缓存所有请求的KV,如果你把max-num-seqs调大了,内存自然会涨,最好用continuous batching配合PagedAttention的显存池上限做限制,或者直接开--enable-chunked-prefill拆分长前缀。还有个野路子,如果业务允许,把输入输出长度都限制到512以内,同时用torch.compile或TensorRT-LLM重编译一下模型,速度能再快20%左右,就是部署麻烦点。你检查下是不是用了HuggingFace的默认tokenizer,那个在并发下也有锁竞争,换成vLLM自带的tokenizer能减小开销。最后问下你用的vLLM版本是0.6.x还是0.7+?新版对Qwen的attention优化差别还挺大的,老版本确实容易慢。
量化到int8或int4试试,吞吐能翻倍,另外vLLM记得开continuous batching,别用默认参数。
你试试把max model len调低点,Qwen2.5-7B默认的sequence长度很吃显存带宽,我上次也是没设max_num_seqs直接慢到怀疑人生,调成128后吞吐直接翻倍。量化的话int8对速度帮助不大,但能省内存,建议先搞懂你的瓶颈是显存带宽还是计算。对了,并发高内存飙是正常的,配个paged attention的vLLM版本会好很多,别用TGI了。
A100 40G跑7B其实没必要上量化,fp16直接vLLM就行,关键看你是不是把max_num_seqs和max_model_len调小了,这俩对吞吐影响特别大。我之前也是卡到怀疑人生,后来把max_num_seqs调到64,max_model_len设成2048,速度直接翻倍。并发高内存飙的话,试试vLLM的continuous batching,再配合--gpu-memory-utilization参数留点显存给KV cache,别让它全占满。另外你单请求慢是不是没开streaming?首token延迟和总延迟是两码事,生产环境一般得配合prefill/decode的调度策略看。
量化到4bit试试,吞吐能翻倍,但记得用awq别用gptq,质量掉得少。
A100 40G跑7B其实挺宽裕的,瓶颈大概率不在显存而是吞吐配置。你试试把vLLM的max-num-seqs调大到32或64,同时把--gpu-memory-utilization设到0.9,让显存尽可能多留给KV cache,这样并发上来时调度效率会明显改善。量化的话,AWQ或GPTQ对速度提升有限,但能省显存换更长上下文,如果业务对延迟敏感不如先上FP8。内存飙高可能是prefill阶段峰值,建议开continuous batching,再把max-model-len限制到实际需要的长度,别给默认值。另外可以看下是不是模型加载时没走safetensors的mmap,导致重复拷贝内存。
A100 40G跑7B其实有点浪费,但慢的话大概率不是显存问题,而是吞吐和延迟的权衡没调好。你试试把max tokens设小点,比如512或1024,同时把batch size拉高到16或32,vLLM的continuous batching吃这个。量化的话,AWQ或GPTQ能快个20%-30%,但质量损失得自己测,内网用应该能接受。内存飙高可能是prefill阶段峰值,建议开一下vLLM的chunked prefill,能压不少。另外,检查下是不是CPU负载或磁盘IO瓶颈,有时候数据加载比推理还慢。
试试把max_tokens调小点再开个动态batching,A100跑7B量化到int8应该能快不少。
A100 40G跑7B其实算力瓶颈更多在显存带宽和计算密度上,量化到INT8或者AWQ通常能带来2-3倍收益,可以先试试GPTQ版。另外vLLM的continuous batching一定要开,max tokens别设太大,不然prefill阶段会卡住后续请求。并发内存飙高大概率是KV cache没限制,设个--max-num-seqs 16或者256的缓存上限会稳很多。你用的是FP16还是BF16?有时候精度格式对速度影响也蛮大的。
建议先试试GPTQ或者AWQ量化到4bit,吞吐能翻倍,另外把max tokens调小点试试,别让显存白白浪费。
A100 40G跑7B绰绰有余,建议优先开vLLM的continuous batching,再配合AWQ量化,延迟能砍半。
A100 40G跑7B其实算力瓶颈比显存更明显,你试vLLM和TGI觉得提升有限,大概率是没把continuous batching开到位,或者max_num_seqs设太小了。我建议你先把并发数拉上去,比如同时塞20-30个请求,再看吞吐量变化,很多时候单请求延迟高是prefill阶段卡住了。量化的话,AWQ或GPTQ对Qwen2.5效果不错,4bit下显存占用能砍一半还多,但注意量化后max tokens别设太长,否则长上下文时精度损失会被放大。另外你提到内存飙高,我猜是KVCache没做swap或者没限制显存利用率的阈值,vLLM里可以设gpu_memory_utilization到0.85,给预留一点余量。还有个细节,如果你们是内网部署,检查下是不是CPU在做tokenizer或者post-processing,这块很容易被忽略,把那些操作挪到GPU或者并行处理会快不少。最后,如果并发实在高,可以试试把模型切成两半用张量并行,虽然A100单卡够,但双卡能明显降低单请求延迟,前提是你有第二张卡。
A100 40G跑7B确实不该这么慢,先别急着上量化,我怀疑你命中的瓶颈根本不在显存,而在batch size和并发策略上。vLLM的continuous batching你得手动调大max_num_seqs,默认值往往保守,试试从256起步往上加,同时把max_tokens设成你业务实际需要的上限,别给个2048这种虚高的值,因为KV cache会按最大长度预留,直接拖慢每token生成速度。另外你提到并发一高内存就爆,这很可能是因为你用了默认的preemption模式,换成swap或者干脆把gpu_memory_utilization开到0.95试试,让vLLM更激进地占用显存来缓存。如果还是慢,建议看看是不是输入prompt太长,7B模型对长上下文的prefill计算量很吃性能,可以考虑用prompt cache或者把历史对话截断。量化的话,AWQ或GPTQ在A100上收益主要是带宽,但如果你卡在prefill阶段,量化帮助不大,不如先检查一下是不是CPU在跑tokenizer或者数据预处理,把这块挪到GPU上。最后,如果并发真的很高,考虑上Ray Serve或者NVIDIA Triton做多副本调度,单实例扛并发很容易瓶颈在GPU利用率上,而不是显存。
说实话你这个问题我上个月刚踩过一遍,A100 40G跑7B确实显存宽裕,但瓶颈压根不在显存上,而在prefill阶段和batch策略。vLLM和TGI提升有限很可能是因为你默认配置下并发度没打满,试试把max_num_seqs调到64以上,同时限制max_model_len到2048或4096,别让长序列把prefill的计算量拖死,不然单个请求看着慢,实际是等待排队。量化的话建议先别上INT4,AWQ或者GPTQ对7B效果还行,但你要是追求吞吐,FP16加continuous batching反而更稳,量化有时候会让小batch下的延迟更糟。内存飙高那个大概率是KVCache没限制,vLLM里gpu_memory_utilization设到0.85,然后留点CPU offload给极端情况,别让它全吃显存。另外你试过把请求拆成流式输出吗?首token延迟能压到300毫秒以内的话,体感会好很多,用户感知的是TTFT不是总时长。还有个坑是模型加载时用torch.compile或者flash attention,A100上能再快个20%,但记得要跑几轮warmup再上线。最后问一下,你那边请求的平均输入长度大概多少?如果都是长文档问答,那瓶颈可能在prefill,可以试试split推理或者换一下调度策略,我这边调完这些参数后吞吐翻了将近三倍。
A100 40G跑7B其实余量很大,问题大概率不在显存而在服务化配置和模型加载方式上。你试了vLLM和TGI但提升有限,我猜是不是没开continuous batching,或者max_num_seqs设太小了,这个参数直接决定并发吞吐的峰值,建议先调到64以上看看。另外Qwen2.5-7B的attention实现挺吃显存带宽的,量化到INT8或者AWQ能让单token延迟砍半,但要注意如果你用vLLM,量化后要重新测一下prefill长度,别让长输入把延迟又拉回去。内存飙升那个事儿,八成是因为你给每个请求预分配了KV cache,但没限制max_total_tokens或者max_model_len,导致空闲连接也占着池子,建议开vLLM的prefix caching,同时把gpu_memory_utilization设到0.9以下,留点余量给碎片。还有一个坑是别用默认的调度策略,试试vLLM的抢占式调度,长请求和短请求混跑时能明显改善尾延迟。我这边之前用TGI遇到过类似问题,后来发现是它的tokenizer并行没开,需要设num_tokenizer_instances,不然多并发时CPU那边直接瓶颈。最后如果还是慢,可以看看是不是CPU offload了部分算子,用nvidia-smi看GPU利用率,如果没打满八成是数据预处理或者Python GIL拖后腿了。
A100 40G跑7B其实余量很大,问题多半出在vLLM的配置上,比如max_num_seqs和max_model_len没调好,默认值有时候会卡住吞吐。你可以试试把max_model_len设成2048或4096,然后开continuous batching,看看并发下的延迟曲线有没有改善。量化的话,AWQ或GPTQ对Qwen2.5效果挺稳的,显存占用降下来还能塞更大batch,但注意别让精度损失影响业务。内存飙高这个,大概率是KV cache没限制,vLLM里设个gpu_memory_utilization比如0.9,再配个swap空间,能缓解不少。我自己踩坑时发现,别一上来就追最新版,先锁个稳定版本跑通再调参,不然问题混在一起更难排查。
A100 40G跑7B其实瓶颈不在显存,大概率卡在显存带宽和计算调度上。我之前遇到过类似情况,后来发现是max tokens设得太高,默认生成长度会直接影响显存占用和批处理效率,你试试把max tokens压到实际业务需要的长度,比如512或1024,吞吐能明显上来。另外vLLM的话,连续批处理(continuous batching)要确认真的开启了,有时候版本默认配置没生效,得在启动参数里显式指定。量化的话,AWQ或者GPTQ对7B来说性价比很高,INT4下显存占用减半,速度能快个30%左右,但精度损失得自己评估下,如果业务对输出质量敏感,可以先跑个评测集对比。并发内存飙高这个,多半是KV cache没限制,vLLM里有个gpu_memory_utilization参数,别拉到0.9以上,留点余量给调度和碎片,同时可以开enable_prefix_caching,重复前缀的请求能省不少内存。还有个容易被忽略的点,你检查下是不是用了Eager模式而不是FlashAttention,A100上FlashAttention能快很多,编译一次之后就不用管了。最后如果还是慢,试试把模型拆分到多卡(虽然40G单卡够),或者用Tensor Parallelism,但单卡场景下意义不大,不如看看是不是CPU负载或磁盘IO拖了后腿,比如tokenizer加载或者权重首次读取没缓存。
A100 40G跑7B其实算力瓶颈大于显存瓶颈,你试试把max tokens调低一点,有时候默认配置会留太多prefill余量。vLLM的话记得开continuous batching,还有paged attention的block大小要调,默认值不一定适合你的请求长度分布。量化的话可以先上INT8,AWQ或者GPTQ都行,FP16其实浪费了A100的算力。并发内存飙高大概率是KV cache没限制住,vLLM里设个--max-num-seqs或者gpu_memory_utilization别拉满,留点余量给碎片。另外你测速度是单请求延迟还是吞吐?如果追求并发吞吐,把batch size往上顶,但别超过模型的最大序列长度。还有个容易忽略的点,检查下是不是CPU解码瓶颈,比如tokenizer或者采样那部分没走GPU。我之前遇到过类似问题,最后发现是请求里带了超长的system prompt,每轮都重新算prefill,把这部分缓存起来直接快了3倍。你那边请求上下文有什么规律吗?可以按长度分桶处理,效果会比统一配置好很多。
A100 40G跑7B确实不该这么慢,建议先确认下是不是没开continuous batching,vLLM默认是开的但TGI要手动配。另外max_num_seqs和gpu_memory_utilization这两个参数调一下试试,吞吐差挺多的。量化的话可以上AWQ或GPTQ,7B量化后显存占用能降不少,延迟也会好一些。并发高内存飙可能是KV cache没限制好,看看max_model_len是不是设太大了。