调试GPU问题——看看你的GPU到底在干什么?

本文探讨了在训练大型深度学习模型时遇到GPU内存不足的问题,介绍了如何使用nvidia-smi检查GPU使用情况,并通过删除不再需要的张量和利用Python的垃圾回收来释放内存。当这些方法仍不足以解决问题时,文章提出使用梯度检查点技术,通过分段计算来减少GPU上的中间状态,从而允许更大的批量大小,虽然会增加计算时间。PyTorch中的torch.utils.checkpoint.checkpoint_sequential()函数用于实现这一策略,允许在不影响模型性能的前提下训练更大的模型。文章还提醒,对于BatchNorm和Dropout层,需要特别注意其在检查点技术中的使用位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们来谈谈使用GPU时,常常会面临的一个内存不足的问题,以及如何解决。
当我们在训练较大的深度学习模型时,你很快就会发现,你花了那么多钱买的炫酷的GPU(或者可能更明智地使用了云实例上的GPU)会经常出问题,总是抱怨内存不足。不过,要知道GPU有数GB的内存!怎么可能不足呢?
模型往往会占用大量内存。例如,ResNet-152有约6000万激活,所有这些都会占用GPU上宝贵的空间。下面我们来看看GPU内部,确定内存不足时可能在做什么。
检查GPU
如果你使用了一个NVIDIA GPU(如果你使用的是其他显卡,需要查看该GPU供应商的驱动程序网站来得到相应工具),CUDA安装包含有一个很有用的命令行工具,名为nvidia-smi。运行时如果没有提供参数,这个工具会给出GPU上所用内存的一个快照,更好的一点是,还会给出谁在使用这些内存。
如果确定认为你的GPU占用的内存超过了应有的使用量,可以尝试让Python的垃圾回收器介入。如果有一个不再需要的tensor_to__be_deleted,你想将它从GPU删除,fast.ai库提供的方法是用del删除:

import gc
del tensor_to_be_deleted
gc.collect()

梯度检查点
尽管可以使用上一节的删除和垃圾回收技巧,但你可能还是发现内存不足。对于大多数应用来说,但是这样一来,就会增加每个epoch的训练时间,而且与有足够内存来处理更大批量数据的模型相比,这个模型可能稍逊一筹,因为,前者每次传播可以看到数据集中的更多数据。不过,在PyTorch中可以使用梯度检查点(gradient checkpointing),用计算量为大模型换取内存。
处理更大的模型时,问题之一就是前向和反向传播会创建大量中间状态,所有这些都会占用GPU内存。内存检查点的目的就是通过分段(segmenting)减少可能存放在GPU上的状态数量。这个方法意味着,模型的批量大小可以达到非分段模型的4到10倍,但与此同时,训练的计算量更大。在前向传播中,PyTorch将输入和参数存储到一个分段,但本身并不具体完成前向传播。在反向传播中,由PyTorch获取这些输入和参数,为该分段计算前向传播。中间值传递到下一个分段,但这些只能一个分段一个分段地完成。
将一个模型切分为这些分段是由torch.utils.checkpoint.checkpoint_sequential()处理的。它作用于nn.Sequential层或生成的层列表,条件是需要按照它们在模型中出现的顺序进行处理。
为了更清楚的说明,这里放一段代码进行说明:

from torch.utils.checkpoint import chechpoint_sequential
sefl.avgpool=nn.AdaptiveAvgPool2d((6,6))
self.classifier=nn.Sequential(
     nn.Dropout(),
     nn.Linear(256*6*6,4096),
     nn.ReLU(inplace=True),
     nn.Dropout(),
     nn.Linear(4096,4096),
     nn.ReLU(inplace=True),
     nn.Linear(4096,num_classes),
)
def forward(self,x):
  x=checkpoint_sequential(self.features,chunks,x)
  x=self.avgpool(x)
  x=x.view(x.size(0),256*6*6)
  x=self.classifier(x)
  return x

可以看到,这里并没有太多不同,所以必要时,可以很容易地为模型增加检查点。我们为这个新版本的模型增加一个chunks参数,默认地将它分为两个分段。然后所要作的就是调用checkpoint_sequential并传入features模块,分段数以及我们的输入。
检查点技术有一个小问题:对于BatchNorm或者Dropout层,它的表现不太好,原因在于这些层于前向传播的交互方式。为了避免这个问题,可以对这些层之前或者之后的模型部分增加检查点。在我们的ChenckpointedAlexNet中,可以把classifier模块分解为两部分:包含Dropout层的部分不加检查点,另一个部分是最后的一个nn.Sequential模块(其中包含我们的Linear层),可以像前面对features一样对同样的方式对这个模块增加检查点。
如果你发现,为了让一个模型运行,你要减少批量大小,再要求得到更大的GPU之前,可以先考虑使用检查点技术!
:文章选自《基于PyTorch的深度学习》Ian Pointer著

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毛毛真nice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值