最近在跑一个简单的ResNet50迁移学习项目,数据集大概2万张图片,每张resize到224x224。我设batch size=32,结果跑第一个epoch就报CUDA out of memory。我用的是RTX 3060 12G,按理说应该够用吧?是不是我DataLoader里开了太多num_workers?还是说模型里用了什么隐藏的显存泄露?尝试把batch size降到8倒是能跑了,但训练慢得离谱,而且准确率也不太行。
想请教下各位大佬,这种场景下一般怎么优化显存?混合精度、梯度累积这些方法真的能立竿见影吗?还是说我哪里写得不规范?求指点,孩子快被显存整自闭了。
用PyTorch做图像分类训练时显存炸了,是我代码写错还是batch size太大?
全部回复
共 158 条12G跑ResNet50加224输入,batch32按理说真不该炸,我怀疑你DataLoader里pin_memory或者worker开太多,有时候内存爆了也会报成显存错误。试试把batch降到16,然后开AMP混合精度,显存直接砍半,速度还能提上去。梯度累积适合大batch效果,但你这个场景不如直接调小batch实在。另外训练慢跟准确率低大概率是学习率没跟着调,batch小了lr也得改。
12G跑224的ResNet50按理说够,检查下是不是pin_memory和workers开太多,混合精度能省不少。
12G跑ResNet50加224分辨率,batch32按说真不至于直接炸,你先排查下是不是把验证集也塞进GPU算了,或者DataLoader的pin_memory和num_workers开太高反而吃显存。混合精度肯定要开,amp能省将近一半显存,梯度累积我试过对收敛速度影响不大但确实能救急,不过你batch掉到8准确率就崩,建议先检查下学习率有没有跟着batch size调。另外试试把图片预处理放到CPU上做,别在GPU上resize,能省不少临时显存。
说实话12G跑ResNet50加224分辨率,batch32按理说真不该炸,你这大概率不是batch size的锅。先检查下是不是把梯度也存了或者模型没切eval模式,再就是确认下有没有在循环里重复加载数据没释放。混合精度挺管用的,开了之后显存能省将近一半,3060支持tf32,配合amp试一下。梯度累积也别急着上,那只是曲线救国,真正瓶颈可能在你DataLoader的pin_memory和prefetch设置上。建议先用torch.cuda.max_memory_allocated()看看峰值在哪一步爆的,比瞎猜靠谱。
12G跑224的ResNet50,batch32确实有点紧,开AMP加梯度累积基本能解决。
12G跑224的ResNet50,batch32确实有点紧,降到16或者开amp试试,效果比梯度累积直观多了。
12G跑224的ResNet50,batch32按理说真不难,但你这情况大概率不是num_workers的锅,检查下是不是在训练循环里把每个batch的梯度都手动调用了backward,或者模型里有个大尺寸的中间变量没释放。混合精度值得先试,直接能省一半多显存,梯度累积得配合着调学习率,不然收敛慢到怀疑人生。另外准确率不行可能跟batch变小后BN统计量震荡有关,试试先用能跑的最大batch预热几个epoch再切小。
12G跑ResNet50加224的输入,batch32按理真不该爆,你先看下是不是pin memory或者验证阶段忘了no_grad,很多显存都是这么悄悄吃掉的。混合精度我个人觉得是最立竿见影的,开了之后显存直接砍半,速度还能快不少,你这卡完全能扛住。梯度累积其实对显存帮助不大,它主要是模拟大batch,该爆还是爆,不如直接调小batch加AMP实在。另外准确率不行的话先别怪batch,看看学习率是不是该跟着调一下,8和32的optimal lr差挺多的。
12G跑resnet50加224的batch32确实紧,先上AMP试试,基本能省一半显存。
梯度累积对显存没帮助,那是省算力的,你这情况换8batch加AMP才是正解。
12G跑ResNet50加224的输入,batch32按理说真不该爆,你先排查下是不是把梯度清空写成了optimizer.zero_grad(set_to_none=True)或者忘了在backward前调用,另外确认下验证集有没有也开着梯度。混合精度建议直接上AMP,省显存效果很明显,而且你这数据量梯度累积反而可能拖慢收敛。num_workers只影响数据加载,不影响显存占用,别被带偏了。
12G跑ResNet50加224分辨率,batch32按理说真不该爆,你检查下是不是无意中把梯度也存进显存了,比如没设requires_grad=False。混合精度确实立竿见影,显存直接砍半,3060的安培架构对fp16支持很好,我试过从batch32直接上到64。梯度累积也是常规操作,但准确率掉的话可能跟学习率没调好有关,batch变小后学习率要按比例降。另外num_workers只影响CPU内存,跟显存没关系,但可以试试pin_memory=False,偶尔会有奇效。
12G跑resnet50加224的图,32确实悬,先开amp试试,能省一半多。
梯度累积配混合精度,基本能解决你这问题,num_workers影响不大。
3060 12G跑224的ResNet50,batch32理论上真不该爆,你先查查是不是pin_memory或者数据增强那块把内存也吃满了,有时候是CPU和GPU争抢导致显存临时飙升。混合精度绝对值得试,apex或者原生amp一开,显存直接砍半,速度还能提一截。至于梯度累积,它不省显存,只是让你能用小batch模拟大batch效果,对你的情况帮助不大。我怀疑你准确率不行是学习率没跟着batch size调,降到8的话lr也得相应降低,不然收敛会很不稳。
12G跑ResNet50加224分辨率,batch32按理说确实够,但你得看下是不是加载了预训练权重后没冻结BN层,或者输入管道里有个什么意外把图复制了好几份。混合精度建议直接上AMP,显存能省一半,而且代码改动就几行,梯度累积反而是你这种小卡更实际的解法,但记得把学习率按累积步数调大。另外num_workers开太多会吃内存,但一般不会爆显存,你不如先看一眼nvidia-smi确认是不是别的进程占用了。准确率不行大概率不是batch的问题,lr或者优化器设置检查下?
说实话12G跑ResNet50加224输入,batch32确实有点紧但没道理直接爆,你先检查下是不是在验证阶段也把梯度算上了,model.eval()加torch.no_grad()能省不少。混合精度建议直接上,amp对显存和速度的提升都很明显,尤其你这种单卡场景。梯度累积的话,感觉不如先把batch降到16配合amp试试,效果应该接近32而且不会爆。另外num_workers影响的是CPU内存不是显存,这个锅它不背。
12G跑ResNet50加224分辨率,batch32按理说真不该爆,你查下是不是开了gradient checkpointing或者模型没切eval模式,有时候验证集也会占显存。混合精度建议直接上,AMP那几行代码改动量很小,显存能省将近一半,训练速度还快。梯度累积我没试过但听人说效果还行,不过你batch8跑不动更可能是lr没跟着调,小batch得把学习率降下来,不然收敛确实烂。
12G跑224的ResNet50按理够,先查查是不是pinned memory开太多,混合精度能省一半显存。
梯度累积对显存没用,那是省显存不省时间,试试AMP加gradient checkpointing,32应该能跑。
12G跑ResNet50加224的输入,batch32按理说真不至于爆,你先看看是不是在训练里把整个验证集也一次性塞进GPU了,或者忘了给模型加eval模式。混合精度确实立竿见影,显存直接砍半,梯度累积也行但会变相降低有效batch,你降到8感觉慢可能反而说明瓶颈在数据加载上。另外可以查一下是不是有变量在循环里累积了计算图,那种隐式泄漏比batch size更常见。
3060 12G跑ResNet50,batch32确实有点紧,但降到8又太保守了,试试混合精度加上梯度累积,基本能稳住。
12G跑ResNet50+224x224,batch 32按理说确实能挤一挤,但迁移学习如果没冻结bn层,显存占用会比你预期高不少。你可以先试试把num_workers降到4,顺便确认下dataloader有没有开pin_memory,这两个有时候会额外吃显存。混合精度我觉得挺值得试的,3060的amp支持很成熟,显存能省接近一半,梯度累积的话效果有但训练时间不会缩短,主要看你瓶颈在哪。另外你降到batch 8准确率不行,可能是bn的统计量抖得太厉害,可以试试用更大的虚拟batch配合梯度累积,或者干脆冻结前几层只训分类头。