首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用矩阵运算加速实现神经网络误差的反向传播

使用矩阵运算加速实现神经网络误差的反向传播

作者头像
望月从良
发布2018-07-19 11:43:42
1.1K0
发布2018-07-19 11:43:42
举报
文章被收录于专栏:Coding迪斯尼Coding迪斯尼

在上一节,我们通过逐步分析的方式讲清楚了神经网络是如何将终端计算获得的误差逐层反向传播给每一个神经元的,同时我们根据节点链路上的权重比值,将误差依次分配给对应的节点,并通过笔算的方式计算了下面例子中每个神经元节点所应该承担的误差。

如果每次都这么繁琐的计算神经元节点误差的话,那么对于那些更复杂,节点更多,层次更多的神经网络,运算量是不可估计的,因此我们必须要找到行之有效的运算方式,快速计算每个神经元的误差,而矩阵则是我们解决该问题的有利武器。

从上图看,神经网络在输出层有两个节点,因此它对应两个误差值假设分别为e1,e2,我们用一维向量来表示:

根据上节描述,误差要从最外层节点反向传播给中间层节点,传播的方式是根据节点链接链路上的权重比值来确定。假设中间层节点1与最外层节点1间连线的权重是w11,中间层节点2与最外层节点1连接线路的权重是w21,那么中间层节点1应该承担的误差有一部分来自e1,其值为:e1*[w11/(w11+w21)],同时误差的一部分来自e2,假设中间层节点1与最外层节点2的链路权重为w12,中间层节点2与最外层节点2的链路权重为w22,那么来自e2的部分误差为:e2*[w12(w12+w22)]。

同理可以计算中间层节点2所应承担的误差。假设中间层节点2与最外层节点1的链路权重为w21,中间层节点2与最外层节点2链路权重为w22,那么中间层节点2所对应的误差为: e1*[w21/(w11+w21)] + e2*[w22/(w12+w22)]。

中间层两个神经元节点的误差运算正好等于下面的矩阵运算:

上面左边大矩阵里,我们可以做进一步的简化,把矩阵每个元素中的分母给去掉,因为分母是固定该行元素的和,并且去掉分母后,神经元对应的误差只不过是做了一次线性变换,因此把分母去掉不影响运算的最终结果。于是上面的式子简化后结果如下:

回想前面我们说过的用矩阵驱动神经网络数据加工链所说的,用矩阵来表示神经元链路的内容,那里提到如何用矩阵运算上一层节点如何把信号传递给下一层节点时,用到了下面公式:

注意看上面公式与误差回传公式里面左边矩阵有何差异,误差公式中左边矩阵的第一行是上面传播公式中左边矩阵的第一列,误差公式中左边矩阵的第二行是上面传播公式中左边矩阵的第二列,这种将矩阵的列变成对应行的过程叫转置,例如下面矩阵的变换:

我们用矩阵符号右上角加个T来表示转置。于是误差反向传播公式就转换为:

其中的W就是信号从上一层神经元传递到下一层神经元时的传播矩阵。这里有一个问题是,我们把反向传播矩阵中元素的分母拿掉,这回影响最终计算的结果吗?由于神经网络是一种以迭代方式进行的数值运算,因此参与运算的数值产生一些线性变换是不影响最终结果的。

我们不厌其烦的说了一大堆如何计算的过程,但始终没有触及如何通过误差来修正每个神经元对应链路上的权重。还记得我们前面讲过的线性分类器吧,得到误差后,我们根据分界线对应的直线函数,来计算相关误差,但由于神经元的信号是由上一层的多个神经元传入,并且多个信号组合在一起后,还经历了一次非线性的激活函数运算,如果我们要像前面说过的通过分析函数表达式,然后通过误差反向计算出神经元链路修改后的数值,那么这个过程是相当复杂的。

我们简单看看从下一层的神经元逆向回算到上上一层神经元需要怎样的复杂运算过程吧:

这种复杂是因为第一层神经元把信号传递到第二层神经元时,后者经过激活函数进行了信号的运算,第二层神经元再把信号传递到第三层神经元时,后者有再次进行了激活函数的运算,因此激活函数随着层次的增多而不断的间套,于是从最外层向后回卷时,就需要把层层间套的激活函数做逆运算,这个过程是及其复杂的。

这个困难是阻碍深度学习发展的一个重要门槛,知道70年代科学家才找到了有效出路。正是因为解决了这个难题,以深度学习为基础的人工智能才蓬勃发展起来。在数值运算中有一种办法叫牛顿下山法,它是一种如何在由非线性函数构成的复杂曲面找找到极值的方法,这种方法有点像一个人如何从山顶上下山。

试想你一个人在山顶上,你手里又没有地图,只有一个手电筒,那么你如何从山顶走到山地呢?办法其实很简单,你环顾四周,看哪一个方向是往下走的,你就朝那个方向一直走到底,不能继续往下走时,你再次环顾四周,看看那个方向又能继续往下走,这个方法一直循环,直到你下到山底为止。

对应到数学上,这种“环顾四周,找到往下走的方向”,叫做梯度下降法。我们不管一个函数形成的曲线或曲面有多复杂,我们只要在给定点上做这条曲线或曲面的切线,如果切线的斜率表明切线是向下倾斜的,那么朝着切线的方向增大或减小变量的值,那么根据函数计算出来的值就会相应的变小。反复进行该步骤,我们就能得到越来越小的函数值。神经网络的信号传递过程,可以看做是一个非常复杂的多变量,非线性函数,每一个变量对应一个“方向”,我们要看改变该变量的值后,函数最终的结果是增大了还是减小了,只要对该变量求“偏导数”,这个“偏导数”就是该变量对应方向上的切线,如果得到的切线方向是向下的,那意味着增加该变量的值可以减小函数输出结果,如果切线方向是向上的,那意味着增加该变量的值会增大函数的输出结果。

举个具体例子来看才好明白,假设我们有一个简单的非线性函数y = (x-1)^2 + 1,如果y对应的值就是误差,那么我们如何调整x的值,使得y取得最小值呢?该函数对应的曲线如下图:

上图中的蓝色曲线就是函数y,假设当前x的值对应于红色点处,现在我们要看x的值是增大还是减少才能让y的值变小,于是我们就在红点出做一条曲线的切线,也就是带箭头的那条绿色直线,这时我们发现切线的斜率是负值,这意味着我们增大x的值就能让y值减小,于是我们”适当“的增加x,于是我们从红色点处来到粉色点处,显然粉色点处对应的y值比红色点出对应的y值要小,这个过程一直进行,知道走到曲线最低点为止。

还有另一种情况是,一开始我们所在的红点位置如下图所示:

我们找改点处对应的曲线的切线,发现切线的斜率是正的,也就是说,只要我们减少x的值,y值就能相应的降低,于是我们”适当“的减少x的值,我们从红点所在处来到粉色点所在处,不难发现,粉色的对应的y值比红色点对应的y值要少,这个过程反复进行,直到走到曲线的最低点为止。

这里有一点需要非常注意的是,我们如何“适当”的改变x的值,如果改变“不适当”的话,假设我们处于最低点左边,要达到最低点我们就得增加x的值,如果增加大了,我们就会一下次跑到最低点的右边,于是就得减少x的值,如果我们对x的改变幅度“不适当”的话,我们就会在最低点处左右摇摆,永远停不下来。

为了能让x改变的幅度保持一种“适当”的范围,我们就可以根据y值来调整x改变的幅度,一开始x改变的幅度可以大一些,但随着y值变得越来越小,这意味着x距离底部最低点越来越近,于是我们就逐渐缩小x改变的幅度,如下图所示:

这里还有一点值得注意的是,x改变的方向与切线的斜率成反向关系。如果切线的斜率是负的,那么我们就要增加x的值,如果切线的斜率是正的,我们就需要减少x的值。根据这种做法,我们不需要把原函数进行瓦解,找到反函数后才能确定x如何变化以便减少y的值。这个总走一步看一步,寻找最小值的方法叫牛顿下山法,也称之为梯度下降法,该方法面对含有多个变量的非线性函数尤其有用。

如果y不仅依赖变量x,还依赖变量a,b,c,d,那么牛顿下山法照样管用。对神经网络而言,终端节点的输出与网络中每一条链路,每一个节点都有关,也就是说,整个神经网络如果看做一个函数的话,那么这个函数可能包含着成千上万个变量。对如此复杂的函数,我们依然可以向上面一样,做每个变量对应的切线,根据切线的斜率来决定变量是增大还是减少。我们看简单一点的多变量情况,假设函数含有2个变量,那么在坐标轴上绘制出来就是一个三维空间上一个曲面:

我们要从曲面的顶部下到曲面的最底部,我们只要求出变量x和y所在位置的切线,根据切线斜率觉得两个变量的增减,如果变量y对应的切线斜率是正的,那么我们就适当的减少y的值,如果变量x的斜率是负的,那么我们就适当增加x的值,这样就跟上图所示,从顶部摸索出一条走到底部的路径。

牛顿下山法有个问题就是会落入局部最低点。一条曲线或曲面可能有多个低谷,其中只有一个低谷位置是最低的,利用牛顿下山法时,如果进入一个局部低谷,那么可能就再也出不来了,也就是说我们确实走到了低谷,当只是局部低谷,而不是全局低谷,例如下面曲线:

这条曲线有两个低谷,左边低谷是局部低谷,因为它不是最低的,右边低谷才是全局最低的低谷。如同上面中间所示情况,如果一开始x的初始值在局部低谷的左边,而且x的变化幅度太小时,那么我们用牛顿下山法会进入局部低谷,再也出不了,如果像图1那样,x的初始值,也就是红点,一开始在右边的话,那么牛顿下山法就能帮我们走到最低点,当然我们也可以采取增大x改变的幅度,让他越过局部低谷,最终落入到全局低谷。

这种做法对应到神经网络上就是,一开始神经网络每条链路上的权重是随机赋值的,经过第一轮训练后,我们得到一个优化的网络,第二次我们再次随机赋予每条链路随机值,然后再进行一轮新的训练,反复如此操作多次,从多次训练结果中选择最优的结果。

下一节我们再对牛顿下山法的运算过程做深入剖析,并通过手算的方式把流程的每个步骤走一遍,进而让我们加深对算法的理解。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coding迪斯尼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档