本文的思路如下:
偏微分 -> 梯度下降 -> 矩阵求导 -> 反向传播
1 梯度下降
1.1 偏微分
下图是一个 z=cos(x)+sin(y) 的函数图像,假设有一个点p1(x1,y1),求在p1点处关于x的偏微分 ∂x∂z∣x=x1 的思路如下:

- 取一个平行于x、z的平面a要求这个平面过p1,与函数相交于上图中的绿色曲线
- 画出平面a的正视图,视角沿着上图中的视角箭头,得到下图(注意坐标值)。
- 在上述图像中求解曲线在p1点处的导数,即我们要求的 ∂x∂z∣x=x1
通过图投影图,在p1处的导数<0;在p2处的导数>0。从而:
- 沿着x增大的方向,下坡方向,那么导数<0;如果要到达谷底,需要 x−α∂x∂z
- 沿着x增大的方向,上坡方向,那么导数>0;如果要到达谷底,需要 x−α∂x∂z
即:无论在哪里,偏导数值相反方向,都是到达谷底的方向。
其中 α 应为一个小数,偏导数只是指明了谷底的方向,但是要是迈步过大,容易直接跨过谷底到达另一个山坡位置
1.2 梯度下降
总结偏微分的原理,得到梯度下降公式如下:
θi=θi−α∂θi∂J(θ0,⋯,θn),for i=0 to n
其中 α 控制步伐大小,不断重复上述更新,直到拟合,即到达下图的山谷位置,过程如下图所示:

即:梯度更新的算法核心在于求目标函数关于变量 θ 偏微分
2 反向传播
2.1 矩阵乘法求导
常见的矩阵乘法有两种,一种是数学上的乘法,另一种是对应位置相乘,例如:
- 数学上的乘法,这里我们记为 ⋅ ,例如:
[a11a21a12a22]⋅[b11b21b12b22]=[a11b11+a12b21a21b11+a22b21a11b12+a12b22a21b12+a22b22]
- numpy中的默认乘法,为对应位置相乘,这里我们记为 ⋅∗ ,例如:
[a11a21a12a22]⋅∗[b11b21b12b22]=[a11b11a21b21a12b12a22b22]
2.1.1 数学中的乘法(.)求导
假设有如下计算矩阵:
⎣⎡x11x21x31x12x22x32⎦⎤⋅[a11a21a12a22a13a23]=⎣⎡z11z21z31z12z22z32z13z23z33⎦⎤
且上述运算只是链式计算中的一环,即有 J=f(Z) ,如果对z矩阵的每个元素求偏导,那么组合起来的矩阵一定是和z矩阵一样,即有:
∂Z∂J=Δ=⎣⎡δ11δ21δ31δ12δ22δ32δ13δ23δ33⎦⎤
在此基础上求解: ∂X∂J
由于:
x11a11+x12a21=z11x11a12+x12a22=z12x11a13+x12a23=z13⋯
所以:
∂x11∂J=∂z11∂J⋅∂x11∂z11+∂z12∂J⋅∂x11∂z12+∂z13∂J⋅∂x13∂z11=δ11a11+δ12a12+δ13a13
于是:
∂X∂J=⎣⎡δ11a11+δ12a12+δ13a13δ21a11+δ22a12+δ23a13δ31a11+δ32a12+δ33a13δ11a21+δ12a22+δ13a23δ21a21+δ22a22+δ23a23δ21a21+δ22a22+δ23a23⎦⎤=Δ⋅aT
也就是说:
∂X∂Z=AT
通过同样的推导方式可得到如下结论:
如果:
Z=K1Y,Y=XK2
那么 (要注意左乘和右乘的区别):
∂X∂Z=K1T⋅numpy.oneslike(Z)⋅K2T
这里为什么要乘以numpy.oneslike(Z)
(numpy函数,shape和Z相同,但全为1),可以理解成上述 Δ 作用,目的是为了保证形状
上面是比较直观的矩阵展开推导过程,现在用矩阵乘法公式进行求导过程。条件和上面一致,所以 X⋅A=Z ,令 xij,ajk,zik 分别为对应的元素,则:
zik=j∑xijajk
因此:
∂xij∂J=ijk∑zik∂J⋅∂xij∂zik=k∑δik⋅∂xij∂zik=k∑δik⋅j∑ajk=k∑δik⋅ajk
所以:
∂X∂J=Δ⋅AT
同理:
∂ajk∂J=i∑δik⋅xij
所以:
∂A∂J=XT⋅Δ
从上面展开式发现:
dxijdZ=j∑ajkdajkdZ=i∑xij
所以:
dXdZ=numpy.oneslike(Z)⋅AT dAdZ=XT⋅numpy.oneslike(Z)
这也就是矩阵链式求导使用numpy.oneslike
的原因
2.1.2 numpy中的默认乘法,对应位置相乘 (⋅∗) 求导
假设有一个运算:
[z11z21z12z22]⋅∗[σ11σ21σ12σ22]=[a11a21a12a22]
且上述运算只是链式计算中的一环,即有 J=f(A) ,如果对 a 矩阵的每个元素求偏导,那么组合起来的矩阵一定是和z矩阵一样shape,即有:
∂A∂J=[δ11δ21δ12δ22]
在此基础上求解:∂Z∂J
由于:
z11σ11=a11z12σ12=a12⋯
所以:
∂z11∂J=∂a11∂J⋅∂z11∂a11=δ11⋅σ11
于是:
∂Z∂J=[δ11⋅σ11δ21⋅σ21δ12⋅σ12δ22⋅σ22]=δ⋅∗σ
其中 表示 对应的矩阵,通过同样的推导方式可以得到:
如果:
Z=K1Y,Y=X⋅∗K2
那么:
∂X∂Z=K1T⋅numpy.oneslike(Z)⋅∗K2
2.2 反向传播算法
反向传播算法本质是梯度更新,只不过它为了更方便计算机计算,先求出每一层的误差并缓存,然后再梯度更新
2.2.1 求每一层的误差 δ
假设如下神经网络结构,包含2个hidden layer,3个输入feature,4个输出result,**函数都是sigmoid,loss function使用cross entropy

分解后如下图所示:

其中各个参数意义如下:
-
a(i):表示第 i 层**值,其中 a(1)为网络输入数据,a(4) 为网络输出值
-
z(i) :表示第 i-1 层(上一层)网络输出值
-
θ(i) :表示第 i 层网络参数
-
δ(i) :表示第 i 层网络的误差,我们定义误差为 δ(i)=∂z(i)∂J
-
g(z(i)) :表示第 i 层的**函数
由于采用cross entropy为损失函数,所以损失函数 J 有:
J=−[yloga(4)+(1−y)log(1−a(4))]=−[ylogg(z(4))+(1−y)log(1−g(z(4)))]
又因为使用**函数都是 σ=e−x+11 ,所以 g′(z(i))=a(i)⋅∗(1−a(i))
上述神经网络涉及两种运算:
- 点积( ⋅ ): a(i−1)→z(i)
- 点乘 (⋅∗) : z(i)→a(i)
因此:
δ(4)=∂z(4)∂J=∂a(4)∂J⋅∗∂z(4)∂a(4)=a(4)⋅∗(1−a(4))a(4)−y⋅∗g′(z(4))=a(4)−y
根据链式求导:
δ(3)=∂z(3)∂J=∂z(4)∂J⋅∂a(3)∂z(4)⋅∗∂z(3)∂a(3)=δ(4)⋅∂a(3)∂z(4)⋅∗g′(z(3))
根据2.1的矩阵求导法则,因为 z(4)=θ(3)⋅a(3) ,所以:
δ(3)=∂z(3)∂J=(θ(3))T⋅δ(4)⋅∗g′(z(3))
同理:
δ(2)=(θ(2))T⋅δ(3)⋅∗g′(z(2))
所以:
δ(i)=∂z(i)∂J=(θ(i))T⋅δ(i+1)⋅∗g′(z(i))
2.2.2 求每一层权重的偏导数 ∂θ(i)∂J
求解了每一层的误差,接下来需要求我们需要更新的权重的梯度:
∂θ(3)∂J=∂z(4)∂J⋅∂θ(3)∂z(4)=δ(4)⋅∂θ(3)∂z(4)
根据2.1矩阵求导公式,因为 θ(3)⋅a(3)=z(4) ,所以:
∂θ(3)∂J=δ(4)⋅(a(3))T
同理:
∂θ(2)∂J=δ(3)⋅(a(2))T ∂θ(1)∂J=δ(2)⋅(a(1))T
所以:
∂θ(i)∂J=δ(i+1)⋅(a(i))T
从而就可以应用梯度更新公式了
2.2.3 反向传播算法总结
第 i 层的误差,与对应层使用的**函数相关:
δ(i)=∂z(i)∂J=(θ(i))T⋅δ(i+1)⋅∗g′(z(i))
最后一层误差,需要结合损失函数求导得到
第 i 层的梯度:
∂θ(i)∂J=δ(i+1)⋅(a(i))T
3 梯度爆炸和梯度消失
3.1 梯度爆炸消失对反向传播的影响
梯度消失和梯度爆炸问题,字面上理解就是 θ(i)=θ(i)−α∂θ(i)∂J 中的 ∂θ(i)∂J 梯度项,接近0或者接近无穷。下面特例说明梯度消失梯度爆炸在反向传播中的表现。
因为:
∂θ(i)∂J=δ(i+1)⋅(a(i))T
假设网络采用线性**,即不采用**函数,即:
δ(i+1)=∂z(i+1)∂J=(θ(i+1))T⋅δ(i+2)⋅∗g′(z(i+1))=(θ(i+1))T⋅δ(i+2)
令每一层为权重 θ(i)=[kk] ,那么:
δ(i)=l=i∏L−1θ(i)⋅δ(L)=[kL−1−ikL−1−i]⋅δ(L)
其中 L 表示网络层数,当网络很深时, L−1−i→∞ ,且 a(i) 在计算梯度时,做常数处理,所以梯度的值和上一层的误差成正相关所以:
k<1⇒δ→0⇒∂θ∂J→0 k>1⇒δ→∞⇒∂θ∂J→∞
小结:当网络很深时,深层网络的梯度更新与输出层误差无关,即梯度不一定朝着梯度变小的方向更新。
3.2 梯度爆炸消失对前馈网络的影响
条件还是和上述一致,那么:
y^=σ(l=1∏Lθ(l)⋅X)=σ([kLkL]⋅X)
当网络很深, L→∞ ,所以:
k<1⇒kL→0⇒y^→0k>1⇒kL→∞⇒y^→1
小结:当存在梯度爆炸或梯度消失时,网络的输出和网络的输入X不相关。
3.3 梯度爆炸、梯度消失原因总结
通过3.1、3.2的总结,我们发现如果权重矩阵设置不当,即:
- 所有权重 Θ>I ,容易产生梯度爆炸问题
- 所有权重 Θ<I ,容易产生梯度消失问题
所以权重初始化很重要,至于怎么初始化,我们后续再讲解