反向传播的背景
Back propagation这个方法其实也是Gradient Descent,只是为了让神经网络有效率地train出来,所以才有了反向传播。
- 假设一堆参数 θ \theta θ (weight and bias)
- 初始化一个值 θ 0 \theta^0 θ0
- 计算 θ 0 \theta^0 θ0对Loss function的偏微分,就是gradient, ∇ L ( θ ) \nabla L(\theta) ∇L(θ)是一个vector
- 计算完这个vector的偏微分,就可以去更新 θ \theta θ
- 神经网络有百万级别的参数,而反向传播就是有效率地计算梯度(那个vector)
Chain Rule链式法则
这个是微分的法则,不懂的可以去搜一下就可以了,很好理解~
反向传播
科普环节:损失函数Loss,代价函数Cost,总体损失函数Total Loss区别
- 损失函数:定义在单个训练样本上的,单指一个样本的误差
- 代价函数:定义在整个训练集上的,即所有样本的误差的总和的平均
- 总体损失函数:定义在整个训练集上的,即所有样本的误差的总和,也是我们反向传播需要最小化的值
L
(
θ
)
L(\theta)
L(θ)就是神经网络的总体损失函数,我们要求每个样本的损失函数
C
(
θ
)
C(\theta)
C(θ)的偏微分,加起来就是
L
(
θ
)
L(\theta)
L(θ),先对一个神经元进行分析。
神经元分析
- 第一个Neuron的输入就是x,根据之前做过的步骤,就得到z
- 计算w对C的偏微分,可以通过链式法则,分解开为w对z偏微分乘上z对C偏微分
- ∂ z ∂ w \frac { \partial z } { \partial w } ∂w∂z很容易就可以计算出来,称之为Forward Pass
- ∂ C ∂ z \frac { \partial C } { \partial z } ∂z∂C是比较复杂的,称之为Backward Pass
Forward pass
forward pass是很容易计算的,因为我们已知输入是x,根据公式,w对z的微分,就是我们的输入。
Backward pass
这一部分就非常的困难复杂,因为我们要求
∂
C
∂
z
\frac{ \partial C } { \partial z }
∂z∂C,我们先用链式法则,把它分解开。
- 假设神经元function是sigmoid,然后 a = σ ( z ) a=\sigma(z) a=σ(z)
- a通过weight w 3 w_3 w3,加上别的value,得到 z ′ z^\prime z′
- a还会乘上别的weight w 4 w_4 w4,加上别的value,得到 z ′ ′ z^{\prime\prime} z′′
-
∂
C
∂
z
=
∂
a
∂
z
∂
C
∂
a
\frac { \partial C } { \partial z } = \frac { \partial a } { \partial z } \frac { \partial C } { \partial a }
∂z∂C=∂z∂a∂a∂C
∂ a ∂ z \frac { \partial a } { \partial z } ∂z∂a其实就是对sigmoid函数做偏微分,这个很好计算,那 ∂ C ∂ a \frac { \partial C } { \partial a } ∂a∂C又如何计算呢?
a会通过影响 z ′ 和 z ′ ′ z^{\prime}和z^{\prime\prime} z′和z′′来影响C,通过上面链式法则中case 2的形式,就会获得上面最后一条式子,如果有很N个neuron,就会加上N个,这里的例子就只假设了两项。 - ∂ z ′ ∂ a = w 3 \frac { \partial z ^ { \prime } } { \partial a }=w_3 ∂a∂z′=w3
- ∂ z ′ ′ ∂ a = w 4 \frac { \partial z ^ { \prime\prime } } { \partial a }=w_4 ∂a∂z′′=w4
现在我们还是不知道
∂
C
∂
z
′
\frac {\partial C } { \partial z ^ { \prime } }
∂z′∂C和
∂
C
∂
z
′
′
\frac {\partial C } { \partial z ^ { \prime\prime } }
∂z′′∂C,不过我们假设已经知道了它们的值,继续运算下去。
最后就可以得到上面这条式子。我们可以从另外一个观点去看待这个式子
有另外一个神经元,把forward的过程逆向过来,其中
σ
′
(
z
)
\sigma^{\prime}(z)
σ′(z)是常数,因为它在向前传播的时候就已经确定了。
case1 :已经到达输出层
- 假设红色的两个神经元就是已经是output layer,已经计算出来了y1和y2
- 可以得到 ∂ C ∂ z ′ = ∂ y 1 ∂ z ′ ∂ C ∂ y 1 \frac { \partial C } { \partial z ^ { \prime } } = \frac { \partial y _ { 1 } } { \partial z ^ { \prime } } \frac { \partial C } { \partial y _ { 1 } } ∂z′∂C=∂z′∂y1∂y1∂C
- 最后一个神经元的function是已知的,这个看我们怎么设计而已,这样可以算出 ∂ y 1 ∂ z ′ \frac { \partial y _ { 1 } } { \partial z ^ { \prime } } ∂z′∂y1,,即这个function的偏微分。
- ∂ C ∂ y 1 \frac { \partial C } { \partial y _ { 1 } } ∂y1∂C这个要看你的cost function怎么定义,即ouput和target之间是如何评估的,可以是entropy,可以是mean square error,总之它也是可以计算出来的
case2:未到达输出层
后面还有很多layers,就会继续往后一直通过链式法则算下去。
对于这个问题,我们要继续计算后面绿色的
∂
C
∂
z
a
\frac{\partial C}{\partial z_a}
∂za∂C
和
∂
C
∂
z
b
\frac{\partial C}{\partial z_b}
∂zb∂C ,然后通过继续乘
w
5
和
w
6
w_5和w_6
w5和w6得到
∂
C
∂
z
′
\frac{\partial C}{\partial z'}
∂z′∂C ,但是要是
∂
C
∂
z
a
\frac{\partial C}{\partial z_a}
∂za∂C和
∂
C
∂
z
b
\frac{\partial C}{\partial z_b}
∂zb∂C 都不知道,那么我们就继续往后面层计算,一直到碰到输出值,得到输出值之后再反向往输入那个方向走。
简短的例子:
要求z对C的偏微分,需要知道z1和z2对C的偏微分,要知道前面这个,又要知道z3和z4对C的偏微分,以此类推,所以其实我们可以反过来思考,从output层往前计算。
σ
′
(
z
n
)
\sigma^{\prime}(z_n)
σ′(zn)就像个放大器一样,通过乘以这个可以得z对C的微分值,这个是取决于你的激活函数的,这里只是刚好用上了sigmoid函数
实际上进行backward pass时候和向前传播的计算量差不多
总结:
- 计算 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂zForward pass的部分)和计算 ∂ C ∂ z \frac{\partial C}{\partial z} ∂z∂C( Backward pass的部分 )
- 然后把 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂z 和 ∂ C ∂ z \frac{\partial C}{\partial z} ∂z∂C相乘,我们就可以得到 ∂ C ∂ w \frac{\partial C}{\partial w} ∂w∂C
- 得到神经网络中所有的参数,然后用梯度下降就可以不断更新,得到损失最小的函数