我正在查看Tensorflow MNIST example for beginners并发现在此部分:
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
将批量大小从100更改为大于204会导致模型无法收敛。它可以工作到204,但在205和我试过的任何更高的数字,准确度将最终< 10%。这是一个错误,关于算法,还有什么?
这是运行OS X的二进制安装,似乎是0.5.0版本。
答案 0 :(得分:28)
您是否在初学者示例中使用了非常基本的线性模型?
这是调试它的技巧 - 在增加批量大小时观察交叉熵(第一行来自示例,我刚刚添加的第二行):
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
cross_entropy = tf.Print(cross_entropy, [cross_entropy], "CrossE")
批量大小为204时,您会看到:
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[92.37558]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[90.107414]
但是在205,你从一开始就会看到这样的序列:
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[472.02966]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[475.11697]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1418.6655]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1546.3833]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1684.2932]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1420.02]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1796.0872]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[nan]
Ack - NaN出现了。基本上,大批量大小正在创造如此巨大的梯度,使您的模型失控 - 它应用的更新太大,并且应该超出它应该大幅度的方向。
在实践中,有几种方法可以解决这个问题。您可以将学习率从.01降低到比如.005,这样最终的准确度为0.92。
train_step = tf.train.GradientDescentOptimizer(0.005).minimize(cross_entropy)
或者你可以使用更复杂的优化算法(Adam,Momentum等),它试图做更多的事情来弄清楚渐变的方向。或者你可以使用一个更复杂的模型,它有更多的自由参数来分散那个大的梯度。
答案 1 :(得分:15)
@dga给出了一个很好的答案,但我想稍微扩展一下。
当我编写初学者教程时,我实现了成本函数,如下所示:
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
我这样写的是因为它看起来与交叉熵的数学定义最相似。但实际上这样做可能会更好:
cross_entropy = -tf.reduce_mean(y_ * tf.log(y))
为什么使用均值而不是总和会更好?好吧,如果我们求和,那么批量加倍会使成本增加一倍,并且还会使梯度的幅度加倍。除非我们调整我们的学习率(或使用为我们调整它的算法,如@dga建议),否则我们的训练会爆炸!但是如果我们使用均值,那么我们的学习率就会变得与我们的批量大小无关,这很好。
我鼓励你查看亚当(tf.train.AdamOptimizer()
)。它比SGD更容忍摆弄东西。
答案 2 :(得分:15)
当0 * log(0)发生时发生Nan:
取代:
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
使用:
cross_entropy = -tf.reduce_sum(y_*tf.log(y + 1e-10))
答案 3 :(得分:2)
@dga很好地解释了这种行为的原因(交叉熵变得太大),因此算法将无法收敛。有几种方法可以解决这个问题。他已经建议降低学习率。
梯度下降是最基本的算法。几乎所有其他optimizers都能正常运作:
train_step = tf.train.AdagradOptimizer(0.01).minimize(cross_entropy)
train_step = tf.train.AdamOptimizer().minimize(cross_entropy)
train_step = tf.train.FtrlOptimizer(0.01).minimize(cross_entropy)
train_step = tf.train.RMSPropOptimizer(0.01, 0.1).minimize(cross_entropy)
另一种方法是使用处理数字不稳定性的tf.nn.softmax_cross_entropy_with_logits。