The value of knowledge lies not in possession, but in share.

0%

前向传播(Forward Propagation)与反向传播(Back Propagation)个人理解与总结

深度学习中的的前向传播(Forward Propagation)与反向传播(Back Propagation)的目的就是,寻找一组最优的参数,使得损失函数(Lost Function)或称为成本函数(Cost Function)获取到最小值。

下图为一个多层的神经网络,本文则对此图例进行前向传播和反向传播的解析。

NeuralNetworks

前向传播(Forward propagation)

单个数据前向传播的计算过程:(此处损失函数以平方差损失函数为例)

多数据前向传播的计算过程:

其中:为激活函数,为Loss Function ,为Cost Function,为神经网络的第L层,用大写字母表示相应参数的向量化表示。下同。

反向传播(Back Propagation)

单个数据反向传播的计算过程:

多数据反向传播的计算过程:

权值更新:

反向传播(Back Propagation)与链式法则

反向传播(BP, Back Propagation)算法是多层神经网络的训练中举足轻重的算法,其基于复合函数的链式法则,但在实际运算中的意义比链式法则要大的多。

以求$e=(a+b)\times(b+1)$的偏导为例。
为方便,在图中,引入了中间变量$c$,$d$。 其复合关系图如下所示:
这里写图片描述

接着,分别求$\frac{\partial e}{\partial a}$,$\frac{\partial e}{\partial b}$的值。
这里写图片描述

利用链式法则可得:

不难发现,$\frac{\partial e}{\partial a}$的值等于从 e -> a 的路径上的偏导值的乘积,而$\frac{\partial e}{\partial b}$的值等于从 e -> b 路径 e -> c -> b 上的偏导值的乘积加上路径 e -> d -> b 上的偏导值的乘积。可以注意到,这样做是十分耗时,因为很多路径被重复访问了。比如上图中, e ->c -> ae -> c -> b 就都走了路径e -> c 。对于权值动则数万的深度模型中的神经网络,这样的冗余所导致的计算量是相当大的。

同样是利用链式法则,反向传播(BP, Back Propagation)算法则机智地避开了这种冗余,它对于每一个路径只访问一次就能求顶点对所有下层节点的偏导值。 梯度下降法需要给定一个初始点,并求出该点的梯度向量,然后以负梯度方向为搜索方向,以一定的步长进行搜索,从而确定下一个迭代点,再计算该新的梯度方向,如此重复直到损失函数收敛。

  1. 从最上层的节点 e开始,初始值为1,以层为单位进行处理。

  2. 对于e的下一层的所有子节点,将1乘以e到某个节点路径上的偏导值,并将结果“堆放”在该子节点中。

    如,对于子节点c

    如,对于子节点d

  3. 然后将第二层的节点各自作为起始顶点,初始值设为第2步分别得到的偏导值,以”层”为单位重复上述传播过程,即可求出顶点e对每一层某个节点的偏导值。

    如,对于子节点a

    如,对于子节点b

由上述过程可以发现,BP算法很好的解决了重复计算的问题。

前向传播及反向传播具体计算过程示例

下图为一个三层神经网络结构,分别输入层(第0层),隐藏层(第1层),输出层(第2层):

CNNSimple

整个输入、各层参数矩阵、输出,表示如下:

对于前向传播

第1层的输出为:

经激活函数处理后的输出为:

同理,对与第2层的输出、经过经激活函数后的输出分别为:

可得最终的损失函数的值为:(为下文方便表示,

优化的目标则是通过训练,调节参数,来使得损失函数的值越小越好。反向传播(BP,Back Propagation)算法,便是利用梯度下降法来求得使损失函数达到最小值得一种方法。

对于反向传播

首先对于第2层而言:

求解$\frac{\partial F_{loss}}{\partial w_{53}}$,则根据反向传播(BP, Back Propagation)算法可得:

其中Sigmod函数导数为:

(注:不同激活函数求导后的结果是不同的,在BP过程中所谓的梯度消失,梯度爆炸与激活函数的不恰当有很大关系!)

求解$\frac{\partial F_{loss}}{\partial w_{54}}$,根据则根据反向传播(BP, Back Propagation)算法可得:

求解$\frac{\partial F_{loss}}{\partial b_5}$,根据则根据反向传播(BP, Back Propagation)算法可得:

进一步的,我们计算第1层的参数:

求解$\frac{\partial F_{loss}}{\partial w_{31}}$,则根据反向传播(BP, Back Propagation)算法可得:

同理可得到其它几个参数权值:$\frac{\partial F_{loss}}{\partial w_{32}}$,$\frac{\partial F_{loss}}{\partial w_{41}}$,$\frac{\partial F_{loss}}{\partial w_{42}}$。

求解$\frac{\partial F_{loss}}{\partial b_3}$,则根据反向传播(BP, Back Propagation)算法可得:

这里重点说明一下,一个函数在某一点的导数描述了这个函数在这一点附近的变化率。$ {\partial F_{loss}}/{\partial w_{31}}$描述了$ F_{loss}$在$ w_{31}$该点变化率(或切线斜率),则有:

通过搜索方向和步长来对参数进行更新,其中搜索方向是目标函数在当前位置的负梯度方向,因为这个方向是最快的下降方向。

则第1层的各权值更新为:

按照更新后的权重参数再进行一次正向传播得出来的损失函数的值为:$F_{loss}=0.0099$

而这个值比第一次迭代时的0.0108更小,如果继续迭代,则会不断修正各层的权值参数,使得损失函数越来越小,预测值不断逼近 0.5

经过迭代了100次后,$F_{loss}=7.09786073e-07$(已经很小很小很小了,说明预测值与真实值非常接近),最后的权值为:

到此,整个前向传播(Forward propagation)与反向传播(Back Propagation)的过程可能差不多就是这样了。

上面实现的python代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import numpy as np

def nonlin(x, deriv=False):
if (deriv == True):
return x * (1 - x) #如果deriv为true,求导数
return 1 / (1 + np.exp(-x))

# 输入层
X = np.array([[0.8],[0.3]])
# 输出值
y = np.array([[0.5]])

np.random.seed(1)

W0 = np.array([[0.3,0.5],[0.6,0.4]])
W1 = np.array([[0.2,0.7]])
B1 = np.array([[0.02,0.03]])
B2 = np.array([[0.03]])
# print('original: ', '\n', W0, '\n',W1)
for j in range(100):
# 输入层(第0层)
l0 = X
# 隐藏层(第1层)
l1 = nonlin(np.dot(W0,l0) + B1.T)
print("l1:",'\n', l1)
# 输出层(第2层)
l2 = nonlin(np.dot(W1,l1) + B2.T)
print("l2:",'\n', l2)
# 损失函数
l2_error = y - l2
Error = 1/2.0*(y-l2)**2
print("Error:",'\n', Error)
# 反向传播
l2_delta = l2_error * nonlin(l2, deriv=True)
l1_error = l2_delta*W1
l1_delta = l1_error * nonlin(l1, deriv=True)
# 更新权值
W1 += l2_delta*l1.T;
W0 += l0.T.dot(l1_delta)
print('W0:', '\n', W0, '\n','W1:', '\n',W1)

本文参考了以下文献:

[1]. 如何直观地解释 backpropagation 算法

[2]. 通俗理解神经网络BP传播算法

🍭支持一根棒棒糖吧!