反向传播这个术语经常被误解为用于多层神经网络的整个学习算法。实际上,反向传播仅指用于计算梯度的方法,而另一种算法,例如随机梯度下降,使用该梯度来进行学习。此外,反向传播经常被误解为仅适用于多层神经网络,但是原则上它可以计算任何函数的导数(对于一些函数,正确的响应是报告函数的导数是未定义的)。
在讲解误差反向传播算法之前,我们来回顾一下信号在神经网络中的流动过程。请细细体会,当输入向量X输入感知器时,第一次初始化权重向量W是随机组成的,也可以理解成我们任意设置了初始值,并和输入做点积运算,然后模型通过权重更新公式来计算新的权重值,更新后的权重值又接着和输入相互作用,如此迭代多次,得到最终的权重。
信号向前传播,权重的更新反向传播,是这样吗?
是的,你的直觉没错,确实是反向传播。
1. 前馈的实质
反向传播这个术语经常被误解为用于多层神经网络的整个学习算法。实际上,反向传播仅指用于计算梯度的方法,而另一种算法,例如随机梯度下降,使用该梯度来进行学习。此外,反向传播经常被误解为仅适用于多层神经网络,但是原则上它可以计算任何函数的导数(对于一些函数,正确的响应是报告函数的导数是未定义的)。
1.1 初始化权重和输入信号
不如我们还是使用上一节矩阵乘法的列子来可视化的讲解,这样有助于我们去理解反向传播。假设有如下三层网络,输入层、隐藏层、输出层,现有一组信号X输入网络,输入层和隐藏层的链接权重Winput−hidden和隐藏层与输出层之间的权重Whidden−ouput我们随机初始化。为了清晰效果,我们仅标注了几个权重,第一个输入节点和中间隐藏层第一个节点之间的权重为w1,1 = 0.9,正如上图中的神经网络所示。同样,你可以看到输入的第二节点和隐藏层的第二节点之间的链接的权重为w2,2 = 0.8,隐藏层第三个节点和输出层第二个节点之间链接的权重为w3,2 = 0.2......此命名方式前面解释过,标注之后在分析反向传播时可帮助我们理解。
图5.2.1
输入矩阵:
X=⎡⎢⎣0.90.10.8⎤⎥⎦
输入层和隐藏层之间的连接权重:
Winput−hidden=⎡⎢⎣0.90.30.40.20.80.20.80.10.9⎤⎥⎦
隐藏层和输出层之间的连接权重:
Whidden−output=[0.30.70.50.60.50.2]
1.2 输入层到隐藏层
初始值定义好以后,开始计算输入到隐藏层的组合调节输入值Xhidden。
Xhidden=Winputhidden⋅X
此处的矩阵乘法还是交由计算机来执行,计算出的答案如下:
Xhidden=⎡⎢⎣0.90.30.40.20.80.20.80.10.9⎤⎥⎦⋅⎡⎢⎣0.90.10.8⎤⎥⎦
Xhidden=⎡⎢⎣1.160.420.62⎤⎥⎦
别着急往下走,让我们来整理一下网络的信号流动情况,Xhidden作为第一层的输出,第二层的输入已经正确求解,现在它准备进入隐藏层。
图5.2.2
Xhidden一进入隐藏层,我们就对Xhidden的这些节点使用S激活函数,使其变得更加自然,并且我们把经过S函数处理后的这组输出信号命名为Ohidden。
Ohidden=Sigmoid(Xhidden)=Sigmoid(⎡⎢⎣1.160.420.62⎤⎥⎦)=⎡⎢⎣0.7610.6030.650⎤⎥⎦
1.3 隐藏层到输出层
让我们再次可视化这些输入到第二层隐藏层的组合调节输入。现在信号已经向前流动到了第二层,下一步当然是计算第三层的输出信号Xoutput(还未经过S函数的输出信号),计算的方法和前面一样,没有什么区别,不管我们的网络是几层,这种方法都适用。
图5.2.3
于是,我们有:
Xoutput=Whidden−output⋅Ohidden=[0.30.70.50.60.50.2]⋅⎡⎢⎣0.7610.6030.650⎤⎥⎦=[0.9750.888]
现在,更新示意图展示我们的进展,从初始输入信号开始,一层层往前流动的前馈信号,最后得到了最终层的组合输入信号。
图5.2.4
最后一步当然是使用S函数得到最后一层的输出,用Oouput表示:
Oouput=Sigmoid(Xoutput)=Sigmoid([0.9750.888])=[0.7260.708]
前馈信号的流动到此为止,任务完成!通过可视化的图形,前馈神经网络中信号流入方向,变化等情况我们用网络图最后形展示出来。
图5.2.5
毫无疑问,整个过程就是前馈的意思,信号一直向前流动,最后输出,中间任意层没有信号反回上一级网络。
下一步我们会将神经网络的输出值与训练样本中的输出值进行比较,计算出误差,并使用这个误差值来反向调节权重值。
2. 反向传播的实质
上一步我们得到了前向传播的输出值为[0.726, 0.708],这个值与真实值[0.01,0.99]还存在一定差距,不过没关系,反向传播误差会帮助我们更新权值,缩小这些误差,让我们来实验一下。
2.1 计算总误差
因为总误差为:E=∑(target−Ooutput)2=E1+E2=(target1−Ooutput1)2+(target2−Ooutput2)2
由于我们的实验网络有两个输出,因此总误差为两个输出误差之和。
第一个误差:
E1=(target1−Ooutput1)2=(0.726−0.01)2=0.512656
第二个误差:
E2=(target2−Ooutput2)2=(0.706−0.99)2=0.079524
总误差:
E=E1+E2=0.512656+0.079524=0.59218
2.2 隐藏层和输出层的权重更新
对于隐藏层和输出层之间的权重w1,1来说,如果我们想知道w1,1对整体误差产生了多少影响,可以用总误差对w1,1求偏导,该偏导可以使用链式法则表示。
∂E∂w1,1=∂E∂Oouput1⋅∂Oouput1∂Xouput1⋅∂Xouput1∂w1,1
如图所示的反向传播示意图,并结合求导表达式,可以帮助我们更清楚的了解误差是怎么反向传播的。
图5.2.6
下面我们对以上求导式子中的每个小式子分别求值
1、首先是计算∂E∂Oouput1
E=(target1−Ooutput1)2+(target2−Ooutput2)2
∂E∂Oouput1=−2(target1−Ooutput1)+0=−2(0.01−0.726)=1.432
2、再来计算∂Oouput1∂Xouput1
Oouput1=11+e−Xouput1
∂Oouput1∂Xouput1=Oouput1(1−Oouput1)=0.726(1−0.726)=0.198924
3、最后计算∂Xouput1∂w1,1
Xouput1=w1,1⋅Ohidden1+w2,1⋅Ohidden2+w3,1⋅Ohidden3
∂Xouput1∂w1,1=Ohidden1=0.761
所以:
∂E∂w1,1=∂E∂Oouput1⋅∂Oouput1∂Xouput1⋅∂Xouput1∂w1,1=1.432×0.198924×0.761=0.216777826848
我们取学习率η=0.5,利用公式$${w_{1,1}}{new}=w-\eta \frac{\partial E}{\partial w_{1,1}}$$
得到更新后的w1,1new为:w1,1new=0.3−0.5×0.216777826848=0.191611086576
综上所述,也可以这样去计算∂E∂w1,1:
∂E∂w1,1=−2(target1−Ooutput1)⋅Oouput1(1−Oouput1)⋅Ohidden1
因此,改变上述式子的变量可以更新w2,1,w2,1,w1,2,w2,2,w3,2等权重值。
2.3 输入层和隐藏层的权重更新
计算输入层和隐藏层之间的权重和上面的方法一样,但使用误差对权重进行求导时,该误差应使用两个输出口的总误差,而不是一个输入口的误差。我们仍然用图形化的方式来展示:
图5.2.7
如上图所示,对于隐藏层和输出层之间的权重w1,1来说,如果我们想知道w1,1对整体误差产生了多少影响,可以用总误差对w1,1求偏导,该偏导可以使用链式法则表示。
∂E∂w1,1=∂E∂Ohidden1⋅∂Ohidden1∂Xhidden1⋅∂Xhidden1∂w1,1
我们还是一个一个的计算上面的式子。
1、首先计算∂E∂Ohidden1
对于隐藏层的输出,它会接受来自两个输出传来的误差,所以:
∂E∂Ohidden1=∂E1∂Ohidden1+∂E2∂Ohidden1
∵∂E1∂Ohidden1=∂E1∂Xoutput1⋅∂Xoutput1∂Ohidden1
∵∂E1∂Xoutput1=∂E1∂Ooutput1⋅∂Ooutput1∂Xoutput1=1.437×0.198924=0.285853788
下面的w′j,k为隐藏层和输出层的链接权重
Xoutput1=w′1,1⋅Ohidden1+w′2,1⋅Ohidden2+w′3,1⋅Ohidden3
∴∂Xoutput1∂Ohidden1=w′1,1=0.3
∴∂E1∂Ohidden1=∂E1∂Xoutput1⋅∂Xoutput1∂Ohidden1=0.285853788×0.3=0.0857561364
再来计算∂E2∂Ohidden1
∵∂E2∂Ohidden1=∂E2∂Xoutput2⋅∂Xoutput2∂Ohidden1
∵∂E2∂Xoutput2=∂E2∂Ooutput2⋅∂Ooutput2∂Xoutput2
∵Xoutput2=w′1,2⋅Ohidden1+w′2,2⋅Ohidden2+w′3,2⋅Ohidden3
∴∂Xoutput2∂Ohidden1=w′1,2
∴∂E2∂Ohidden1=∂E2∂Xoutput2⋅∂Xoutput2∂Ohidden1=−0.116599104×0.2=−0.0233198208
最后得到
∂E∂Ohidden1=∂E1∂Ohidden1+∂E2∂Ohidden1=0.0857561364−0.0233198208=0.0624363156
2、再计算∂Ohidden1∂Xhidden1
∵Ohidden1=11+e−Xhidden1
∂Ohidden1∂Xhidden1=Ohidden1(1−Ohidden1)=0.761(1−0.761)=0.181879
3、最后计算∂Xhidden1∂w1,1
∵Xhidden1=w1,1⋅X1+w2,1⋅X2+w3,1⋅X3
∴∂Xhidden1∂w1,1=X1=0.9
∂E∂w1,1=∂E∂Ohidden1⋅∂Ohidden1∂Xhidden1⋅∂Xhidden1∂w1,1=0.0624363156×0.181879×0.9=0.01022026918051116
我们取学习率η=0.5,利用公式$${w_{1,1}}{new}=w-\eta \frac{\partial E}{\partial w_{1,1}}$$
得到更新后的w1,1new为:w1,1new=0.9−0.5×0.01022026918051116=0.191611086576=0.89488986540974442
同样的方法可以更新其他权重的值。这样我们就完成了误差反向传播算法的介绍,在实际训练中我们通过这种方法不停的迭代,直到总误差接近0为止,得到的最优权重保留下来,训练完成。
参考文献:
1、《Python神经网络编程》
2、https://www.cnblogs.com/charlotte77/p/5629865.html
以上内容有任何错误或不准确的地方请大家指正,不喜勿喷!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库