GPU 显存不足时的Trick

  • 降低batch size
    这应该很好理解,适当降低batch size, 则模型每层的输入输出就会成线性减少, 效果相当明显。

  • 选择更小的数据类型
    一般默认情况下, 整个网络中采用的是32位的浮点数,如果切换到 16位的浮点数,其显存占用量将接近呈倍数递减。

  • 精简模型
    在设计模型时,适当的精简模型,如原来两层的LSTM转为一层; 原来使用LSTM, 现在使用GRU; 减少卷积核数量; 尽量少的使用 Linear 等。

  • 数据角度
    对于文本数据来说,长序列所带来的参数量是呈线性增加的, 适当的缩小序列长度可以极大的降低参数量。

  • total_loss
    考虑到 loss 本身是一个包含梯度信息的 tensor, 因此,正确的求损失和的方式为:

total_loss += loss.item()
  • Relu 的 inplace 参数
    激活函数 Relu() 有一个默认参数 inplace ,默认为Flase, 当设置为True的时候,我们在通过relu() 计算得到的新值不会占用新的空间而是直接覆盖原来的值,这表示设为True, 可以节省一部分显存。

  • 梯度累积
    首先, 要了解一些Pytorch的基本知识:
    在Pytorch 中,当我们执行 loss.backward() 时, 会为每个参数计算梯度,并将其存储在 paramter.grad 中, 注意到, paramter.grad 是一个张量, 其会累加每次计算得到的梯度。
    在 Pytorch 中, 只有调用 optimizer.step()时才会进行梯度下降更新网络参数。
    我们先来看看传统训练:

for i,(feature,target) in enumerate(train_loader):
    outputs = model(feature)  # 前向传播
    loss = criterion(outputs,target)  # 计算损失

    optimizer.zero_grad()   # 清空梯度
    loss.backward()  # 计算梯度
    optimizer.step()  # 反向传播, 更新网络参数

而加入梯度累加之后,代码是这样的:

for i,(features,target) in enumerate(train_loader):
    outputs = model(images)  # 前向传播
    loss = criterion(outputs,target)  # 计算损失
    loss = loss/accumulation_steps   # 可选,如果损失要在训练样本上取平均

    loss.backward()  # 计算梯度
    if((i+1)%accumulation_steps)==0:
        optimizer.step()        # 反向传播,更新网络参数
        optimizer.zero_grad()   # 清空梯度

其实,这块有两种理解方式(受到评论区同学启发), 我谈谈在 bert 里面最常见的那种。
比较来看, 我们发现,梯度累加本质上就是累加 accumulation_steps 个 batchsize/accumulationsteps 的梯度, 再根据累加的梯度来更新网络参数,以达到真实梯度类似batch_size 的效果。在使用时,需要注意适当的扩大学习率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值