交叉熵损失突然增加到无穷大

7
我正在尝试复制一篇研究论文中的深度卷积神经网络。我已经实现了这个结构,但是在10个epochs之后,我的交叉熵损失突然增加到无限大。下面的图表可以看出。问题发生后准确率的变化可以忽略。 这里是Github仓库链接,其中包含该网络结构的图片。
经过一些研究,我认为使用AdamOptimizer或relu可能存在问题。
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))

编辑 如果有人感兴趣,解决方法是我基本上输入了错误的数据。


事故发生后,损失降低了很多,准确性也提高了很多?您能否使用其他随机洗牌数据集设置重现该问题,以验证它是否是偶然的对抗案例? - THN
问题提到在问题发生后忽略准确性。 - Jai
@Jai 是的,但为什么要忽视它呢?这更加有趣。 - THN
是的,我认为这不是正确的图表... - Jai
损失降至0,因为图表无法显示nan(无穷大)的值。准确性增加是因为问题发生后,模型将每个类别标记为“0”。恰好标记所有内容为“0”非常准确。 - Devin Haslam
3个回答

5
解决方案:控制解决方案空间。这可能意味着在训练时使用较小的数据集,可能意味着使用较少的隐藏节点,可能意味着以不同的方式初始化你的wb。你的模型达到了一个损失未定义的点,这可能是由于梯度未定义或最终卷积信号未定义。 为什么:有时无论如何,都会出现数值不稳定性。最终添加一个机器epsilon来防止除以零(这里是交叉熵损失)就无济于事,因为即使这样,这个数字也不能被你正在使用的精度准确表示。(参考:https://en.wikipedia.org/wiki/Round-off_errorhttps://floating-point-gui.de/basic/
注意事项:
1)当调整epsilon时,请确保与您的数据类型一致(使用您所使用的精度的机器epsilon,在您的情况下,float32为1e-6 参考:https://en.wikipedia.org/wiki/Machine_epsilonpython numpy machine epsilon)。
2) 仅供其他读者参考:Adamoptimizer构造函数中的值是学习速率,但是您可以设置epsilon值(参考:How does paramater epsilon affects AdamOptimizer?https://www.tensorflow.org/api_docs/python/tf/train/AdamOptimizer)。
3)TensorFlow的数值不稳定性存在,很难解决。是的,有tf.nn.softmax_with_cross_entropy,但这太特定了(如果你不想要softmax怎么办?)。请参阅Vahid Kazemi的“Effective Tensorflow”获得深入的解释:https://github.com/vahidk/EffectiveTensorflow#entropy

3

你损失图中的那个跳跃非常奇怪...

我希望你能关注以下几点:

  • 如果你的图片没有归一化到0到1之间,那么请将它们归一化
  • 如果你已经将值归一化到-1到1之间,请使用sigmoid层代替softmax层,因为softmax会将值压缩到0到1之间
  • 在使用softmax之前添加一个sigmoid层来压缩你的值(强烈推荐)
  • 每一层都可以添加dropout
  • 我建议你使用tf.clip,这样你的梯度就不会爆炸或崩溃
  • 你也可以使用L2正则化
  • 尝试调整AdamOptimizer的学习率和epsilon
  • 我还建议你使用tensor-board来跟踪权重,这样你就会知道权重在哪里爆炸了
  • 你也可以使用tensor-board来跟踪损失和准确率

  • 下面是softmax公式:

enter image description here

  • 可能是因为那个e的指数x非常大,导致softmax输出了无穷大,从而损失变成了无穷大
  • 请大量使用tensorboard来调试和打印softmax的值,以便找出问题所在
  • 我还注意到你没有在卷积层之后使用任何激活函数...我建议你在每个卷积层之后使用leaky relu
  • 你的网络是一个庞大的网络,使用leaky relu作为激活函数非常重要,因为它增加了非线性,从而提高了性能

我的图像已经在0到1之间进行了归一化。我已经尝试过调整adam优化器的学习率和epsilon,您会建议使用其他优化器吗?原始论文并没有在每个卷积层后使用leaky relu,所以我有些犹豫。感谢您推荐tensorboard,我对它不太熟悉。 - Devin Haslam
你使用了相同的数据吗?尝试在softmax之前使用sigmoid层... 使用tf.clip... 使用dropouts。 - Jai
我对tesnorflow/tensorboard还不熟悉。根据我提供的代码,如何打印我的softmax值?我相信当前softmax是与交叉熵同时计算的。如果我想要打印交叉熵,目前我只需在训练期间使用cross_entropy.eval()即可。 - Devin Haslam
1
你是对的,softmax和交叉熵同时计算... 但你可以显式地使用tf.nn.softmax(),如下所示:print(sess.run(tf.nn.softmax(logits))) - Jai
1
logits = tf.nn.sigmoid(output_layer) 然后 softmax_with_cross_entropy(logits, targets)。如果您发现此答案有助于解决您的问题,请不要忘记将其标记为正确,以便其他人知道。 - Jai
显示剩余2条评论

1

您可能希望在Adam优化器中使用不同的epsilon值(例如0.1-1.0)。这在文档中有提到:

默认值1e-8的epsilon通常不是一个好的默认值。例如,在ImageNet上训练Inception网络时,当前的良好选择是1.0或0.1。


这不是一个初始网络。我非常有信心,提高训练速率不是答案。 - Devin Haslam
Epsilon不是一个训练速率,它是一个正则化因子。而笔记只是以Inception为例,而不是一个具体要求。 - RobR
对不起,我误解了。你能解释一下为什么ε会导致这个问题吗? - Devin Haslam
如果更改有帮助的话,我可以解释一下 :-). 我不确定这是否是问题,但较大的 epsilon 可能有助于稳定自适应学习率,以防平均平方梯度趋近于零。请参考 TF 文档中链接的原始论文。也许只需尝试一下,看看是否有所不同。 - RobR
3
RobR可能是正确的。仅为明确起见,AdamOptimizer有一些输入参数,如learning_rate、beta1、beta2、EPSILON等。他的意思是你应该调整第四个参数。在你的代码中,你为learning_rate指定了一个值为1e-5,但你正在使用默认的epsilon。尝试更改那个epsilon。 - bremen_matt
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接