张量流 LSTM 模型中的 NaN 损失
Posted
技术标签:
【中文标题】张量流 LSTM 模型中的 NaN 损失【英文标题】:NaN loss in tensorflow LSTM model 【发布时间】:2018-02-03 19:31:37 【问题描述】:以下网络代码应该是您的经典简单 LSTM 语言模型,一段时间后开始输出 nan loss...在我的训练集上需要几个小时,而且我无法在较小的数据集上轻松复制它。但它总是发生在严肃的训练中。
Sparse_softmax_with_cross_entropy 应该在数值上是稳定的,所以这不可能是原因……但除此之外,我看不到任何其他可能导致图表出现问题的节点。可能是什么问题?
class MyLM():
def __init__(self, batch_size, embedding_size, hidden_size, vocab_size):
self.x = tf.placeholder(tf.int32, [batch_size, None]) # [batch_size, seq-len]
self.lengths = tf.placeholder(tf.int32, [batch_size]) # [batch_size]
# remove padding. [batch_size * seq_len] -> [batch_size * sum(lengths)]
mask = tf.sequence_mask(self.lengths) # [batch_size, seq_len]
mask = tf.cast(mask, tf.int32) # [batch_size, seq_len]
mask = tf.reshape(mask, [-1]) # [batch_size * seq_len]
# remove padding + last token. [batch_size * seq_len] -> [batch_size * sum(lengths-1)]
mask_m1 = tf.cast(tf.sequence_mask(self.lengths - 1, maxlen=tf.reduce_max(self.lengths)), tf.int32) # [batch_size, seq_len]
mask_m1 = tf.reshape(mask_m1, [-1]) # [batch_size * seq_len]
# remove padding + first token. [batch_size * seq_len] -> [batch_size * sum(lengths-1)]
m1_mask = tf.cast(tf.sequence_mask(self.lengths - 1), tf.int32) # [batch_size, seq_len-1]
m1_mask = tf.concat([tf.cast(tf.zeros([batch_size, 1]), tf.int32), m1_mask], axis=1) # [batch_size, seq_len]
m1_mask = tf.reshape(m1_mask, [-1]) # [batch_size * seq_len]
embedding = tf.get_variable("TokenEmbedding", shape=[vocab_size, embedding_size])
x_embed = tf.nn.embedding_lookup(embedding, self.x) # [batch_size, seq_len, embedding_size]
lstm = tf.nn.rnn_cell.LSTMCell(hidden_size, use_peepholes=True)
# outputs shape: [batch_size, seq_len, hidden_size]
outputs, final_state = tf.nn.dynamic_rnn(lstm, x_embed, dtype=tf.float32,
sequence_length=self.lengths)
outputs = tf.reshape(outputs, [-1, hidden_size]) # [batch_size * seq_len, hidden_size]
w = tf.get_variable("w_out", shape=[hidden_size, vocab_size])
b = tf.get_variable("b_out", shape=[vocab_size])
logits_padded = tf.matmul(outputs, w) + b # [batch_size * seq_len, vocab_size]
self.logits = tf.dynamic_partition(logits_padded, mask_m1, 2)[1] # [batch_size * sum(lengths-1), vocab_size]
predict = tf.argmax(logits_padded, axis=1) # [batch_size * seq_len]
self.predict = tf.dynamic_partition(predict, mask, 2)[1] # [batch_size * sum(lengths)]
flat_y = tf.dynamic_partition(tf.reshape(self.x, [-1]), m1_mask, 2)[1] # [batch_size * sum(lengths-1)]
self.cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logits, labels=flat_y)
self.cost = tf.reduce_mean(self.cross_entropy)
self.train_step = tf.train.AdamOptimizer(learning_rate=0.01).minimize(self.cost)
【问题讨论】:
它是直接从具有合理的损失值变为突然变为 NaN 还是逐渐增加损失直到最终失控? loss徘徊在2左右,然后突然变成NaN。 我过去在调试此类事情时所做的事情是确保在第一个 NaN 发生时立即退出训练循环。然后查看最后一个 mini-batch 中的任何数据,看看是否有任何异常。例如,可能有一个长度为零的序列搞砸了。 【参考方案1】:检查您输入模型的列,在我的例子中,有一列具有 NaN 值,在删除 NaN 后,它起作用了
【讨论】:
【参考方案2】:可能是exploding gradients
的情况,在 LSTM 的反向传播过程中,梯度可能会爆炸,导致数量溢出。处理爆炸梯度的常用技术是执行Gradient Clipping。
【讨论】:
感谢您的回答。我选择用一个非常小的值(1.e-10
)初始化 LSTM 内核来解决这个问题。将不得不看看这是否不会在其他地方搞砸......以上是关于张量流 LSTM 模型中的 NaN 损失的主要内容,如果未能解决你的问题,请参考以下文章
为啥尽管损失衰减且评估结果合理,但张量流的“准确度”值始终为 0
为啥我的 tensorflow 模型输出在 x 个时期后变为 NaN?
LSTM 词预测模型仅预测最频繁的词,或用于不平衡数据的损失