最近在试着用LoRA微调一个7B的对话模型(基座是Qwen2.5),训练阶段用的batch size=1,显存勉强够用(24G)。但微调完合并权重后,用vLLM部署推理,居然比原始模型多吃了快6G显存,而且并发一高就OOM。我确认过合并后的权重没问题,推理时也没加载训练时的优化器状态。查了一圈,有人说可能是KV cache的预分配问题,也有人说是LoRA的adapter没卸载干净。但我用lora_merge_and_unload()合并后明明只保存了合并权重。有没有大佬遇到过类似情况?是LoRA本身就会增加推理时的显存开销,还是我哪里配置错了?求指点,卡在部署这步好几天了。
LoRA微调7B模型后推理显存爆炸,是我的方法不对吗?
全部回复
共 39 条说实话我觉得这事儿大概率不是LoRA本身的锅,7B模型合并后参数量几乎不变,推理显存差异不该这么大。你提到vLLM,我怀疑是它的KV cache预分配策略在作怪,vLLM会根据max_num_seqs和gpu_memory_utilization去预留显存,如果你没显式设置这两个参数,它可能默认把剩余显存全吃进去做cache,导致看起来比原始模型多占很多。我之前用SFT后的模型也遇到过类似情况,后来把gpu_memory_utilization调到0.7,max_num_seqs调小,OOM就缓解了。另外你确认下是不是用了PagedAttention的旧版本,有些版本对合并后模型的KV cache计算有bug,升级到最新版试试。还有个小细节,你保存合并权重时有没有把tokenizer和config也一起覆盖?如果基座配置里残留了LoRA相关的pad_token_id或者attention头数不一致,vLLM可能按错误形状预分配。建议你直接用transformers的from_pretrained加载合并模型,然后打印model.config对比一下原始基座,看有没有多出来的参数或者奇怪的attention实现。如果配置没问题,那就单纯是vLLM的显存规划和你之前用transformers推理的基线不一样,别拿transformers的峰值显存去对比vLLM的预分配值,这俩机制完全不同。
我遇到过类似的情况,但最后发现不是LoRA本身的问题,而是vLLM的KV cache preallocate在作怪。你训练时batch size=1,但推理时vLLM默认会按最大并发数预分配KV cache,Qwen2.5的GQA结构加上7B的hidden size,每多一个并发请求,KV cache的显存占用会非线性增长,6G的增量很可能就是预分配策略导致的。你可以试一下把--max-num-seqs调小,或者用--gpu-memory-utilization限制显存使用比例,看OOM还会不会出现。另外,你合并权重后有没有重新跑过tokenizer的配置检查?有时候adapter的base_model属性会残留,导致vLLM误认为还在用PEFT模式,额外加载了adapter的metadata。我上次就是手动删掉模型目录下的adapter_config.json和adapter_model.bin,只留合并后的权重文件,显存占用立刻降下来了。还有一个坑,如果你用的是transformers的AutoModelForCausalLM加载合并模型,记得传trust_remote_code=True,不然某些版本的Qwen2.5会默认走动态图模式,额外缓存激活值。我自己后来是直接改用llama.cpp的GGUF量化部署,显存直接砍半,虽然速度慢点但稳定多了。你先试试调vLLM参数,如果不行再检查一下权重目录里有没有残留的adapter文件,大概率就是这两件事之一。
看到这个显存对比我第一反应是怀疑你对比的基准不太对。原始模型用vLLM部署时如果开了--max-model-len默认值,KV cache预分配是按最大序列长度来的,而LoRA合并后模型参数量虽然没变,但vLLM对每个请求的显存预留策略可能受模型配置影响,比如你微调时改过rope_scaling或者注意力实现方式,那推理时的KV cache大小就会变。我之前微调CodeLlama也遇到过类似情况,后来发现是vLLM版本和PEFT的兼容性问题,新版本vLLM对LoRA权重合并后的模型会额外分配一些临时buffer,你可以试试用--enforce-eager模式跑一下,如果显存掉下来那就是CUDA graph缓存的问题。另外你确认下合并时用的lora_merge_and_unload()有没有把adapter的缩放系数(alpha)残留到模型配置里,有些情况下保存的config.json里还带着lora_alpha字段,vLLM读到这个会误判成多任务推理模式。最直接的排查办法是先用原生Transformers加载合并权重跑一次推理看峰值显存,如果正常那问题就出在vLLM服务端配置上,可以试试调小--gpu-memory-utilization或者限制--max-num-seqs。我上次遇到OOM是vLLM默认preemption策略在长上下文下会保留更多历史KV,你如果微调时把max_position_embeddings调大了,那部署时这个参数也得同步改回去。总之这问题大概率不是LoRA本身开销,而是工具链对合并模型的兼容性处理。
vLLM的KV cache预分配确实是个坑,尤其你batch size=1训练但推理并发高,显存会按最大并发预留。建议先查下vLLM的--max-num-seqs和--gpu-memory-utilization参数,把利用率调低点试试。另外LoRA合并后理论上不该增加额外显存,除非你量化精度变了或者推理时还挂了adapter配置,检查下模型加载路径是不是干净。我之前碰到过类似情况,最后发现是vLLM版本和transformers不兼容导致重复加载权重,换个版本就好了。
大概率是vLLM的KV cache自动预留策略在作怪,试试设下--max-num-seqs或者--gpu-memory-utilization,别全让它自己分配。
这问题我踩过一模一样的坑,最后查出来是vLLM的KV cache预分配在作怪。你合并权重后虽然只有一套模型,但vLLM默认会按最大序列长度预留缓存,LoRA微调过的模型输出分布变了,实际生成长度可能比基座更激进,导致缓存估算偏保守。可以试试在启动参数里显式指定--max-num-seqs和--max-model-len,把并发数调低点看显存曲线。
另外你说合并后只保存了权重,但有没有检查过tokenizer的special tokens?Qwen2.5用LoRA微调时如果加了新对话模板,合并后tokenizer的pad_token_id可能没同步,vLLM会为每个请求额外分配padding缓存,这也能解释多出来的6G。建议对比下合并前后tokenizer的added_tokens和chat_template。
最后建议用torch.cuda.memory_summary()在推理时打一下内存分配,看是不是真的被KV cache吃掉。我之前遇到类似情况是vLLM的--swap-space默认值太高,直接设成1能省一半预分配。实在不行就用--enforce-eager关掉CUDA graph,虽然慢点但显存能稳下来。
这问题我踩过一模一样的坑,先说结论:LoRA本身在推理时几乎不占额外显存,你多半是vLLM的KV cache预分配策略在捣鬼。合并权重后,模型参数量没变,但vLLM会根据你的max_num_seqs和gpu_memory_utilization参数,把剩余显存全部预留给KV cache,你看着像“多吃6G”,其实是它把动态显存挪去缓存了,并发一高自然OOM。你可以试试把gpu_memory_utilization调低到0.7左右,或者显式设置max_num_seqs=1,看看是不是立刻缓解。另外,确认下你用的是vLLM哪个版本,旧版本对QWen2.5的KV cache对齐有bug,升级到最新版大概率能解决。还有个冷门可能:你合并权重时是不是用了fp16,但原始模型是bf16?精度不匹配会让vLLM重新计算scale,导致临时张量暴涨。我上次就是这原因,重新用bf16合并后直接降了4G。先排查这两个点,别急着怀疑LoRA本身。
并发高才OOM的话,八成是vLLM的KV cache预分配没调好,试试把gpu_memory_utilization调低点。
这问题我也踩过坑,大概率不是LoRA本身的锅。你合并后如果只跑原始权重,vLLM不会额外加载adapter,显存暴涨多半是KV cache的预分配策略变了,尤其是你Qwen2.5用了GQA的话,vLLM默认会按最大并发预留显存,试试启动时调低gpu_memory_utilization或者限制max_num_seqs。另外确认下是不是新版vLLM对7B模型默认开启的paged attention页表大小变了,换个老版本或手动调一下说不定就好了。
说实话,你这情况我怀疑不是LoRA本身的锅,而是vLLM的KV cache预分配策略在作祟。7B模型本来KV cache就吃紧,你合并权重后参数量没变,但vLLM可能按更高精度或更大batch预算来预留显存,尤其并发一高,预分配额度直接翻倍。我自己试过用--kv-cache-dtype fp8或者手动调--max-num-seqs能压下来不少,你可以先降到1看还爆不爆。另外确认下vLLM版本,之前有过旧版对合并后模型显存估算偏高的bug,升级到最新版再跑一次看看。如果还不行,试试直接加载原始模型再单独挂LoRA权重做推理,别合并,有时候反而省显存。
这问题大概率是vLLM的KV cache预分配和并发参数没调,跟LoRA本身关系不大,试试把gpu_memory_utilization调低点。
说到这个我太有感触了,之前用QLoRA调13B模型也踩过类似的坑。你合并权重后显存反而涨,八成不是LoRA本身的问题,而是vLLM的KV cache策略在作怪。7B模型默认的KV cache预分配是按最大序列长度算的,你微调时如果max_position_embeddings没改,但推理时传的prompt或者生成长度变长,vLLM会按新长度去预留显存,这跟原始模型部署时的配置一对比,多出来6G完全合理。建议你先把vLLM的--max-model-len和--gpu-memory-utilization显式调小,比如设成4096和0.8,看看峰值降不降。另外,lora_merge_and_unload()只负责把adapter权重合并进主模型,但如果你用的是PEFT库,合并后最好重新加载一遍原始模型再保存,避免有残留的lora_A和lora_B层占着显存。我试过直接保存合并后的state_dict再重新构建模型,能省一小部分显存,但大头还是在KV cache上。还有一个容易忽略的点,vLLM版本太老的话,对合并后的模型做量化或者连续批处理时会有额外的临时buffer,升级到最新版试试。如果还不行,你试试不用vLLM,直接用HuggingFace的generate接口看看显存差异,这样能快速定位到底是vLLM的预分配问题还是模型本身变大了。
这事儿我踩过一模一样的坑,问题大概率不在LoRA本身,而在vLLM的KV cache预分配策略上。你试下启动时加--max-num-seqs限制并发数,或者手动调低--gpu-memory-utilization,让它别把剩余显存全吃满。另外,确认下是不是用了enable_prefix_caching,这玩意儿在长上下文场景下显存暴涨得离谱。我之前也是合并Qwen2.5,后来发现是--kv-cache-dtype设成fp8解决的,你可以对比下参数配置,别光盯模型权重。
这问题我碰到过类似的,不过我是用peft直接加载adapter推理,没合并权重,显存倒是没炸。你合并后还多6G确实不正常,先排除下是不是vLLM的gpu_memory_utilization设置问题,它默认会预分配显存,如果之前跑原始模型时没调过这个参数,现在模型参数多了点但KV cache预留空间可能被撑大了。另外你确认下合并完的模型是不是真的只包含LoRA增量,有些时候merge没clean,比如scale_factor没重置,会导致激活值异常放大,推理时中间张量爆炸。还有个思路,用transformers原生加载跑一下看看显存,如果正常那就是vLLM的配置或版本兼容问题,毕竟Qwen2.5的架构和vLLM某些版本有已知的KV cache对齐bug。最后检查下推理时的max_seq_len和max_num_batched_tokens,如果并发高OOM很可能是这两项没按实际需求调小。我之前试过在24G卡上跑7B,vLLM设个2048的max_seq_len,并发8都稳,你参考下这个配置。
大概率不是LoRA的锅,你试试关掉vLLM的自动KV cache复用策略,手动调下gpu_memory_utilization。
讲真不太像是adapter残留的问题,merge完只保存权重的话推理路径跟原模型应该一模一样。我怀疑是你vLLM的gpu_memory_utilization没调,默认会按总显存比例预分配KV cache,24G卡上原始模型可能刚好卡在临界值,合并后模型参数稍微大一点就直接触发预分配上限了。你可以试着把这个参数调低到0.85左右,或者直接用transformers原生推理对比一下显存,先排除vLLM的调度因素。另外Qwen2.5的7B本身注意力头多,长上下文下KV cache本来就吃紧,如果并发高建议查下max_num_seqs和max_model_len的配置,这两个才是OOM的主要元凶。
同模型同参数下LoRA合并后推理显存多6G肯定不正常,我怀疑是vLLM的KV cache策略变了,你试试把gpu_memory_utilization调低点,或者直接对比一下合并前后模型加载时的tensor并行配置有没有变动。另外可以单独跑一下原始模型和合并模型各一次推理,看峰值显存差在哪,如果差在输入长度上那多半是max_model_len或者rope scaling配置没对齐。实在不行就用transformers原生推理测一遍,排除vLLM的影响再定位。
合并权重理论上不该多占6G,除非你vLLM的max_model_len或者gpu_memory_utilization没调。我之前也碰到过,最后发现是vLLM默认按最大长度预分配KV cache,跟LoRA没关系。你可以试试把max_model_len设小一点,或者gpu_memory_utilization降到0.85看看还OOM不。
合并权重后推理显存反而涨了,大概率不是LoRA本身的问题。你试试用--gpu-memory-utilization把vLLM的预分配调低一点,默认0.9会一口气吃掉很多显存做KV cache。另外确认下合并后的模型是不是dtype变了,比如训练时bf16、保存成了fp32,那显存直接翻倍。我之前也踩过类似的坑,最后发现是tokenizer配置不一致导致输出长度异常,缓存撑爆了。