这一章介绍了一些搭建网络的方式和技巧,可以帮助我们的网络更好的学习,包括:一种更好的损失函数叫cross-entropy交叉熵损失函数;四种“正则化”方法(L1和L2正则化、dropout、训练数据的artificial expansion);更好的初始化权重的方法;一些帮助我们选择超参数hyper-parameters的启发。【一些词汇我怕自己翻译不准确就直接用英文了
cross-entropy cost function
大家都知道如果有人把自己的错误指出来了,下次就会进步的特别快,那我们对待神经元也要认真的指出它们的错误,它们才可以好好学习呀~来,让我们从一个可爱的小神经元说起,要求它接收1的输入,输出为0。
当我们初始weight为0.6,初始bias为0.9时,我们大概需要经历300个epoch可以将output降为0.09,C函数曲线如图
但是我们如果把初始权重和偏置改为2.0,则曲线如图所示(两个学习率都是0.15)
可以看到,几乎有一半的时间,权重、偏置和损失函数没有太大的改变。那为什么在刚开始错误比较大时学习这么慢呢?有没有方法避免?
说学习慢,其实我们只需要关注
∂
\partial
∂C/
∂
\partial
∂w和
∂
\partial
∂C/
∂
\partial
∂b两个值。根据损失函数公式C=
(
y
−
a
)
2
2
\frac{(y-a)^{2}}{2}
2(y−a)2计算两个值
so,这两个值跟sigmoid函数的平缓程度都很大的关系,回想一下sigmoid函数的图像,在值接近1或者0时特别平缓,导数趋近于0,所以这两个值就变得很小,导致学习太慢。上面的第二个例子初始输出是0.98,所以刚开始学习就慢了。
Introducing the cross-entropy cost function
定义cross-entropy损失函数为:
这个是单层的,下面给出多层神经网络的交叉熵损失:
首先,显而易见这个函数是非负的,而且当a接近于理想输出y时,这个函数趋近于零,具备了成为损失函数的条件。并且它比原先的损失函数好在它没有学习变慢的问题,我们先计算一下偏导数,将a=
σ
\sigma
σ(z)代入上式:
代入sigmoid函数的导数形式,上式变为
所以这个偏导数的大小取决于
σ
\sigma
σ(z)-y而不是单纯的
σ
\sigma
σ(z),所以error越大的时候,学习越快,这也是比较符合常识的。对于偏置的偏导也是一样不含
σ
\sigma
σ’(z)。【交叉熵损失就是因为约掉了
σ
\sigma
σ’(z),所以才没有了学习速率下降的问题
Classify MNIST digits
与第一章的network.py相比我们用cross-entropy损失来计算的记为network2. py。【30个隐藏神经元,mini_batch大小为10,学习率为0.5,训练30个周期
import mnist_loader
training_data, validation_data, test_data = \mnist_loader.load_data_wrapper()
import network2
net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)
net.large_weight_initializer()
net.SGD(training_data, 30, 10, 0.5, evaluation_data=test_data, monitor_evaluation_accuracy=True)
正确率95.49%【第一章95.42%。当隐藏神经元个数为100个时,正确率96.82%【第一章96.59%,进步还是蛮大的。不过也不能确信cross-entropy cost就一定比quadratic cost好,因为我们还没有关注其他的参数,之后会说到。
这边顺便关注一下,我们到底应该如何理解交叉熵?这个稍微有些复杂难以理解的式子刚开始到底怎么被想出来的?
学习率变慢是因为有
σ
\sigma
σ’(z),只要找到一个损失函数,其对权重和偏置的偏导数不包含这个项就行了,从链式法则我们得知:
代入
σ
\sigma
σ’(z)=
σ
\sigma
σ(z)(1-
σ
\sigma
σ(z))=a(1-a):
对比我们需要满足的条件:
可以得到:
对上式积分:
这是对于一个训练样本的损失,对于所有的我们取其平均值:
Softmax
softmax层是定义了一种新的输出方式,不再是sigmoid函数输出,而是用一种新的输出:
输出满足:
所以其中一个增加,其他的会减少一样的数量,保证总体为1。所以output是一系列正数,总和为1,可以被当做是概率分布。
那softmax层如何帮助我们减少learning slowdown问题呢?定义一个log-likelihood损失函数【损失基于其中一个输出,这个输出越接近1,损失越小】:
OK,我们也避开了sigmoid函数的导数,所以这个也没有learning slowdown问题。
Overfitting and regularization
每天都在纠结如何理解外国人举得奇妙的例子。。anyway,作者说,自由参数很重要啦!这一部分就讲参数!
首先第一个例子是30隐藏神经元,23860参数,1000训练图片,cross-entropy cost,学习率0.5,mini-batch为10,400个周期,训练数据损失和accuracy如下:
在大概280个周期之后,accuracy并没有提高,但是cost的数据显示我们的模型还在慢慢学习,这种情况叫overfitting或者overtraining。或者是出现这种情况,在training data的时候正确率非常高,但是放到test data中,正确率很低。
有一种防止过拟合的方法,在上面import数据集的时候:
training_data, validation_data, test_data = \mnist_loader.load_data_wrapper()
validation_data是验证集,有10000张图片,我们使用这个数据集防止过拟合,在每个epoch结束后,计算validation_data的accuracy,一旦饱和我们就停止训练。使用validation_data而不是test_data设置超参数是因为我们怕超参数对test_data过拟合,这样子的正确率就是不准确的了。
但是有一个问题就是,对于test_data,当我们取得了更好的正确率的时候,我们并不能知道到底是模型更好了,还是过拟合了。在现在的条件下,我们可以用增加训练数据的方式减小过拟合,比如之前我们只用1000张训练图片,当我们训练全部50000张图片后,training_data和validation_data的正确率如下所示:
比之前只训练1000张图片时好得多,之前最大的差距有17.73%,现在只有2.53%。
Regularization
另外一种减少过拟合的方法就是正则化。这一节讲了L2 regularization或者叫weight decay,在损失函数只后加一项正则项:
在原来的损失函数上加了一项权重的平方和和一个系数,
λ
\lambda
λ是正则化系数。【不仅是交叉熵,其他的损失函数也都是一样的
这个的意思是让网络倾向于学习小权重,除非大的权重可以使第一项降低的比第二项增加的多才会被允许。这两者之间的平衡在于
λ
\lambda
λ这个系数,当
λ
\lambda
λ很小时,我们倾向最小化原来的损失函数,当
λ
\lambda
λ较大时,我们倾向学习小权重。
新的偏导:
所以对于偏置还是原来的算法:
权重变成:
跟之前的形式差不多,权重之前多了一个系数,这个系数让weight更小,所以这个方法也被称作weight decay。
之前讨论随机梯度下降的时候,我们说过可以用一个mini_batch代替所有的训练样本来计算偏导:
所以正则化之后的权重算法变成:
对于mini_batch中所有样本求和,Cx每一个样本的(未正则化)损失函数。而偏置的变化与未正则化之前一样滴:
这次我们的训练样本与之前一样,
λ
\lambda
λ取0.1。
import mnist_loader
training_data, validation_data, test_data = \ mnist_loader.load_data_wrapper()
import network2
net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)
net.large_weight_initializer()
net.SGD(training_data[:1000], 400, 10, 0.5, evaluation_data=test_data, lmbda = 0.1, monitor_evaluation_cost=True, monitor_evaluation_accuracy=True, monitor_training_cost=True, monitor_training_accuracy=True)
这次cost还是像之前一样持续减少,但是与之前不同,accuracy在持续升高:
不仅过拟合问题解决了,正确率也比之前高了很多。在我们使用50000张训练图片时,我们的正确率如下(
λ
\lambda
λ取5.0):
正确率提高了,而且两个集合之间的不同也减小了。
Other techniques for regularization
还有一些其他的减少过拟合的方法:L1 regularization,dropout,扩大数据集。
L1 regularization
在原先的损失函数后添加权重的绝对值之和为L1正则化:
此时对权重偏导为:
与L2不同的是,权重减小的量与权重无关,所以在权重绝对值非常大的时候,L1减小的量不如L2,反之权重绝对值小的时候,L1减小更多。
Dropout
Dropout不关注损失函数,而是关注神经网络本身。
我们将隐藏层中一半的神经元随机删除,其实没有删除,只是不管它们了,用剩下一般计算:
完成计算(更新权重和偏置)之后,从原来的网络中选取新的神经元集合删除,重复上述步骤多次,每次都是drop一半的神经元。由此,神经网络学习出了一系列权重和偏置。
不同的网络是有不同的过拟合的,但是在dropout过程中,我们每次都是用不同的神经元集合去训练这个网络,就相当于用了不同的网络学习,所以,我们期望这个方法可以平均过拟合的误差,达到减小过拟合的效果。
artificially expanding the training data
还是原先的30个隐藏神经元的神经网络,我们看一下数据集大小对于accuracy的影响(mini_batch为10,学习率0.5,正则化系数5.0,交叉熵损失,训练30个周期):
可以看到accuracy是在单调上升的,只不过到后面慢慢达到饱和。不过有一种方法可以提供帮助,就是人工增大数据集。比如我们可以给数字都旋转15度:
当然还可以对图片做很多微小的改变,用增加之后的数据集我们可以极大的改善结果。