赞
踩
目录
我们知道正向传播就是把x拿下来一层层的和w乘,然后经过function非线性变化,最后得到一个y输出结果。反向传播(reverse-mode autodiff)就是反过来,从最后的y到x,反向的自动求导。前向传播是make predictions,去预测ŷ,然后计算出误差,再计算出每个神经节点对误差的贡献。这里的求贡献就是反向传播过程,首先根据前向传播的误差来求梯度,梯度越大贡献越大。然后根据梯度调整原来的权重。总结下来反向传播就是求导、求梯度,然后根据梯度在迭代里面调整w的一个过程。
反向自动求导是tensorflow实现的方案,首先,它执行图的前向阶段,从输入到输出,去计算节点值;然后反向阶段,从输出到输入去计算所有变量的偏导。
什么是偏导数:在数学中,一个多变量的函数的偏导数,就是它关于其中一个变量的导数而保持其他变量恒定(相对于全导数,在其中所有变量都允许变化)。偏导数在向量分析和微分几何中是很有用的。
说白了就是假如f对x求偏导:∂f*∂x。就是把除x以外的自变量当成常数,然后再进行正常的求导即可。
比如
这个计算逻辑,即这个算法。可以用如图来表达正向传播和反向传播逻辑。图中红色虚线表示正向传播,黑色实线是反向传播。
如果x=3,y=4,正向传播之后,结果为42,体现在n7节点上。
那反向传播是做什么事情呢?怎样传播? 如何计算每根线上面的梯度呢?
这里依赖反向自动求导(reverse-mode autodiff),求解的想法是逐渐的从上往下,来计算f(x,y)的偏导,使用每一个中间连续的节点,直到我们达到变量节点,这里严重依赖链式求导法则。
链式求导法则,就是x不能直接连接f,我们通过一个中间的节点,比如ni,如果ni可以连接f,就可以让f对ni求偏导;然后x可以连接ni,ni对xi求偏导,然后根据链式求导法则相乘,得到的就是f对x求偏导的一个值。
比如上图中的算法逻辑我们最终的f对x来求偏的, f是最后节点出现的结果,x是第一个节点,中间有好长的路要走。所以如果对x求偏导的话,得把每一步节点输出对x求偏导。n1节点没有直接连上n7节点, n1节点也没有直接连上n5节点,但是n1节点可以连上n4节点;n4节点连不上n7节点,但是能连接n5节点。那么我们可以让xn1通过n4去连接n5,然后再通过n5连接到n7,它就成为一条链,求这条链上面的导数,最后就可以把n7对n1也就是f对x偏导求出来。
因为最后的function,对x求偏导,不能直接对x求导,我们倒过来一点点来推,所以它叫反向传播,反过来一点点的去传播梯度。
接下来我们一层一层的解释。
对于f来说,f就是n7的结果,所以f对n7求导。因为是对本身求导,相当于f(x)=x这种情况下,对x求导,结果就变成前面的一个系数,等于1。
下一层,我们要求图中红色这根线上所对应的梯度
这根线的输出是n5节点,所以就要求一下n7对n5节点function的一个偏导,根据链式法则,如图,把它俩的结果相乘。f对n7这一部分已经得到了结果,n7节点的function是加和,n7=n5+n6,如果n7对n5求偏导,结果就是1。可以这样理解这一步,比如f(x)=ax+by,对x求导,那跟b、y没有关系,只用看x前面所对应的斜率,就等于a,这里同样只看n5前面的系数即为1。记住:
对谁求偏导,就把谁看做未知数。其他的都是常数!
∂f/∂n5=∂f*∂n7*∂n7/∂n5,就是1*1=1,所以图中这根红线上的梯度就是1。此时我们有一个中间结果,
接下来再往下来传播。求如下红色线的梯度:
即求∂f/∂n4,等于∂f/∂n5*∂n5/∂n4,上一步求出来的∂f/∂n5=1,接着计算∂n5/∂n4,n5的计算节点的function是,乘法。n5=n4*n2,对n4求偏导,把n4当做未知数,n2为系数,所以结果是n2。同理,反过来,对n2求偏导结果n4。然后把n2节点的数值4代进来,即∂f/∂n4=1*4=4。
再往下传播:求图中红色线梯度
即∂f/∂x,这里有两根线,根据上面传播下来的梯度,那∂f/∂x=∂f/∂n4*∂n4/∂n1,∂f/∂n4已经根据前面算出来的逻辑,∂f/∂n4=4,下面求∂n4/∂n1,∂n4/∂n1看n4节点的function逻辑。此时n4=n1*n1=n1^2。因为(x^2)'=2x,所以∂n4/∂n1=2n1=6。所以∂f/∂x=∂f/∂n4*∂n4/∂n1=4*6=24。
下面求f对y的梯度,y就是n2,如图,因为y是有两条线连接,先求下图左边的梯度:
n2上面连接n5,那么梯度∂f/∂n2=∂f/∂n5*∂n5/∂n2,∂f/∂n5=1(上面已经求出),∂n5/∂n2这部分看n5的逻辑是n5=n4*n2,对n2求偏导结果为n4。n4不用算,因为在正向传播的时候,每个节点的值已经算出来了,所以n4是3^2=9。即∂n5/∂n2=9。所以∂f/∂n2=∂f/∂n2=∂f/∂n5*∂n5/∂n2=1*9=9。
然后再求y连线的右半部分如图:
n7经过n6再连接n2,那么∂n7/∂n2=∂n7/∂n6*∂n6/∂n2,∂n7/∂n6看n7的逻辑n7=n5+n6,对n6求偏导结果为1;∂n6/∂n2看n6的逻辑n6=n2+n3,对n2求偏导也是1。所以∂n7/∂n2=1*1=1。
所以最后∂f/∂y=∂f/∂n2+∂nf/∂n2=1+9=10。
我们再看下f对n3的梯度:
其实我们也不用算这根线,换成机器学习的角度去看,n1是第一个维度x1,n2是第而个维度x2,n3是截距,对截距求偏导,把n3看做未知数,前面系数恒为1 。所以对截距求偏导结果恒为1。
反向传播,如果想求每根线上所对应的梯度,得从后面往前,反着一层层的推出来,才能推出来。这样沿着图一路向下,我们可以计算出所有连线梯度,最后就能计算出??/ ?x = 24, ?? /?y = 10。
同理那我们就可以利用和上面类似的方式方法去计算?cost/?w,如下看一个通用的损失函数对参数求梯度的过程。
抛开具体的实例,我们看下通用的神经元的求导,如图:
这是一个神经元,里面有∑加和,还有f激活函数。正向传播会求得相对应的结果z,一直传播会得到Loss损失;如果我们想要知道最右边红色这根线上面的梯度,就是∂L/∂z求得一个结果。再往前反着推,想知道x这根线上所对应的梯度,用∂L/∂x,根据链式求导法则,先要得到∂L/∂z,然后再得到∂z /∂x ,此时∂L/∂x即已经求得;∂z /∂x 这一部分要看前面的逻辑是什么。
一个神经元分为两部分,一部分是加和∑,一部分是f激活函数,前面有很多的输入x1,x2,x0恒为1,x1对应w1,x2对应w2,x0对应w3,然后它们相乘相加,如果f是Sigmoid函数的话,经过相乘相加得到f(w,x)。加和∑和 function两个逻辑。
算法逻辑用图的方式表达出来如下:
如果正向传播,w0和x0相乘,w1和x1相乘。绿色数字为传入的值,比如w0=2,x0=-1,w0*x0结果为-2;w1=-3,x1=-2,结果为6;w与x相乘完之后,还有加和的节点,加和之后再加上偏距w2,结果为1,即z算出来为1。之后要带到Sigmoid函数里面去,首先坐变化-z,即z乘以(-1)=-1然后经过e^-z,即e^-1=0.37,然后分母+1,0.37+1=1.37,然后求倒数,1/1.37=0.73。
所以在x1=-2;x2=-1;x0=1; w2=2;w1=-3;w0=-3的数值下,相当于给了x输入和w,经过相乘相加之后,再经过Sigmoid函数计算,得到结果0.73。0.73的这个输出结果,很有可能再往下去传递,变成下一个神经元的输入。
我们的目标是调整参数w1,w2,w0,因此需要求出梯度g1,g2,g0。所以我们要算g1=∂L/∂w1,g2=∂L/∂w2,g0=∂L/∂w0。
怎么反向求梯度g?首先得知道L走一条线是什么样的如图,反向传播的线路图(也就是图中蓝色的线)。
假设神经元的输出0.73就是终点,如果我们假设输出不是终点的话,我们就没法知道这根线上的梯度是多少,就没法往回去传。
最后一根线的梯度相当于对自己求导,它的梯度就是1。我们要求g0,g2,g1,即求在w它们线上所对应的g0,g1,g2。
根据前面描述最后结节对本身求梯度相当于对自己求导,所以梯度是1,从后往前传播。那么∂f/∂n6=∂n7/∂n6 * ∂f/∂n7,∂f/∂n7=1,∂n7/∂n6这部分要看n7的计算逻辑是1/x,(1/x)'=-1/x^2,相当于n6是x,因为n6是1.37,那么∂n7/∂n6=-1/(1.37)^2=-0.53。
接着n5到n6这条线上的梯度,就是∂f/∂n5=∂n6/∂n5 * ∂f/∂n6,∂f/∂n6这一部分刚刚求得是-0.53,∂n6/∂n5看n6的计算逻辑f(x)=x+1,求导结果为1。那么∂f/∂n5=1*(-0.53)=-0.53。
接着求n4到n5这个线上的梯度,∂f/∂n4=∂n5/∂n4 * ∂f/∂n5,∂f/∂n5这一部分刚刚求得是-0.53,∂n5/∂n4看n5的计算逻辑是exp,f(x)'=(e^x)'=ex,n4的输出-1作为x,所以∂f/∂n4=e^-1*0.53=1/e *(-0.53)=-0.2。
然后求n4到n3这个线上的梯度,∂f/∂n3=∂f/∂n4 * ∂n4/∂n3,∂f/∂n4刚求得是-0.2,∂n4/∂n3看n4的计算逻辑是f(x)=-x,求导是-1,所以∂n4/∂n3=-1。那么∂f/∂n3=-0.2*(-1)=0.2。
然后求梯度g2,即n3和w2的连线。∂f/∂w2=∂f/∂n3 * ∂n3/∂w2,∂f/∂n3等是0.2,∂n3/∂w2看n3的逻辑为加和,w2前面系数为1,所以∂n3/∂w2=1,那么g0=∂f/∂w2=0.2*1=0.2。
g2求出来了,怎么用 梯度下降调整w2?
用梯度下降的公式,w2^(t+1)=w2^t-α*g2,α学习率,是传进来的超参数,比如学习率是0.01,g2是0.2,那么得到新w2^(t+1)=-3.002,它会影响正向传播每条线上绿色数值,之后它又会影响下次反向传播的梯度。
接下来调整w0。w0这部分是*的一个门操作:
f(a,b)=a*b,对a求导结果是b,对b求导结果是a。那么∂f/∂w0=0.2 * ∂w0*x2/∂w0,x0=-1,那么∂f/∂w0=-0.2。
之后按照公式,w0^(t+1)=w0^t-α*g0=2-0.01*(-0.2)=2.002,就是w0经过一次迭代调整之后的结果。
x0前的梯度,因为它是*,跟w0有关系,所以梯度就是0.2*2=0.4。
接下来调节w1。
计算逻辑是*,那么g1=x1*0.2=-2*0.2=-0.4。调w1:w1^t+1=w1^t-α*g1=-3+0.01*0.4=-2.996,是w1经过一次迭代调整之后的结果。x1前的梯度,和w1有关系,那么-3*0.2=-0.6。
现在我们得到图上每个线所对应的梯度,我们需要调的是w2所对的线g2、w1所对得线g1、w0所对得线g0;我们不用调x2,x1两根线上的梯度,因为每一次迭代的时候,传的都是原始的那份数据。也就是说我们调的是w,然后调完之后,下一次再把原始的的数据代进来,然后再正向传播,求这一路所有的绿色的数值。然后反向传播,再来调w,然后再把x带进来,循环往复。
这就是梯度下降反向传播的流程。它每一次迭代内部就是一个正向传播,求绿色的值,一次反向传播,求红色的梯度,然后在内部根据最优解的公式调w,不同的最优解的求法,公式就不一样,但是不管什么方法,都要去求梯度。这个就是神经网络里面的反向传播,虽然以后写代码不需要自己去算,也不用去画图,它会自动帮你求导,但是要知道它自动求导数是怎样去求的。
假设1/x输出的结果就是最终的结果了,它求出来的梯度是1。但实际上做机器学习的话,Sigmoid函数出的结果不是咱们想象的,它输出的值相当于ŷ。也就是说我们还得根据 ŷ 和真实的y再去求一个损失函数,损失函数不管是交叉熵还是mse,你还得画这样一个传播图, 0.73还没有完,还得再往后去,如果是mse的话,就用预测的0.73跟真实的相减,然后再汇总,计算function函数。
举个例子,比如后面是交叉熵,那ŷ还要经过节点log,然后再接一个节点去乘以真实的y,后面还得再去加和,最后输出的L才是Loss function。
这里x2,x1是一个样本求梯度,如果去做批量梯度下降的时候,损失函数是mse,它的公式是:
前面计算的x2,x1相当于批量梯度下降样本里的一条,而随机梯度下降需要m个样本,都来去算总的损失,因为这里用了一个加和,所以求它整体梯度的时候,需要求每一条样本梯度的加和平均。
比如如果function函数是ax+by,如果对x求导,就看ax这一部分的导数,如果对y求导 ,只考虑by这一部分的导数,加和∑相当于把它俩导数再加和求平均,也就是相当于是每个样本求梯度的一个平均值。
反向传播和梯度下降这两个词,第一眼看上去似懂非懂,不明觉厉。这两个概念是整个神经网络中的重要组成部分,是和误差函数/损失函数的概念分不开的。
神经网络训练的最基本的思想就是:先“蒙”一个结果,我们叫预测结果h,看看这个预测结果和事先标记好的训练集中的真实结果y之间的差距,然后调整策略,再试一次,这一次就不是“蒙”了,而是有依据地向正确的方向靠近。如此反复多次,一直到预测结果和真实结果之间相差无几,亦即|h-y|->0,就结束训练。这里面不断地调整策略就是其背后的原理就是反向传播和梯度下降。
在神经网络训练中,我们把“蒙”叫做初始化,可以随机,也可以根据以前的经验给定初始值。即使是“蒙”,也是有技术含量的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。