最近开始认真学习了下反向传播算法和梯度传递的问题,其本质是导数的链式法则的应用,由此可以分析出为什么sigmoid激活函数不适合用于做多层网络的激活函数,可以考虑联系我的另一篇关于激活函数的文章。如有谬误,请联系指正。转载请注明出处。
联系方式:
e-mail: [email protected]
QQ: 973926198
github: https://github.com/FesianXu
完整代码开源: click me || 其中的sigmoid_base_BP.py
要知道什么是反向传播算法,我们还是要从神经网络开始将起。神经网络如图所示。
图中所示的是一个具有一个输入层(input layer),一个隐藏层(hidden layer),一个输出层(output layer)的三层神经网络。我们都知道,在神经网络的训练过程中,其权值是通过梯度的变化大小来更新的,我们这里先进行符号规定,以便于接下来的分析。
w j k l w^l_{jk} wjkl 是l-1层的第k个神经元与l层的第j个神经元的连接权值
b j l b^l_{j} bjl 是l层的第j个神经元的偏置。
z j l z^l_{j} zjl 是l层的第j神经元的输入。
a j l a^l_{j} ajl 是l层的第j神经元的激活输出。
用公式表达即是:
(1.1) z j l = ∑ k ( w j k l ∗ a k l − 1 + b j l ) z^l_{j} = \sum_{k} (w^l_{jk}*a^{l-1}_{k}+b^l_j) \tag{1.1} zjl=k∑(wjkl∗akl−1+bjl)(1.1)
(1.2) a j l = σ ( z j l ) = σ ( ∑ k ( w j k l ∗ a k l − 1 + b j l ) ) a^l_j = \sigma(z^l_j) = \sigma(\sum_k (w^l_{jk}*a^{l-1}_k+b^l_j) ) \tag{1.2} ajl=σ(zjl)=σ(k∑(wjkl∗akl−1+bjl))(1.2)
其中的 σ ( x ) \sigma(x) σ(x)为激活函数。多采用sigmoid,ReLU,tanh等。
C = 1 2 n ∗ ∑ x ∣ ∣ y − a L ∣ ∣ 2 C = \frac{1}{2n}*\sum_x||y-a^L||^2 C=2n1∗∑x∣∣y−aL∣∣2 代价函数,其中L是神经网络的层数。
我们知道,进行权值更新的时候,我们采用的是梯度下降法更新(Gradient Descent), 公式如下:
(1.3) w j k l : = w j k l − η ∗ ∂ C ∂ w j k l w^l_{jk} := w^l_{jk}-\eta*\frac{\partial{C}}{\partial{w^l_{jk}}} \tag{1.3} wjkl:=wjkl−η∗∂wjkl∂C(1.3)
这里最重要的便是需要求得 ∂ C ∂ w j k l \frac{\partial{C}}{\partial{w^l_{jk}}} ∂wjkl∂C,为了求得这个导数,我们现在有几个公式需要推导,这些公式大多都有链式法则推导而出。
其中我们要注意的是,对于某层的误差 δ l \delta^l δl定义为 δ l = ∂ C ∂ z l \delta^l = \frac{\partial{C}}{\partial{z^l}} δl=∂zl∂C,其中具体到某一个神经元j的误差为 δ j l = ∂ C ∂ z j l \delta^l_j = \frac{\partial{C}}{\partial{z^l_j}} δjl=∂zjl∂C。
推导:
(2.1) δ j L = ∂ C ∂ z j L = ∂ C ∂ a j L ∗ ∂ a j L ∂ z j L = ∂ C ∂ a j L ∗ σ ′ ( z j L ) \delta^L_j = \frac{\partial{C}}{\partial{z^L_j}} = \frac{\partial{C}}{\partial{a^L_j}}*\frac{\partial{a^L_j}}{\partial{z^L_j}} = \frac{\partial{C}}{\partial{a^L_j}}*\sigma^\prime(z^L_j) \tag{2.1} δjL=∂zjL∂C=∂ajL∂C∗∂zjL∂ajL=∂ajL∂C∗σ′(zjL)(2.1)
所以当扩展到对于所有的第L层的神经元时,我们为了方便用一个矩阵去代表我们的结果:
(2.2) δ L = ( δ 1 L δ 2 L ) \delta^L = \left(\begin{array}{c} \delta^L_1 \\ \delta^L_2 \end{array}\right) \tag{2.2} δL=(δ1Lδ2L)(2.2)
需要注意的是,所有的误差矩阵都可以这样定义,如:
(2.3) δ l = ( δ 1 l , δ 2 l , ⋯   , δ n l ) T \delta^l = (\delta^l_1, \delta^l_2, \cdots,\delta^l_n)^T \tag{2.3} δl=(δ1l,δ2l,⋯,δnl)T(2.3)
其中n是l层神经元的数量,类似的,可以得出:
(2.4) σ ′ ( z l ) = ( σ ′ ( z 1 l ) , σ ′ ( z 2 l ) , ⋯   , σ ′ ( z n l ) ) \sigma^\prime(z^l) = (\sigma^\prime(z^l_1),\sigma^\prime(z^l_2),\cdots,\sigma^\prime(z^l_n)) \tag{2.4} σ′(zl)=(σ′(z1l),σ′(z2l),⋯,σ′(znl))(2.4)
其中n是第l层的神经元数量
由此可以得出结论:
(2.5) δ L = ∇ a C ⨀ σ ′ ( z L ) \delta^L = \nabla_a{C}\bigodot \sigma^\prime(z^L) \tag{2.5} δL=∇aC⨀σ′(zL)(2.5)
其中, ∇ ( ⋅ ) \nabla(·) ∇(⋅)算子代表了梯度,具体为 ∇ x f ( x ) \nabla_xf(x) ∇xf(x)代表 f ( x ) f(x) f(x)对 x x x的所有偏导数的矩阵,类似于:
(2.6) ∇ x f ( x ) = ( ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , ⋯   , ∂ f ( x ) ∂ x n ) , x ∈ R n \nabla_xf(x) = (\frac{\partial{f(x)}}{\partial{x_1}}, \frac{\partial{f(x)}}{\partial{x_2}}, \cdots, \frac{\partial{f(x)}}{\partial{x_n}}), x \in R^n \tag{2.6} ∇xf(x)=(∂x1∂f(x),∂x2∂f(x),⋯,∂xn∂f(x)),x∈Rn(2.6)
而 ⨀ \bigodot ⨀是点乘,表示了两个操作数的各个元素的分别相乘,前提是两个操作数的维度统一。
(3.1) δ j l = ∂ C ∂ z j l = ∑ k ∂ C ∂ z k l + 1 ∗ ∂ z k l + 1 ∂ a j l ∗ ∂ a j l ∂ z j l = ∑ k δ k l + 1 ∗ ∂ ( w k j l + 1 ∗ a j l + b k l + 1 ) ∂ a j l ∗ σ ′ ( z j l ) = ∑ k ( δ k l + 1 ∗ w k j l + 1 ∗ σ ′ ( z j l ) ) \delta^l_j = \frac{\partial{C}}{\partial{z^l_j}} = \sum_k \frac{\partial C}{ \partial z^{l+1}_k} * \frac{ \partial{z^{l+1}_k} }{ \partial{a^l_j} } * \frac{ \partial{a^l_j} }{ \partial{z^l_j} } \\ = \sum_k \delta^{l+1}_k * \frac{ \partial({w^{l+1}_{kj}} * a^l_j+b^{l+1}_k )}{ \partial{a^l_j} } * \sigma^\prime(z^l_j) = \sum_k(\delta^{l+1}_k*w^{l+1}_{kj}*\sigma^\prime(z^l_j)) \tag{3.1} δjl=∂zjl∂C=k∑∂zkl+1∂C∗∂ajl∂zkl+1∗∂zjl∂ajl=k∑δkl+1∗∂ajl∂(wkjl+1∗ajl+bkl+1)∗σ′(zjl)=k∑(δkl+1∗wkjl+1∗σ′(zjl))(3.1)
同样的,为了表示方便,也多用矩阵形式表示,有:
(3.2) δ 1 l = δ 1 l + 1 ∗ w 11 l + 1 ∗ σ ′ ( z 1 l ) + δ 2 l + 1 ∗ w 21 l + 1 ∗ σ ′ ( z 1 l ) \delta^l_1 = \delta^{l+1}_1*w^{l+1}_{11}*\sigma^\prime(z^l_1)+ \delta^{l+1}_2*w^{l+1}_{21}*\sigma^\prime(z^l_1) \tag{3.2} δ1l=δ1l+1∗w11l+1∗σ′(z1l)+δ2l+1∗w21l+1∗σ′(z1l)(3.2)
(3.3) δ 2 l = δ 1 l + 1 ∗ w 12 l + 1 ∗ σ ′ ( z 2 l ) + δ 2 l + 1 ∗ w 22 l + 1 ∗ σ ′ ( z 2 l ) \delta^l_2 = \delta^{l+1}_1*w^{l+1}_{12}*\sigma^\prime(z^l_2)+ \delta^{l+1}_2*w^{l+1}_{22}*\sigma^\prime(z^l_2) \tag{3.3} δ2l=δ1l+1∗w12l+1∗σ′(z2l)+δ2l+1∗w22l+1∗σ′(z2l)(3.3)
(3.4) δ 3 l = δ 1 l + 1 ∗ w 13 l + 1 ∗ σ ′ ( z 3 l ) + δ 2 l + 1 ∗ w 23 l + 1 ∗ σ ′ ( z 3 l ) \delta^l_3 = \delta^{l+1}_1*w^{l+1}_{13}*\sigma^\prime(z^l_3)+ \delta^{l+1}_2*w^{l+1}_{23}*\sigma^\prime(z^l_3) \tag{3.4} δ3l=δ1l+1∗w13l+1∗σ′(z3l)+δ2l+1∗w23l+1∗σ′(z3l)(3.4)
(3.5) δ 4 l = δ 1 l + 1 ∗ w 14 l + 1 ∗ σ ′ ( z 4 l ) + δ 2 l + 1 ∗ w 24 l + 1 ∗ σ ′ ( z 4 l ) \delta^l_4 = \delta^{l+1}_1*w^{l+1}_{14}*\sigma^\prime(z^l_4)+ \delta^{l+1}_2*w^{l+1}_{24}*\sigma^\prime(z^l_4) \tag{3.5} δ4l=δ1l+1∗w14l+1∗σ′(z4l)+δ2l+1∗w24l+1∗σ′(z4l)(3.5)
(3.6) W l + 1 = ( w 11 l + 1 w 12 l + 1 w 13 l + 1 w 14 l + 1 w 21 l + 1 w 22 l + 1 w 23 l + 1 w 24 l + 1 ) W^{l+1} = \left(\begin{array}{ccc} w^{l+1}_{11} & w^{l+1}_{12} & w^{l+1}_{13} & w^{l+1}_{14}\\ w^{l+1}_{21} & w^{l+1}_{22} & w^{l+1}_{23} & w^{l+1}_{24} \end{array}\right) \tag{3.6} Wl+1=(w11l+1w21l+1w12l+1w22l+1w13l+1w23l+1w14l+1w24l+1)(3.6)
所以,有:
(3.7) δ l = ( ( W l + 1 ) T ∗ δ l + 1 ) ⨀ σ ′ ( z l ) \delta^l = ((W^{l+1})^T * \delta^{l+1}) \bigodot \sigma^\prime(z^l) \tag{3.7} δl=((Wl+1)T∗δl+1)⨀σ′(zl)(3.7)
(4.1) ∂ C ∂ w j k l = ∂ C ∂ z j l ∗ ∂ z j l ∂ w j k l = a k l − 1 ∗ δ j l = a k l − 1 ∗ ∑ k ( δ k l + 1 ∗ w k j l + 1 ∗ σ ′ ( z j l ) ) \frac{\partial{C}}{\partial{w^l_{jk}}} = \frac{\partial{C}}{\partial{z^l_{j}}} * \frac{\partial{z^l_j}}{\partial{w^l_{jk}}} = a^{l-1}_k*\delta^l_j=a^{l-1}_k * \sum_k(\delta^{l+1}_k*w^{l+1}_{kj}*\sigma^\prime(z^l_j)) \tag{4.1} ∂wjkl∂C=∂zjl∂C∗∂wjkl∂zjl=akl−1∗δjl=akl−1∗k∑(δkl+1∗wkjl+1∗σ′(zjl))(4.1)
由此可以看出, ∂ C ∂ w j k l \frac{\partial{C}}{\partial{w^l_{jk}}} ∂wjkl∂C与 σ ′ ( z j l ) \sigma^\prime(z^l_j) σ′(zjl)呈正相关的关系,当激活函数采用了sigmoid函数时,由于x越大,其导数呈现指数衰减,所以在层数太大而且输出值范围太大的时候, ∂ C ∂ w j k l \frac{\partial{C}}{\partial{w^l_{jk}}} ∂wjkl∂C就会变得很小,从而使得参数的更新速率变得很慢,因此会出现梯度消散的问题(The problem of gradient vanishing)。
此时,可以考虑替换代价函数或者激活函数,对于更换激活函数,可以更换为ReLU(Rectified Linear Units)函数, R e L U = m a x ( 0 , x ) ReLU = max(0, x) ReLU=max(0,x)其导数为分段导数,在激活区 x > 0 x > 0 x>0时,其导数恒为1,不会存在梯度消散的问题。
(5.1) ∂ C ∂ b j l = ∂ C ∂ z j l ∗ ∂ z j l ∂ b j l = δ j l ∗ 1 = δ j l \frac{\partial{C}}{\partial{b^l_j}} = \frac{\partial{C}}{\partial{z^l_j}} * \frac{\partial{z^l_j}}{\partial{b^l_j}} = \delta^l_j*1 = \delta^l_j \tag{5.1} ∂bjl∂C=∂zjl∂C∗∂bjl∂zjl=δjl∗1=δjl(5.1)
(6.1) w l : = w l − η ∗ δ l ∗ ( a l − 1 ) T w^l := w^l-\eta*\delta^l*(a^{l-1})^T \tag{6.1} wl:=wl−η∗δl∗(al−1)T(6.1)
(6.2) b l : = b l − η ∗ δ l b^l := b^l-\eta*\delta^l \tag{6.2} bl:=bl−η∗δl(6.2)
我们在这篇文章中推导了BP算法的公式,我们接下来将在下一篇文章《基于numpy和python的反向传播算法的实现与分析》中利用numpy和python实现BP算法,有兴趣的朋友请移步。