2017-03-27 71 views
2

我有一个Tensorflow模型,它是一个使用长期短期记忆的递归神经网络。状态大小为3000,每次输入步骤有300个输入,大约有500个时间步,每个时间步有1个输出。我正在训练一个序列到序列的模型。Tensorflow GPU在均方误差期间耗尽的内存

它运行罚款输入小于500层时的步骤,但地方约500个时间步长,它具有以下内存不足错误崩溃:

ResourceExhaustedError (see above for traceback): OOM when allocating tensor with shape[20375,20375] 
    [[Node: gradients/mean_squared_error/Mul_grad/mul_1 = Mul[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/gpu:0"](mean_squared_error/Square, gradients/mean_squared_error/Sum_grad/Tile)]] 
    [[Node: gradients/MatMul_grad/tuple/control_dependency_1/_225 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/cpu:0", send_device="/job:localhost/replica:0/task:0/gpu:0", send_device_incarnation=1, tensor_name="edge_5086_gradients/MatMul_grad/tuple/control_dependency_1", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/cpu:0"]()]] 

,这是在GPU上运行带有12GB内存。

我已经尝试在我的笔记本电脑CPU上运行它,它似乎使用很少的内存(大约1到2 GB),但它太慢了,它从来没有达到500个时间步。我正在进行一些更改,这会使其跳到500个时间步,以查看未在GPU上运行时使用的内存量。

我的问题是:Tensorflow可能想要分配张量形状[20375,20375]?它似乎与tf.mean_squared_error函数有关,但这看起来不像是一个需要如此大量内存的操作。

我已经尝试减少批量大小,但这只是将故障点推到更多的时间步骤,而且我将需要多达几千个时间步骤,所以这看起来不像一个好长的期限的解决方案。我宁愿找到问题的根源。

这里是平均值的相关代码误差平方:

initial_state_tuple = tf.contrib.rnn.LSTMStateTuple(initial_state, initial_hidden_state) 


# Create the actual RNN 
with tf.variable_scope(VARIABLE_SCOPE, reuse=None): 
    cell = tf.contrib.rnn.BasicLSTMCell(STATE_SIZE) 
    rnn_outputs, finalstate = tf.nn.dynamic_rnn(cell=cell, inputs=networkinput, 
               initial_state=initial_state_tuple) 

with tf.variable_scope(VARIABLE_SCOPE, reuse=True): 
    weights = tf.get_variable(name=WEIGHTS_NAME, shape=[STATE_SIZE, 1], dtype=tf.float32) 
    biases = tf.get_variable(name=BIASES_NAME, shape=[1], dtype=tf.float32) 

# Build the output layers 
rnn_outputs_reshaped = tf.reshape(rnn_outputs, [-1, STATE_SIZE]) 
network_outputs = tf.sigmoid(tf.matmul(rnn_outputs_reshaped, weights) + biases) 
expected_outputs_reshaped = tf.reshape(expected_outputs, [-1, 1]) 

# Loss mask just cancels out the inputs that are padding characters, since not all inputs have the same number of time steps 
loss_mask_reshaped = tf.reshape(loss_mask, shape=[-1]) 

expected_outputs_reshaped = loss_mask_reshaped * expected_outputs_reshaped 
network_outputs = loss_mask_reshaped * network_outputs 

loss = tf.losses.mean_squared_error(labels=expected_outputs_reshaped, predictions=network_outputs) 

如果你想所有的代码,可以发现here。相关的函数是buildtower()和buildgraph()。在具有GPU的机器上运行时,常量NUM_GPUS和BATCH_SIZE设置为适当的值。

更新:我更换了线

loss = tf.losses.mean_squared_error(labels=expected_outputs_reshaped, predictions=network_outputs) 

error_squared = tf.pow(expected_outputs_reshaped - network_outputs, 2) 
loss = tf.reduce_mean(error_squared) 

和同样的错误发生。我将状态大小减少到了30,批量大小减少到了5,并且错误仍然发生,尽管它使它达到了大约3000个时间步长。

更新:在做了一些研究之后,我发现,当训练一个具有大量时间步长的RNN时,经常会使用截断后向传播。这使我相信通过大量时间步骤的反向传播本质上需要大量的内存,而我的问题不是我构建了错误的图形,而是我对梯度计算的资源需求存在根本的误解。为此,我正在努力将我的代码更改为使用截断后向传播。我会报告结果。

回答

0

这个项目是我第一次使用机器学习和Tensorflow的经验,经过一番研究,似乎我有一些根本性的误解。

我以为内存使用量会随着我数据中的时间步数而线性缩放。因为我的模型(批量大小,状态大小)的每个其他维度都很小,所以我预计在内存不足之前可能需要几个时间步骤。但是,计算梯度的内存使用率似乎与时间步数成指数关系,所以无论我如何缩小状态大小和批量大小,由于大量的时间步长,它最终会耗尽我所有的内存。

为了解决这个问题,我使用了truncated backpropagation,其中每个批次都被分成几个固定数量的时间步长。这并不完美,因为这意味着错误最多只能传播多次。但是,基于我在网上找到的内容,它似乎工作得很好,并且没有太多其他方法可以解决内存使用问题。

正如我之前所说的,这是我第一次使用机器学习的经验,所以如果在这里有什么是公然错误的,请告诉我。