哪些会占用GPU显存
占用:卷积层,全连接层,batchNorm层,Embedding层
不占用:relu激活层,池化层
上面这些指的是对应层的参数会占用显存
额外的显存占用:模型在计算时产生的中间参数(也就是输入图像在计算时每一层产生的输入和输出)
- 需要计算每一层的feature map的形状
- 需要保存输出对应的梯度用以反向传播
- 显存占用与batch_size近似成正比
backward的时候产生的额外的中间参数
优化器在优化时产生的额外的模型参数,不同优化算法需要占用不同大小的内存
https://zhuanlan.zhihu.com/p/31558973
1
显存占用 = 模型显存占用 + batch_size × 每个样本的显存占用
如何优化显存占用
减少图像的输入尺寸
减少batch_size
多使用下采样,池化层
feature map是需要保存的,也就是我们上面说的额外的显存占用:模型在计算时产生的中间参数(也就是输入图像在计算时每一层产生的输入和输出)。特征图是一个层在前向传播中生成的中间输出结果,且在后向传输的梯度计算中作为输入。
https://zhuanlan.zhihu.com/p/31863033
特征图的大小通常由批尺寸(batchsize)和模型架构决定(如CNN架构的卷积步幅大小、输出通道数量;RNN架构的门数量、时间步长和隐层大小)。不再需要作为输入的特征图占用的显存将会被释放,导致图1中显存占用曲线的下降。
这些数据使用的内存主要和两个参数有关系, 一是batch size,另一个是每条序列(Sequence)长度。所以,其实也是和每个mini-batch中包含 的时间步信息成正比。
- 减小batch size。 即在网络配置中
settings(batch_size=1000)
设置成一个小一些的值。但是batch size本身是神经网络的超参数,减小batch size可能会对训练结果产生影响。 - 减小序列的长度,或者直接扔掉非常长的序列。比如,一个数据集大部分序列长度是100-200, 但是突然有一个10000长的序列,就很容易导致内存超限,特别是在LSTM等RNN中。因为RNN中存在沿着时间反向传播的操作,所以我们需要记录每个时间步的feature map
对于权重参数而言,权重参数占用内存相对较少。权重一般作为GPU内存中的持久内存,只有训练任务完成后才会被释放。特征图才是GPU显存占用的主要因素。
- 减小batch size。 即在网络配置中
变量共享
https://blog.csdn.net/wwwwenming2007/article/details/70821467
1
可以通过tf.get_variable_scope().reuse函数来获取上下文管理器中reuse参数的值
https://www.cnblogs.com/weizhen/p/6751792.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#通过tf.variable_scope和tf.get_variable函数,以下代码对inference函数的前向传播结果做了一些改进
def inference(input_tensor,reuse=False):
#定义第一层神经网络的变量和前向传播过程
with tf.variable_scope('layer1',reuse=reuse):
#根据传进来的reuse来判断是创建新变量还是使用已经创建好了。在第一次构造网络时需要创建新的变量,
#以后每次调用这个函数都直接使用reuse=True就不需要每次将变量传进来了
weights= tf.get_variable("weights",[INPUT_NODE,LAYER1_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
biases= tf.get_variable("biases",[LAYER1_NODE],initializer=tf.constant_initializer(0.0))
layer1 = tf.nn.relu(tf.matmul(input_tensor,weights)+biases)
#类似地定义第二层神经网络的变量和前向传播过程
with tf.variable_scope('layer2',reuse=reuse):
weights=tf.get_variable("weights",[LAYER1_NODE,OUTPUT_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
biases=tf.get_variable("biases",[OUTPUT_NODE],initializer=tf.constant_initializer(0.0))
layer2=tf.matmul(layer1,weights)+biases
#返回最后的前向传播结果
return layer2
x=tf.placeholder(tf.float32,[None,INPUT_NODE],name='x-input')
y=inference(x)
#在程序中需要使用训练好的神经网络进行推倒时,可以直接调用inference(new_x,True)