Tensorflow的坑

  • 哪些会占用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内存中的持久内存,只有训练任务完成后才会被释放。特征图才是GPU显存占用的主要因素。

  • 变量共享

    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)