最近在试着用LoRA微调一个7B的对话模型(基座是Qwen2.5),训练阶段用的batch size=1,显存勉强够用(24G)。但微调完合并权重后,用vLLM部署推理,居然比原始模型多吃了快6G显存,而且并发一高就OOM。我确认过合并后的权重没问题,推理时也没加载训练时的优化器状态。查了一圈,有人说可能是KV cache的预分配问题,也有人说是LoRA的adapter没卸载干净。但我用lora_merge_and_unload()合并后明明只保存了合并权重。有没有大佬遇到过类似情况?是LoRA本身就会增加推理时的显存开销,还是我哪里配置错了?求指点,卡在部署这步好几天了。
LoRA微调7B模型后推理显存爆炸,是我的方法不对吗?
全部回复
共 31 条大概率是vLLM的KV cache预分配策略变了,试试--max-num-seqs调小或者开--enable-prefix-caching。
大概率是vLLM的KV cache按pytorch默认dtype预分配了,试试把gpu_memory_utilization调低点,或者开下--quantization fp8。
这问题我踩过一模一样的坑,最后发现不是LoRA的锅,是vLLM的KV cache预分配策略。你合并权重后模型参数量没变,但vLLM默认按最大序列长度预留显存,如果你推理时的max_model_len设得比训练时大很多,或者并发数没调好,它就会猛吃显存。我那次也是7B,合并后显存从14G飙到20G,后来把gpu_memory_utilization降到0.85,再把max_num_seqs调小,瞬间就稳了。另外你确认一下是不是用了--enable-lora参数,虽然你合并了,但vLLM有时候会残留adapter配置,干脆把模型重新tokenizer保存一遍再加载。还有个冷门可能,就是你合并时用的dtype和推理时不一致,比如训练用bf16,合并后变成fp32,显存直接翻倍。建议你先单独跑一次纯原始模型,对比下显存基线,再用nvidia-smi监控推理峰值,基本就能定位是预分配还是权重问题。我最后是把max_model_len调到和训练时一样,显存就只多了0.5G,属于正常波动。别老想着是LoRA的锅,大概率是部署配置没对齐。
你这个情况我前两天刚踩过,问题大概率不在LoRA本身,而是vLLM的KV cache预分配策略。7B模型加上LoRA后虽然单层参数量没变,但vLLM会按最大序列长度统一预留显存,合并后的模型如果某个config参数(比如max_position_embeddings)没跟上,预分配就会翻倍。建议你看下合并后的config.json和原始模型对比,特别是rope_scaling和max_len相关字段,我上次就是改完这个显存直接降了4G。另外确认下vLLM的gpu_memory_utilization设置,别让它自动分配,手动调低一点试试。
同款问题折腾过,最后发现基本跟LoRA本身没关系,大概率是vLLM的显存调度策略变了。你合并权重后,模型结构其实和原始Qwen2.5完全一致,所以推理时KV cache的预分配逻辑应该是一样的。但有个坑:vLLM默认会按最大序列长度预分配KV cache,如果你之前训练时显存紧张,可能下意识调低了max-position-embeddings或max-seq-len,而推理时没改回来,导致它按超长序列预留了空间,自然多占好几个G。
另一个更隐蔽的点是,你对比显存的时候是不是用了同一个并发数和同样的请求长度?如果之前测原始模型时用的小并发,现在直接上高并发测LoRA版本,那多出来的显存其实是并发翻倍带来的,不是LoRA的锅。建议先用单请求、固定max-model-len跑一遍对比,排除变量。
至于adapter没卸载干净,你确认过merged_weights的state_dict里没有lora_A和lora_B的key吗?有时候merge_and_unload后,LoRA的缩放参数还留在模型里(比如scaling这种非张量属性),虽然不影响前向,但vLLM加载时可能会为每个层多分配一些临时buffer。保险起见,用torch.save的模型直接加载到HuggingFace的AutoModel里验证一下,如果显存正常,那就是vLLM配置问题。
最后提醒一下,如果你用的是GPTQ或AWQ量化版基座来LoRA,那合并后量化参数会被破坏,vLLM会回退到FP16推理,显存直接翻倍。你基座是原生FP16的话就忽略这条。先按我说的调调看,大概率是配置没对齐。
这问题我踩过一模一样的坑,你大概率不是LoRA本身的问题,而是vLLM的KV cache策略和模型配置不匹配。合并权重后模型参数量没变,但Qwen2.5的attention实现和vLLM默认的paged attention在长上下文下会有额外的缓存预留,尤其是你如果没设置--max-num-seqs或者--gpu-memory-utilization,它会按最大可能上下文去预分配显存,7B模型动辄给你留个几十GB的KV池,实际用不到就白占。你试试部署时显式限制--max-model-len到训练时的实际长度(比如2048或4096),再把--gpu-memory-utilization调到0.85,基本能压回去。另外,确认下微调时有没有改rope_scaling或者max_position_embeddings,如果改过但vLLM没同步,它会按原始配置分配,也会导致显存虚高。至于adapter没卸载干净,你合并后用torch.save单独存一次state_dict再加载,或者直接在vLLM里加载原始权重对比下就知道了。我上次就是--max-model-len没改,白白多吃了4G,改完立刻正常。你要是方便,把启动命令和config贴出来,大概率能帮你定位到具体参数。
大概率是vLLM的KV cache策略问题,试试把gpu_memory_utilization调低点,或者开下enable_prefix_caching。
这个现象挺典型的,大概率不是LoRA本身的问题,而是vLLM的KV cache预分配策略在作怪。你试试在启动时显式设置--max-num-seqs或者调低--gpu-memory-utilization,把预留比例压一压。另外确认下是不是用了paged attention,旧版本vLLM对合并后的模型尺寸变化很敏感,升级到最新版可能就解决了。我之前也遇到过类似情况,最后发现是tokenizer配置里的model_max_length没对齐,导致缓存计算翻倍。
之前调Qwen的时候也踩过类似的坑,不过我是7B+8卡才勉强跑起来。你试试把vLLM的gpu_memory_utilization调低点,比如0.8,这货默认会吃满显存来预分配KV cache,并发一高就炸。另外合并后有没有重新跑一遍tokenizer的配置?有时候padding和bos_id不一致也会导致显存异常。
这问题我踩过类似的坑,LoRA合并后理论上不该增加显存,重点查下vLLM的gpu_memory_utilization设置,默认会预留给KV cache很大比例,调低到0.7左右试试。另外确认下是不是用了--enable-lora参数,如果没删adapter配置,vLLM会按LoRA模式加载反而多占资源。我之前是换回transformers原生推理对比了下,发现纯粹是vLLM的缓存策略导致的,跟合并权重本身没关系。
说实话LoRA本身理论上推理时零开销,权重合回去就合回去了,但你这个现象我见过类似的,多半是vLLM的KV cache预分配策略被模型config里的max_position_embeddings带偏了,比如Qwen2.5的7B默认支持32K长度,你如果没改这个参数,vLLM会按最大长度预分配显存,并发一高自然爆。建议先把max_model_len调成你实际用的长度试试,比如2K或4K,显存能立刻降下来。另外确认下是不是用了paged attention的旧版本,有些版本对长上下文支持有bug。要是还不行,可以考虑直接用transformers原生推理对比一下,排除是vLLM的问题还是合并权重时某些scale参数没对齐。
说实话你这情况我猜大概率不是LoRA本身的问题,7B合并后参数也就多几十MB,推理显存不该有这么大差距。vLLM默认会按最大并发预分配KV cache,你如果没调gpu_memory_utilization或者max_num_seqs,它可能直接吃满剩余显存,OOM多半是这原因。建议先把这两个参数显式设小一点试试,比如gpu_memory_utilization=0.6,然后看下vLLM启动日志里实际分配的cache大小。另外确认下你是不是用了paged attention的旧版本,有时候版本bug也会导致显存异常。
vLLM的KV cache预分配确实是常见坑,你试试启动时把--max-num-seqs调小点,或者限制--gpu-memory-utilization到0.8看看。另外确认下是不是加载了多个lora adapter,vLLM默认会为每个adapter预留额外显存,即使只用主权重也会吃资源。我之前也遇到过类似情况,最后发现是tokenizer_config里新增了special token导致padding长度变长,间接推高了显存峰值。
并发高才OOM的话,大概率是KV cache预分配太大,试试调低--max-num-seqs或--gpu-memory-utilization。
八成是vLLM的KV cache策略问题,试试启动时调低gpu_memory_utilization或者换下版本。
这问题我之前也踩过,LoRA合并后理论上不应该增加显存,但vLLM的KV cache预分配是按你设置的max_num_seqs和gpu_memory_utilization来的,7B模型直接默认配置很容易给KV cache留太多显存,你试试调低这两个参数,或者用--limit-mm-per-prompt这种限制一下。另外确认下是不是用了PagedAttention的旧版本,有时候版本bug也会导致显存异常,升级vLLM到最新版说不定就好了。
你这情况我猜大概率不是LoRA本身的问题,因为合并后就是普通权重,和原模型推理路径一样。倒是可以检查下是不是加载时把adapter配置也带进去了,有些框架会默认加载多个LoRA分支,用--disable-lora或手动指定单adapter试试。还有,如果训练时用了梯度检查点,推理时没对应调整也可能有隐性开销。
vLLM对合并权重的显存占用确实比原生HF推理要激进一些,尤其并发高时。你试试不用vLLM,直接用transformers的generate接口跑一下,对比显存差异,如果正常那就纯粹是vLLM配置问题。另外7B模型在24G卡上本来就紧张,建议把gpu_memory_utilization设到0.85以下,给KV cache留点余量,别贪满。
我怀疑你合并后用了fp16加载,但训练时
vLLM本身对合并后的模型是重新build cache的,如果原始模型和微调后模型结构一致,理论上不该差这么多。你确认下是不是加载时把adapter的配置路径也带进去了,或者试试用transformers直接推理对比下显存。另外Qwen2.5的attention实现和vLLM版本兼容性也可能有坑,升级到最新版vLLM试试?我之前遇到过类似问题,最后是发现旧版本对GQA支持不好导致KV cache翻倍。
这问题我踩过一模一样的坑,最后发现还真不是LoRA本身的锅。你合并权重后推理显存暴涨,大概率是vLLM对模型的KV cache预留策略变了,尤其是7B模型在长上下文场景下,默认的cache块大小和预分配比例会激进很多。我之前把gpu_memory_utilization从默认的0.9调低到0.7,再配合--max-num-seqs限制并发,OOM就基本消失了。另外你确认下是不是用了--enable-lora,如果推理时还挂着adapter配置,即使权重合并了,vLLM也会额外维护一份LoRA相关元数据,这玩意儿贼吃显存。还有个细节,合并后记得重新跑一遍tokenizer的chat_template,有时候旧配置里的pad_token_id会和新权重不匹配,导致推理时动态padding,间接把KV cache撑爆。我后来干脆直接用transformers原生推理对比了下,发现显存占用其实只比原模型高不到1G,所以问题大概率出在vLLM的配置上,不是模型本身。你试试用--kv-cache-dtype fp8或者调小--max-model-len,应该能缓解。要是还不行,贴下你的vLLM启动参数,咱一起看看。
vLLM的KV cache预分配确实会吃掉不少显存,尤其你并发拉高的时候。可以试试把gpu_memory_utilization调低点,或者开一下enable_prefix_caching,另外检查下vLLM版本,老版本对合并后模型的内存管理有bug。LoRA本身推理时不会增加显存开销,除非你加载了adapter配置没清干净,但你都merge了应该没这问题,大概率还是部署参数没调好。
大概率是vLLM按原始模型尺寸预分配了KV cache,合并后参数没变但显存策略没跟上,试试调低gpu_memory_utilization。