RuntimeError: CUDA out of memory. Tried to allocate 50.00 MiB (GPU 0; 4.00 GiB total capacity; 682.9

1. 问题

训练模型时报错:
RuntimeError: CUDA error: out of memory CUDA kernel errors might be asynchronously reported at some other API call,so the stacktrace below might be incorrect. For debugging consider passing CUDA_LAUNCH_BLOCKING=1.
或任务管理器手动释放进程后:
再次训练模型时报错:
RuntimeError: CUDA out of memory. Tried to allocate 50.00 MiB (GPU 0; 4.00 GiB total capacity; 682.90 MiB already allocated; 1.62 GiB free; 768.00 MiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

2. 分析

这种问题,是GPU内存不够引起的

3. 解决

方法一:通过修改代码减少GPU内存使用量

(1)不计算梯度

部分代码:

for x, y in dataload:
    step += 1
    inputs = x.to(device)
    labels = y.to(device)
    # zero the parameter gradients
    optimizer.zero_grad()
    # forward
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    loss.backward()#梯度下降,计算出梯度
    optimizer.step()

在 outputs = model(inputs)那里加上一行代码:with torch.no_grad():

    optimizer.zero_grad()
    # forward
    with torch.no_grad():#添加这行代码
        outputs = model(inputs)#再缩进这行
    loss = criterion(outputs, labels)

说明:对于tensor的计算操作,默认是要计算梯度和进行反向传播的,而torch.no_grad()用来禁止梯度的计算和反向传播,可以减少GPU的内存使用量。在验证和测试阶段不需要计算梯度反向传播,可以添加with torch.no_grad():。在作用域范围内的操作不会计算梯度,也不会进行反向传播。

如果添加上述代码后还不行,那是因为我们前面虽然禁止了计算梯度,但是却没有计算梯度的Variable,因为这里的inputs本身默认就是不求梯度的。所以还会报错:
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

这时需要构建Variable,并传入参数:requires_grad=True,这个参数表示对这个变量求梯度,默认是False。

inputs = x.to(device)
labels = y.to(device)
#添加下面两行代码
inputs = Variable(inputs,requires_grad=True)
labels = Variable(labels,requires_grad=True)

记得还需要在代码最前面添加 from torch.autograd import Variable才能导入Variable

(2)调整Batch Size

还有一种方法就是调整Batch Size(即一次训练所抓取的数据样本数量)的大小,Batch size大小的选择也至关重要。为了在内存效率和内存容量之间寻求最佳平衡,batch size应该精心设置,从而最优化网络模型的性能及速度。
在卷积神经网络中,大的batch size通常可使网络更快收敛,但由于内存资源的限制,batch size过大可能会导致内存不够用,如果GPU内存不够用出现以上情况,可以将Batch Size适当的设置小一点。

BatchSize是非常重要的超参数,它不仅影响训练速度,也影响模型精度。本篇来讨论如何选择BatchSize。

BatchSize是否越大越好?

BatchSize一般指同时代入训练模型的实例个数,最直接的经验是如果GPU显存不大,又设置较大的BatchSize时直接报错“cuda runtime error(2): out of memory”。

是不是只要机器性能允许,就要设置尽可能大的Batch size呢?同时训练多个实例比逐个代入单个实例训练速度又能提高多少?
使用较大的batchSize的确可以提速,但是batchSize大到一定程度后,效果并不十分明显。

如何选择batch大小?

两种极端的情况是BatchSize大小为1,每次只训练一个实例,或者BatchSize大小等于所有训练集数据大小,即每次训练所有数据。但更多的时候BatchSize设置在二者之间。

batchSize较小时,抖动大,训练过程有很大运气的成份,可能某个实例将模型带偏了,防止被模型被带偏的方法是使用较小的学习率,这样即非并行处理,又使用较小的学习率,使得收敛变慢。

batchSize较大时,任务并行执行,训练速度快, 且大Batch正负样本更均衡可以有效更新BN层参数精度更高。代价函数也能相对比较稳定,平滑地下降。但是如果代入了所有数据后再调参,可能会使很多梯度相互抵消,调参也比较粗糙。如果不进行特殊处理,过大的BatchSize一将会损失模型精度。另外,较大的batchSize会使模型的泛化能力下降(generalization gap)。

如果遇到较大的数据集,一般需要切分成batch分批训练,对于较少的数据,也可以使用全部数据训练。当有足够算力时,选取BatchSize为32,64,128或更小一些的batch_size。算力不够时,在效率和泛化性之间做权衡,选择更小的batchSize。

在训练过程中,可以将batch_size作为超参数做多次尝试。另一方面,也可以在前期使用较大的学习率和较越BatchSize粗调,后期(比如论文实验/比赛最后)将BatchSize变小精调,并使用SGD优化方法,慢慢把Error磨低。

BatchSize是否只与速度有关?

BatchSize不仅与速度相关,如果模型中使用了Batch Normalization(BN)归一化方法,那么太小的BatchSize会影响模型效果,如果受算法或性能限制只能使用小的BatchSize,则建议在fine-tune时锁住BN归一化层,或者使用其它归一化方法(如Group Normalization)。

Batch Normalization works well for large enough batch sizes but not well for small batch sizes, because it normalizes over the batch. Training large models with large batch sizes is not possible due to the memory capacity of the devices.

另外,BN归一化时的统计值针对每一Batch计算,而非对整个训练集计算,从而引入了噪声,当噪声在合理范围以内时,它能实现类似Dropout的效果,使模型更加健壮;BatchSize太小噪声太大,则使模型效果变差;如果BatchSize太大,统计值能有效地表示整体训练数据的统计数据,则无法产生类似Dropout的正则化效果。

BatchSize与Learning rate的关系

Krizhevsky提出,如果BatchSize加大,可以加大学习率,当BatchSize加大k倍,则学习率也加大k的开根号位数,后来发现使用线性变换调节二者关系效果更好。用这种方法将AlexNet的BatchSize从128加大到1024精度只损失1%。但是太大的学习率又会在一开始使模型训练不稳定,解决该问题的方法是学习率warm-up。

方法二:更换更高性能更高显存的显卡

这样所有问题都解决了。

方法三:租用云服务器进行训练

这个后面有空单独出一期讲。

  • 35
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
模型推理中出现"RuntimeError: CUDA out of memory"错误是因为在GPU上使用的显存不足。这个错误通常发生在模型的输入数据量过大或模型占用的显存资源过多时。 解决这个问题可以采用以下方法: 1. 减少批处理大小:可以通过减少每次推理时的图像批处理大小来减少内存消耗。较小的批处理大小会减少每个批处理所需的显存量。 2. 减少模型的参数量:如果模型的参数量过大,可以尝试减少参数量来缓解显存不足的问题。可以通过减少模型的深度、宽度或者使用降低维度的技术(如降低卷积核的尺寸)来减少参数量。 3. 使用更高效的模型:可以考虑使用比原始模型更加轻量级和高效的模型结构。例如,可以使用MobileNet、EfficientNet等模型来代替较重的ResNet、VGG等模型。 4. 降低精度:可以尝试将模型的参数精度从32位浮点数降低为16位浮点数,以减少显存的使用量。这通常不会对模型的性能产生显著的影响,但会大幅度减少显存的使用。 5. 使用更大的显存:如果以上方法无法解决问题,可以考虑更换具有更大显存容量的GPU设备来运行模型推理。 总之,修复"RuntimeError: CUDA out of memory"错误的主要思路是通过减少模型参数量、降低精度、优化模型结构或减少输入数据量来减少GPU显存的使用。根据具体问题情况选择适当的解决方法,以确保模型能够在GPU上正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yuezero_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值