实验:dropout(训练时废掉某些神经元),overfitting(过拟合)
训练神经网络的时候,您可能会留意到:
测试和训练数据的交叉熵曲线一开始的变化趋势几乎一样,两者的差距非常小。
但是在几千次迭代之后,这两条曲线开始分离。
(训练集的准确率留在比较高的位置,测试集的准确率却开始一点点下降了)
这是因为我们的学习算法仅仅对训练数据起作用,并相应地优化了训练交叉熵。
可是它从来都看不到测试数据,所以它训练一段时间后,不再对测试集的交叉熵产生影响也就不足为奇了。
测试集的交叉熵会停止下降,有时甚至会反弹。
这种测试集的交叉熵和训练集的交叉熵不再重合的现象通常被称为“过拟合”,通常意味着我们的训练不能再继续提高网络的性能。当过拟合的现象出现时,尽管它不会立即影响模型对真数据的识别能力,但是我们没有办法通过多次迭代去提高模型的效果,既然再训练下去也是徒劳无功,一般在过拟合出现后,我们就可以停止迭代了。
当过拟合现象出现时,可以尝试使用名为“dropout”的规则化方法。
在使用dropout时,您需要在每次迭代训练中,从网络中随机删除神经元。
您要选择一个概率p,神经元有概率p被保留下来(被删除的概率为1-p)。
概率p的值通常在50%到75%之间。
然后在循环训练的每一次迭代中,随机删除神经元(包括相关的权重W和偏置B的)。
每次迭代时都会丢弃不同的神经元。
您还需要按比例提高剩余神经元的输出(神经元的输出乘 ),以确保下一层的激活不会移位。
当然,在测试网络性能时,需要将所有神经元放回(p.=1)。
TensorFlow提供了一个用于一层神经元输出的dropout函数。
它随机地将一些输出归零,并将剩余的输出提高1/p.。
下面是如何在2层网络中使用它的例子:
# feed in 1 when testing, 0.75 when training
pkeep = tf.placeholder(tf.float32)
Y1 = tf.nn.relu(tf.matmul(X, W1) + B1)
Y1d = tf.nn.dropout(Y1, pkeep)
Y = tf.nn.softmax(tf.matmul(Y1d, W2) + B2)
现在可以在网络中的每个中间层添加dropout函数。
这是实验里的一个可选步骤,如果时间紧迫,请继续阅读
如果你自己写不出来了,相应的代码可以在文件mnist_2.2_five_layers_relu_lrdecay_dropout.py中找到。
我们可以观察到,测试集的反弹在很大程度上得到了控制,不过噪声又重新出现了
(我们现在对于dropout函数如何工作已经有一定的了解了,神经元被随机地删除,这肯定会让结果不稳定,所以出现这种“噪声”并不令人惊讶)
但在这种情况下,测试集的准确度依旧保持不变,没办法通过训练继续提升,这还是有点令人失望。“overfitting-过拟合”肯定还有其他原因。
在继续探究之前,回顾一下我们迄今为止尝试过的所有操作:
无论我们做什么,我们似乎都无法以一种突破性的方式打破98%的障碍,我们的损失函数的曲线仍然显示“过拟合”。
什么是真正的“过度拟合”?
当神经网络学习“糟糕”时,就会发生过拟合,这种学习方法对于训练实例有效,但对于真实数据效果不佳。
有些正规化的技术,比如dropout函数,可以迫使它以更好的方式学习,但过度拟合也有更深的根源。
当神经网络对于手头上的问题具有太多的自由度时(可调参数过多),基本上都会引起过拟合。
想象一下,如果我们有足够多的神经元,让一个网络可以将我们所有的训练图像都存储在这些神经元中,然后通过模式匹配来识别它们。毫无疑问,它对真实的数据毫无辨识能力。
一个神经网络必须受到一定的约束,这样它才能被迫去用更少的神经元去概括它在训练过程中学到的东西。
如果你的训练数据很少,即使是一个小型网络也可以把数据死记硬背下来。
一般来说,你总是需要大量的数据来训练神经网络。
最后,如果你把一切都做得很好,用不同大小的网络进行实验,以确保它的自由度受到限制,应用dropout函数,并针对大量数据进行训练,可能你仍然会停留在一定的性能水平上,似乎已经没有什么可以改进了。
这意味着,您的神经网络,在目前的形状下,已经没办法从您的数据中提取更多的信息了,如同我们在这里遇到的情况一样。
还记得我们是如何把我们的图像里所有像素(28*28)都排成为单个向量(724)吗?
这真是个馊主意!
手写数字是由不同形状构成的,当我们对像素进行向量化时,会丢弃形状信息。
然而,有一种可以利用形状信息的神经网络:卷积神经网络。
让我们试试看。