概念介绍
Backpropagation本质上就是一个提升Gradient Descent效率的算法,核心在于其可以有效率地计算出一个偏移量来update下一组未知参数。
难点在于:Neural Network有很多层,而且每层参数都非常多,所以不能立即算出来该组未知参数的偏微分,如果只有一层当然可以快速计算,无需使用Backpropagation进行优化
推理步骤
1.Loss function定义:
L
(
θ
)
=
∑
n
=
1
N
C
n
(
θ
)
L(\theta)=\displaystyle\sum_{n=1}^NC^n(\theta)
L(θ)=n=1∑NCn(θ)
C
n
C^n
Cn是一个function,代表模型计算出来的值
y
n
y^n
yn和真实的值
y
^
n
\widehat{y}^n
y
n的距离,两个向量之间的距离。在所有参数
θ
\theta
θ已知的情况下
y
n
y^n
yn也是一个已知量,那么他们之间的距离也是一个已知量(是通过
C
n
C^n
Cn计算出来的一个已知量)
那么难点在于我们要求 θ \theta θ的偏微分
2.对w进行偏微分
这些未知参数用w来表示,b在计算微分的时候无用所以忽略
∂ L ( θ ) ∂ w = ∑ n = 1 N ∂ C n ( θ ) ∂ w \dfrac{{\partial}L(\theta)}{\partial{w}}=\displaystyle\sum_{n=1}^N\dfrac{{\partial}C^n(\theta)}{\partial{w}} ∂w∂L(θ)=n=1∑N∂w∂Cn(θ)
3.先考虑一个Neuron
(1)假设w只有2个w1和w2,并且n=1,现在要计算 ∂ C ∂ w \dfrac{{\partial}C}{\partial{w}} ∂w∂C
∂
C
∂
w
=
∂
z
∂
w
∂
C
∂
z
\dfrac{{\partial}C}{\partial{w}}=\dfrac{{\partial}z}{\partial{w}}\dfrac{{\partial}C}{\partial{z}}
∂w∂C=∂w∂z∂z∂C
(两个z的偏微分可以约掉,所以可以写成这样)
其中计算 ∂ z ∂ w \dfrac{{\partial}z}{\partial{w}} ∂w∂z叫做【Forward pass】,计算 ∂ C ∂ z \dfrac{{\partial}C}{\partial{z}} ∂z∂C叫做【Backword pass】
(2)求解 ∂ z ∂ w \dfrac{{\partial}z}{\partial{w}} ∂w∂z
假设w只有2个w1和w2
我们发现:w1的微分就是 x 1 x_1 x1;w1的微分就是 x 2 x_2 x2
∂ z ∂ w = x 1 + x 2 \dfrac{{\partial}z}{\partial{w}}=x_1+x_2 ∂w∂z=x1+x2
如果我们知道输入,那可以很快求出任何一个w在activation function上的偏微分就是他的输入
第一层的输入x是已知量,第二层的输入也是可以通过activation function计算出来
现在已经解决了 ∂ z ∂ w \dfrac{{\partial}z}{\partial{w}} ∂w∂z,还需要解决的是 ∂ C ∂ z \dfrac{{\partial}C}{\partial{z}} ∂z∂C
(2)求解 ∂ C ∂ z \dfrac{{\partial}C}{\partial{z}} ∂z∂C
假设输出只有2个z
如图假设a是sigmoid function通过z计算出来的
因为 ∂ C ∂ z = ∂ a ∂ z ∂ C ∂ a \dfrac{{\partial}C}{\partial{z}}=\dfrac{{\partial}a}{\partial{z}}\dfrac{{\partial}C}{\partial{a}} ∂z∂C=∂z∂a∂a∂C,所以我们现在需要求后面两个偏微分
∂ a ∂ z \dfrac{{\partial}a}{\partial{z}} ∂z∂a是很容易求出来的,因为是一个已知的激活函数sigmoid function,在进行forward pass计算的时候z就是一个已知量了,那么 ∂ a ∂ z \dfrac{{\partial}a}{\partial{z}} ∂z∂a就可以当做一个常量
那么就只剩下 ∂ C ∂ a \dfrac{{\partial}C}{\partial{a}} ∂a∂C,它等于a在 z 1 z^1 z1上的偏微分加上其他其他输出a在z上的微分,那么如图很容易知道 ∂ z ′ ∂ a = w 3 \dfrac{{\partial}z^{'}}{\partial{a}}=w^3 ∂a∂z′=w3, ∂ z ′ ′ ∂ a = w 4 \dfrac{{\partial}z^{''}}{\partial{a}}=w^4 ∂a∂z′′=w4
根据后面节点的微分就可以得到当前节点的微分,如下:
现在就只剩下 ∂ C ∂ z ′ \dfrac{{\partial}C}{\partial{z^{'}}} ∂z′∂C需要求解了,上面只讨论了两层,但实际上有很多层,现在就是求解下面这个模型,下面这个模型和上面的求解是一样的,继续往下分解即可。
但是继续往下分解那不就是和一般的Gradient Descent一样了么?
我们发现正向的求解过程和逆向的求解过程完全一样
如果我们知道了
∂
C
∂
z
a
\dfrac{{\partial}C}{\partial{z_a}}
∂za∂C和
∂
C
∂
z
b
\dfrac{{\partial}C}{\partial{z_b}}
∂zb∂C,就很容易求出
∂
C
∂
z
′
\dfrac{{\partial}C}{\partial{z^{'}}}
∂z′∂C
假设 Z a Z_a Za已经是最后一层,那么是可以通过y来计算出 Z a Z_a Za的微分,从而可以往上计算出所有的微分。
如果我们反向计算,那么效率就会高很多,之前是通过x往后计算,现在通过y往前计算,因为x是已知量y也是已知量,所以可以建立一个反向的Neural Network
那么现在我们可以很容易知道任何一个w的偏微分,然后就可以算出下一个w’的值
个人总结
一般的Gradient Descent是从上往下计算偏微分,但在一个函数里面不仅要展开当前层所有的Neuron,而且每个Neuron还要继续展开下一层所有的Neuron,直到最后一层。这样效率是不高的,主要是递归计算带来的开销。
那么优化方案就是递归改递推,就好像算法中【递归】改成【动态规划】,效率会提高很多倍,不仅每次计算的结果不会丢,而且没有栈溢出的问题。