CVHub手把手帮你榨干GPU的显存

简介: CVHub手把手帮你榨干GPU的显存

引言

Out Of Memory, 一个炼丹师们熟悉得不能再熟悉的异常,其解决方法也很简单,减少输入图像的尺寸或者Batch Size就好了。但是,且不说输入尺寸对模型精度的影响,当BatchSize过小的时候网络甚至无法收敛的。

下图来源知乎:

深度学习中的batch的大小对学习效果有何影响?

6a1ad542f3a8223219f3dd8c58bf6d82.png

作者使用LeNet在MNIST数据集上进行测试,验证不同大小的BatchSize对训练结果的影响。我们可以看到,虽然说BatchSize并不是越大越好,但是过小的BatchSize的结果往往更差甚至无法收敛。


因此本文将会介绍如何在不减少输入数据尺寸以及BatchSize的情况下,进一步榨干GPU的显存。

什么在占用显存

显存主要是被以下三部分内容占用:1、网络模型,2、模型计算的过程中的中间变量,3、框架自身的显存开销。

网络模型的占用的显存主要是来自于所有有参数的层,包括:卷积、全连接、BN等;而不占用显存的有:激活函数、池化层以及Dropout等。

计算过程中产生的显存主要有:优化器、中间过程的特征图、backward过程产生的参数

而框架自身的显存开销一般不大,并且我们也不好优化,所以我们只能考虑从前面两点对显存进行优化,针对这两个部分,本文接下来将会介绍常用的显存占用优化策略。

模型显存优化

尽量使用Inplace

在PyTorch中,inplce操作指的是改变一个tensor值的时候,不经过复制操作而是直接在原来的内存上修改它的值,也就是原地操作。基本上,所有提供inplace参数的操作都可以使用inplace,并且官方文档也说了,如果你使用了inplace operation而没有报错的话,那么你可以确定你的梯度计算是正确的。


335e3e53f71c93e3c869aa02b94af75f.png


pytorch中所有inplace操作一般都是以_为后缀,如tensor.add_()、tensor.scatter_()等。除了自带的一些函数提供inplace操作外,一些运算法也存在inplace操作。如上图展示的是两个向量相加操作使用inplace与否的区别,但是要注意写法:


x = x+y属于case 1

x += y属于case2

同理, *=也是inplace操作


尽量少产生中间结果

下面两份代码,效果是一样的,但是占用显存却是不一样的。

不推荐写法

def forward(self, x):
  out_1 = self.conv_1(x)
  out_2 = self.conv_2(out_1)
  out_3 = self.conv_3(out_2)
  return out_3

推荐写法

def forward(self, x):
  x = self.conv_1(x)
  x = self.conv_2(x)
  x = self.conv_3(x)
  return x


不需要的中间变量尽可能的都是用一个变量来代替,因为这些变量都是会占用显存的。因此,网络中如果存在一些较长的连接(比如第10层的网络需要使用来自网络第一层的输出结果),这部分的特征图就会一直占用显存。

不使用过大全连接


相比于卷积的参数,全连接的参数量可就大多了。因为卷积只是一个局部的连接,而全连接则是一个全局的连接。举个栗子:


卷积的参数只与输出的通道数、卷积核大小相关。在不考虑偏置的情况下,卷积核大小为3,输入通道为32,输出通道数为64的时候,参数量大小为3 ∗ 3 ∗ 32 ∗ 64 = 18432

image.png

所以一般来说,特征图比较大的时候,直接用全连接显卡会直接冒烟。因此往往只能在深层或者特征进行压缩之后才能够使用全连接。比如像SENet中,就是先将特征图使用GAP(Global Average Pooling)之后,才使用全连接,并且在全连接的中间层还是用了一定的压缩倍率。


亦或者可以像ECA-Net那般,不使用全连接,采用邻域连接的方式来减少计算量。


计算过程优化

使用checkpoint


PyTorch在0.4版本后推出了一个新功能,可以将一个模型的计算过程分为两半。也就是说,如果一个模型训练需要占用的显存太大,可以先计算网络的一半,保存后半部分所需要的中奖结果,再计算后半部分。当然,这样的操作显然是一个牺牲时间换空间的方法没,其使用方式如下:


# 常规写法
def forward(self, x):
  x = self.conv_1(x)
  x = self.conv_2(x)
  x = self.conv_3(x)
  return x
# 引入checkpoint
from torch.utils.checkpoint import checkpoint
def forward(self, x):
  x = checkpoint(self.conv_1(x), x)
  x = checkpoint(self.conv_2(x), x)
  x = checkpoint(self.conv_3(x),x)
  return x

梯度累加

大多数情况下,其实我们降低显存就是为了获得更大的Batchsize,因此使用gradient accumulation(梯度累加)也可以达到类似的效果。一般来说,我们使用pytorch写网络的训练过程主要是下面这个流程:


for i in range(epochs):
        optimizer.zero_grad()                   # 梯度清零
        outputs = network(input)                   # 正向传播
        loss = criterion(output, label)       # 计算损失
        loss.backward()                         # 反向传播,计算梯度
        optimizer.step()                        # 更新参数

而梯度累加的代码则只需要多一步:

for i in range(epochs):
        optimizer.zero_grad()                   # 梯度清零
        outputs = network(input)                   # 正向传播
        loss = criterion(output, label)/accumulation_steps
        if (i+1) % accumulation_steps == 0: 
            optimizer.step()                    # 更新参数
            optimizer.zero_grad()               # 梯度清零

通过这种方法能够比较简单的在有限的内存下模拟更大batchsize 的效果,并且效果也比较接近。

降低计算精度


PyTorch中,所有Tensor默认的精度都是FP32,也就是说每一个浮点型参数都需要占用32bit的显存。因此,如果直接把精度降低到FP16,那理论上直接就能减少一半的显存占用。那么,古尔丹,代价是什么呢?代价就是,在反向传播的过程中,大多数更新值都非常小但不为零。反向传播的舍入误差可以把这些数字变成0或者nans,使得梯度更新不准确,影响网络的收敛。ICLR2018论文中Mixed Precision Training发现,使用FP16进行训练的网络约有5%的梯度都会被“吞掉”。


4246534d78798cf330670b5f0c4711f7.png

在PyTorch1.6之前,降低训练进度普遍使用的都是NVIDIA提供的apex库。而在1.6版本之后,PyTorch推出了AMP(Automatic mixed precision),自动混合精度训练。这套技术并不是简单的将所有的参数降低精度,而是根据不同向量的不同操作对于误差的敏感程度来决定其使用的是FP16还是FP32。其使用起来也十分简单,下面是一个简单的例子,代码参考知乎:

from torch.cuda.amp import autocast,GradScaler
# 创建model,默认是torch.FloatTensor
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)
# 在训练最开始之前实例化一个GradScaler对象
scaler = GradScaler()
for epoch in epochs:
    for input, target in data:
        optimizer.zero_grad()
        # 前向过程(model + loss)开启 autocast
        with autocast():
            output = model(input)
            loss = loss_fn(output, target)
        # Scales loss. 为了梯度放大.
        scaler.scale(loss).backward()
        # scaler.step() 首先把梯度的值unscale回来.
        # 如果梯度的值不是 infs 或者 NaNs, 那么调用optimizer.step()来更新权重,
        # 否则,忽略step调用,从而保证权重不更新(不被破坏)
        scaler.step(optimizer)
        # 准备着,看是否要增大scaler
        scaler.update()


终极解决办法

加钱

写在最后

如果您也对人工智能和计算机视觉全栈领域感兴趣,强烈推荐您关注有料、有趣、有爱的公众号『CVHub』,每日为大家带来精品原创、多领域、有深度的前沿科技论文解读及工业成熟解决方案!欢迎添加小编微信号:cv_huber,一起探讨更多有趣的话题!


相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
TensorFlow 算法框架/工具 异构计算
GPU 显存释放
GPU 显存释放
453 1
|
异构计算 算法框架/工具 TensorFlow
|
1月前
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
4月前
|
机器学习/深度学习 编解码 人工智能
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
随着人工智能、大数据和深度学习等领域的快速发展,GPU服务器的需求日益增长。阿里云的GPU服务器凭借强大的计算能力和灵活的资源配置,成为众多用户的首选。很多用户比较关心gpu云服务器的收费标准与活动价格情况,目前计算型gn6v实例云服务器一周价格为2138.27元/1周起,月付价格为3830.00元/1个月起;计算型gn7i实例云服务器一周价格为1793.30元/1周起,月付价格为3213.99元/1个月起;计算型 gn6i实例云服务器一周价格为942.11元/1周起,月付价格为1694.00元/1个月起。本文为大家整理汇总了gpu云服务器的最新收费标准与活动价格情况,以供参考。
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
|
20天前
|
人工智能 弹性计算 编解码
阿里云GPU云服务器性能、应用场景及收费标准和活动价格参考
GPU云服务器作为阿里云提供的一种高性能计算服务,通过结合GPU与CPU的计算能力,为用户在人工智能、高性能计算等领域提供了强大的支持。其具备覆盖范围广、超强计算能力、网络性能出色等优势,且计费方式灵活多样,能够满足不同用户的需求。目前用户购买阿里云gpu云服务器gn5 规格族(P100-16G)、gn6i 规格族(T4-16G)、gn6v 规格族(V100-16G)有优惠,本文为大家详细介绍阿里云gpu云服务器的相关性能及收费标准与最新活动价格情况,以供参考和选择。
|
25天前
|
机器学习/深度学习 人工智能 弹性计算
什么是阿里云GPU云服务器?GPU服务器优势、使用和租赁费用整理
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等多种场景。作为亚太领先的云服务提供商,阿里云的GPU云服务器具备灵活的资源配置、高安全性和易用性,支持多种计费模式,帮助企业高效应对计算密集型任务。
|
25天前
|
机器学习/深度学习 人工智能 弹性计算
阿里云GPU服务器全解析_GPU价格收费标准_GPU优势和使用说明
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等场景。作为亚太领先的云服务商,阿里云GPU云服务器具备高灵活性、易用性、容灾备份、安全性和成本效益,支持多种实例规格,满足不同业务需求。
164 2
|
1月前
|
弹性计算 异构计算
2024年阿里云GPU服务器多少钱1小时?亲测价格查询方法
2024年阿里云GPU服务器每小时收费因实例规格不同而异。可通过阿里云GPU服务器页面选择“按量付费”查看具体价格。例如,NVIDIA A100的gn7e实例为34.742元/小时,NVIDIA A10的gn7i实例为12.710156元/小时。更多详情请访问阿里云官网。
97 2
|
1月前
|
机器学习/深度学习 人工智能 弹性计算
阿里云AI服务器价格表_GPU服务器租赁费用_AI人工智能高性能计算推理
阿里云AI服务器提供多种配置选项,包括CPU+GPU、CPU+FPGA等组合,支持高性能计算需求。本文汇总了阿里云GPU服务器的价格信息,涵盖NVIDIA A10、V100、T4、P4、P100等多款GPU卡,适用于人工智能、机器学习和深度学习等场景。详细价格表和实例规格见文内图表。
123 0
|
3月前
|
机器学习/深度学习 存储 人工智能
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考
阿里云的GPU云服务器产品线在深度学习、科学计算、图形渲染等多个领域展现出强大的计算能力和广泛的应用价值。本文将详细介绍阿里云GPU云服务器中的gn6v、gn7i、gn6i三个实例规格族的性能特点、区别及选择参考,帮助用户根据自身需求选择合适的GPU云服务器实例。
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考