Softmax 交叉熵损失爆炸式增长

Posted

技术标签:

【中文标题】Softmax 交叉熵损失爆炸式增长【英文标题】:Softmax Cross Entropy loss explodes 【发布时间】:2018-08-07 13:48:15 【问题描述】:

我正在为逐像素分类创建一个深度卷积神经网络。我正在使用亚当优化器,带有交叉熵的softmax。

Github Repository

我问了一个类似的问题,发现 here,但我得到的答案并没有让我解决问题。我也有一个更详细的图表,说明它出了什么问题。每当我使用 softmax 时,都会出现图中的问题。我做了很多事情,例如调整训练和 epsilon 速率,尝试不同的优化器等。损失永远不会超过 500。我目前不打乱我的数据。使用 sigmoid 代替 softmax 不会出现这个问题。但是,我的问题有多个类,所以sigmoid的准确率不是很好。还应该提到的是,当损失较低时,我的准确率只有 80% 左右,我需要比这更好。 为什么我的损失会突然像这样飙升?

x = tf.placeholder(tf.float32, shape=[None, 7168])
y_ = tf.placeholder(tf.float32, shape=[None, 7168, 3])

#Many Convolutions and Relus omitted

final = tf.reshape(final, [-1, 7168])
keep_prob = tf.placeholder(tf.float32)
W_final = weight_variable([7168,7168,3])
b_final = bias_variable([7168,3])
final_conv = tf.tensordot(final, W_final, axes=[[1], [1]]) + b_final

cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=final_conv))
train_step = tf.train.AdamOptimizer(1e-5).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(final_conv, 2), tf.argmax(y_, 2))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

【问题讨论】:

使用 sigmoid 层,在 sigmoid 之后使用 softmax 层......这就是我所做的......它对我来说效果很好......我不会回答这个问题,因为在上一个问题我已经提供了足够的详细信息...返回并参考我对您上一个问题的回答...并深入思考我的回答 当我尝试这样做时,损失从 ~1.3 开始,并且从未进一步减少。你有过这样的经历吗? 显示您的代码...您的代码而不是其他人的代码,然后我可以更好地帮助您 我已将相关代码添加到问题中。其余代码位于上面链接的 github 存储库中。如果你帮我解决问题,我会为这个问题加分。 我对加法操作持怀疑态度(实际上不确定)...架构看起来不错...您可以尝试在您要添加的所有最终反卷积层上应用 relu,然后再使用 softmax。 . 试试看... 即使我只是看代码也不确定出了什么问题,因为代码看起来不错,并使用tf.clip 来剪裁渐变... 尝试那些反卷积层... 【参考方案1】:

不确定,具体是什么原因造成的。我有几次同样的问题。一些事情通常会有所帮助:您可能会降低学习率,即。 Adam 的学习率的界限(例如 1e-5 到 1e-7 左右)或尝试随机梯度下降。 Adam 试图估计可能导致训练不稳定的学习率:参见 Adam optimizer goes haywire after 200k batches, training loss grows

有一次我也删除了 batchnorm,这确实有帮助,但这是针对笔画数据(= 点序列)的“专门”设计的网络,它在 Conv1d 层中不是很深。

【讨论】:

【参考方案2】:

你需要标签平滑。

我也遇到了同样的问题。我正在使用 tf.nn.sparse_softmax_cross_entropy_with_logits 进行培训,这与您使用带有 one-hot 标签的 tf.nn.softmax_cross_entropy_with_logits 相同。我的数据集预测了罕见事件的发生,因此训练集中的标签是 99% 的 0 类和 1% 的 1 类。我的损失会开始下降,然后停滞(但有合理的预测),然后突然爆炸,然后预测也坏了。

使用 tf.summary 操作将内部网络状态记录到 Tensorboard 中,我观察到 logits 的绝对值不断增长。最终在 >1e8 时,tf.nn.softmax_cross_entropy_with_logits 在数值上变得不稳定,这就是产生那些奇怪的损失峰值的原因。

在我看来,发生这种情况的原因在于 softmax 函数本身,这与 Jai 的评论一致,即在 softmax 之前将 sigmoid 放入其中可以解决问题。但这肯定也会使 softmax 似然度不可能准确,因为它限制了 logits 的值范围。但是这样做可以防止溢出。

Softmax 定义为likelihood[i] = tf.exp(logit[i]) / tf.reduce_sum(tf.exp(logit[!=i]))。交叉熵定义为tf.reduce_sum(-label_likelihood[i] * tf.log(likelihood[i]),因此如果您的标签是单热标签,则它会减少到目标可能性的负对数。在实践中,这意味着您将likelihood[true_class] 尽可能接近1.0。并且由于 softmax,唯一的方法是让tf.exp(logit[!=true_class]) 尽可能接近0.0

实际上,您已经要求优化器生成tf.exp(x) == 0.0,而唯一的方法是生成x == - infinity。这就是数值不稳定的原因。

解决方案是“模糊”标签,因此您可以使用 [0.01,0.01,0.98] 而不是 [0,0,1]。现在优化器可以达到tf.exp(x) == 0.01,这导致x == -4.6安全地处于GPU计算准确可靠的数值范围内。

【讨论】:

以上是关于Softmax 交叉熵损失爆炸式增长的主要内容,如果未能解决你的问题,请参考以下文章

softmax交叉熵损失函数求导

Pytorch - 使用一种热编码和 softmax 的(分类)交叉熵损失

神经网络 - Softmax 交叉熵损失减少对应于准确性降低

交叉熵损失函数

在pytorch中使用交叉熵损失时我应该使用softmax作为输出吗?

交叉熵 相关链接