PyTorch训练显存越跑越涨,隐式保留计算图导致OOM,怎么办?🔍
- 内容介绍
- 文章标签
- 相关推荐
你有没有遇到过这种情况:PyTorch训练模型时 一开始显存占用还行,但越跑越卡,再说说直接OOM? 是不是? 你是不是也像我一样,盯着屏幕上的“CUDA out of memory”报错,心里一阵阵发毛?
显存越跑越高,这到底是谁的锅?
蚌埠住了... 其实这事儿不完全是PyTorch的错,但它的“锅”也不小。问题出在PyTorch的“计算图”上。你可能没意识到,PyTorch默认会为每个张量保留完整的计算图,哪怕你只是想看看模型输出个啥。这就像你去超市买东西,后来啊收银员非得把每样商品的生产记录都给你背一遍,你说烦不烦?

不错。 而更烦的是这些记录还赖在显存里不走,哪怕你已经用不上它了。于是乎,显存就像吹气球一样,越吹越大,再说说“砰”地一声炸了。
计算图是个啥玩意儿?
简单说计算图就是记录你模型是怎么一步步算出来的。比如你输入x,经过一层层网络,再说说输出y。PyTorch会记住每一步的计算过程,方便你回头求导。但问题是它记住了就不放,哪怕你已经用不着了它还死死攥着不放。这就像你吃完饭,服务员还非得看着你把盘子舔干净,你说气不气,ICU你。?
所以 显存越跑越高,不是你代码写错了而是PyTorch太“记仇”了啥都给你记着,哪怕你已经不想再见到它了,基本上...。
显存爆炸的“罪魁祸首”
我们来列几个“罪魁”:
- retain_graph=True这个参数就像一个“粘人精”, 你一用它,PyTorch就死活不释放计算图,哪怕你已经跑完一个batch了它还赖着不走。
- loss += loss你以为这只是个累加?错!它会把每次的loss都保留下来然后越加越多,再说说显存直接被撑爆。
- logits_buf.append你可能只是想保存一下中间后来啊, 后来啊一不小心把整个计算图都给留了下来显存能不涨吗?
所以别再随便用retain_graph了除非你真的知道自己在干啥。否则, PyTorch会像一个记仇的前女友,把你说过的每句话都记在小本本上,然后等你哪天想不起来的时候,直接给你来个“你忘了我记你仇的时候了”。
解决办法来了别慌!
我们来点实际的,怎么解决?
1. 用完就删, 别留情面
PyTorch的张量就像你家的快递盒子,用完记得扔,别让它堆在那儿发霉。 境界没到。 你得时不时地清理一下别让它在显存里“养老”。
del logits_buf
_cache
这行代码就像你家的“断舍离”大师,帮你把没用的显存给清了。别小看它,关键时刻能救你一命,观感极佳。。
2. no_grad, 别让它瞎记
验证阶段,你明明只是想看看模型输出个啥,后来啊PyTorch还非得给你记个计算图,你说它是不是有病,挽救一下。?
with _mode:
# 验证阶段啥都别记, 只管输出
pass
我个人认为... 这行代码就像你给PyTorch戴了个眼罩,告诉它:“你啥都别记,只管输出。”
3. loss别累加, 别让它“上头”
你可能觉得loss += loss很酷,但其实它就像你家的“老赖”, 胡诌。 越积越多,再说说直接把你显存给撑爆。
loss = loss + new_loss # 错误写法
loss = new_loss # 正确写法
这家伙... 别再搞什么“累加”了 直接覆盖,省得它在显存里“赖着不走”。
PyTorch显存优化工具大比拼
下面这张表, 是我从一堆模型优化工具里挑出来的几个“显存杀手锏”,你看看有没有你中意的:
| 工具名称 | 功能简介 | 显存优化效果 | 推荐指数 |
|---|---|---|---|
| torch.utils.checkpoint | 只在需要时保存中间激活,节省显存 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| torch.no_grad | 验证阶段关闭梯度计算 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 混合精度训练 | 用半精度浮点数减少显存占用 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 显存缓存清理 | 手动释放未使用的显存 | ⭐⭐⭐ | ⭐⭐⭐ |
| 模型并行/数据并行 | 将模型拆分到多个GPU上 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
再说说的忠告
动手。 别再让你的模型“粘人”了显存不是无限的,PyTorch也不是“记仇专业户”。你得时不时地给它“断舍离”一下别让它把你的GPU当成“储物间”。
别怕... 记住显存不是你的敌人,但PyTorch的“记忆”可能是。所以该删就删,该清就清,别让它在你显存里“养老”。
再说说 送你一句忠告:
好吧... 所以 别让它记太多,不然你下次训练,它可能就直接给你来个“CUDA out of memory”。
你有没有遇到过这种情况:PyTorch训练模型时 一开始显存占用还行,但越跑越卡,再说说直接OOM? 是不是? 你是不是也像我一样,盯着屏幕上的“CUDA out of memory”报错,心里一阵阵发毛?
显存越跑越高,这到底是谁的锅?
蚌埠住了... 其实这事儿不完全是PyTorch的错,但它的“锅”也不小。问题出在PyTorch的“计算图”上。你可能没意识到,PyTorch默认会为每个张量保留完整的计算图,哪怕你只是想看看模型输出个啥。这就像你去超市买东西,后来啊收银员非得把每样商品的生产记录都给你背一遍,你说烦不烦?

不错。 而更烦的是这些记录还赖在显存里不走,哪怕你已经用不上它了。于是乎,显存就像吹气球一样,越吹越大,再说说“砰”地一声炸了。
计算图是个啥玩意儿?
简单说计算图就是记录你模型是怎么一步步算出来的。比如你输入x,经过一层层网络,再说说输出y。PyTorch会记住每一步的计算过程,方便你回头求导。但问题是它记住了就不放,哪怕你已经用不着了它还死死攥着不放。这就像你吃完饭,服务员还非得看着你把盘子舔干净,你说气不气,ICU你。?
所以 显存越跑越高,不是你代码写错了而是PyTorch太“记仇”了啥都给你记着,哪怕你已经不想再见到它了,基本上...。
显存爆炸的“罪魁祸首”
我们来列几个“罪魁”:
- retain_graph=True这个参数就像一个“粘人精”, 你一用它,PyTorch就死活不释放计算图,哪怕你已经跑完一个batch了它还赖着不走。
- loss += loss你以为这只是个累加?错!它会把每次的loss都保留下来然后越加越多,再说说显存直接被撑爆。
- logits_buf.append你可能只是想保存一下中间后来啊, 后来啊一不小心把整个计算图都给留了下来显存能不涨吗?
所以别再随便用retain_graph了除非你真的知道自己在干啥。否则, PyTorch会像一个记仇的前女友,把你说过的每句话都记在小本本上,然后等你哪天想不起来的时候,直接给你来个“你忘了我记你仇的时候了”。
解决办法来了别慌!
我们来点实际的,怎么解决?
1. 用完就删, 别留情面
PyTorch的张量就像你家的快递盒子,用完记得扔,别让它堆在那儿发霉。 境界没到。 你得时不时地清理一下别让它在显存里“养老”。
del logits_buf
_cache
这行代码就像你家的“断舍离”大师,帮你把没用的显存给清了。别小看它,关键时刻能救你一命,观感极佳。。
2. no_grad, 别让它瞎记
验证阶段,你明明只是想看看模型输出个啥,后来啊PyTorch还非得给你记个计算图,你说它是不是有病,挽救一下。?
with _mode:
# 验证阶段啥都别记, 只管输出
pass
我个人认为... 这行代码就像你给PyTorch戴了个眼罩,告诉它:“你啥都别记,只管输出。”
3. loss别累加, 别让它“上头”
你可能觉得loss += loss很酷,但其实它就像你家的“老赖”, 胡诌。 越积越多,再说说直接把你显存给撑爆。
loss = loss + new_loss # 错误写法
loss = new_loss # 正确写法
这家伙... 别再搞什么“累加”了 直接覆盖,省得它在显存里“赖着不走”。
PyTorch显存优化工具大比拼
下面这张表, 是我从一堆模型优化工具里挑出来的几个“显存杀手锏”,你看看有没有你中意的:
| 工具名称 | 功能简介 | 显存优化效果 | 推荐指数 |
|---|---|---|---|
| torch.utils.checkpoint | 只在需要时保存中间激活,节省显存 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| torch.no_grad | 验证阶段关闭梯度计算 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 混合精度训练 | 用半精度浮点数减少显存占用 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 显存缓存清理 | 手动释放未使用的显存 | ⭐⭐⭐ | ⭐⭐⭐ |
| 模型并行/数据并行 | 将模型拆分到多个GPU上 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
再说说的忠告
动手。 别再让你的模型“粘人”了显存不是无限的,PyTorch也不是“记仇专业户”。你得时不时地给它“断舍离”一下别让它把你的GPU当成“储物间”。
别怕... 记住显存不是你的敌人,但PyTorch的“记忆”可能是。所以该删就删,该清就清,别让它在你显存里“养老”。
再说说 送你一句忠告:
好吧... 所以 别让它记太多,不然你下次训练,它可能就直接给你来个“CUDA out of memory”。

