- 前言:反向传播实质就是链式求导法则的反复用。本文记录一下反向传播的过程,也是为了理解后续出现的梯度消失和爆炸问题(连乘效应)。本文完全按照一位大佬的博客来推理反向传播。
说起神经网络大家会想起以下的只有三层的简单神经网络
该神经网络共三层:输入层(L1)、隐含层(L2)和输出层(L3)。我们现在手里有一堆数据{x1,x2,x3,......,xn},输出也是一堆数据{y1,y2,y3,......,yn}。现在就是要把这些数据灌进去,经过隐含层做某种变换,获得我们期望的输出结果。
case1:如果我们希望输出与输入一样,那这样就是常见的自编码模型(Auto-Encoder)。可能有人会问,为什么要输入输出都一样呢?有什么用啊?其实应用挺广的,在图像识别,文本分类等等都会用到,大佬说他会专门再写一篇Auto-Encoder的文章来说明,包括一些变种之类的。
case2:如果你的输出与原始输入不一样,那么就是很常见的人工神经网络了。相当于让原始数据通过一个映射来得到我们想要的输出数据。这也是我接下来要学习所记录的。
本文直接举一个例子,带入数值演示反向传播法的过程,公式的推导等到下次写Auto-Encoder的时候再写,其实也很简单,感兴趣的同学可以自己推导下试试:(推导过程见另一篇博客))
假设有这样一个网络:
第一层是输入层包含两个神经元i1,i2以及一个截距项b1; 第二层是隐藏层,包含两个神经元h1,h2以及一个截距项b2,第三层是输出o1和o2。每条线上标的wi是层与层之间连接的权重。激活函数我们默认为sigmoid函数。
现在对他们赋上初值如下:
其中,
输入数据i1=0.05,i2=0.10
输出数据o1=0.01, o2=0.99
权重w1=0.15, w2=0.20, w3=0.25, w4=0.30, w5=0.40, w6=0.45, w7=0.50, w8=0.55
目的:给出输入数据i1和i2,使输出尽可能与原始输出o1和o2接近。
step1:前向传播
(1)输入层--->隐含层
计算神经元h1的输入加权和:
h1 =(i1*w1+i2*w2)+ b1 = (0.05*0.15+0.10*0.20)+ 0.35 = 0.3775
计算神经元h2的输入加权和:
h2 = (i1*w3+i2*w4)+b1 = (0.05*0.25+0.10*0.30) + 0.35 = 0.3925
神经元h1和h2经过激活函数sigmoid后输出为:
out_h1 = S(h1) = sigmoid(h1) = = 0.5933
同理out_h2 = S(h2) = sigmoid(h2) = 0.5969
(2) 隐含层--->输出层
计算输出层神经元o1和o2的值:
o1 = (out_h1*w5+out_h2*w6) + b2 = (0.5933*0.40+0.5969*0.45) + 0.60 = 1.1059
o2 = (out_h1*w7 + out_h2*w8) + b2 = (0.5933*0.50+0.5969*0.55) + 0.60 = 1.2249
输出层神经元o1和o2经过激活函数sigmoid后输出为:
这样,我们的前向传播的过程就结束了。我们得到输出值为[0.7514, 0.7729],这与实际值[0.01, 0.99]相差还很远。现在我们对误差进行反向传播,更新权值,重新计算输出。
step2:反向传播
(1) 计算总误差
总误差(平方误差)
但是有两个输出,所以分别计算o1和o2的误差,总误差为两者之和。
(2) 隐含层--->输出层的权值更新:
以权重参数w5为例,如果我们想知道w5对整体误差产生了多少影响,可以用整体误差对w5进行求偏导求出:(链式法则)
(注意:w5与o1(即下图中的)关联,然后o1(即下图中的)与(即下图中的)关联, 最后与Etotal关联)
下面的图可以更直观的看清楚误差是怎么样做反向传播的:
注意:图中的实际是本文中的o1, 实际是本文中的该图是大佬博客里面的原图,我懒得画直接用了。
现在我们分别计算每个式子的值:
1.求 的值
=
2.求的值
===>
=
3.求的值
o1 = (out_h1*w5+out_h2*w6)
out_h1=0.5933
4.最后三者相乘结果为
这样我们就计算出了整体误差对w5的偏导值!!!!!!!!!!!!!
##############################################################
回过头我们再来观察上面三个公式,我们发现:
注意:就是out_h1
为了表达方便,我们用表示输出层的误差,即:
因此整体误差对w5的偏导可以写成:
注意:这个也就是吴恩达视频9-2里面的Delta
如果输出层误差计为负值的话,也可以写成:
最后我们来更新权值w5的值:
其中,是我们常说的学习率,表征梯度下降的快慢
同理可更新w6,w7,w8:
(3) 隐含层--->输入层的权值更新:
方法与上面的差不多,但是有个地方需要变一下。在上文计算总误差对w5的偏导时,是从finalout(o1)--->o1(o1)--->w5。
但是在隐含层与输入层之间的权值更新时,是finalout(h1)--->o1(h1)--->w1
而finalout(h1)会接受Eo1和Eo2两个地方传来的误差,所以这个地方两个都要算。
为什么finalout(h1)会跟Eo1和Eo2两个有关联?
回答:对于Eo2--->--->o2--->out_h1,说明h1除了跟E01有关系,也是跟Eo2有关系的。
1.首先计算总误差带来的影响
由可知:
1)先计算 :
又因为:
所以:
2)再计算
同理计算得到
3)两者相加
2.再计算
因为
所以
3.然后再计算
因为h1 =(i1*w1+i2*w2)+ b1
所以
4.最后三者相乘
最后更新w1的权值:
同理,可更新w2,w3,w4的权值:
这样误差反向传播就完成了,最后我们再把更新的权值wi重新计算,不停的迭代。在这个例子中第一次迭代后,总误差由0.29837下降到0.29103。迭代一万次后,总误差为0.000035,输出为
[0.015912196,0.984065734](原输入为[0.01,0.99]),证明效果还是不错的。
注意:为什么隐含层到输出层的权重w5, w6, w7, w8在反向传播过程中更新了,而在更新输入层到隐含层的权重w1, w2, w3, w4时,使用到的w5....w8还是未更新之前的0.4, 0.45, 0.5, 0.55?
答:反向传播更新权重时,用到的loss是本次前向推理用到的权重,所以所有的weight都是本次的迭代的。换句话说如果你传播还没结束的过程中就把权重更新了再计算,那你用的loss就不对了。梯度下降法里面的参数更新都是一个一个更新的,用的是更新原来的式子求偏导(看书里都是这样)
参考文章:https://blog.csdn.net/weixin_38347387/article/details/82936585#commentBox
参考文章:BP神经网络与Python实现 - -Finley- - 博客园
参考文章:https://blog.duohuo.org/2019/02/19/155/
参考文章:机器学习练习四:用Python实现BP神经网络 - 掘金