代码之家  ›  专栏  ›  技术社区  ›  rwallace

显示二次内存消耗的反向传播

  •  1
  • rwallace  · 技术社区  · 7 年前

    我在TensorFlow上遇到了一个奇怪的问题。我建立了一个非常简单的分类问题,四个输入变量,一个二进制输出变量,一层权重和偏差,输出通过一个sigmoid到0或1。

    问题是,内存消耗是训练数据记录数的二次方!只有5000条记录,已经是900兆字节了;在10000字节时,它会运行到几GB。由于我希望最终使用至少数万条记录,这是一个问题。

    它具体发生在反向传播步骤中;当我尝试评估成本函数时,正如预期的那样,内存消耗与记录数呈线性关系。

    代码如下。我做错了什么?

    import numpy as np
    import os
    import psutil
    import tensorflow as tf
    process = psutil.Process(os.getpid())
    sess = tf.InteractiveSession()
    
    # Parameters
    learning_rate = 0.01
    random_seed = 1
    tf.set_random_seed(random_seed)
    
    # Data
    data = np.loadtxt('train.csv', delimiter=',', dtype=np.float32)
    train_X = data[:, :-1]
    train_Y = data[:, -1]
    
    rows = np.shape(train_X)[0]
    cols = np.shape(train_X)[1]
    
    # Inputs and outputs
    X = tf.placeholder(np.float32, shape=(rows, cols))
    Y = tf.placeholder(np.float32, shape=rows,)
    
    # Weights
    W = tf.Variable(tf.random_normal((cols, 1)))
    b = tf.Variable(tf.random_normal(()))
    
    # Model
    p = tf.nn.sigmoid(tf.matmul(X, W) + b)
    cost = tf.reduce_sum((p-Y)**2/rows)
    optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
    tf.global_variables_initializer().run()
    
    # Just one optimizer step is enough to demonstrate the problem
    optimizer.run({X: train_X, Y: train_Y})
    
    # Memory consumption is quadratic in number of rows
    print('{0:,} bytes'.format(process.memory_info().peak_wset))
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   rwallace    7 年前

    结果又是形状的问题。使用matmul,就像我在那里做的那样,生成形状(n,1)的输出。在预期形状(n,)的上下文中使用它,会无声地生成二次放大。

    解决方案是挤压。明确地 tf.squeeze(tf.matmul(X, W)) .

        2
  •  1
  •   Abhai Kollara    7 年前

    内存消耗像这样激增是有道理的,因为backprop需要额外的内存来跟踪每个操作的梯度(尽管我不知道它是如何以二次方式结束的)。

    解决方案:小批量

    在训练模型时,这通常是goto方法。将您的培训数据拆分为几个小批量,每个小批量包含固定数量的样本(很少超过200个样本),然后将其一次一个小批量地提供给优化器。所以如果你的 batch_size=64 然后 train_X train_Y 输入到优化器的将是以下形状 (64, 4) (64,) 分别地

    我想试试这样的

    batch_size = 64
    for i in range(rows):
        batch_X = train_X[i*batch_size : (i + 1)*batch_size]
        batch_Y = train_Y[i*batch_size : (i + 1)*batch_size]
    
        optimizer.run({X: batch_X, Y:batch_Y})