文章目录
1函数求导链式法则
- 链式法则①:对于 y = g ( x ) y=g(x) y=g(x)和 z = h ( y ) z=h(y) z=h(y):
Δ x → Δ y → Δ z \Delta{x}\rightarrow\Delta{y}\rightarrow\Delta{z} Δx→Δy→Δz
d z d x = d z d y d y d x \frac{dz}{dx}=\frac{dz}{dy}\frac{dy}{dx} dxdz=dydzdxdy
- 链式法则②:对于
x
=
g
(
s
)
x=g(s)
x=g(s)、
y
=
h
(
s
)
y=h(s)
y=h(s)以及
z
=
k
(
x
,
y
)
z=k(x,y)
z=k(x,y):
d z d s = ∂ z ∂ x d x d s + ∂ z ∂ y d y d s \frac{dz}{ds}=\frac{\partial{z}}{\partial{x}}\frac{dx}{ds}+\frac{\partial{z}}{\partial{y}}\frac{dy}{ds} dsdz=∂x∂zdsdx+∂y∂zdsdy
2反向传播基本思想
- 对于一个有 N N N个样本的训练集,经神经网络前向传播计算之后,得到输出值,计算每一个样本的输出值与实际值的差值 C n C^n Cn(当然也可以是其他的计算误差的函数),并求和,就得到当前神经网络参数设置下的损失值。如式(1)和下图所示:
L ( θ ) = ∑ n = 1 N C n ( θ ) (1) L(\theta)=\sum_{n=1}^{N}{C^n(\theta)} \tag{1} L(θ)=n=1∑NCn(θ)(1)
- 根据在线性回归中的梯度下降的思想,需要对代价函数求偏导数,然后用偏导数来更新参数(具体为什么这样做就牵扯到方向导数以及梯度的概念,我暂时没理解,感兴趣的可以看文末的参考文章)。因此在神经网络中,我们沿用这种思想,即计算代价函数对网络中每个参数的偏导数,如式(2)所示。因此,我们只需要计算单个样本的代价函数对参数的偏导数,然后用循环来重复计算所有的样本。
∂ L ( θ ) ∂ θ = ∑ n = 1 N ∂ C n ( θ ) ∂ θ (2) \frac{\partial{L(\theta)}}{\partial{\theta}}=\sum_{n=1}^{N}{\frac{\partial{C^n(\theta)}}{\partial{\theta}}} \tag{2} ∂θ∂L(θ)=n=1∑N∂θ∂Cn(θ)(2)
3反向传播算法全览
- 由式(2)可知,反向传播算法可以是一个遍历所有样本的循环,其中计算每个样本带来的偏导数,如下图所示。
- 接下来,我们结合李宏毅老师和吴恩达老师的相关讲解来逐步理清反向传播算法的过程。
4反向传播算法理解过程
4.1一个输入层+一个输出层(两层的神经网络)
- 对单个样本而言,如果一个神经网络如下图所示(只有两层,第一层是输入层(两个神经元),第二层是输出层(一个神经元))。其中
z
=
x
1
θ
1
+
x
2
θ
2
+
b
z=x_1\theta_1+x_2\theta_2+b
z=x1θ1+x2θ2+b(将
w
w
w换成
θ
\theta
θ纯属为了与吴恩达的一致,而
b
b
b也可以看作是第一层最上面再加一个偏置神经元,其权值为
b
b
b).我们暂且就让
z
=
x
1
θ
1
+
x
2
θ
2
z=x_1\theta_1+x_2\theta_2
z=x1θ1+x2θ2。
- 此时就可以计算代价函数对参数 θ \theta θ的偏导数,如式(3)所示(用到函数求导链式法则①):
∂ C ∂ θ = ∂ C ∂ z ∂ z ∂ θ (3) \frac{\partial{C}}{\partial{\theta}}=\frac{\partial{C}}{\partial{z}}\frac{\partial{z}}{\partial{\theta}} \tag{3} ∂θ∂C=∂z∂C∂θ∂z(3)
- 很显然, ∂ z ∂ θ 1 = x 1 \frac{\partial{z}}{\partial{\theta_1}}=x_1 ∂θ1∂z=x1, ∂ z ∂ θ 2 = x 2 \frac{\partial{z}}{\partial{\theta_2}}=x_2 ∂θ2∂z=x2。而由于存在式(4)所示的关系(其中 y y y是常数,而 a a a是函数),
C = L o s s F u n c t i o n ( a , y ) = L o s s F u n c t i o n ( f u n c t i o n s i g m o i d ( z ) , y ) (4) C=LossFunction(a,y)=LossFunction(function_{sigmoid}(z),y) \tag{4} C=LossFunction(a,y)=LossFunction(functionsigmoid(z),y)(4)
所以 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} ∂z∂C=∂a∂C∂z∂a。因为此时的神经网络只有两层,所以 ∂ C ∂ a \frac{\partial{C}}{\partial{a}} ∂a∂C的值可以由具体的代价函数求得,而 ∂ a ∂ z \frac{\partial{a}}{\partial{z}} ∂z∂a则是具体的激活函数的偏导数(导数),也可以直接求得。
4.2多层神经网络
- 现在神经网络结构变成了下图的样子。即至少包含三层结构:两个输入单元,第二层有一个神经元,第三层有两个神经元。
- 在两层的神经网络结构中,我们已经知道 ∂ z ∂ θ 1 = x 1 \frac{\partial{z}}{\partial{\theta_1}}=x_1 ∂θ1∂z=x1, ∂ z ∂ θ 2 = x 2 \frac{\partial{z}}{\partial{\theta_2}}=x_2 ∂θ2∂z=x2。在多层神经网络中,由于每一个 z z z都是关于 θ \theta θ的线性组合,因此只需知道所有的神经元的激活值 a a a就可以求得所有的 ∂ z ∂ θ \frac{\partial{z}}{\partial{\theta}} ∂θ∂z了。一个实际的例子如下图所示。
- 所以在多层神经网络中,求代价函数对某一个参数的偏导数 ∂ C ∂ θ \frac{\partial{C}}{\partial{\theta}} ∂θ∂C,依旧可以使用 ∂ C ∂ θ = ∂ C ∂ z ∂ z ∂ θ \frac{\partial{C}}{\partial{\theta}}=\frac{\partial{C}}{\partial{z}}\frac{\partial{z}}{\partial{\theta}} ∂θ∂C=∂z∂C∂θ∂z。而问题的关键就还是落在了求解 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C上。而此时 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} ∂z∂C=∂a∂C∂z∂a依旧成立。
- 从图4的结构我们可以知道,此时的 ∂ C ∂ a \frac{\partial{C}}{\partial{a}} ∂a∂C的值不可以直接根据代价函数的具体形式求得(因为后面还有其他隐藏层神经元),而需要根据函数求导的链式法则②来求解,根据图6所示的链式法则,可以得到式(5)。
∂ C ∂ a = ∂ C ∂ z ′ ∂ z ′ ∂ a + ∂ C ∂ z ′ ′ ∂ z ′ ′ ∂ a (5) \frac{\partial{C}}{\partial{a}}=\frac{\partial{C}}{\partial{z^{'}}}\frac{\partial{z^{'}}}{\partial{a}}+\frac{\partial{C}}{\partial{z^{''}}}\frac{\partial{z^{''}}}{\partial{a}} \tag{5} ∂a∂C=∂z′∂C∂a∂z′+∂z′′∂C∂a∂z′′(5)
- 因此只需要求得 ∂ C ∂ z ′ \frac{\partial{C}}{\partial{z^{'}}} ∂z′∂C和 ∂ C ∂ z ′ ′ \frac{\partial{C}}{\partial{z^{''}}} ∂z′′∂C,就可以求得 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C。如式(6)所示。而 σ ′ ( z ) \sigma^{'}(z) σ′(z)是一个常数(在神经网络正向计算时就已经算出来 z z z了)。式(6)更直观的图示如图7所示。
∂
C
∂
z
=
∂
C
∂
a
∂
a
∂
z
=
(
θ
3
∂
C
∂
z
′
+
θ
4
∂
C
∂
z
′
′
)
σ
′
(
z
)
(6)
\frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}}=(\theta_3\frac{\partial{C}}{\partial{z^{'}}}+\theta_4\frac{\partial{C}}{\partial{z^{''}}})\sigma^{'}(z) \tag{6}
∂z∂C=∂a∂C∂z∂a=(θ3∂z′∂C+θ4∂z′′∂C)σ′(z)(6)
- 那么如果图4就是完整的神经网络,则根据 ∂ C ∂ z = ∂ C ∂ a ∂ a ∂ z \frac{\partial{C}}{\partial{z}}=\frac{\partial{C}}{\partial{a}}\frac{\partial{a}}{\partial{z}} ∂z∂C=∂a∂C∂z∂a可以求得式(7)(8)。其中我们就认为 y 1 y_1 y1、 y 2 y_2 y2相当于是激活值 a a a。 ∂ C ∂ y \frac{\partial{C}}{\partial{y}} ∂y∂C由具体的代价函数求出, ∂ y ∂ z \frac{\partial{y}}{\partial{z}} ∂z∂y由激活函数的导数求出。
∂ C ∂ z ′ = ∂ C ∂ y 1 ∂ y 1 ∂ z ′ (7) \frac{\partial{C}}{\partial{z^{'}}}=\frac{\partial{C}}{\partial{y_1}}\frac{\partial{y_1}}{\partial{z^{'}}} \tag{7} ∂z′∂C=∂y1∂C∂z′∂y1(7)
∂ C ∂ z ′ ′ = ∂ C ∂ y 2 ∂ y 2 ∂ z ′ ′ (8) \frac{\partial{C}}{\partial{z^{''}}}=\frac{\partial{C}}{\partial{y_2}}\frac{\partial{y_2}}{\partial{z^{''}}} \tag{8} ∂z′′∂C=∂y2∂C∂z′′∂y2(8)
- 而如果后面还有其他神经元,则继续重复上述过程,如图8所示。直到到达了输出层。
4.3反向传播过程梳理
- 纵观4.1和4.2节可以发现,求解代价函数对参数的偏导数,最终将归结到求解 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C上。如图9所示。
- 以图9为例,并且还具有以下两个规律:
- 要求解 ∂ C ∂ z 1 \frac{\partial{C}}{\partial{z_1}} ∂z1∂C和 ∂ C ∂ z 2 \frac{\partial{C}}{\partial{z_2}} ∂z2∂C,就需要知道 ∂ C ∂ z 3 \frac{\partial{C}}{\partial{z_3}} ∂z3∂C和 ∂ C ∂ z 4 \frac{\partial{C}}{\partial{z_4}} ∂z4∂C。以此类推,直到输出层(根据代价函数求得最后的偏导数)。
- 而某一个 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C是由下一层的 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C分别乘上对应参数,并与激活函数的导数值相乘,就如同式(6)所示的那样。
- 一个更加直观的图如图10所示。
- 综上,由于前一层的偏导数需要下一层的偏导数来支撑,因此求偏导数的过程实际上是反过来求的,也就是所谓的反向传播算法了。整个过程关键就是求出 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C和 ∂ z ∂ θ \frac{\partial{z}}{\partial\theta} ∂θ∂z,如图11所示。而 ∂ C ∂ z \frac{\partial{C}}{\partial{z}} ∂z∂C是关键之关键,也是最麻烦的。
5反向传播算法过程与第3节算法全览的联系
这一节主要是在第4节理解反向传播过程的基础上,理解反向传播算法的伪代码流程(即第3节所列的算法流程)
- 首先,第4节描述的过程是针对某一个样本的,因此实际需要对所有的样本都执行这样的操作,也就对应了算法流程的循环体;
- 整个反向传播过程中需要用到的变量的值,如 a a a、 z z z等也都需要先进行正常的前向计算过程(即forward propagation)。
- 以图12为例,计算一下几个偏导数。
- 求代价函数对参数矩阵第三层的各参数的偏导数,如图13所示。
- 接着计算第二层(这里只计算了一个),如图14所示,并且逐步向第3节反向传播算法中计算 Δ l i j \Delta^l{_{ij}} Δlij的形式靠拢:
- 将图14中红框中的式子与图15中红框的式子对比,可以发现式图16所示的联系(需要注意的是,按照吴的视频,图12中
z
z
z和
a
a
a的上标均需要加1才能够完全对的上)
6总结
- 本文将李宏毅老师对反向传播算法的过程推导和吴恩达老师关于该算法的算法流程做了对比,希望能够帮助大家加深对该算法的理解
- 文中可能存在相关符号的错误,公式的不严谨等
- 之后还会通过神经网络的python的实现来进一步理解该算法。