【问题标题】:How to avoid "CUDA out of memory" in PyTorch如何避免 PyTorch 中的“CUDA 内存不足”
【发布时间】:2020-03-26 12:40:49
【问题描述】:

我认为对于 GPU 内存不足的 PyTorch 用户来说,这是一条很常见的信息:

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

我想为我的课程研究对象检测算法。而且许多深度学习架构需要大容量的 GPU 内存,所以我的机器无法训练这些模型。我尝试通过将每一层加载到 GPU 然后再加载来处理图像:

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

但它似乎不是很有效。我想知道在使用少量 GPU 内存的同时训练大型深度学习模型是否有任何提示和技巧。提前致谢!

编辑:我是深度学习的初学者。如果这是一个愚蠢的问题,请道歉:)

【问题讨论】:

  • 笑脸是怎么回事?大声笑..另外,减少你的批量大小和/或训练更小的图像。查看 Apex 库以进行混合精度训练。最后,例如,当将批量大小减小到 1 时,您可能希望在每次迭代后推迟将梯度设置为零,因为它仅基于单个图像。
  • 我在使用 Kaggle 时遇到了同样的问题。它适用于 64 批次,然后一旦我尝试 128 并得到错误,则没有任何效果。即使是64批次也给了我同样的错误。尝试重置几次。 torch.cuda.empty_cache() 没用。而是先禁用 GPU,然后重新启动内核,然后重新激活 GPU。这对我有用。
  • 减少提供给模型的数据的批量大小。为我工作

标签: python deep-learning pytorch object-detection low-memory


【解决方案1】:

虽然,

    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 内存不足的原因并重新启动内核以避免再次发生错误(就像我在我的案例中所做的那样)。

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

【讨论】:

  • This gives a readable summary of memory allocation and allows you to figure the reason of CUDA running out of memory。我打印了torch.cuda.memory_summary() 调用的结果,但似乎没有任何信息可以导致修复。我看到Allocated memoryActive memoryGPU reserved memory 等的行。我应该看什么,我应该如何采取行动?
  • 我有一台带有 MX130 和 16GB 内存的小型笔记本电脑。合适的批量为 4。
  • @stackoverflowuser2010 你应该在函数调用之间打印出来,看看哪一个导致内存增加最多
【解决方案2】:

只需减少批量大小,它就会起作用。 当我在训练时,它给出了以下错误:

CUDA 内存不足。尝试分配 20.00 MiB(GPU 0;10.76 GiB 总容量; 4.29 GiB 已分配; 10.12 MiB 免费; 4.46 GiB PyTorch 总共保留)

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

【讨论】:

    【解决方案3】:

    以迭代方式将批次发送到 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

    【讨论】:

    • 如果我运行一个多次开始训练的单元格,我会在 jupyter 笔记本中收到此错误消息。重新启动内核可以解决这个问题,但如果我们能以某种方式清除缓存会很好......例如,torch.cuda.empty_cache() 目前没有帮助。即使它可能应该...... :(
    【解决方案4】:

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

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

    loss =  self.criterion(pred, label)
    
    total_loss += loss
    

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

    loss =  self.criterion(pred, label)
    
    total_loss += loss.item()
    

    下面的解决方案归功于kaggle question中的yuval reina

    此错误与 GPU 内存有关,而不是一般内存 => @cjinny 评论可能不起作用。
    你使用 TensorFlow/Keras 还是 Pytorch?
    尝试使用较小的批量大小。
    如果您使用 Keras,请尝试减少一些隐藏层大小。
    如果你使用 Pytorch:
    您是否一直将所有训练数据保存在 GPU 上?
    确保不要把毕业生拖得太远
    检查隐藏层的大小

    【讨论】:

      【解决方案5】:

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

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

      此外,如果您想重新训练模型,则必须再次进行垃圾收集和清理缓存部分。

      【讨论】:

      • 我正在训练 NLP 模型并且批量大小为 2。更改为 1 并且它有效。
      【解决方案6】:

      按照以下步骤操作:

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

      在我的例子中,当我在 kaggle 内核中训练通用语音数据集时,也会出现同样的错误。我将训练数据集减少到 20000,批量大小减少到 16,模型参数减少到 112K。

      【讨论】:

        【解决方案7】:

        实施:

        1. 将图像分批输入gpu。

        2. 在训练或推理期间使用小批量。

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

        技术上:

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

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

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

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

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

            【解决方案9】:

            有一些方法可以避免,但这当然取决于你的 GPU 内存大小:

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

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

            【讨论】:

              【解决方案10】:

              虽然这看起来很奇怪,但我发现有许多会话在后台运行以进行协作,即使我们将运行时重置为出厂设置或关闭选项卡也是如此。我通过单击菜单中的“运行时”然后选择“管理会话”来克服这个问题。我终止了所有不需要的会话,一切顺利。

              【讨论】:

                【解决方案11】:

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

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

                【讨论】:

                  【解决方案12】:

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

                  pip install koila
                  

                  在您的代码中,只需用惰性包装输入:

                  from koila import lazy
                  input = lazy(input, batch=0)
                  

                  【讨论】:

                  • pip install koila 仍然给我ModuleNotFoundError: No module named 'koila',即使在重新启动并全部运行之后
                  • 听起来您安装到了不同的环境中。试试which pipwhich pythonwhich python3which pip3,看看你是如何运行你的python代码的,这应该可以说明发生了什么。
                  【解决方案13】:

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

                  【讨论】:

                    【解决方案14】:

                    最好的方法是降低批量大小。通常它会起作用。否则试试这个:

                    import gc
                    
                    del variable #delete unnecessary variables 
                    gc.collect()
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-12-16
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-06-12
                      • 2021-12-03
                      • 2020-03-21
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多