训练因 ResourceExausted 错误而中断

Training broke with ResourceExausted error

我是张量流和机器学习的新手。最近我在做一个模型。我的模型如下,

  1. 字符级嵌入向量 -> 嵌入查找 -> LSTM1

  2. 词级嵌入向量->嵌入查找-> LSTM2

  3. [LSTM1+LSTM2] -> 单层 MLP -> softmax 层

  4. [LSTM1+LSTM2] -> 单层 MLP -> WGAN 判别器

  5. 他的rnn模型代码

我在处理这个模型时遇到了以下错误。我以为我的批次太大了。因此,我试图将批量大小从 20 减少到 10,但它不起作用。

ResourceExhaustedError (see above for traceback): OOM when allocating tensor with shape[24760,100] [[Node: chars/bidirectional_rnn/bw/bw/while/bw/lstm_cell/split = Split[T=DT_FLOAT, num_split=4, _device="/job:localhost/replica:0/task:0/device:GPU:0"](gradients_2/Add_3/y, chars/bidirectional_rnn/bw/bw/while/bw/lstm_cell/BiasAdd)]] [[Node: bi-lstm/bidirectional_rnn/bw/bw/stack/_167 = _Recvclient_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device_incarnation=1, tensor_name="edge_636_bi-lstm/bidirectional_rnn/bw/bw/stack", tensor_type=DT_INT32, _device="/job:localhost/replica:0/task:0/device:CPU:0"]]

tensor with shape[24760,100] 表示 2476000*32/8*1024*1024 = 9.44519043 MB 内存。我是 运行 titan X(11 GB) GPU 上的代码。会出什么问题?为什么会出现这种类型的错误?

* Extra info *:LSTM1 的大小为 100。对于双向 LSTM,它变为 200。 LSTM2 的大小为 300。对于双向 LSTM,它变为 600。

*注意*:错误发生在32个epoch之后。我的问题是为什么在 32 个纪元之后出现错误。为什么不在初始时期。

*Note *: The error occurred after 32 epoch. My question is why after 32 epoch there is an error. Why not at the initial epoch.

这是一个主要线索,表明图形在执行期间不是静态的。我的意思是,您可能正在做 sess.run(tf.something) 而不是

my_something = tf.something
with tf.Session() as sess: 
    sess.run(my_something)

我 运行 在尝试实现有状态 RNN 时遇到了同样的问题。我偶尔会重置状态,所以我在做sess.run([reset if some_condition else tf.no_op()])。只需将 nothing = tf.no_op() 添加到我的图表并使用 sess.run([reset if some_condition else nothing]) 即可解决我的问题。

如果你可以 post 训练循环,就可以更容易地判断出问题所在。

这些天我一直在调整很多来解决这个问题。

终于没有解开题中描述的内存大小之谜。我猜想在计算梯度时,tensoflow 会为计算梯度积累大量额外的内存。我需要检查tensorflow的来源,这在这个时候看起来很麻烦。您可以通过以下命令从终端检查您的模型使用了多少内存,

nvidia-smi

从这个命令来看,你可以猜出你可以使用多少额外的内存。

但是解决这类问题的方法在于减小批量大小,

For my case reducing the size of the batch to 3 works. This may vary model to model.

但是,如果您使用的模型的嵌入矩阵大得多,您无法将它们加载到内存中怎么办?

解决方案是编写一些痛苦的代码。

您必须查找嵌入矩阵,然后将嵌入加载到模型中。简而言之,对于每个批次,您必须将查找矩阵提供给模型(通过 sess.run() 中的 feed_dict 参数提供它们)。

接下来你将面临新的问题,

您不能以这种方式进行嵌入 trainable。解决方案是使用 placeholder 中的嵌入并将它们分配给 Variable(例如 A)。在每批训练之后,学习算法都会更新变量 A。然后通过张量流计算 A 向量的输出,并将它们分配给模型外部的嵌入矩阵。 (我说过程很痛苦)

现在你的下一个问题应该是,如果你不能将嵌入查找提供给模型,因为它太大了怎么办。这是您无法避免的基本问题。这就是为什么 NVIDIA GTX 1080、1080ti 和 NVIDA TITAN Xp 的价格差异如此之大,尽管 NVIDIA 1080ti 和 1080 的执行频率更高 运行。