如何在 PyTorch 中避免 "CUDA out of memory"

How to avoid "CUDA out of memory" in PyTorch

我认为对于 GPU 内存较低的 PyTorch 用户来说,这是一个很常见的消息:

RuntimeError: CUDA out of memory. Tried to allocate  MiB (GPU ;  GiB total capacity;  GiB already allocated;  MiB free;  cached)

我尝试通过将每一层加载到 GPU 然后再加载回来来处理图像:

for m in self.children():
    m.cuda()
    x = m(x)
    m.cpu()
    torch.cuda.empty_cache()

不过好像不是很有效。我想知道在使用少量 GPU 内存的同时训练大型深度学习模型是否有任何提示和技巧。

将批次迭代地发送到 CUDA,并制作小批量。一开始不要将所有数据一次发送到 CUDA。相反,按如下方式进行:

for e in range(epochs):
    for images, labels in train_loader:   
        if torch.cuda.is_available():
            images, labels = images.cuda(), labels.cuda()   
        # blablabla  

您还可以使用占用较少内存的 dtypes。例如,torch.float16torch.half.

虽然

import torch
torch.cuda.empty_cache()

为清除占用的cuda内存提供了一个很好的选择,我们也可以通过使用手动清除未使用的变量,

import gc
del variables
gc.collect()

但是仍然在使用这些命令之后,错误可能会再次出现,因为pytorch并没有真正清除内存而是清除了对变量占用的内存的引用。 所以在重启内核后减少 batch_size 并找到最佳 batch_size 是最好的选择(但有时不是一个非常可行的选择)。

另一种深入了解 gpu 内存分配的方法是使用:

torch.cuda.memory_summary(device=None, abbreviated=False)

其中,两个参数都是可选的。这给出了内存分配的可读摘要,并允许您找出 CUDA 运行 内存不足的原因并重新启动内核以避免错误再次发生(就像我在我的情况下所做的那样)。

迭代传递数据可能会有所帮助,但改变网络层的大小或将它们分解也会被证明是有效的(因为有时模型也会占用大量内存,例如,在进行迁移学习时)。

只需减小批量大小,即可奏效。 在我训练时,出现以下错误:

CUDA out of memory. Tried to allocate 20.00 MiB (GPU 0; 10.76 GiB total capacity; 4.29 GiB already allocated; 10.12 MiB free; 4.46 GiB reserved in total by PyTorch)

我使用的批量大小为 32。所以我将其更改为 15,它对我有用。

实施:

  1. 将图像逐批输入gpu。

  2. 在训练或推理过程中使用小批量。

  3. 使用较小的图像尺寸调整输入图像的大小。

技术上:

  1. 大多数网络都过度参数化,这意味着它们对于学习任务来说太大了。所以找到一个合适的网络结构可以帮助:

一个。使用模型压缩、网络修剪和量化等技术压缩您的网络。

b。直接使用更紧凑的网络结构如mobileNetv1/2/3.

c。网络架构搜索(NAS)。

最好的方法是降低批量大小。通常它有效。否则试试这个:

import gc

del variable #delete unnecessary variables 
gc.collect()

尽量不要把你的毕业生拖得太远。

当我试图总结所有批次的损失时,我遇到了同样的错误。

loss =  self.criterion(pred, label)

total_loss += loss

然后我用loss.item代替需要grads的loss,然后解决了问题

loss =  self.criterion(pred, label)

total_loss += loss.item()

以下解决方案归功于yuval reina in the kaggle question

This error is related to the GPU memory and not the general memory => @cjinny comment might not work.
Do you use TensorFlow/Keras or Pytorch?
Try using a smaller batch size.
If you use Keras, Try to decrease some of the hidden layer sizes.
If you use Pytorch:
do you keep all the training data on the GPU all the time?
make sure you don't drag the grads too far
check the sizes of you hidden layer

有很多方法可以避免,但这当然取决于您的 GPU 显存大小:

  1. 迭代解包数据时在GPU中加载数据,
features, labels in batch:
   features, labels = features.to(device), labels.to(device)
  1. 使用 FP_16 或单精度浮点数据类型。
  2. 如果 运行 内存不足,请尝试减小批量大小。
  3. 使用 .detach() 方法从 GPU 中删除不需要的张量。

如果以上所有都使用得当,PyTorch 库已经是高度优化器和高效的。

我有同样的错误,但通过使用以下行将我的图像从 ~600 调整为 100 来修复它:

import torchvision.transforms as transforms
transform = transforms.Compose([
    transforms.Resize((100, 100)), 
    transforms.ToTensor()
])

按照以下步骤操作:

  1. 减少训练、验证、测试数据
  2. 减少批量大小{例如。 16 或 32}
  3. 减少模型参数的数量{例如。不到百万}

就我而言,当我在 kaggle 内核中训练普通语音数据集时,会出现相同的错误。我决定将训练数据集减少到 20000,批量大小减少到 16,模型参数减少到 112K。

虽然这看起来很奇怪,但我发现即使我们恢复出厂设置运行时或关闭选项卡,后台仍有许多会话 运行 用于协作。我通过单击菜单中的“运行时”然后选择“管理会话”来解决这个问题。我终止了所有不需要的会话,一切顺利。

我建议使用 PyTorch 进行混合精度训练。它可以使训练速度更快并消耗更少的内存。

看看https://spell.ml/blog/mixed-precision-training-with-pytorch-Xuk7YBEAACAASJam

大部分内容都涵盖了,还会补充一点。

如果 torch 给出错误如“已尝试分配 2 MiB”等,这是误导性消息。实际上,CUDA 用完了训练模型所需的总内存。您可以减少批量大小。比如说,即使 1 的批量大小不起作用(当你训练具有大量序列的 NLP 模型时发生),尝试传递较少的数据,这将帮助你确认你的 GPU 没有足够的内存来训练模型。

此外,如果你想重新训练模型,垃圾收集和清理缓存部分必须重新完成。

现在有一个非常棒的库使这变得非常简单:https://github.com/rentruewang/koila

pip install koila

在您的代码中,只需使用 lazy:

包装输入
from koila import lazy
input = lazy(input, batch=0)

只要不超过 32 的批量大小,就可以了。请记住刷新或重新启动运行时,否则即使减小批处理大小,也会遇到相同的错误。 我将批量大小设置为 16,它减少了训练期间出现的零梯度,并且模型与真实函数的匹配度更高。而不是使用 4 或 8 的批量大小,这会导致训练损失波动

我遇到同样的错误,我的GPU是GTX1650,显存4G,内存16G。当我将 batch_size 减少到 3 时,它对我有用。 希望对您有所帮助