神经网络中反向传播算法的推导

上一篇写了反向传播算法在logistic回归中的应用,的确是杀鸡用牛刀,但是神经网络就相当于若干组logistic回归叠加在一起,这篇就开始对神经网络中的反向传播算法进行介绍和推导。

浅层神经网络

先来看看一个浅层神经网络,也就是只有一层隐藏层的神经网络(这里先以二分类为例)。
浅层神经网络

符号说明

x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3是一个输入样本的三个特征, a 1 [ 1 ] a_1^{[1]} a1[1]表示第一层的第一个激活单元。我们不把输入层包括在层数内,第一层从隐藏层开始计算,或者说,把输入层看做是第0层。在这里上标中括号里的数字表示层数,下标的数字表示从上到下数第几个单元,所以 a 2 [ 1 ] a_2^{[1]} a2[1]就表示第一层第二个激活单元, a 1 [ 2 ] a_1^{[2]} a1[2]表示第二层第一个激活单元。预测值就是输出层的激活单元的值。这里再假设第l层有 n [ l ] n^{[l]} n[l]个结点。

正向传播过程

有了前面logistic回归的基础,这里神经网络的正向传播过程也很容易。
先来看输入层到隐藏层的传播过程,先计算输入层到隐藏层第一个结点的输出,如下图所示:
在这里插入图片描述
和logistic回归一样,这里输入层到隐藏层第一个结点的传播过程就应该是这样计算:

z 1 [ 1 ] = w 1 [ 1 ] T x + b 1 [ 1 ] z_1^{[1]} = w_1^{[1]T}x + b_1^{[1]} z1[1]=w1[1]Tx+b1[1]

a 1 [ 1 ] = g ( z 1 [ 1 ] ) a_1^{[1]} = g(z_1^{[1]}) a1[1]=g(z1[1])

这里 w 1 [ 1 ] w_1^{[1]} w1[1]表示输入层到隐藏层第一个结点的权重,是一个列向量,即维度是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1) x = ( x 1 , x 2 , x 3 ) T x=(x_1,x_2,x_3)^T x=(x1,x2,x3)T b 1 [ 1 ] b_1^{[1]} b1[1]表示作用在第一个激活单元上的偏置,是一个数。 g ( z ) g(z) g(z)表示激活函数, g [ 1 ] ( z 1 [ 1 ] ) g^{[1]}(z_1^{[1]}) g[1](z1[1])就是线性组合 z 1 [ 1 ] z_1^{[1]} z1[1]通过第一层激活函数的结果。
这样一共可以写出三组方程:

z 1 [ 1 ] = w 1 [ 1 ] T x + b 1 [ 1 ] z_1^{[1]} = w_1^{[1]T}x + b_1^{[1]} z1[1]=w1[1]Tx+b1[1]

a 1 [ 1 ] = g ( z 1 [ 1 ] ) a_1^{[1]} = g(z_1^{[1]}) a1[1]=g(z1[1])

z 2 [ 1 ] = w 2 [ 1 ] T x + b 2 [ 1 ] z_2^{[1]} = w_2^{[1]T}x + b_2^{[1]} z2[1]=w2[1]Tx+b2[1]

a 2 [ 1 ] = g ( z 2 [ 1 ] ) a_2^{[1]} = g(z_2^{[1]}) a2[1]=g(z2[1])

z 3 [ 1 ] = w 3 [ 1 ] T x + b 3 [ 1 ] z_3^{[1]} = w_3^{[1]T}x + b_3^{[1]} z3[1]=w3[1]Tx+b3[1]

a 3 [ 1 ] = g [ 1 ] ( z 3 [ 1 ] ) a_3^{[1]} = g^{[1]}(z_3^{[1]}) a3[1]=g[1](z3[1])

这样我们就可以向量化:
[ z 1 [ 1 ] z 3 [ 1 ] z 3 [ 1 ] ] = [ w 1 [ 1 ] T w 2 [ 1 ] T w 3 [ 1 ] T ] [ x 1 x 2 x 3 ] + [ b 1 [ 1 ] b 2 [ 1 ] b 3 [ 1 ] ] \left[ \begin{array}{l} z_1^{[1]}\\ z_3^{[1]}\\ z_3^{[1]} \end{array} \right] = \left[ \begin{array}{l} w_1^{[1]T}\\ w_2^{[1]T}\\ w_3^{[1]T} \end{array} \right]\left[ \begin{array}{l} {x_1}\\ {x_2}\\ {x_3} \end{array} \right] + \left[ \begin{array}{l} b_1^{[1]}\\ b_2^{[1]}\\ b_3^{[1]} \end{array} \right] z1[1]z3[1]z3[1]=w1[1]Tw2[1]Tw3[1]Tx1x2x3+b1[1]b2[1]b3[1]
对应的有:

z [ 1 ] = W [ 1 ] x + b [ 1 ] {z^{[1]}} = {W^{[1]}}x + {b^{[1]}} z[1]=W[1]x+b[1]

a [ 1 ] = g [ 1 ] ( z [ 1 ] ) a^{[1]}=g^{[1]}(z^{[1]}) a[1]=g[1](z[1])

检查一下维度: z [ 1 ] {z^{[1]}} z[1] ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1) W [ 1 ] W^{[1]} W[1] ( n [ 1 ] , n [ 0 ] ) (n^{[1]},n^{[0]}) (n[1],n[0]) x x x ( n [ 0 ] , 1 ) (n^{[0]},1) (n[0],1) b [ 1 ] b^{[1]} b[1] ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1)。确定没有问题。这就是输入层到隐藏层的正向传播过程。

再来看隐藏层到输出层的传播,就相当于一个递归的过程:

z [ 2 ] = W [ 2 ] a [ 1 ] + b [ 2 ] {z^{[2]}} = {W^{[2]}}a^{[1]} + {b^{[2]}} z[2]=W[2]a[1]+b[2]

a [ 2 ] = g [ 2 ] ( z [ 2 ] ) a^{[2]}=g^{[2]}(z^{[2]}) a[2]=g[2](z[2])

我们现在将其推广到m个样本,和logistic回归类似,我们需要将这些向量横向排列,就可以非常方便地得到如下方程:

Z [ 1 ] = W [ 1 ] X + b [ 1 ] {Z^{[1]}} = {W^{[1]}}X + {b^{[1]}} Z[1]=W[1]X+b[1]

A [ 1 ] = g ( Z [ 1 ] ) A^{[1]}=g(Z^{[1]}) A[1]=g(Z[1])

Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] {Z^{[2]}} = {W^{[2]}}A^{[1]} + {b^{[2]}} Z[2]=W[2]A[1]+b[2]

A [ 2 ] = g [ 2 ] ( Z [ 2 ] ) A^{[2]}=g^{[2]}(Z^{[2]}) A[2]=g[2](Z[2])

简要说明一下这些矩阵的维度,很好理解:
X X X就是将m个 x x x横向排列得到的结果,所以其维度是 ( n [ 0 ] , m ) (n^{[0]},m) (n[0],m) Z [ 1 ] {Z^{[1]}} Z[1]的维度是 ( n [ 1 ] , m ) (n^{[1]},m) (n[1],m),而 b [ 1 ] {b^{[1]}} b[1]的维度是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1),这里用到了和之前logistic回归中一样的做法,利用Python的广播,可以将这一列加到相应矩阵对应的每一列中,所以这里也这么来表示即可。相应的 A [ 1 ] {A^{[1]}} A[1]的维度也是 ( n [ 1 ] , m ) (n^{[1]},m) (n[1],m) Z [ 2 ] {Z^{[2]}} Z[2]的维度是 ( n [ 2 ] , m ) (n^{[2]},m) (n[2],m) A [ 2 ] {A^{[2]}} A[2]的维度也是 ( n [ 2 ] , m ) (n^{[2]},m) (n[2],m) b [ 2 ] {b^{[2]}} b[2]的维度是 ( n [ 2 ] , 1 ) (n^{[2]},1) (n[2],1)

反向传播过程

这个浅层神经网络的损失函数与logistic回归是一样的,代价函数也类似,只不过这里代价函数的参数有4个矩阵:
J ( W [ 1 ] , b [ 1 ] , W [ 2 ] , b [ 2 ] ) = 1 m ∑ i = 1 m L ( y ^ , y ) J({W^{[1]}},{b^{[1]}},{W^{[2]}},{b^{[2]}}) = \frac{1}{m}\sum\limits_{i = 1}^m {L(\hat y,y)} J(W[1],b[1],W[2],b[2])=m1i=1mL(y^,y)
上一篇的logistic回归的反向传播算法推导中,得到了相应的偏导,不妨再来回顾一下(先以一个样本为例):
d a = − y a + 1 − y 1 − a da=- \frac{y}{a} + \frac{{1 - y}}{{1 - a}} da=ay+1a1y d z = d a ⋅ g ′ ( z ) dz=da\cdot g'(z) dz=dag(z) d w = x d z dw=xdz dw=xdz d b = d z db=dz db=dz
而二分类的浅层神经网络中,隐藏层到输出层之间的连接与logistics回归完全一致,因此,我们可以类比得到:

d z [ 2 ] = d a [ 2 ] ⋅ g [ 2 ] ′ ( z [ 2 ] ) dz^{[2]}=da^{[2]}\cdot g^{[2]'}(z^{[2]}) dz[2]=da[2]g[2](z[2]),输出层的激活函数为sigmoid函数,所以可以得到:
d z [ 2 ] = a [ 2 ] − y dz^{[2]}=a^{[2]}-y dz[2]=a[2]y

d W [ 2 ] = d z [ 2 ] a [ 1 ] T dW^{[2]}=dz^{[2]}a^{[1]T} dW[2]=dz[2]a[1]T(这里与logistic回归不一致是因为 W [ 2 ] W^{[2]} W[2]在构建的时候是将 w 1 [ 2 ] w^{[2]}_1 w1[2]给转置了,所以现在相当于这个等式整体转置了一下)

d b [ 2 ] = d z [ 2 ] db^{[2]}=dz^{[2]} db[2]=dz[2]

隐藏层到输入层的反向传播中, d W [ 1 ] dW^{[1]} dW[1] d b [ 1 ] db^{[1]} db[1]是非常好求得的,因为类比logistic回归,这两个值的求解都依赖于 d z [ 1 ] dz^{[1]} dz[1],所以有:

d W [ 1 ] = d z [ 1 ] x T dW^{[1]}=dz^{[1]}x^{T} dW[1]=dz[1]xT

d b [ 1 ] = d z [ 1 ] db^{[1]}=dz^{[1]} db[1]=dz[1]

但是求解 d z [ 1 ] dz^{[1]} dz[1]就比较麻烦了,因为求解 d z [ 1 ] dz^{[1]} dz[1],就必须得到 d a [ 1 ] da^{[1]} da[1],而求解 d a [ 1 ] da^{[1]} da[1] d a [ 2 ] da^{[2]} da[2]不同,它有四个单元,对每个单元的求导都涉及到多个偏导分量的求和,我们不妨用链式法则,从头推导得到 d z [ 1 ] dz^{[1]} dz[1],具体过程如下:

先以求 L L L z 1 [ 1 ] z^{[1]}_1 z1[1]的偏导为例,根据链式法则,有:

∂ L ∂ z 1 [ 1 ] = ∂ L ∂ a 1 [ 1 ] ⋅ d a 1 [ 1 ] d z 1 [ 1 ] \frac{{\partial L}}{{\partial z_1^{[1]}}} = \frac{{\partial L}}{{\partial a_1^{[1]}}} \cdot \frac{{da_1^{[1]}}}{{dz_1^{[1]}}} z1[1]L=a1[1]Ldz1[1]da1[1]

d a 1 [ 1 ] d z 1 [ 1 ] = g [ 1 ] ′ ( z 1 [ 1 ] ) \frac{{da_1^{[1]}}}{{dz_1^{[1]}}} = g^{[1]'}(z_1^{[1]}) dz1[1]da1[1]=g[1](z1[1])

所以我们需要求得 ∂ L ∂ a 1 [ 1 ] \frac{{\partial L}}{{\partial a_1^{[1]}}} a1[1]L

根据链式法则:

∂ L ∂ a 1 [ 1 ] = ∂ L ∂ z 1 [ 2 ] ⋅ d z 1 [ 2 ] d a 1 [ 1 ] + ∂ L ∂ z 2 [ 2 ] ⋅ d z 2 [ 2 ] d a 1 [ 1 ] + . . . + ∂ L ∂ z n [ 2 ] [ 2 ] ⋅ d z n [ 2 ] [ 2 ] d a 1 [ 1 ] \frac{{\partial L}}{{\partial a_1^{[1]}}} = \frac{{\partial L}}{{\partial z_1^{[2]}}} \cdot \frac{{dz_1^{[2]}}}{{da_1^{[1]}}} + \frac{{\partial L}}{{\partial z_2^{[2]}}} \cdot \frac{{dz_2^{[2]}}}{{da_1^{[1]}}} + ... + \frac{{\partial L}}{{\partial z_{{n^{[2]}}}^{[2]}}} \cdot \frac{{dz_{{n^{[2]}}}^{[2]}}}{{da_1^{[1]}}} a1[1]L=z1[2]Lda1[1]dz1[2]+z2[2]Lda1[1]dz2[2]+...+zn[2][2]Lda1[1]dzn[2][2]

(注意,在这里,虽然这个简单神经网络的输出层只有一个单元,但是此证明是根据一般情况来说明的,即第2层有 n [ 2 ] n^{[2]} n[2]个单元)

又有:
d z 1 [ 2 ] d a 1 [ 1 ] = W 11 [ 2 ] \frac{{dz_1^{[2]}}}{{da_1^{[1]}}} = W_{11}^{[2]} da1[1]dz1[2]=W11[2]

d z 2 [ 2 ] d a 1 [ 1 ] = W 21 [ 2 ] \frac{{dz_2^{[2]}}}{{da_1^{[1]}}} = W_{21}^{[2]} da1[1]dz2[2]=W21[2]

d z n [ 2 ] [ 2 ] d a 1 [ 1 ] = W n [ 2 ] 1 [ 2 ] \frac{{dz_{{n^{[2]}}}^{[2]}}}{{da_1^{[1]}}} = W_{{n^{[2]}}1}^{[2]} da1[1]dzn[2][2]=Wn[2]1[2]

因此,有:
∂ L ∂ a 1 [ 1 ] = ∂ L ∂ z 1 [ 2 ] ⋅ W 11 [ 2 ] + ∂ L ∂ z 2 [ 2 ] ⋅ W 21 [ 2 ] + . . . + ∂ L ∂ z n [ 2 ] [ 2 ] ⋅ W n [ 2 ] 1 [ 2 ] \frac{{\partial L}}{{\partial a_1^{[1]}}} = \frac{{\partial L}}{{\partial z_1^{[2]}}} \cdot W_{11}^{[2]} + \frac{{\partial L}}{{\partial z_2^{[2]}}} \cdot W_{21}^{[2]} + ... + \frac{{\partial L}}{{\partial z_{{n^{[2]}}}^{[2]}}} \cdot W_{{n^{[2]}}1}^{[2]} a1[1]L=z1[2]LW11[2]+z2[2]LW21[2]+...+zn[2][2]LWn[2]1[2]

用d Var来表示损失函数L对变量Var的偏导这种记法,就是:
d a 1 [ 1 ] = d z 1 [ 2 ] ⋅ W 11 [ 2 ] + d z 2 [ 2 ] ⋅ W 21 [ 2 ] + . . . + d z n [ 2 ] [ 2 ] ⋅ W n [ 2 ] 1 [ 2 ] da_1^{[1]} = dz_1^{[2]} \cdot W_{11}^{[2]} + dz_2^{[2]} \cdot W_{21}^{[2]} + ... + dz_{{n^{[2]}}}^{[2]} \cdot W_{{n^{[2]}}1}^{[2]} da1[1]=dz1[2]W11[2]+dz2[2]W21[2]+...+dzn[2][2]Wn[2]1[2]

我们可以很容易的对其进行向量化:

d a 1 [ 1 ] = [ W 11 [ 2 ] , W 21 [ 2 ] , . . . , W n [ 2 ] 1 [ 2 ] ] [ d z 1 [ 2 ] d z 2 [ 2 ] . . . . . . d z n [ 2 ] [ 2 ] ] da_1^{[1]} = \left[ {W_{11}^{[2]},W_{21}^{[2]},...,W_{{n^{[2]}}1}^{[2]}} \right]\left[ \begin{array}{l} dz_1^{[2]}\\ dz_2^{[2]}\\ ......\\ dz_{{n^{[2]}}}^{[2]} \end{array} \right] da1[1]=[W11[2],W21[2],...,Wn[2]1[2]]dz1[2]dz2[2]......dzn[2][2]

这样,就可以得到:
d z 1 [ 1 ] = d a 1 [ 1 ] ⋅ g [ 1 ] ′ ( z 1 [ 1 ] ) = [ W 11 [ 2 ] , W 21 [ 2 ] , . . . , W n [ 2 ] 1 [ 2 ] ] [ d z 1 [ 2 ] d z 2 [ 2 ] . . . . . . d z n [ 2 ] [ 2 ] ] ⋅ g [ 1 ] ′ ( z 1 [ 1 ] ) dz_1^{[1]} = da_1^{[1]} \cdot g^{[1]'}(z_1^{[1]}) = \left[ {W_{11}^{[2]},W_{21}^{[2]},...,W_{{n^{[2]}}1}^{[2]}} \right]\left[ \begin{array}{l} dz_1^{[2]}\\ dz_2^{[2]}\\ ......\\ dz_{{n^{[2]}}}^{[2]} \end{array} \right] \cdot g^{[1]'}(z_1^{[1]}) dz1[1]=da1[1]g[1](z1[1])=[W11[2],W21[2],...,Wn[2]1[2]]dz1[2]dz2[2]......dzn[2][2]g[1](z1[1])

同理,我们可以得到所有的 d z i [ 1 ] dz_i^{[1]} dzi[1] d a i [ 1 ] da_i^{[1]} dai[1],我们将 d z i [ 1 ] dz_i^{[1]} dzi[1] d a i [ 1 ] da_i^{[1]} dai[1]均纵向堆叠起来,可以得到:

[ d z 1 [ 1 ] d z 2 [ 1 ] . . . . . . d z n [ 1 ] [ 1 ] ] = [ d a 1 [ 1 ] d a 2 [ 1 ] . . . . . . d a n [ 1 ] [ 1 ] ] ∗ [ g [ 1 ] ′ ( z 1 [ 1 ] ) g [ 1 ] ′ ( z 2 [ 1 ] ) . . . . . . g [ 1 ] ′ ( z n [ 1 ] [ 1 ] ) ] \left[ \begin{array}{l} dz_1^{[1]}\\ dz_2^{[1]}\\ ......\\ dz_{{n^{[1]}}}^{[1]} \end{array} \right] = \left[ \begin{array}{l} da_1^{[1]}\\ da_2^{[1]}\\ ......\\ da_{{n^{[1]}}}^{[1]} \end{array} \right]*\left[ \begin{array}{l} g^{[1]'}(z_1^{[1]})\\ g^{[1]'}(z_2^{[1]})\\ ......\\ g^{[1]'}(z_{{n^{[1]}}}^{[1]}) \end{array} \right] dz1[1]dz2[1]......dzn[1][1]=da1[1]da2[1]......dan[1][1]g[1](z1[1])g[1](z2[1])......g[1](zn[1][1])

这里的“*”代表对应元素相乘。

再进一步向量化 d a i [ 1 ] da_i^{[1]} dai[1],有:
[ d a 1 [ 1 ] d a 2 [ 1 ] . . . . . . d a n [ 1 ] [ 1 ] ] = [ W 11 [ 2 ] , W 21 [ 2 ] , . . . , W n [ 2 ] 1 [ 2 ] W 12 [ 2 ] , W 22 [ 2 ] , . . . , W n [ 2 ] 2 [ 2 ] . . . . . . W 1 n [ 2 ] [ 2 ] , W 2 n [ 2 ] [ 2 ] , . . . , W n [ 2 ] n [ 2 ] [ 2 ] ] [ d z 1 [ 2 ] d z 2 [ 2 ] . . . . . . d z n [ 2 ] [ 2 ] ] \left[ \begin{array}{l} da_1^{[1]}\\ da_2^{[1]}\\ ......\\ da_{{n^{[1]}}}^{[1]} \end{array} \right] = \left[ \begin{array}{l} W_{11}^{[2]},W_{21}^{[2]},...,W_{{n^{[2]}}1}^{[2]}\\ W_{12}^{[2]},W_{22}^{[2]},...,W_{{n^{[2]}}2}^{[2]}\\ ......\\ W_{1{n^{[2]}}}^{[2]},W_{2{n^{[2]}}}^{[2]},...,W_{{n^{[2]}}{n^{[2]}}}^{[2]} \end{array} \right]\left[ \begin{array}{l} dz_1^{[2]}\\ dz_2^{[2]}\\ ......\\ dz_{{n^{[2]}}}^{[2]} \end{array} \right] da1[1]da2[1]......dan[1][1]=W11[2],W21[2],...,Wn[2]1[2]W12[2],W22[2],...,Wn[2]2[2]......W1n[2][2],W2n[2][2],...,Wn[2]n[2][2]dz1[2]dz2[2]......dzn[2][2]

d a [ 1 ] = W [ 2 ] T d z [ 2 ] d{a^{[1]}} = {W^{[2]T}}d{z^{[2]}} da[1]=W[2]Tdz[2]

d z [ 1 ] = W [ 2 ] T d z [ 2 ] ∗ g [ 1 ] ′ ( z [ 1 ] ) d{z^{[1]}} = {W^{[2]T}}d{z^{[2]}}*{g^{[1]}}^\prime ({z^{[1]}}) dz[1]=W[2]Tdz[2]g[1](z[1])

(“*”表示对应元素相乘)

这样我们就推导了 d z [ 1 ] d{z^{[1]}} dz[1]的表达式。不妨来检验一下维度,看看结果是否正确:
d z [ 1 ] dz^{[1]} dz[1]的维度是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1) W [ 2 ] T W^{[2]T} W[2]T的维度是 ( n [ 1 ] , n [ 2 ] ) (n^{[1]},n^{[2]}) (n[1],n[2]) d z [ 2 ] dz^{[2]} dz[2]的维度是 ( n [ 2 ] , 1 ) (n^{[2]},1) (n[2],1),所以 W [ 2 ] T d z [ 2 ] {W^{[2]T}}d{z^{[2]}} W[2]Tdz[2]的维度就是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1),而 g [ 1 ] ′ ( z [ 1 ] ) {g^{[1]}}^\prime ({z^{[1]}}) g[1](z[1])的维度和 z [ 1 ] z^{[1]} z[1]是一样的,也是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1),因此,和 W [ 2 ] T d z [ 2 ] {W^{[2]T}}d{z^{[2]}} W[2]Tdz[2]对应元素相乘,维度依然是 ( n [ 1 ] , 1 ) (n^{[1]},1) (n[1],1)。完全正确。

这样我们就得到了浅层神经网络反向传播的重要方程(单个样本):

d z [ 2 ] = d a [ 2 ] ⋅ g [ 2 ] ′ ( z [ 2 ] ) dz^{[2]}=da^{[2]}\cdot g^{[2]'}(z^{[2]}) dz[2]=da[2]g[2](z[2]),输出层的激活函数为sigmoid函数,所以可以得到:
d z [ 2 ] = a [ 2 ] − y dz^{[2]}=a^{[2]}-y dz[2]=a[2]y

d W [ 2 ] = d z [ 2 ] a [ 1 ] T dW^{[2]}=dz^{[2]}a^{[1]T} dW[2]=dz[2]a[1]T

d b [ 2 ] = d z [ 2 ] db^{[2]}=dz^{[2]} db[2]=dz[2]

d W [ 1 ] = d z [ 1 ] x T dW^{[1]}=dz^{[1]}x^{T} dW[1]=dz[1]xT

d b [ 1 ] = d z [ 1 ] db^{[1]}=dz^{[1]} db[1]=dz[1]

d z [ 1 ] = W [ 2 ] T d z [ 2 ] ∗ g [ 1 ] ′ ( z [ 1 ] ) d{z^{[1]}} = {W^{[2]T}}d{z^{[2]}}*{g^{[1]}}^\prime ({z^{[1]}}) dz[1]=W[2]Tdz[2]g[1](z[1])

类似于logistic回归中的情况,我们现在可以将其推广到m个样本的情况中:

d Z [ 2 ] = A [ 2 ] − Y dZ^{[2]}=A^{[2]}-Y dZ[2]=A[2]Y

d W [ 2 ] = 1 m d Z [ 2 ] A [ 1 ] T dW^{[2]}=\frac{1}{m}dZ^{[2]}A^{[1]T} dW[2]=m1dZ[2]A[1]T

d b [ 2 ] = 1 m n p . s u m ( d Z [ 2 ] , a x i s = 1 , k e e p d i m s = T r u e ) db^{[2]}=\frac{1}{m}np.sum(dZ^{[2]},axis=1,keepdims=True) db[2]=m1np.sum(dZ[2],axis=1,keepdims=True) (这里用Python中numpy的函数来表示,更加方便,下面的db^{[1]}也一样,这里keepdims=True是为了让乘法结果的维度不会消失,依然保持为 ( n [ 2 ] , 1 ) (n^{[2]},1) (n[2],1),而不是numpy中的 ( n [ 2 ] , ) (n^{[2]},) (n[2],)

d W [ 1 ] = 1 m d Z [ 1 ] X T dW^{[1]}=\frac{1}{m}dZ^{[1]}X^{T} dW[1]=m1dZ[1]XT

d b [ 1 ] = 1 m n p . s u m ( d Z [ 1 ] , a x i s = 1 , k e e p d i m s = T r u e ) db^{[1]}=\frac{1}{m}np.sum(dZ^{[1]},axis=1,keepdims=True) db[1]=m1np.sum(dZ[1],axis=1,keepdims=True)

有了这些方程,就可以再结合正向传播的过程,进行梯度下降了,梯度下降不再赘述。

深度神经网络

深度神经网络就是隐藏层数大于一的神经网络,比浅层神经网络多了若干层,其实大体上类似,公式可以类比得到。
深度神经网络

前向传播

由浅层神经网络的前向传播过程,我们可以直接得到深度神经网络的前向传播过程:

z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] {z^{[l]}} = {W^{[l]}}a^{[l-1]} + {b^{[l]}} z[l]=W[l]a[l1]+b[l]

a [ l ] = g [ l ] ( z [ l ] ) a^{[l]}=g^{[l]}(z^{[l]}) a[l]=g[l](z[l])

这里依然以一个样本为例,其中 l l l表示第 l l l层。我们也很容易得到m个样本的结果:

Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] {Z^{[l]}} = {W^{[l]}}A^{[l-1]} + {b^{[l]}} Z[l]=W[l]A[l1]+b[l]

A [ l ] = g [ l ] ( Z [ l ] ) A^{[l]}=g^{[l]}(Z^{[l]}) A[l]=g[l](Z[l])
其中, l l l的范围是[1,m]。

代价函数

这次,我们考虑更一般的情况,也就是多分类的情况。此时,损失函数为:

L ( y , y ^ ) = − ∑ k = 1 K [ y k log ⁡ ( y ^ k ) + ( 1 − y k ) log ⁡ ( 1 − y ^ k ) ] L(y,{\hat y})=- \sum\limits_{k = 1}^K {[{y_k}\log ({{\hat y}_k}) + (1 - {y_k})} \log (1 - {\hat y_k})] L(y,y^)=k=1K[yklog(y^k)+(1yk)log(1y^k)]

在这里, y ^ k {{\hat y}_k} y^k表示 y ^ {\hat y} y^的第k个元素。
如果标签 y = [ 1 0 0 ] y = \left[ \begin{array}{l} 1\\ 0\\ 0 \end{array} \right] y=100
说明分类结果为第一个分类,
如果 y = [ 0 1 0 ] y = \left[ \begin{array}{l} 0\\ 1\\ 0 \end{array} \right] y=010
说明分类结果为第二个分类,以此类推。用这样的方式来表示标签 y y y

对于m个样本来说,总的代价函数为:

J ( W [ l ] , b [ l ] ) = − 1 m ∑ i = 1 m ∑ k = 1 K [ y k ( i ) log ⁡ ( y ^ k ( i ) ) ] J({W^{[l]}},{b^{[l]}}) = - \frac{1}{m}\sum\limits_{i = 1}^m {\sum\limits_{k = 1}^K {[{y_k}^{(i)}\log (\hat y_k^{(i)}) }]} J(W[l],b[l])=m1i=1mk=1K[yk(i)log(y^k(i))]

这实际上就是softmax回归了。
此时,代价函数的参数为 W W W b b b两组矩阵,每组有 L L L个,也就是神经网络的层数。

反向传播

反向传播的过程和浅层神经网络也很类似,之前已经证明过相应的过程。
反向传播每一层的输入为 d a [ l ] da^{[l]} da[l],输出为 d a [ l − 1 ] da^{[l-1]} da[l1] W [ l ] W^{[l]} W[l] b [ l ] b^{[l]} b[l],同时会产生 d z [ l ] dz^{[l]} dz[l]
类似于浅层网络,我们可以得到通用的表达式如下(单个样本):

d z [ l ] = d a [ l ] ∗ g [ l ] ′ ( z [ l ] ) d{z^{[l]}} = d{a^{[l]}}*{g^{[l]'}}({z^{[l]}}) dz[l]=da[l]g[l](z[l]) (“*” 表示对应元素相乘)

d W [ l ] = d z [ l ] ⋅ a [ l − 1 ] T d{W^{[l]}} = d{z^{[l]}} \cdot {a^{[l - 1]T}} dW[l]=dz[l]a[l1]T

d b [ l ] = d z [ l ] d{b^{[l]}} = d{z^{[l]}} db[l]=dz[l]

d a [ l − 1 ] = W [ l ] T d z [ l ] d{a^{[l - 1]}} = {W^{[l]T}}{dz^{[l]}} da[l1]=W[l]Tdz[l]

推广到m个样本中即为:

d Z [ l ] = d A [ l ] ∗ g [ l ] ′ ( Z [ l ] ) d{Z^{[l]}} = d{A^{[l]}}*{g^{[l]'}}({Z^{[l]}}) dZ[l]=dA[l]g[l](Z[l]) (“*” 表示对应元素相乘)

d W [ l ] = 1 m d Z [ l ] A [ l − 1 ] T d{W^{[l]}} = \frac{1}{m}d{Z^{[l]}}{A^{[l - 1]T}} dW[l]=m1dZ[l]A[l1]T

d b [ l ] = 1 m n p . s u m ( d Z [ l ] , a x i s = 1 , k e e p d i m s = T r u e ) d{b^{[l]}} = \frac{1}{m}np.sum(dZ^{[l]},axis=1,keepdims=True) db[l]=m1np.sum(dZ[l],axis=1,keepdims=True)

d A [ l − 1 ] = W [ l ] T d Z [ l ] d{A^{[l - 1]}} = {W^{[l]T}}{dZ^{[l]}} dA[l1]=W[l]TdZ[l]

总结

在理解浅层神经网络的基础上,理解深度神经网络其实是非常容易的。在正向传播中,每一层都输入 A [ l − 1 ] A^{[l-1]} A[l1],输出 A [ l ] A^{[l]} A[l],起始的输入为 X X X。在反向传播过程中,每一层都输入 d A [ l ] dA^{[l]} dA[l],输出 d A [ l − 1 ] dA^{[l-1]} dA[l1] W [ l ] W^{[l]} W[l] b [ l ] b^{[l]} b[l],起始的输入为 d A [ L ] dA^{[L]} dA[L],也就是代价函数关于最终输出值的导数,可以由代价函数的公式直接求得。一次正向传播加上一次反向传播后,就可以得到相应的梯度,进行一次梯度下降。

关于神经网络BP算法的记录就到此结束,本文涉及到的代价函数均不包含正则项,如果加上正则项,只需要在每一项偏导后加上相应的值。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》,课程链接 https://edu.csdn.net/course/detail/29865【为什么要学习这门课】 Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. 冗谈不够,放码过来!  代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。【课程内容与收获】 本课程将解析YOLOv4的实现原理和源码,具体内容包括:- YOLOv4目标检测原理- 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算- 代码阅读工具及方法- 深度学习计算的利器:BLAS和GEMM- GPU的CUDA编程方法及在darknet的应用- YOLOv4的程序流程- YOLOv4各层及关键技术的源码解析本课程将提供注释后的darknet的源码程序文件。【相关课程】 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括:《YOLOv4目标检测实战:训练自己的数据集》《YOLOv4-tiny目标检测实战:训练自己的数据集》《YOLOv4目标检测实战:人脸口罩佩戴检测》《YOLOv4目标检测实战:国交通标志识别》建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。【YOLOv4网络模型架构图】 下图由白勇老师绘制  
【为什么要学习这门课程】深度学习框架如TensorFlow和Pytorch掩盖了深度学习底层实现方法,那能否能用Python代码从零实现来学习深度学习原理呢?本课程就为大家提供了这个可能,有助于深刻理解深度学习原理。左手原理、右手代码,双管齐下!本课程详细讲解深度学习原理并进行Python代码实现深度学习网络。课程内容涵盖感知机、多层感知机、卷积神经网络、循环神经网络,并使用Python 3及Numpy、Matplotlib从零实现上述神经网络。本课程还讲述了神经网络的训练方法与实践技巧,且开展了代码实践演示。课程对于核心内容讲解深入细致,如基于计算图理解反向传播算法,并用数学公式推导反向传播算法;另外还讲述了卷积加速方法im2col。【课程收获】本课程力求使学员通过深度学习原理、算法公式及Python代码的对照学习,摆脱框架而掌握深度学习底层实现原理与方法。本课程将给学员分享深度学习的Python实现代码。课程代码通过Jupyter Notebook演示,可在Windows、ubuntu等系统上运行,且不需GPU支持。【优惠说明】 课程正在优惠!  备注:购课后可加入白勇老师课程学习交流QQ群:957519975【相关课程】学习本课程的前提是会使用Python语言以及Numpy和Matplotlib库。相关课程链接如下:《Python编程的术与道:Python语言入门》https://edu.csdn.net/course/detail/27845《玩转Numpy计算库》https://edu.csdn.net/lecturer/board/28656《玩转Matplotlib数据绘图库》https://edu.csdn.net/lecturer/board/28720【课程内容导图及特色】

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值