最近在跑一个简单的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跑224的ResNet50,batch32确实有点悬,换mixed precision加梯度累积试试,效果立竿见影。
12G跑224的resnet50开32确实紧,先开AMP试试,能省一半显存。
梯度累积治标不治本,建议换AdamW加mixup,8的batch也能练出效果。
3060 12G跑224的ResNet50,32的batch确实不太够,降到16加混合精度基本就能稳。
梯度累积也行,但本质还是等效小batch,准确率掉了不奇怪。
这卡12G跑ResNet50按理说没问题,先查查是不是梯度没清零或者优化器参数搞错了。
反正我当年直接开AMP(自动混合精度)加梯度累积,显存立马就降下来了,你这情况八成是batch开猛了。
12G跑ResNet50加224尺寸,batch32按理说真不至于爆,你查下是不是把梯度也存了或者有个什么变量没detach,我之前遇到过类似情况是验证集里忘关grad导致显存持续累积。混合精度确实有效,AMP一开基本能省一半,但前提是你得把cudnn.benchmark设成True,不然速度反而更慢。梯度累积适合你这种batch降下来但想保持等效大batch的场景,不过注意要手动除一下loss。准确率不行大概率不是batch size的锅,你检查下学习率是不是没跟着调,迁移学习用0.001起始就挺稳的。
你这配置跑32按理说真不该炸,先检查下是不是把验证集也一起塞进显存了,或者梯度的backward没设retain_graph。混合精度(AMP)在3060上提升明显,能省一半左右显存,梯度累积的话相当于变相减小batch size,但注意要和bn层配合好。另外num_workers别开太大,8个就够,多试几组batch size找找甜点区,准确率低可能跟学习率没调有关,跟batch size关系不大。
12G跑ResNet50加224输入,batch32按理说真能挤一挤,问题大概率出在验证阶段或者梯度回传时把中间变量全攒住了。你试试把pin_memory关掉,或者用torch.cuda.empty_cache()在每轮清一下,说不定能好不少。混合精度我个人觉得是立竿见影的,尤其3060有Ampere架构加持,开了之后显存直接砍半,速度也上去。至于梯度累积,救急可以但感觉你这种情况不如先查查代码里有没有把整个数据集tensor一次性丢进GPU的骚操作。准确率不行可能不是显存问题,先跑通再调参吧。
12G跑ResNet50加224分辨率,batch32按理说真不至于爆,你检查下是不是在验证阶段也把梯度打开了,或者模型没切eval模式。混合精度确实立竿见影,显存能省一半,训练速度还快,梯度累积适合你这种小batch想模拟大batch的情况。另外num_workers跟显存没关系,但开太多容易爆内存,8到16就够用。准确率不行大概率是学习率没跟着batch size调,降batch后lr也得相应降。
12G跑ResNet50加224的输入,batch32按理说不是特别极限,但你这情况大概率不是num_workers的锅,那个只影响数据加载的CPU内存和速度,跟显存占用关系不大。我怀疑你可能是没关梯度或者模型里带了BN的running stats更新,但更常见的坑是——你是不是在训练模式里把整个验证集也一起塞进显存了?或者你用了torch.no_grad但没切model.eval(),导致验证时还是保留了中间变量。
混合精度(AMP)是真的立竿见影,显存直接砍半,而且3060的Tensor Core支持得挺好,训练速度还能提一截。梯度累积的话,本质是拿时间换空间,如果你batch8能跑,累积4步等效32,效果会比直接batch8好很多,但训练时间不会缩短。另外你试试把pin_memory关掉,有时候这个也会多占一些显存,虽然不多但可能就差那么一点。
准确率不行可能不是batch size的锅,迁移学习的话lr要调小,1e-4到1e-5之间,还有可能是你只冻了backbone没冻BN层,或者数据增强太激进。先开AMP,batch设16,累积2步,看看显存能不能扛住,同时把num_workers降到4,基本能解决你的问题。如果还炸,那就检查一下是不是有哪里写了loss.backward()之后没清梯度,或者有奇怪的hook在跑。
3060 12G跑ResNet50加224分辨率,batch32按理说真不该炸,我怀疑是你验证阶段没关梯度计算,或者混合精度没开但模型里用了FP32的BN层导致的额外开销。我之前用同款卡跑类似任务,把amp和gradient accumulation加上,batch32直接稳过,速度还快了一倍。另外num_workers其实不占显存,但如果你用了pin_memory=True又不开non_blocking,反而可能让内存交换变慢,显存碎片化。你试试先只开amp,不行再检查一下DataLoader里是不是把整个数据集都load进显存了。
12G跑ResNet50加224分辨率,batch32按理说真不该炸,先检查下是不是pin_memory或者验证阶段忘了关梯度,这俩坑我踩过。混合精度我试过,显存直接砍一半,训练速度还提升,你装apex或者用torch自带的amp试试。梯度累积对显存没用,只是等效增大batch,你这种情况不如直接开gradient checkpointing。还有,如果准确率因为batch变小就掉,可能学习率没跟着调,8的batch对应lr也得降一截。
12G跑ResNet50加224的输入,batch32按理说确实不该爆,但你要是开了混合精度又没设torch.cuda.amp的GradScaler,或者用了BN的momentum默认值,有时候会莫名多占一些显存。先把num_workers降到4试试,这玩意儿真不是越多越好,还有检查下是不是把验证集的梯度也保留了。混合精度和梯度累积肯定有用,尤其梯度累积基本等于白嫖大batch,但注意学习率得相应调大,不然收敛慢。准确率不行大概率是学习率没配好,跟batch size关系不大,先跑个小的过拟合测试看看模型对不对。
12G跑ResNet50加224分辨率,batch32确实有点紧,但直接炸说明可能没开混合精度,AMP能省将近一半显存,试过就知道差别很大。梯度累积也能缓解,但本质是拿时间换空间,你降到8能跑就别急着上累积,先看准确率是不是数据增强或学习率的问题。另外num_workers跟显存没关系,那玩意儿只影响CPU加载速度,别甩锅给它。建议先开AMP加torch.no_grad评估一下,显存占用能下来一大截,再慢慢调batch。
3060 12G跑ResNet50 batch 32按理说真不该爆,先查下是不是pin_memory或者transform里不小心把图像归一化写成了保留float64,我之前就栽在这上面。混合精度确实立竿见影,直接开AMP能省一半多显存,梯度累积对显存没用但能救收敛效果。另外别忽略num_workers,开太多会占额外显存但影响没那么大,主要还是检查下模型有没有误开梯度或缓存。建议先用batch 16+AMP跑通,再逐步往上加,准确率不行大概率是学习率没跟着调。
12G跑224的ResNet50,batch32确实紧,开AMP和梯度累积基本能稳,顺便查下pin_memory别开太大。
12G跑ResNet50加224分辨率,batch32按说真不该爆,你检查下是不是开了pin_memory又叠加了验证集的loader,这俩经常一起把显存顶爆。混合精度我试过,显存能砍一半还多,训练速度也上去不少,你这情况属于典型该上AMP的。梯度累积其实也能救,但别一上来就堆大累积步数,会拖慢收敛。要不先试试把验证集也砍成batch16,顺便关掉pin_memory看看,很多时候问题就出在这种小细节上。
12G跑224的ResNet50按理说真够,你降到8才勉强过大概率不是batch的问题,先看看是不是在backbone里没冻结BN或者梯度传到了所有层。混合精度和梯度累积对显存是真的立竿见影,尤其AMP基本无损速度还快,建议先开AMP再试batch 32。另外DataLoader的num_workers跟显存没关系,那是CPU的事,别甩锅给它。如果还炸,检查下是不是验证阶段也算了梯度,或者有没有不小心把整个数据集都load进显存里。
3060 12G跑ResNet50加224输入,batch 32按理说真不至于爆,你先把DataLoader的num_workers调成0试试,有时候多进程加载反而会占额外显存。混合精度肯定要开,amp那几行代码能省将近一半显存,训练速度还能提上去。另外你迁移学习是不是没冻结前面几层?全量微调的话梯度占显存很大,先freeze backbone只训分类头,稳得很。准确率低跟batch size关系不大,看看学习率是不是没跟着调。
12G跑ResNet50加224的输入,batch32按理说确实够,但你这情况更像是DataLoader的pin_memory和num_workers叠加导致的显存碎片化,先把workers降到4试试。混合精度是真的有用,我3070跑类似任务直接开AMP,显存能省快一半,而且精度基本不掉。梯度累积的话,如果你不是特别在意训练速度,凑个等效batch也行,但我更建议你查下模型里是不是忘了加zero_grad,或者把验证集的梯度也保留下来了。另外,准确率不行跟batch大小关系不大,你降到8跑慢是正常的,但精度问题可能出在迁移学习的冻结层或者学习率上,建议单独排查下。
12G跑ResNet50加224分辨率,batch32按理说真不至于直接爆,但你这情况我太熟了,八成不是单纯batch size的问题。你先看看是不是在验证阶段也把梯度打开了,或者模型里不小心加了什么大的中间变量没detach,这俩是显存泄露最常见的坑。另外num_workers跟显存其实关系不大,那玩意儿主要吃CPU内存,你把workers调高反而可能因为数据加载快把GPU喂得更满。混合精度确实立竿见影,尤其你3060有Tensor Core,开个AMP显存能省将近一半,训练速度还能上去。梯度累积也行,但只解决batch size不够大的问题,不会减少单步显存峰值,你不如先把batch降到16配合AMP试试。还有个野路子,把图片resize到192或者用RandomResizedCrop,显存压力会小很多,准确率掉得也有限。最后检查下PyTorch版本和CUDA版本匹配不匹配,有时候老版本有显存碎片化问题,升级一下能缓解。别自闭,这问题基本人人都踩过。