为啥我的 tensorflow 模型输出在 x 个时期后变为 NaN?

Posted

技术标签:

【中文标题】为啥我的 tensorflow 模型输出在 x 个时期后变为 NaN?【英文标题】:Why my tensorflow model outputs become NaN after x epochs?为什么我的 tensorflow 模型输出在 x 个时期后变为 NaN? 【发布时间】:2018-12-04 21:39:24 【问题描述】:

在 85 个 epoch 之后,我的模型(具有 3 个 LSTM 层的 RNN)的损失(余弦距离)变为 NaN。为什么会发生,我该如何解决?我的模型的输出也变成了 NaN。

我的模特:

tf.reset_default_graph()

seqlen = tf.placeholder(tf.int32, [None])
x_id = tf.placeholder(tf.int32, [None, None])
y_id = tf.placeholder(tf.int32, [None, None])

embeddings_matrix = tf.placeholder(np.float32, [vocabulary_size, embedding_size])
x_emb = tf.nn.embedding_lookup(embeddings_matrix, x_id)
y_emb = tf.nn.embedding_lookup(embeddings_matrix, y_id)

cells = [tf.contrib.rnn.LSTMCell(s, activation=a) for s, a in [(400, tf.nn.relu), (400, tf.nn.relu), (400, tf.nn.tanh)]]
cell = tf.contrib.rnn.MultiRNNCell(cells)

outputs, _ = tf.nn.dynamic_rnn(cell, x_emb, dtype=tf.float32, sequence_length=seqlen)

loss = tf.losses.cosine_distance(tf.nn.l2_normalize(outputs, 2), tf.nn.l2_normalize(y_emb, 2), 1)
tf.summary.scalar('loss', loss)
opt = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)
merged = tf.summary.merge_all()

训练的输出:

Epoch 80/100
    Time : 499 s    Loss : 0.972911523852701    Val Loss : 0.9729658
Epoch 81/100
    Time : 499 s    Loss : 0.9723407568655597   Val Loss : 0.9718646
Epoch 82/100
    Time : 499 s    Loss : 0.9718870568505438   Val Loss : 0.971976
Epoch 83/100
    Time : 499 s    Loss : 0.9913996352643445   Val Loss : 0.990693
Epoch 84/100
    Time : 499 s    Loss : 0.9901496524596137   Val Loss : 0.98957264
Epoch 85/100
    Time : 499 s    Loss : nan  Val Loss : nan
Epoch 86/100
    Time : 498 s    Loss : nan  Val Loss : nan
Epoch 87/100
    Time : 498 s    Loss : nan  Val Loss : nan
Epoch 88/100
    Time : 499 s    Loss : nan  Val Loss : nan
Epoch 89/100
    Time : 498 s    Loss : nan  Val Loss : nan
Epoch 90/100
    Time : 498 s    Loss : nan  Val Loss : nan

这是整个训练过程中的厕所曲线:

蓝色曲线是训练数据的损失,橙色曲线是验证数据的损失。

用于 ADAM 的学习率为 0.001。

我的 x 和 y 得到以下形状:[batch size, maximum sequence length],它们都设置为 None,因为每个 epoch 的最后一批更小,并且每批的最大序列长度变化。

x和y经过一个embedding lookup,形状为[batch size, maximum sequence length, embedding size],padding word的embedding是一个0的向量。

动态 rnn 获取每个序列的长度(代码中的 seqlen,形状为 [batch size]),因此它只会对每个序列的确切长度进行预测,其余的输出将被填充零向量,对于 y。

我的猜测是输出的值变得非常接近于零,一旦将它们平方以计算余弦距离,它们就会变为 0,因此会导致除以零。

余弦距离公式:

我不知道我是否正确,也不知道如何防止这种情况。

编辑: 我刚刚检查了每一层的权重,它们都是 NaN

已解决: 使用 l2 正则化有效。

tf.reset_default_graph()

seqlen = tf.placeholder(tf.int32, [None])
x_id = tf.placeholder(tf.int32, [None, None])
y_id = tf.placeholder(tf.int32, [None, None])

embeddings_matrix = tf.placeholder(np.float32, [vocabulary_size, embedding_size])
x_emb = tf.nn.embedding_lookup(embeddings_matrix, x_id)
y_emb = tf.nn.embedding_lookup(embeddings_matrix, y_id)

cells = [tf.contrib.rnn.LSTMCell(s, activation=a) for s, a in [(400, tf.nn.relu), (400, tf.nn.relu), (400, tf.nn.tanh)]]
cell = tf.contrib.rnn.MultiRNNCell(cells)

outputs, _ = tf.nn.dynamic_rnn(cell, x_emb, dtype=tf.float32, sequence_length=seqlen)

regularizer = tf.reduce_sum([tf.nn.l2_loss(v) for v in tf.trainable_variables()])
cos_distance = tf.losses.cosine_distance(tf.nn.l2_normalize(outputs, 2), tf.nn.l2_normalize(y_emb, 2), 1)
loss = cos_distance + beta * regularizer

opt = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)

tf.summary.scalar('loss', loss)
tf.summary.scalar('regularizer', regularizer)
tf.summary.scalar('cos_distance', cos_distance)
merged = tf.summary.merge_all()

【问题讨论】:

在第 85 个 epoch 之后,你的层中元素的激活值是否也变为 NaN @a_r41 idk,当我尝试获取任何层的输出时,我收到此错误:层 lstm_cell_x 没有入站节点。我使用的代码如下: sess.run(cells[x].output, feed_dict=...) 权重都是 NaN,所以每一层的输出也应该是 NaN 【参考方案1】:

每一层的权重变为NaN 可能表明您的模型正在经历exploding gradient problem。

我认为随着 epoch 数量的增加,层中的权重值可能会变得太大。我建议您实现某种渐变剪裁权重正则化(查看随附的链接)。

【讨论】:

我要尝试一个 l2 正则化,训练我的模型需要几个小时,我会在明天更新帖子。

以上是关于为啥我的 tensorflow 模型输出在 x 个时期后变为 NaN?的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow,为啥保存模型后有3个文件?

为啥 tensorflow 模块会占用所有 GPU 内存? [复制]

如何在 MultiOutput LSTM Tensorflow 中优先考虑某些输出?

让 Keras / Tensorflow 输出 OneHotCategorical,但操作没有梯度

Tensorflow,MultiRNN,为啥会有这么多cell?

为啥我的逻辑回归模型输出的因子不是 2 个水平? (错误:`data`和`reference`应该是相同级别的因素。)