今天要讲得是Backpropagation,实际上如果你要用Gradient Descent的方法来训练一个神经网络的时候,你应该要怎么做。 我们上次已经讲过神经网络的基本架构。我们来讲一下反向传播算法怎么让神经网络的训练变得有效的。
梯度下降法:是用来更新参数的。 BP算法:是用来更快地求偏微分的。
-------------------------------------------------------------------------------------------------------------------------------------- 在Gradient Descent里面,假设Network有一大堆参数,有一大堆w和b。
首先选一个初试的参数。
然后计算对Loss function的gradient,也就是计算每一个w和b对Loss function的偏微分。这个gradient实际上是一个向量。
计算出来以后呢,就可以更新参数:
再算梯度,更新参数:
这个过程持续下去,就可以找到最好的参数了。
-------------------------------------------------------------------------------------------------------------------------------------- 所以在神经网络里面呢,用Gradient descent的方法的时候,跟我们在做Logistic Regression、linear Regression等等是没有太多差别的。但是最大的差别就是在神经网络里面,我们有非常非常多的参数。比如做声音识别,网络通常比如说有七八层,每层有1000个神经元,这样共有上百万个参数。所以gradient这个向量是非常长的,是一个上百万维的向量。
现在最大的困难是,你要如何有效地把这个有百万维的向量计算出来。这个就是反向传播算法在做的事情。
反向传播算法并不是一个和gradient descent不同的方法,它就是gradient descent。它只是一个比较有效率的演算法,让你在计算梯度这个向量的时候,比较有效率。 -------------------------------------------------------------------------------------------------------------------------------------- 其实,反向梯度算法中并没有特别高深的数学。你唯一要记得的就是链式法则。这个没啥好讲的,不懂的童鞋可以回去翻一下微积分或者高数。等一下会用到这个东西。
-------------------------------------------------------------------------------------------------------------------------------------- 在上一节中讲了,total Loss为所有data的loss之和:
其中网络结构为:
把这个式子,两边对某一个w求偏微分的话,就得到:
只所以写这个式子,是要说接下来我们就不用计算,而是只考虑对某一个data的。能够把一个data的偏微分求出来,再把所有的求和,就可以算出total Loss对w的偏微分了。 所以等一下,我们就只focus在对于某一个data,它的损失对w的偏微分就行了,即:
-------------------------------------------------------------------------------------------------------------------------------------- 那怎么做呢?我们先考虑某一个神经元。我们从下面的神经网络里面拿一个神经元出来。
这个神经元是第一个Layer的神经元。它前面的input就是x1,x2(假设有两个输入)。x1,x2分别乘上w1,w2,再加上b,会得到z。得到z以后再经过激活函数,再经过非常非常多的事情以后,会得到最终的output y1,y2。
现在的问题是,怎么来计算某一个weight对某一个data的Cost的偏微分(b也是一样,可以以此类推算出来,我们用w来举例)。
按照链式法则,可以拆成两项:
这两项,我们就可以分别计算出来。前面一项是很简单的,后面一项是比较复杂的。计算前面这一项,我们称之为Forward pass,待会就会知道为什么这么叫。计算后面这一项我们称之为Backward pass,待会将为什么这么叫。
-------------------------------------------------------------------------------------------------------------------------------------- 那么就先来看一下怎么计算。
这个秒算,因为已经知道了z长什么样子。就是x1,就是x2。
它的规律就是看w前面接的什么。接的是什么微分以后就是什么。 所以假如给你一个神经网络,它里面有一大堆参数,你要计算这里面每一个参数对z的偏微分。这件事情非常容易,因为规律就是看w前面接的是什么。所以当问第一个红圈圈的w对它的z的偏微分,就是-1,因为这个1接的是-1。第2个红圈圈的w对它的z的偏微分是0.12,这个0.12是什么呢,是上一层的某一个神经元的output。第3个红圈圈的w对它的z的偏微分是0.11。
所以,你要计算这个神经网络里面每一个weight对它的estimater function z 的偏微分,你就把input丢进去,然后计算每一个神经元的输出(黄色方框内的数字),就结束了。这个步骤叫做,Forward pass,它是非常容易理解的。
-------------------------------------------------------------------------------------------------------------------------------------- 再来,我们要讲的是Backward pass,也就是。
这就比较困难了。因为这个z要经过激活函数得到a,后面还有非常复杂的过程,才得到C。
不过我们可以用链式法则把这一项做一下拆分。假设这个激活函数是sigmoid()函数。,神经元的输出是a。接下来,a会乘上某一个weight,再加一堆东西得到z'。a还会乘上另外一weight,再加上一堆东西得到z''。z',z''之后可能还会发生一大堆事情,我们就先只考虑一步。
通过链式法则,得到:
我们知道,所以就是sigmoid的微分。sigmoid()函数长这个样子,微分长这个样子,我们之前看过。
接下来的问题是,应该长什么样子呢?a通过z'和z''影响C,所以根据链式法则有:
又有:
所以最后的问题就是,z对C的偏微分没法算。因为我们不知道z与C是什么关系,后面的还有发生许多事情。一下子不知道怎么算。
那怎么办呢?假设我们知道。假设这两个值,我们已经通过某种方法算出来了。
这样,我们就可以算了。 (1)
我们发现:(1)式子是一个递推式!只要求出后一层全部的z对C的偏微分,就可以分别求出本层的z对C的偏微分了!! -------------------------------------------------------------------------------------------------------------------------------------- 我们从另外一个角度来看待这个式子。 你可以想象说,现在有另外一个神经元,这个神经元并不在我们原来的网络里面。这个神经元,我把它画成三角形的。这个神经元的输入就是和。而输出。这个神经元所做的运算跟前面的式子是一样的。其中,其实是一个常数,不是一个函数,因为z在计算forward pass的时候就被决定好了,z我们已经知道它是多少,是一个固定的值。所以这个神经元跟之前学的神经元的运算不一样,没有进行非线性变换,而是直接乘上一个常数。
-------------------------------------------------------------------------------------------------------------------------------------- 刚才说,根据递推式(1),只要求出后一层全部的z对C的偏微分,就可以分别求出本层的z对C的偏微分了。 因此,求z对C的偏微分,分为两种情况:
第一种情况,假设现在红色的两个神经元的output就已经是整个网络的output了。
这时候要算z'对C的偏微分,很简单,根据链式法则,就是。其中,这一项没什么问题,只要知道激活函数长什么样子就能轻而易举地算出来。这一项的话,要看你的Coss function 是怎么定义的,你可以用交叉熵损失,可以用均方误差,不同的定义会不一样,但总之是一个比较简单的东西,可以把它算出来。 同样可以算出z''对C的偏微分。
第二种情况,假设现在红色的神经元的输出并不是整个网络的output。 当然是通过递推式(1)来算。
-------------------------------------------------------------------------------------------------------------------------------------- 有的人会说,要算第一层的,需要知道第二层的;要算第二层的,需要知道第三层的;...这样一层层的往后展开,感觉会是一个很可怕的式子。但是,实际上,并不是这样做的。实际上在做的时候,只要换一个方向,从后往前做,就会发现它的运算量跟Forward pass其实是一样的。 假设我们现在有6个神经元。要计算这些z对C的偏微分。本来呢,想要知道z1的偏微分,就要知道z3和z4的偏微分;要算z3的偏微分,就要知道z5和z6的偏微分;要算z4的偏微分,也要知道z5和z6的偏微分。如果是从z1,z2开始算,那就很没有效率。但是,如果返回来,先算z5和z6的偏微分的话,这个过程就变得有效率起来了。
计算的时候,最后一层直接求,其他层就用递推式(1)来做:
这整个过程叫backward pass。就是建立一个反向的网络。
-------------------------------------------------------------------------------------------------------------------------------------- 最后总结一下,反向传播算法是怎么做的。 首先做一个Forward pass,要求出每一个神经元的输出a。a就是它所连接的weight的。 然后做一个Backward pass,在这里面,要把原来的神经网络的方向反过来,反过来的神经网络中,每个神经元的output就是。 最后把和乘起来,就是了。
BP算法,就算不懂也没什么关系,大部分人都不懂,反正有工具~~不过懂了最好,也不难~~
|