最近在跑一个简单的ResNet50迁移学习项目,数据集大概2万张图片,每张resize到224x224。我设batch size=32,结果跑第一个epoch就报CUDA out of memory。我用的是RTX 3060 12G,按理说应该够用吧?是不是我DataLoader里开了太多num_workers?还是说模型里用了什么隐藏的显存泄露?尝试把batch size降到8倒是能跑了,但训练慢得离谱,而且准确率也不太行。
想请教下各位大佬,这种场景下一般怎么优化显存?混合精度、梯度累积这些方法真的能立竿见影吗?还是说我哪里写得不规范?求指点,孩子快被显存整自闭了。
用PyTorch做图像分类训练时显存炸了,是我代码写错还是batch size太大?
全部回复
共 152 条12G跑ResNet50加batch32确实有点紧,试试混合精度加梯度累积,效果立竿见影。
12G显存跑ResNet50加224的图,batch size=32按理说确实不该直接炸,我怀疑是你DataLoader的num_workers开太高或者用了pin_memory=True导致显存预分配太多。混合精度和梯度累积亲测有效,尤其是AMP能把显存占用砍掉将近一半,训练速度还更快。另外检查下代码里是不是无意中保留了中间变量或者梯度没清干净,有时候一个detach()就能救回来。准确率不行大概率是小batch size导致的BN统计量不稳定,试试把lr调低或者用梯度累积模拟大batch。
12G跑224的ResNet50 batch32确实有点紧,但也不至于第一个epoch就炸,建议先检查下DataLoader的num_workers是不是设太高了,一般4-6就够,开太多反而可能造成显存碎片。混合精度真的立竿见影,能直接省一半显存,配合梯度累积你甚至能跑batch64,但准确率低大概率不是batch size的锅,看看学习率是不是没跟着调。另外可以试试把图片预处理放到GPU前用torchvision的transforms在CPU做,别让GPU背数据增强的额外开销。
3060 12G跑224的ResNet50,batch size 32按理说确实能扛住,你检查下是不是开了什么额外的增强或者用了大尺寸的验证集,有时候验证集batch设太大也会炸。混合精度真的立竿见影,显存能省快一半,而且对精度基本没影响,pytorch现在自带的amp用起来也就多两行代码。梯度累积的话更适合你这种batch size被迫缩小的情况,比如设个accumulation steps=4,等效batch size又回到32了,就是训练时间会稍微长点。另外num_workers别开太多,4到8就够,开多了反而可能因为数据加载占显存导致报错。
12G显存跑ResNet50+224x224,batch size=32按理说确实不该直接炸,但你这情况我怀疑是DataLoader的num_workers开太高了,有时候PyTorch的数据预加载机制会在显存里缓存不少中间变量,尤其你图片读取流程里要是用了什么奇奇怪怪的transform,比如RandomResizedCrop这种,显存占用会比想象中高不少。另外迁移学习的话,检查下是不是把整个ResNet50的backbone都反向传播了?如果只训练最后的分类头,可以冻结前面的层,这样梯度计算图会小很多,显存能省下一大截。混合精度(amp)肯定管用,16位浮点直接显存砍半,3060的Tensor Core还能加速,建议你试试torch.cuda.amp,基本无痛。梯度累积其实对显存没直接帮助,它只是让你能用小batch模拟大batch的效果——你batch size降到8之后用梯度累积步数=4,等效batch=32,但每步显存占用还是8张图的量,训练慢是因为迭代次数变多了,不是显存问题。另外准确率不行很可能是学习率没调,batch size变小了lr得跟着降,不然梯度震荡太大,建议先试lr=1e-4配合cosine annealing。最后查查代码里有没有在循环里反复创建tensor或者没释放中间变量,有时候显存泄露就藏在自定义的Dataset里。
12G跑ResNet50加batch32确实有点紧,试试混合精度和梯度累积,效果立竿见影。
3060 12G跑224的ResNet50,batch size=32确实有点勉强,这卡显存带宽和容量都偏紧,我自己的经验是16最稳。混合精度真的立竿见影,显存能省个30%-40%,而且训练速度还快,但记得要把Tensor Core用上。梯度累积也能救急,相当于虚拟增大batch size,不过你降到8跑得慢可能是DataLoader没调好,试试num_workers设成4或者8,pin_memory=True也能提点速。至于准确率不行,batch size小了之后学习率也得跟着调,不然梯度更新不稳定,你搜下linear scaling rule看看。
12G跑ResNet50加224图,batch size开32确实有点勉强,降到16试试混合精度,效果立竿见影。
12G跑ResNet50加224的图,batch size=32确实有点极限,我同样3060试过24就快满了。你先检查下输入图片有没有偷偷转成三倍通道或者用了FP32,另外num_workers开4到6就够了,开太多反而会占额外显存。混合精度(torch.cuda.amp)绝对立竿见影,我试过直接省掉近一半显存,还能保持精度。梯度累积也是个好办法,batch size设小点但多累积几步,效果和打batch一样,就是训练时间稍微长点。至于准确率不行,先确认下是不是学习率没跟着batch size调低。
12G显存跑224x224的ResNet50,batch size=32确实有点极限,3060的带宽和显存管理其实没有想象中那么乐观。你降到8能跑说明不是代码写错,但准确率不行大概率是学习率没跟着调,batch size减半学习率也得相应降,不然梯度更新太抖了。混合精度训练(AMP)绝对是立竿见影的,PyTorch自带torch.cuda.amp,开了之后显存占用能降一半左右,而且速度基本不受影响,强烈建议你先试这个。梯度累积虽然也能缓解,但那是治标不治本,相当于用时间换空间,训练会变慢。另外num_workers确实会占用一些显存,尤其是pin_memory=True的时候,建议你先设成4或者2试试,别盲目开太高。你还可以检查下模型里是不是有没冻结的BN层或者多余的缓存变量,有时候torch.no_grad()没用好也会偷偷吃显存。如果这些调完还是炸,可以考虑用梯度检查点(checkpointing)或者换更轻量的backbone,比如ResNet34或者EfficientNet-B0,对于2万张的数据集来说精度差距不会太大。
12G跑32的batch确实偏极限了,试试梯度累积加混合精度,效果立竿见影。
3060 12G跑224尺寸的ResNet50,batch size=32确实有点极限,我自己的经验是16比较稳。你提到num_workers,这个其实影响不大,主要吃内存不是显存。可以先试下梯度累积,模拟大batch的效果,同时用amp混合精度,显存能省接近一半,训练速度反而更快。准确率不行的话,检查下学习率是不是没跟着batch size调,降batch后lr也要相应降。另外迁移学习建议冻住前几层,只微调最后几层,也能省不少显存。
12G跑ResNet50加224x224,batch size=32按理说确实不该直接炸,我怀疑问题可能出在数据加载上——num_workers开太多并不会直接占满显存,但如果你用了pin_memory=True,它会额外锁住一部分CPU内存和显存之间的缓冲区,有时候反而会加剧显存压力。你可以先试试把num_workers降到2或者4,同时关掉pin_memory,看看第一个epoch能不能跑过去。另外迁移学习的话,检查一下是不是把整个ResNet50都设为trainable了?如果只是微调最后一两层,可以冻结前面所有层的梯度,这样反向传播时不用存中间激活值,显存能省下一大半。混合精度(AMP)绝对立竿见影,RTX 3060支持自动混合精度,开了之后显存占用几乎减半,而且训练速度还会变快,配合梯度累积的话,你甚至能模拟出更大的batch size效果。不过你提到batch size降到8后准确率不行,这倒不一定是显存的问题——小batch size加上学习率没调,确实容易让模型震荡,建议你试试把学习率按比例降低,或者用余弦退火调度器。还有个小技巧:用torch.utils.checkpoint把ResNet的某些层做梯度检查点,用时间换空间,但对3060这种卡来说,通常先试试混合精度和冻结层就够用了。
12G跑ResNet50 batch 32确实有点紧,224x224加上标准数据增强,单卡显存占用大概在7-8G左右,但如果你开了太多num_workers或者用了pin_memory=True,可能会额外吃显存。混合精度我强烈建议试试,AMP能省将近一半显存,而且对精度几乎没影响;梯度累积也可以解决batch size小的问题,但注意学习率要相应调一下。另外检查下模型里是不是误用了requires_grad=True的额外层,有时候预训练模型的fc层没冻结也会多占显存。
12G跑ResNet50加batch32确实会爆,试试混合精度加梯度累积,效果立竿见影。
12G跑ResNet50加batch32确实会爆,建议开混合精度+梯度累积,效果立竿见影。
12G跑ResNet50 + batch size32确实有点紧,尤其是输入224x224的话,第一层卷积就会吃不少显存。你可以先试试把num_workers降到2或4,有时候数据加载线程太多反而会占用额外的显存缓存。混合精度我强烈推荐试一下,开了之后显存直接砍半,训练速度还能快一截,pytorch自带amp很好上手。另外梯度累积也能凑合,但本质治标不治本,batch size太小导致BN层统计不准才是你准确率下降的主因。
巧了,我之前也拿3060 12G跑ResNet50,batch size设32确实容易炸,你这情况其实挺正常的。12G显存对224x224的图来说,32的batch size差不多就是极限边缘了,加上DataLoader的num_workers开多了会额外占一些显存(尤其是pin_memory=True的时候),建议你先试试num_workers=4或者2,别开太多。混合精度绝对是立竿见影的,torch.cuda.amp包一下forward和loss计算,显存能降差不多一半,而且速度还能提,我实测几乎不影响精度。梯度累积也可以配合用,比如设accumulation_steps=4,等效batch size还是32,但每次只算8张的梯度,显存压力小很多。不过你说batch size降到8之后准确率不行,这个得注意——可能是学习率没跟着调,学习率通常得按batch size等比例缩放,你从32降到8,学习率也得大概降到原来的1/4试试。另外检查下你的模型是不是在冻结某些层时不小心把BN层也冻了,或者有没有在DataLoader里用了太大的transform缓存,这些细节也容易吃显存。总之先开混合精度,再把worker数调低,大概率就稳了,别太焦虑。
12G的3060跑ResNet50 batch size=32确实有点极限,我自己的经验是24左右就差不多满了,16比较稳。你降到8能跑说明不是代码bug,就是显存正好卡在临界点上。不过你说准确率不行,这大概率不是batch size的锅,可能是学习率没跟着调,或者数据增强太激进了,你试试把学习率按batch size比例缩一下看看。混合精度真的立竿见影,我开了之后显存能省将近一半,速度还更快,PyTorch自带torch.cuda.amp用起来很方便,强烈建议试一下。梯度累积也能救急,但训练速度会慢一些,适合你这种batch size降太多的情况。另外num_workers别开太多,我一般设4或者8就够,开多了反而容易爆显存,因为DataLoader会缓存一些图片在显存里。还有个小技巧,检查下模型里是不是有额外的dropout或者BN层没冻结,有时候迁移学习忘了设eval模式也会多占显存。你先把混合精度加上,batch size调到24试试,应该能跑起来。
12G跑ResNet50 batch size=32确实有点紧,尤其是224x224输入加DataLoader多进程的话,显存会有额外开销。建议先试试梯度累积,比如设batch size=8、累积4步,效果等效32但显存压力小很多。混合精度也挺管用的,能省将近一半显存,而且训练速度还快。准确率不行可能跟学习率没调有关,batch size变了lr也得跟着动。