神经网络学习(八)优化方法:交叉熵代价函数

##回顾
上一节完成了BP神经网络的Python实现,并稍微改进了分类效果。下面是三层网络 [784,30,50,10],mini_batch_size = 10, eta = 3.0 的结果,

这里写图片描述

识别率基本保持在96.5%-97.0%,多次实验识别率也不能在提高了。下面继续进行学习,学习其他的优化方法。

##问题
我们通常是在犯比较严重的错误时学习的较快。但是人工神经元在其犯错较大的情况很难学习。为何学习如此缓慢?我们能够找到避免这种情况的方法吗?
首先回顾下BP算法中的四个基本公式
(BP1) δ L = ∇ a C . ∗ σ ′ ( z L ) {\bf{\delta }}^L = \nabla_a C .* \sigma'({\bf{z}}^L)\tag{BP1} δL=aC.σ(zL)(BP1) (BP2) δ l = ( ( w l + 1 ) T δ l + 1 ) . ∗ σ ′ ( z l ) \delta^l = (({\bf{w}}^{l+1})^T \delta^{l+1}) .* \sigma'({\bf{z}}^l)\tag{BP2} δl=((wl+1)Tδl+1).σ(zl)(BP2) (BP3) ∂ C ∂ b j l = δ j l \frac{\partial C}{\partial b^l_j} = \delta^l_j\tag{BP3} bjlC=δjl(BP3) (BP4) ∂ C ∂ w j k l = a k l − 1 δ j l \frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j\tag{BP4} wjklC=akl1δjl(BP4)
上面公式显示,代价函数的偏导数( ∂ C / ∂ w \partial C/\partial w C/w ∂ C / ∂ b \partial C/\partial b C/b)决定了速度学习,额 ∂ C / ∂ w \partial C/\partial w C/w ∂ C / ∂ b \partial C/\partial b C/b 的计算依赖于激活函数的导数。如果我们利用sigmoid激活函数(如下图),当神经元的输出接近 1 1 1 的时候,曲线变得相当平,所以 σ ′ ( z ) \sigma'(z) σ(z) 就很小了。这其实就是学习缓慢的原因所在。

这里写图片描述

针对这个问题,使用其他性质更好的激活函数(比如ReLU激活函数)是一种解决方法。当然,我们也可以构造出一种新的代价函数,这个代价函数可以消除掉激活函数导数的影响。
##交叉熵代价函数
下面直接给出交叉熵代价函数的定义 (1) C = − 1 n ∑ x [ y ln ⁡ a + ( 1 − y ) ln ⁡ ( 1 − a ) ] C = -\frac{1}{n} \sum_x \left[y \ln a + (1-y ) \ln (1-a) \right]\tag{1} C=n1x[ylna+(1y)ln(1a)](1)其中 n n n 是训练数据的总数,求和是在所有的训练输入 x x x 上进行的, y y y 是对应的目标输出。由上面的交叉熵函数的定义,我们看看 δ \delta δ 的形式 (2) δ L = ∇ a C ⊙ σ ′ ( z L ) = 1 n ∑ x σ ′ ( z ) σ ( z ) ( 1 − σ ( z ) ) ( σ ( z ) − y ) {\bf{\delta }}^L = \nabla_a C \odot \sigma'({\bf{z}}^L) = \frac{1}{n} \sum_x \frac{\sigma'(z)}{\sigma(z) (1-\sigma(z))} (\sigma(z)-y)\tag{2} δL=aCσ(zL)=n1xσ(z)(1σ(z))σ(z)(σ(z)y)(2)根据 σ ( z ) = 1 / ( 1 + e − z ) \sigma(z) = 1/(1+e^{-z}) σ(z)=1/(1+ez) 的定义,和一些运算,我们可以得到 σ ′ ( z ) = σ ( z ) ( 1 − σ ( z ) ) \sigma'(z) = \sigma(z)(1-\sigma(z)) σ(z)=σ(z)(1σ(z))。我们看到 σ ′ ( z ) \sigma'(z) σ(z) σ ( z ) ( 1 − σ ( z ) ) \sigma(z)(1-\sigma(z)) σ(z)(1σ(z)) 这两项在方程中直接约去了,所以最终形式就是: (3) δ L = 1 n ∑ x ( σ ( z ) − y ) {\bf{\delta }}^L = \frac{1}{n} \sum_x (\sigma(z)-y)\tag{3} δL=n1x(σ(z)y)(3)从公式(BP2)看,即使最后一层的 σ ′ ( z L ) \sigma'(z^L) σ(zL) 消除了,但是从最后一层向前一层传递误差时,我们仍旧需要计算 σ ′ ( z j L ) \sigma'(z^L_j) σ(zjL) 的。这一点没有理解透彻。

我们应该在什么时候⽤交叉熵来替换⼆次代价函数?实际上,如果在输出神经元是 sigmoid神经元时,交叉熵⼀般都是更好的选择。为什么?考虑⼀下我们初始化⽹络的权重和偏置时通常使⽤某种随机⽅法。可能会发⽣这样的情况,这些初始选择会对某些训练输⼊误差相当明显 —— ⽐如说,⽬标输出是 1,⽽实际值是 0,或者完全反过来。如果我们使⽤⼆次代价函数,那么这就会导致学习速度的下降。它并不会完全终⽌学习的过程,因为这些权重会持续从其他的样本中进⾏学习,但是显然这不是我们想要的效果。

##测试
由于单独修改一个因素,很难提升神经网络的总体性能,我们做的测试仅仅是感性地认识下这个优化方法的性能。程序修改十分简单,只要讲gnetwork.pyupdate_mini_batch()函数中的 *delta = (a[-1]-y_train)*sigmoid_prime(z[-1])修改为delta = (a[-1]-y_train)*即可。下面是运行结果

这里写图片描述
网络结构 [784,30,10],mini_batch_size = 50, learning_rate = 1

相比于上一节中使用sigmoid激活函数的结果相比,确实提高了识别率。下面是网络结构为[784,30,50,10],mini_batch_size = 100, learning_rate = 0.5 的结果

这里写图片描述

遗憾的是,就自己编写的这个浅层BP神经网络,将ReLU激活函数和交叉熵代价函数结合起来,识别率反而没有单一方法识别率高。


##softmax和交叉熵
倘若,我们采用如下的sofmax分类器 (4) a i = e z i ∑ k e z k a_i = \frac{e^{z_i}}{\sum_k e^{z_k}}\tag{4} ai=kezkezi(4)softmax 函数能够把一组向量转换成相对应的概率向量。如果我们使用均方误差代价函数或者上面的交叉熵函数(2),我们均需要计算 softmax 函数的导数。一般与 softmax 函数配合使用的交叉熵代价为 (5) C = − ∑ i y i ln ( a i L ) C = - {\sum}_i y_i\text{ln}(a_i^L)\tag{5} C=iyiln(aiL)(5)在多分类问题中,标签 y y y 一般采用 one-hot 编码,即只有对应类别的位置为 1,其他位置为 0,那么交叉熵代价函数简化为: (6) C = − ln ( a i L ) C = - \text{ln}(a_i^L)\tag{6} C=ln(aiL)(6)下面我们看看 δ L \delta^L δL 的形式 (7) δ i L = − ∇ a i L C ⋅ σ ′ ( z i L ) = − y i a i L ( e z i ( ∑ k e z k ) 2 − e z i ∑ k e z k ) = y i ( a i L − 1 ) \delta^L_i = -\nabla_{a^L _i}C\cdot \sigma'({\bf{z}}_i^L) \\=- \frac{y_i}{a_i^L}\left( \frac{e^{z_i}}{\left( {\sum_k e^{z_k}} \right)^2}-\frac{e^{z_i}}{\sum_k e^{z_k}} \right) \\ = y_i \left(a_i^L-1\right)\tag{7} δiL=aiLCσ(ziL)=aiLyi((kezk)2ezikezkezi)=yi(aiL1)(7)Michael Nielsen 给出的形式是 (8) δ i L = a i L − y i \delta^L_i = a_i^L-y_i\tag{8} δiL=aiLyi(8)与上面我自己推导的公式稍有不同。假如对一个样本 y i = 0 y_i = 0 yi=0,按照公式(7),则 δ i L = 0 \delta^L_i = 0 δiL=0,而公式(8)得到是 δ i L = a i L \delta^L_i = a_i^L δiL=aiL,显然公式(8)训练的速度更快(因为它的每个输出神经元都参与了误差传递,而公式(7)仅仅只有 1 个输出神经元都参与了误差传递)。但是公式(7)应该没有推导错误,不知道哪个地方出了理解偏差。


(2018-3-22补充)公式(7)的推导确实是错误的。公式(5)可以分为 i = j i=j i=j i ≠ j i\neq j i̸=j部分,即 (9) C = − ∑ j ≠ i y j ln ( a j L ) + y i ln ( a i L ) C = - {\sum_ {j \neq i}} y_j\text{ln}(a_j^L)+y_i\text{ln}(a_i^L)\tag{9} C=j̸=iyjln(ajL)+yiln(aiL)(9)那么 δ i L = ∑ j ∂ C ∂ a j L ⋅ ∂ a j L ∂ z j L = ∑ j ≠ i ∂ C ∂ a j L ⋅ ∂ a j L ∂ z j L + ∂ C ∂ a i L ⋅ ∂ a i L ∂ z i L = ∑ j ≠ i − y j a j L ⋅ − e z j ⋅ e z i ( ∑ k e z k ) 2 + ( − y i a i L e z i ∑ k e z k − ( e z i ) 2 ( ∑ k e z k ) 2 ) = ∑ j ≠ i y j a j L ⋅ a j L ⋅ a i L + ( − y i a i L ) a i L ( 1 − a i L ) = ∑ j ≠ i y j ⋅ a i L + y i a i L − y i = a i L − y i \begin{array}{l} \delta _i^L = \sum\limits_j {\frac{{\partial C}}{{\partial a_j^L}}} \cdot \frac{{\partial a_j^L}}{{\partial z_j^L}}\\ {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} = \sum\limits_{j \ne i} {\frac{{\partial C}}{{\partial a_j^L}}} \cdot \frac{{\partial a_j^L}}{{\partial z_j^L}} + \frac{{\partial C}}{{\partial a_i^L}} \cdot \frac{{\partial a_i^L}}{{\partial z_i^L}}\\ {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} = \sum\limits_{j \ne i} { - \frac{{{y_j}}}{{a_j^L}}} \cdot \frac{{ - {e^{{z_j}}} \cdot {e^{{z_i}}}}}{{{{\left( {\sum\nolimits_k {{e^{{z_k}}}} } \right)}^2}}} + \left( { - \frac{{{y_i}}}{{a_i^L}}\frac{{{e^{{z_i}}}\sum\nolimits_k {{e^{{z_k}}}} - {{\left( {{e^{{z_i}}}} \right)}^2}}}{{{{\left( {\sum\nolimits_k {{e^{{z_k}}}} } \right)}^2}}}} \right)\\ {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} = \sum\limits_{j \ne i} {\frac{{{y_j}}}{{a_j^L}}} \cdot a_j^L \cdot a_i^L + \left( { - \frac{{{y_i}}}{{a_i^L}}} \right)a_i^L\left( {1 - a_i^L} \right)\\ {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} = \sum\limits_{j \ne i} {{y_j}} \cdot a_i^L + {y_i}a_i^L - {y_i}\\ {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} = a_i^L - {y_i} \end{array} δiL=jajLCzjLajL=j̸=iajLCzjLajL+aiLCziLaiL=j̸=iajLyj(kezk)2ezjezi+(aiLyi(kezk)2ezikezk(ezi)2)=j̸=iajLyjajLaiL+(aiLyi)aiL(1aiL)=j̸=iyjaiL+yiaiLyi=aiLyi公式(7)实际上丢掉了 j ≠ i j \neq i j̸=i的那一部分了,所以是错误的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值