最近在尝试微调一个7B的模型,用的LoRA,rank设的8,batch size调到了2,看显存占用才10G左右(显卡是24G的),按理说应该稳的。但每次训练到大概四五百步的时候,突然就Out of Memory了,训练直接崩掉。我查了日志也没看到什么明显错误,就是显存突然飙升。
我怀疑是不是gradient checkpointing没开对,或者中间缓存没清?也试过把batch size降到1,但还是会在不同步数挂掉。有没有大佬遇到过类似情况?是不是LoRA本身在某个阶段会突然占更多显存?还是我用的peft库版本有bug?
先谢过,真有点被搞懵了。
用LoRA微调7B模型,显存够但训练到一半就OOM了,咋回事?
全部回复
共 172 条这种跑几百步突然OOM的情况我也碰过,大概率不是LoRA本身的问题,而是显存碎片化攒到一定程度炸了。你可以试试设置PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True,或者把optimizer换成8bit的,能省不少。另外检查下是不是eval或者save的时候触发了额外显存分配,有时候是checkpoint保存那一下顶爆的。
你这种跑到几百步才炸的情况,八成是碎片化显存攒出来的。我遇到过类似的,前面看着占用不高,但PyTorch缓存分配器一直没释放干净,到某个点突然要一块连续大显存就崩了。可以试试设一下PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True,或者每几百步手动清一下cache。另外检查下有没有开evaluation或者save时的临时峰值,那一下经常是压死骆驼的最后一根稻草。
可能是内存碎片攒的,试试 torch.cuda.empty_cache() 加定期清理,或者设 PYTORCH_CUDA_ALLOC_CONF 环境变量。
我之前也踩过这个坑,大概率不是LoRA本身的问题,而是训练到中途触发了某种动态显存增长。你留意下是不是在eval或者save checkpoint的时候崩的,HF的Trainer默认会保留一堆中间变量。另外gradient checkpointing如果和某些peft版本搭配不当,反而会在反向传播时多占显存,建议确认下是不是每步都在重算。可以试试设个save_steps和eval_steps错开,再开个PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True看看能不能缓解。
这个现象挺典型的,我之前用LoRA微调7B的时候也踩过类似的坑,不一定是显存本身不够,而是训练到中途某些操作触发了峰值。你可以先看看是不是在eval或者save的时候炸的,有时候是保存checkpoint或者跑验证集那一下显存突然上去了,尤其是你如果没设置eval_steps和save_steps错开的话。另一个常见原因是token长度分布不均,前面几百步都是短样本,显存看着很稳,后面突然来了一批长序列,attention那块直接把显存顶爆了。gradient checkpointing如果开对了确实能压不少,但有些模型和peft版本搭配会有bug,你可以打印一下每步的max_seq_len确认下。还有个小细节是LoRA的optimizer state,如果你用的是adamw,它会在某些步数累积动量,虽然理论上不会暴涨,但配合长序列就容易出事。建议试试把max_seq_len卡死,或者用dynamic padding改成固定长度,另外检查下dataloader有没有把整个batch的label都算loss,那个也会偷偷吃显存。
检查下学习率调度器,有些会在特定步数突然放大梯度导致显存暴涨。
听起来像是训练到中途动态分配显存导致的碎片问题,我遇到过类似的。你试试开一下torch.cuda.empty_cache()在每个step后调一次,或者用PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True这个环境变量,能缓解碎片。另外peft某些版本确实有缓存past_key_values没释放的坑,升级到最新版看看。
你这情况我遇到过,多半是优化器状态和梯度累积到某个点才触发OOM。LoRA虽然参数少,但Adam的动量缓存是按全模型参数量分配的,步数一多显存就慢慢涨上去了。可以试试换成adafactor或者8bit adam,再把gradient checkpointing确认开对。另外peft某些版本确实有中间激活没释放的坑,升级到最新版看看。
是不是某个step触发了长序列样本,attention那块显存瞬间爆了?可以打印下每步的输入长度看看。
这个情况我遇到过,当时也是跑到几百步突然炸显存,一度以为是peft的锅。后来发现跟LoRA本身关系不大,主要是训练过程中某些batch的序列长度差异太大,padding后的激活值瞬间涨上去。你检查下数据里是不是有特别长的样本,或者用了动态padding。另外gradient checkpointing如果没开,激活值会一直累积,开到offload模式会稳很多。还有个比较隐蔽的点是优化器状态,虽然LoRA只更新一小部分参数,但如果你用的是adamw且没设置正确,它可能还是给全量参数分配了状态。我后来换成adafactor或者把优化器只指向lora参数就再没崩过。建议你打印一下每步的显存峰值,看是不是在某个长序列样本进来时飙升的。
这情况我之前也碰到过,挺玄学的。你显存才10G但跑到几百步突然炸,大概率不是LoRA本身的问题,而是中间某个step触发了显存碎片化或者缓存没释放干净。尤其是开了gradient checkpointing之后,反向传播那一下临时激活会集中爆出来,前面看着稳其实是在攒着。
另外你可以重点看一下是不是有变长序列的样本,比如某条数据特别长,attention那块显存直接翻倍,训练到那个batch就崩了。我遇到过类似情况,日志里啥都看不出来,就是突然OOM。
还有个坑是peft某些版本和transformers搭配时,optimizer的state会在特定step才初始化,或者scheduler缓存没清,也会突然吃一波显存。建议你固定一个checkpoint间隔,在崩之前手动save一下,然后看看到底是哪个step前后显存开始爬。
batch size降到1还挂说明不是纯batch的问题,更像是累积或者碎片。可以试试torch.cuda.empty_cache()在每个step后面加一下,虽然土但有时候真管用。再不行就换deepspeed或者把optimizer换成8bit的,能压不少。
写得挺好,建议补充一些性能数据。