最近在跑一个图像分割的模型,用的DeepLabV3+,backbone是ResNet101。我把batch_size降到2了,输入图片也缩到256x256,但显存还是从开始的2G一直涨到12G,最后OOM。我查了网上说可能是梯度累积、或者变量没detach的问题,但我没开梯度累积,损失函数也是常用的CrossEntropy。想问问大家有没有什么成熟的debug思路?比如用torch.cuda.memory_summary()看哪里泄露,或者有没有工具能可视化每层的显存占用?另外,是不是我模型里有循环或者多次forward导致的?感谢各位大佬!
PyTorch训练时显存一直涨但batch_size已经很小了,咋排查?
全部回复
共 189 条DeepLabV3+配ResNet101确实吃显存,但涨到OOM大概率是哪里在累积计算图,不一定是模型本身的问题。你试试在训练循环里每个step都print一下torch.cuda.memory_allocated(),看是稳定增长还是突然跳,这样能判断是慢慢泄漏还是某一步炸的。另外检查下有没有在循环里存loss或者输出到list里,这种很容易忘,尤其做可视化的时候。还有验证阶段记得加torch.no_grad(),不然也会一直堆图。
你这情况听着挺像典型的显存泄漏,但也不一定就是真泄漏,有可能是PyTorch缓存分配器在作怪。先别急着怀疑模型结构,建议你在训练循环里每个epoch结束后打印一下torch.cuda.memory_allocated()和torch.cuda.memory_reserved(),看看allocated是不是稳定,如果allocated一直在涨那才是真有问题,如果只是reserved涨那可能只是缓存没释放,设个torch.cuda.empty_cache()试试。另外DeepLabV3+里如果有ASPPLayer或者多次上采样操作,中间特征图很容易堆积,尤其你backbone是ResNet101,参数量本身就不小。可以试试用torch.cuda.memory_summary()看一下具体是哪一层占的最多,或者装个torchviz画一下计算图,看看有没有意外的重复forward。还有一个容易忽略的点是验证阶段忘了加torch.no_grad(),或者你在训练里调用了model.eval()之后又忘了切回train,这些都会让计算图越积越多。如果这些都没问题,那可以试试把损失函数换成带reduction='sum'的版本手动除batch_size,有时候框架内部实现也会偷偷保留中间变量。
这种情况八成是计算图没释放,比如在循环里累加了loss或者把中间变量存进了list。建议先跑几个iter就调一下torch.cuda.memory_summary(),看allocated和reserved差多少,涨得快的基本就是泄露点。另外DeepLabV3+的ASPP里如果有多次forward同一个tensor,记得包在with torch.no_grad()里,不然图会越叠越大。
你这种情况八成是validation或者log里还在建计算图,比如验证阶段忘了加torch.no_grad(),或者把loss存进list里累计着。我之前也遇到过显存慢慢涨,最后发现是tensorboard把带图的loss给写进去了。建议先跑几个iter就打印memory_summary,看allocated和reserved哪个在飙,基本能定位是缓存还是真泄漏。另外DeepLabV3+的ASPP里如果有BN,batch太小也可能有影响,但不太像主因。
这个显存持续涨最后OOM的情况,八成是计算图没释放掉。你可以先试试在训练循环里每个step结束后手动加一句 del loss,然后 torch.cuda.empty_cache(),看看显存曲线是不是还往上飙。不过更常见的坑是你在验证或者可视化阶段又跑了一次forward,但忘了加 torch.no_grad(),这样每次迭代都会把新计算图挂在内存里,涨到12G太正常了。DeepLabV3+本身ResNet101加上ASPP,特征图占的显存不小,但batch 2加256分辨率真不至于一开始就爆,所以大概率还是累积型泄漏。建议用 torch.cuda.memory_summary(device=None, abbreviated=False) 打印一下,重点看 allocated 和 reserved 的差值,如果 reserved 远大于 allocated,说明碎片或缓存没回收。另外你可以装个 torch.cuda.memory._record_memory_history() 配合可视化工具看快照,能直接定位到哪一行代码在反复分配。还有个容易忽略的点:如果用了类似 poly 学习率或者自定义 scheduler,里面存了tensor引用也会拖住计算图。我上次就是在一个logger里把loss直接append进list了,结果整个图被持有,删掉就好了。
显存从2G涨到12G最后OOM,这个涨幅不太像是单纯碎片化,更像是哪里留了计算图没释放。你检查下训练循环里有没有把loss或中间变量存到list里做日志,这种最容易悄悄hold住整个图。另外DeepLabV3+的ASPP里dilation rate大,中间激活本身就挺吃显存,配合AMP跑一下能省不少。torch.cuda.memory_summary()可以看allocated和reserved的差值,如果reserved远大于allocated基本就是碎片问题,设个PYTORCH_CUDA_ALLOC_CONF能缓解。
显存一路涨到OOM,八成是某个地方把计算图留住了。重点查一下你的loss是不是累加到了列表里,或者验证阶段忘了加torch.no_grad(),这两个坑我踩过好几次。可以装个torch.cuda.memory_summary()打一下快照,再配合pytorch_memlab按行看,基本能定位到是哪一层在漏。另外DeepLabV3+的ASPP里如果有循环反复forward同一批数据,也容易出这问题,建议先跑一个iter看显存稳不稳。
学到了,感谢分享!
学到了,感谢分享!