精华内容
下载资源
问答
  • 今天小编就为大家分享一篇tensorflow 实现自定义梯度反向传播代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 我们用一个简单的例子理解valid卷积的梯度反向传播。假设有一个3×3的未知张量x,以及已知的2×2的卷积核K Tensorflow提供函数tf.nn.conv2d_backprop_input实现了valid卷积中对未知变量的求导,以上示例对应的代码...
  • 今天小编就为大家分享一篇PyTorch: 梯度下降及反向传播的实例详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 反向传播梯度下降这两个词,第一眼看上去似懂非懂,不明觉厉。这两个概念是整个神经网络中的重要组成部分,是和误差函数/损失函数的概念分不开的。 神经网络训练的最基本的思想就是:先“蒙”一个结果,我们叫预测...

    反向传播和梯度下降这两个词,第一眼看上去似懂非懂,不明觉厉。这两个概念是整个神经网络中的重要组成部分,是和误差函数/损失函数的概念分不开的。

    神经网络训练的最基本的思想就是:先“蒙”一个结果,我们叫预测结果h,看看这个预测结果和事先标记好的训练集中的真实结果y之间的差距,然后调整策略,再试一次,这一次就不是“蒙”了,而是有依据地向正确的方向靠近。如此反复多次,一直到预测结果和真实结果之间相差无几,亦即|h-y|->0,就结束训练。

    在神经网络训练中,我们把“蒙”叫做初始化,可以随机,也可以根据以前的经验给定初始值。即使是“蒙”,也是有技术含量的。

    通俗地理解反向传播

    举个通俗的例子,Bob拿了一支没有准星的步枪,或者是准星有bug,或者是Bob眼神儿不好看不清靶子,或者是雾很大......反正就是Bob很倒霉。第一次试枪后,拉回靶子一看,弹着点偏左了,于是在第二次试枪时,Bob就会有意识地向右侧偏几毫米,再看靶子上的弹着点,如此反复几次,Bob就会掌握这支步枪的脾气了。下图显示了Bob的5次试枪过程:

    在这个例子中:

    • 每次试枪弹着点和靶心之间的差距就叫做误差,可以用一个误差函数来表示,比如差距的绝对值,如图中的红色线。
    • 一共试枪5次,就是迭代/训练了5次的过程 。
    • 每次试枪后,把靶子拉回来看弹着点,然后调整下一次的射击角度的过程,叫做反向传播。注意,把靶子拉回来看和跑到靶子前面去看有本质的区别,后者容易有生命危险,因为还有别的射击者。一个不恰当的比喻是,在数学概念中,人跑到靶子前面去看,叫做正向微分;把靶子拉回来看,叫做反向微分。
    • 每次调整角度的数值和方向,叫做梯度。比如向右侧调整1毫米,或者向左下方调整2毫米。如图中的绿色矢量线。

    上图是每次单发点射,所以每次训练样本的个数是1。在实际的神经网络训练中,通常需要多个样本,做批量训练,以避免单个样本本身采样时带来的误差。在本例中,多个样本可以描述为连发射击,假设一次可以连打3发子弹,每次的离散程度都类似,如下图所示:

    • 如果每次3发子弹连发,这3发子弹的弹着点和靶心之间的差距之和再除以3,叫做损失,可以用损失函数来表示。

    其实损失就是所有样本的误差的总和,所以有时候损失函数可以和误差函数混用概念。

    其实射击还不这么简单,如果是远距离狙击,还要考虑空气阻力和风速,在神经网络里,空气阻力和风速可以对应到隐藏层的概念上。

    用数学概念理解反向传播

    我们再用一个纯数学的例子来说明反向传播的概念。

    假设我们有一个函数 z=x∗y,其中:x=w∗2+b,y=b+1,即:z=(w∗2+b)∗(b+1)z=x∗y,其中:x=w∗2+b,y=b+1,即:z=(w∗2+b)∗(b+1)

    关系如下图:

    注意这里x, y, z不是变量,w, b是才变量,因为在神经网络中,我们要最终求解的是w和b的值,x,y,z只是样本值。

    当w = 3, b = 4时,会得到如下结果

    最终的z值,受到了前面很多因素的影响:变量w,变量b,计算式x,计算式y。常数是个定值,不考虑。目前的z=50,如果我们想让z变大一些,w和b应该如何变化呢?

    我们从z开始一层一层向回看,图中各节点关于变量b的偏导计算结果如下图:

    因为z = x * y,其中x = w * 2 + b,y = b + 1
    所以:

     

    ∂z∂b=∂z∂x∗∂x∂b+∂z∂y∗∂y∂b=5∗1+10∗1=15∂z∂b=∂z∂x∗∂x∂b+∂z∂y∗∂y∂b=5∗1+10∗1=15

    其中:

     

    ∂z∂x=∂∂x(x∗y)=y=5∂z∂x=∂∂x(x∗y)=y=5

     

    ∂z∂y=∂∂y(x∗y)=x=10∂z∂y=∂∂y(x∗y)=x=10

     

    ∂x∂b=∂∂b(w∗2+b)=1∂x∂b=∂∂b(w∗2+b)=1

     

    ∂y∂b=∂∂b(b+1)=1∂y∂b=∂∂b(b+1)=1

    有一个很有趣的问题是:z = x * y = 10 * 5 = 50,表面看起来x=10,y=5,似乎x对z的贡献较大。那么x的微小变化和y的微小变化对z来说,哪一个贡献大呢?

    我们假设只有x变化时,△x = 0.1, 则z = (x + △x) * y = 10.1 * 5 = 50.5

    我们再假设只有y变化时,△y = 0.1, 则z = x * (y +△y) = 10 * 5.1 = 51

    50.5 < 51,说明y的微小变化对z的贡献比较大,这个从

     

    ∂z∂x=∂∂x(x∗y)=5<∂z∂y=∂∂y(x∗y)=10∂z∂x=∂∂x(x∗y)=5<∂z∂y=∂∂y(x∗y)=10

    和这两个值的比较来看也可以证明。而△x和△y就可以理解为梯度值。

    同理,我们也可以得到图中各变量对w的偏导值:

    从以上两图可以看出,反向微分保留了所有变量(包括中间变量)对结果z的影响。若z为误差函数,则对图进行一次计算,可以得到所有节点对z的影响,即梯度值,下一步就可以利用这些梯度值来更新w和b的权重。

    w的变化和b的变化,哪一个对z的变化贡献大?从图中还可以注意到:

     

    ∂z∂b=15∂z∂b=15

     

    ∂z∂w=10∂z∂w=10

    所以每次w和b的变化值是不相同的,b的变化会比w大一些,也就是每一步的跨度大一些,这个是与z = xy = (w2+b)*(b+1)这个算式相关的,并不代表神经网络中实际情况。

    反向传播的实际计算过程(单变量)

    还是用上面的例子,目前:

    • w=3w=3
    • b=4b=4
    • x=w∗2+b=10x=w∗2+b=10
    • y=b+1=5y=b+1=5
    • z=x∗y=50z=x∗y=50

    假设我们最终的目的想让z = 60,只改变b的值,如何实现?
    答案就是偏导数:

     

    ∂z∂b=ΔzΔb=15∂z∂b=ΔzΔb=15

    目前z=50, 距离60相差10,所以我们令Δz=60−50=10Δz=60−50=10,则:

     

    ΔzΔb=15=10ΔbΔzΔb=15=10Δb

    所以:

     

    Δb=0.66667Δb=0.66667

    再带入式子中(顺便说一句,下面这个计算过程就叫做前向计算

    • w=3w=3
    • b=4+0.66667=4.66667b=4+0.66667=4.66667
    • x=w∗2+b=10.66667x=w∗2+b=10.66667
    • y=b+1=5.66667y=b+1=5.66667
    • z=x∗y=10.66667∗5.66667=60.4445z=x∗y=10.66667∗5.66667=60.4445

    一下子超过60了,咋办?再来一次(下面的过程就叫做反向传播):

    我们令Δz=60−60.4445=−0.4445Δz=60−60.4445=−0.4445,则:

     

    ΔzΔb=15=−0.4445ΔbΔzΔb=15=−0.4445Δb

    所以:

     

    Δb=−0.02963Δb=−0.02963

    再带入式子中:

    • w=3w=3
    • b=4.666667−0.02963=4.63704b=4.666667−0.02963=4.63704
    • x=w∗2+b=10.63704x=w∗2+b=10.63704
    • y=b+1=5.63704y=b+1=5.63704
    • z=x∗y=10.63704∗5.63704=59.96z=x∗y=10.63704∗5.63704=59.96

    咦哈!十分接近59.96了!再迭代几次,应该可以近似等于60了,直到误差不大于0.00001时,我们就可以结束迭代了,对于计算机来说,这些运算的执行速度很快。

    有的同学会说了:这个问题不是用数学公式倒推求解一个二次方程,就能直接得到准确的b值吗?是的!但是我们是要说明机器学习的方法,机器并不会解二次方程,而且很多时候不是用二次方程就能解决实际问题的。而上例所示,是用机器所擅长的迭代计算的方法来不断逼近真实解,这就是机器学习的真谛!而且这种方法是普遍适用的。

    用二维平面函数说明梯度下降原理

    很多资料中会用下面这个图来说明梯度下降,但是都没有说清楚以下几个问题:

    1) 为啥用这个看上去像y=x2y=x2族的函数来说明梯度下降?
    2) 在最低点的左侧,梯度值是负数;在最低点的右侧,梯度值是正数。为什么说是“下降”?
    3) 为什么1—>2,2—>3等等的连线不是这条曲线的切线呢,而好像是弦线?

    为何用y=x2y=x2函数?

    这是因为有一种损失函数的形式就是均方差,亦即:

     

    loss=∑i(ai−yi)2loss=∑i(ai−yi)2

    其中a是本次迭代的预测结果,y是样本中的真实结果。我们的目的就是在这个函数上求最小值,使loss最小,这样样本值和预测值就会非常非常接近,以便于我们以后预测不在样本中的真实数据。

    为什么说是“梯度下降”?

    “梯度下降”,刚接触这个词时,我总是往“降低难度”或“降低维度”方面去理解,因为有个“下降”的动词在里面。而实际上,“下降”在这里面的含义是“与导数相反的方向”的意思。

    我们假设上面这个图形的函数是y=(x−1)2+0.001y=(x−1)2+0.001,则y′x=2(x−1)yx′=2(x−1)。

    • 在点B上,这个函数的切线(绿色)是指向下方的(Y轴方向),所以是个负数:假设XBXB = 0.1, 则y′=2∗(0.1−1)=−1.8y′=2∗(0.1−1)=−1.8。
    • 在F点上,切线(绿色)向上:假设XFXF = 1.5, 则y′=2∗(1.5−1)=1y′=2∗(1.5−1)=1,是个正数。

    而在标准的权重更新公式里:

     

    w=w–η∗Δww=w–η∗Δw

     

    b=b–η∗Δbb=b–η∗Δb

    可以看到无论是w还是b,都是用上一次的权重值减去步长××梯度。

    • 当梯度(y')是正数时,即点F的位置,x=x−η∗1x=x−η∗1,切线向上,x值会变小,权重值会从右侧向x=1靠近;
    • 当梯度(y')是负数时,亦即点B的位置,切线向下,x值会变大:x=x−η∗(−1.8)=x+η∗1.8x=x−η∗(−1.8)=x+η∗1.8,最终运算结果变成了加法,与切线方向相反,权重值会从左侧向x=1靠近。

    所以总体上看,无论x在极值的左侧还是右侧,都会向中间(坡底)靠拢,确实是“下降”了。

    不知不觉中,我们已经接触到了第一个神经网络中的超参η,即步长值,这个值对于神经网络训练非常重要,决定了训练时间的长短。

    曲线和弦线的关系?

    1. 我们先知道了A点的切线的方向,亦即黄色的线,但是不知道长度
    2. 我们有步长值η,以及梯度下降公式X1=X0–η∗dxX1=X0–η∗dx
    3. 因为y′x的导数dx=2(X−1),η=0.1,X0=0.2,于是有X1=X0–0.1∗2(X0−1)=0.36yx′的导数dx=2(X−1),η=0.1,X0=0.2,于是有X1=X0–0.1∗2(X0−1)=0.36,这就等同于我们知道了切线的长度,亦即绿色的线的长度和方向都确定了
    4. 然后我们可以画出红色的线(亦即弦线)

    所以,弦线在这里面没啥用途,只是表示一个迭代跳跃的动作而已。实际的变化值已经由绿色的线定义好了。

    参考资料

     

    展开全文
  • 反向传播梯度更新

    2021-04-27 10:40:43
    关于梯度的概念 梯度是微积分中一个很重要的概念,之前提到过梯度的意义 在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率 在多变量函数中,梯度是一个向量,向量有方向,梯度的...

     

    关于梯度的概念

    梯度是微积分中一个很重要的概念,之前提到过梯度的意义

    • 在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率
    • 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向。

    这也就说明了为什么我们需要千方百计的求取梯度!我们需要到达山底,就需要在每一步观测到此时最陡峭的地方,梯度就恰巧告诉了我们这个方向。梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向,这正是我们所需要的。所以我们只要沿着梯度的方向一直走,就能走到局部的最低点! 

    因此整个深度网络可以视为是一个复合的非线性多元函数。
     

    2.3.2 梯度要乘以一个负号
    梯度前加一个负号,就意味着朝着梯度相反的方向前进!我们在前文提到,梯度的方向实际就是函数在此点上升最快的方向!而我们需要朝着下降最快的方向走,自然就是负的梯度的方向,所以此处需要加上负号;那么如果时上坡,也就是梯度上升算法,当然就不需要添加负号了。
    原文链接:https://blog.csdn.net/qq_41800366/article/details/86583789

     

    梯度的更新

    深度学习最全优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)

    梯度grad公式_梯度消失梯度爆炸-Gradient Clip

    各种优化算法,其实就是对学习率的改变,有的是对学习率和上一次的梯度等综合考虑,来改变这一次的梯度的计算方法。

     

     

     

    2.公式推导

    我看的这篇推到文章,例题的形式很清晰

    展开全文
  • 在看卷积神经网络的时候,突然想起来池化是会改变特征图的尺寸的,那反向传播是怎么实现的呢。于是搜了一些博客,感觉上面这个博客写得...Pooling池化操作的反向梯度传播 CNN网络中另外一个不可导的环节就是Poolin...

    参考博客:https://blog.csdn.net/qq_21190081/article/details/72871704

    在看卷积神经网络的时候,突然想起来池化是会改变特征图的尺寸的,那反向传播是怎么实现的呢。于是搜了一些博客,感觉上面这个博客写得最清晰直观,就从这个博客里面搬了点东西过来作为笔记。

    Pooling池化操作的反向梯度传播

    CNN网络中另外一个不可导的环节就是Pooling池化操作,因为Pooling操作使得feature map的尺寸变化,假如做2×2的池化,假设那么第l+1层的feature map有16个梯度,那么第l层就会有64个梯度,这使得梯度无法对位的进行传播下去。其实解决这个问题的思想也很简单,就是把1个像素的梯度传递给4个像素,但是需要保证传递的loss(或者梯度)总和不变。根据这条原则,mean pooling和max pooling的反向传播也是不同的。

    1、mean pooling

    mean pooling的前向传播就是把一个patch中的值求取平均来做pooling,那么反向传播的过程也就是把某个元素的梯度等分为n份分配给前一层,这样就保证池化前后的梯度(残差)之和保持不变,还是比较理解的,图示如下 :

    mean pooling比较容易让人理解错的地方就是会简单的认为直接把梯度复制N遍之后直接反向传播回去,但是这样会造成loss之和变为原来的N倍,网络是会产生梯度爆炸的。

    2、max pooling

    max pooling也要满足梯度之和不变的原则,max pooling的前向传播是把patch中最大的值传递给后一层,而其他像素的值直接被舍弃掉。那么反向传播也就是把梯度直接传给前一层某一个像素,而其他像素不接受梯度,也就是为0。所以max pooling操作和mean pooling操作不同点在于需要记录下池化操作时到底哪个像素的值是最大,也就是max id,这个变量就是记录最大值所在位置的,因为在反向传播中要用到,那么假设前向传播和反向传播的过程就如下图所示 :

    展开全文
  • 梯度反向传播(CS231n课程笔记翻译)

    千次阅读 2019-03-26 13:05:08
    CS231n课程笔记翻译:反向传播笔记 - 杜客的文章 - 知乎 译者注:本文智能单元首发,译自斯坦福CS231n课程笔记Backprop Note,课程教师Andrej Karpathy授权翻译。本篇教程由杜客翻译完成,堃堃和巩子嘉进行校对修改...

    CS231n课程笔记翻译:反向传播笔记 - 杜客的文章 - 知乎

    译者注:本文智能单元首发,译自斯坦福CS231n课程笔记Backprop Note,课程教师Andrej Karpathy授权翻译。本篇教程由杜客翻译完成,堃堃巩子嘉进行校对修改。译文含公式和代码,建议PC端阅读。

    内容列表:

    • 简介
    • 简单表达式和理解梯度
    • 复合表达式,链式法则,反向传播
    • 直观理解反向传播
    • 模块:Sigmoid例子
    • 反向传播实践:分段计算
    • 回传流中的模式
    • 用户向量化操作的梯度
    • 小结

    简介

    目标:本节将帮助读者对反向传播形成直观而专业的理解。反向传播是利用链式法则递归计算表达式的梯度的方法。理解反向传播过程及其精妙之处,对于理解、实现、设计和调试神经网络非常关键

    问题陈述:这节的核心问题是:给定函数f(x) ,其中x是输入数据的向量,需要计算函数f关于x的梯度,也就是\nabla f(x)

     

    目标:之所以关注上述问题,是因为在神经网络中f对应的是损失函数(L),输入x里面包含训练数据和神经网络的权重。举个例子,损失函数可以是SVM的损失函数,输入则包含了训练数据(x_i,y_i),i=1...N、权重W和偏差b。注意训练集是给定的(在机器学习中通常都是这样),而权重是可以控制的变量。因此,即使能用反向传播计算输入数据x_i 上的梯度,但在实践为了进行参数更新,通常也只计算参数(比如W,b)的梯度。然而x_i 的梯度有时仍然是有用的:比如将神经网络所做的事情可视化便于直观理解的时候,就能用上。


    如果读者之前对于利用链式法则计算偏微分已经很熟练,仍然建议浏览本篇笔记。因为它呈现了一个相对成熟的反向传播视角,在该视角中能看见基于实数值回路的反向传播过程,而对其细节的理解和收获将帮助读者更好地通过本课程。

    简单表达式和理解梯度

    从简单表达式入手可以为复杂表达式打好符号和规则基础。先考虑一个简单的二元乘法函数f(x,y)=xy。对两个输入变量分别求偏导数还是很简单的:

    \displaystyle f(x,y)=xy \to \frac {df}{dx}=y \quad \frac {df}{dy}=x

    解释:牢记这些导数的意义:函数变量在某个点周围的极小区域内变化,而导数就是变量变化导致的函数在该方向上的变化率。

    \frac{df(x)}{dx}= lim_{h\to 0}\frac{f(x+h)-f(x)}{h}

    注意等号左边的分号和等号右边的分号不同,不是代表分数。相反,这个符号表示操作符\frac{d}{dx}被应用于函数f,并返回一个不同的函数(导数)。对于上述公式,可以认为h值非常小,函数可以被一条直线近似,而导数就是这条直线的斜率。换句话说,每个变量的导数指明了整个表达式对于该变量的值的敏感程度。比如,若x=4,y=-3,则f(x,y)=-12x的导数\frac{\partial f}{\partial x}=-3。这就说明如果将变量x的值变大一点,整个表达式的值就会变小(原因在于负号),而且变小的量是x变大的量的三倍。通过重新排列公式可以看到这一点(f(x+h)=f(x)+h \frac{df(x)}{dx})。同样,因为\frac{\partial f}{\partial y}=4,可以知道如果将y的值增加h,那么函数的输出也将增加(原因在于正号),且增加量是4h

    函数关于每个变量的导数指明了整个表达式对于该变量的敏感程度。

    如上所述,梯度\nabla f是偏导数的向量,所以有\nabla f(x)=[\frac{\partial f}{\partial x},\frac{\partial f}{\partial y}]=[y,x]。即使是梯度实际上是一个向量,仍然通常使用类似“x上的梯度”的术语,而不是使用如“x的偏导数”的正确说法,原因是因为前者说起来简单。

    我们也可以对加法操作求导:

    \displaystyle f(x,y)=x+y \to \frac {df}{dx}=1\quad\frac {df}{dy}=1

    这就是说,无论其值如何,x,y的导数均为1。这是有道理的,因为无论增加x,y中任一个的值,函数f的值都会增加,并且增加的变化率独立于x,y的具体值(情况和乘法操作不同)。取最大值操作也是常常使用的:
    \displaystyle f(x,y)=max(x,y) \to \frac {df}{dx}=1 (x>=y) \quad\frac {df}{dy}=1 (y>=x)

    上式是说,如果该变量比另一个变量大,那么梯度是1,反之为0。例如,若x=4,y=2,那么max是4,所以函数对于y就不敏感。也就是说,在y上增加h,函数还是输出为4,所以梯度是0:因为对于函数输出是没有效果的。当然,如果给y增加一个很大的量,比如大于2,那么函数f的值就变化了,但是导数并没有指明输入量有巨大变化情况对于函数的效果,他们只适用于输入量变化极小时的情况,因为定义已经指明:lim_{h\to 0}

    使用链式法则计算复合表达式

    现在考虑更复杂的包含多个函数的复合函数,比如f(x,y,z)=(x+y)z。虽然这个表达足够简单,可以直接微分,但是在此使用一种有助于读者直观理解反向传播的方法。将公式分成两部分:q=x+yf=qz。在前面已经介绍过如何对这分开的两个公式进行计算,因为fqz相乘,所以\displaystyle\frac{\partial f}{\partial q}=z,\frac{\partial f}{\partial z}=q,又因为qxy,所以\displaystyle\frac{\partial q}{\partial x}=1,\frac{\partial q}{\partial y}=1。然而,并不需要关心中间量q的梯度,因为\frac{\partial f}{\partial q}没有用。相反,函数f关于x,y,z的梯度才是需要关注的。链式法则指出将这些梯度表达式链接起来的正确方式是相乘,比如\displaystyle\frac{\partial f}{\partial x}=\frac{\partial f}{\partial q}\frac{\partial q}{\partial x}。在实际操作中,这只是简单地将两个梯度数值相乘,示例代码如下:

    # 设置输入值
    x = -2; y = 5; z = -4
    
    # 进行前向传播
    q = x + y # q becomes 3
    f = q * z # f becomes -12
    
    # 进行反向传播:
    # 首先回传到 f = q * z
    dfdz = q # df/dz = q, 所以关于z的梯度是3
    dfdq = z # df/dq = z, 所以关于q的梯度是-4
    # 现在回传到q = x + y
    dfdx = 1.0 * dfdq # dq/dx = 1. 这里的乘法是因为链式法则
    dfdy = 1.0 * dfdq # dq/dy = 1
    
    

    最后得到变量的梯度[dfdx, dfdy, dfdz],它们告诉我们函数f对于变量[x, y, z]的敏感程度。这是一个最简单的反向传播。一般会使用一个更简洁的表达符号,这样就不用写df了。这就是说,用dq来代替dfdq,且总是假设梯度是关于最终输出的。

    这次计算可以被可视化为如下计算线路图像:


    上图的真实值计算线路展示了计算的视觉化过程。前向传播从输入计算到输出(绿色),反向传播从尾部开始,根据链式法则递归地向前计算梯度(显示为红色),一直到网络的输入端。可以认为,梯度是从计算链路中回流。


    反向传播的直观理解

    反向传播是一个优美的局部过程。在整个计算线路图中,每个门单元都会得到一些输入并立即计算两个东西:1. 这个门的输出值,和2.其输出值关于输入值的局部梯度。门单元完成这两件事是完全独立的,它不需要知道计算线路中的其他细节。然而,一旦前向传播完毕,在反向传播的过程中,门单元门将最终获得整个网络的最终输出值在自己的输出值上的梯度。链式法则指出,门单元应该将回传的梯度乘以它对其的输入的局部梯度,从而得到整个网络的输出对该门单元的每个输入值的梯度。

    这里对于每个输入的乘法操作是基于链式法则的。该操作让一个相对独立的门单元变成复杂计算线路中不可或缺的一部分,这个复杂计算线路可以是神经网络等。

    下面通过例子来对这一过程进行理解。加法门收到了输入[-2, 5],计算输出是3。既然这个门是加法操作,那么对于两个输入的局部梯度都是+1。网络的其余部分计算出最终值为-12。在反向传播时将递归地使用链式法则,算到加法门(是乘法门的输入)的时候,知道加法门的输出的梯度是-4。如果网络如果想要输出值更高,那么可以认为它会想要加法门的输出更小一点(因为负号),而且还有一个4的倍数。继续递归并对梯度使用链式法则,加法门拿到梯度,然后把这个梯度分别乘到每个输入值的局部梯度(就是让-4乘以xy的局部梯度,x和y的局部梯度都是1,所以最终都是-4)。可以看到得到了想要的效果:如果x,y减小(它们的梯度为负),那么加法门的输出值减小,这会让乘法门的输出值增大。

    因此,反向传播可以看做是门单元之间在通过梯度信号相互通信,只要让它们的输入沿着梯度方向变化,无论它们自己的输出值在何种程度上升或降低,都是为了让整个网络的输出值更高。

    模块化:Sigmoid例子

    上面介绍的门是相对随意的。任何可微分的函数都可以看做门。可以将多个门组合成一个门,也可以根据需要将一个函数分拆成多个门。现在看看一个表达式:

    \displaystyle f(w,x)=\frac{1}{1+e^{-(w_0x_0+w_1x_1+w_2)}}

    在后面的课程中可以看到,这个表达式描述了一个含输入x和权重w的2维的神经元,该神经元使用了sigmoid激活函数。但是现在只是看做是一个简单的输入为x和w,输出为一个数字的函数。这个函数是由多个门组成的。除了上文介绍的加法门,乘法门,取最大值门,还有下面这4种:


    \displaystyle f(x)=\frac{1}{x} \to \frac{df}{dx}=-1/x^2
    \displaystyle f_c(x)=c+x \to \frac{df}{dx}=1\displaystyle f(x)=e^x \to \frac{df}{dx}=e^x
    \displaystyle f_a(x)=ax \to \frac{df}{dx}=a

    其中,函数f_c使用对输入值进行了常量c的平移,f_a将输入值扩大了常量a倍。它们是加法和乘法的特例,但是这里将其看做一元门单元,因为确实需要计算常量c,a的梯度。整个计算线路如下:


    使用sigmoid激活函数的2维神经元的例子。输入是[x0, x1],可学习的权重是[w0, w1, w2]。一会儿会看见,这个神经元对输入数据做点积运算,然后其激活数据被sigmoid函数挤压到0到1之间。


    在上面的例子中可以看见一个函数操作的长链条,链条上的门都对wx的点积结果进行操作。该函数被称为sigmoid函数\sigma (x)。sigmoid函数关于其输入的求导是可以简化的(使用了在分子上先加后减1的技巧):

    \displaystyle\sigma(x)=\frac{1}{1+e^{-x}}
    \displaystyle\to\frac{d\sigma(x)}{dx}=\frac{e^{-x}}{(1+e^{-x})^2}=(\frac{1+e^{-x}-1}{1+e^{-x}})(\frac{1}{1+e^{-x}})=(1-\sigma(x))\sigma(x)

    可以看到梯度计算简单了很多。举个例子,sigmoid表达式输入为1.0,则在前向传播中计算出输出为0.73。根据上面的公式,局部梯度为(1-0.73)*0.73~=0.2,和之前的计算流程比起来,现在的计算使用一个单独的简单表达式即可。因此,在实际的应用中将这些操作装进一个单独的门单元中将会非常有用。该神经元反向传播的代码实现如下:

    w = [2,-3,-3] # 假设一些随机数据和权重
    x = [-1, -2]
    
    # 前向传播
    dot = w[0]*x[0] + w[1]*x[1] + w[2]
    f = 1.0 / (1 + math.exp(-dot)) # sigmoid函数
    
    # 对神经元反向传播
    ddot = (1 - f) * f # 点积变量的梯度, 使用sigmoid函数求导
    dx = [w[0] * ddot, w[1] * ddot] # 回传到x
    dw = [x[0] * ddot, x[1] * ddot, 1.0 * ddot] # 回传到w
    # 完成!得到输入的梯度
    

    实现提示:分段反向传播。上面的代码展示了在实际操作中,为了使反向传播过程更加简洁,把向前传播分成不同的阶段将是很有帮助的。比如我们创建了一个中间变量dot,它装着wx的点乘结果。在反向传播的时,就可以(反向地)计算出装着wx等的梯度的对应的变量(比如ddotdxdw)。

     

    本节的要点就是展示反向传播的细节过程,以及前向传播过程中,哪些函数可以被组合成门,从而可以进行简化。知道表达式中哪部分的局部梯度计算比较简洁非常有用,这样他们可以“链”在一起,让代码量更少,效率更高。

    反向传播实践:分段计算

    看另一个例子。假设有如下函数:

    \displaystyle f(x,y)=\frac{x+\sigma(y)}{\sigma(x)+(x+y)^2}

    首先要说的是,这个函数完全没用,读者是不会用到它来进行梯度计算的,这里只是用来作为实践反向传播的一个例子,需要强调的是,如果对xy进行微分运算,运算结束后会得到一个巨大而复杂的表达式。然而做如此复杂的运算实际上并无必要,因为我们不需要一个明确的函数来计算梯度,只需知道如何使用反向传播计算梯度即可。下面是构建前向传播的代码模式:

    x = 3 # 例子数值
    y = -4
    
    # 前向传播
    sigy = 1.0 / (1 + math.exp(-y)) # 分子中的sigmoi          #(1)
    num = x + sigy # 分子                                    #(2)
    sigx = 1.0 / (1 + math.exp(-x)) # 分母中的sigmoid         #(3)
    xpy = x + y                                              #(4)
    xpysqr = xpy**2                                          #(5)
    den = sigx + xpysqr # 分母                                #(6)
    invden = 1.0 / den                                       #(7)
    f = num * invden # 搞定!                                 #(8)

    ┗|`O′|┛ 嗷~~,到了表达式的最后,就完成了前向传播。注意在构建代码s时创建了多个中间变量,每个都是比较简单的表达式,它们计算局部梯度的方法是已知的。这样计算反向传播就简单了:我们对前向传播时产生每个变量(sigy, num, sigx, xpy, xpysqr, den, invden)进行回传。我们会有同样数量的变量,但是都以d开头,用来存储对应变量的梯度。注意在反向传播的每一小块中都将包含了表达式的局部梯度,然后根据使用链式法则乘以上游梯度。对于每行代码,我们将指明其对应的是前向传播的哪部分。

    # 回传 f = num * invden
    dnum = invden # 分子的梯度                                         #(8)
    dinvden = num                                                     #(8)
    # 回传 invden = 1.0 / den 
    dden = (-1.0 / (den**2)) * dinvden                                #(7)
    # 回传 den = sigx + xpysqr
    dsigx = (1) * dden                                                #(6)
    dxpysqr = (1) * dden                                              #(6)
    # 回传 xpysqr = xpy**2
    dxpy = (2 * xpy) * dxpysqr                                        #(5)
    # 回传 xpy = x + y
    dx = (1) * dxpy                                                   #(4)
    dy = (1) * dxpy                                                   #(4)
    # 回传 sigx = 1.0 / (1 + math.exp(-x))
    dx += ((1 - sigx) * sigx) * dsigx # Notice += !! See notes below  #(3)
    # 回传 num = x + sigy
    dx += (1) * dnum                                                  #(2)
    dsigy = (1) * dnum                                                #(2)
    # 回传 sigy = 1.0 / (1 + math.exp(-y))
    dy += ((1 - sigy) * sigy) * dsigy                                 #(1)
    # 完成! 嗷~~

    需要注意的一些东西:

    对前向传播变量进行缓存:在计算反向传播时,前向传播过程中得到的一些中间变量非常有用。在实际操作中,最好代码实现对于这些中间变量的缓存,这样在反向传播的时候也能用上它们。如果这样做过于困难,也可以(但是浪费计算资源)重新计算它们。

    在不同分支的梯度要相加:如果变量x,y在前向传播的表达式中出现多次,那么进行反向传播的时候就要非常小心,使用+=而不是=来累计这些变量的梯度(不然就会造成覆写)。这是遵循了在微积分中的多元链式法则,该法则指出如果变量在线路中分支走向不同的部分,那么梯度在回传的时候,就应该进行累加。

     

    回传流中的模式

    一个有趣的现象是在多数情况下,反向传播中的梯度可以被很直观地解释。例如神经网络中最常用的加法、乘法和取最大值这三个门单元,它们在反向传播过程中的行为都有非常简单的解释。先看下面这个例子:


    一个展示反向传播的例子。加法操作将梯度相等地分发给它的输入。取最大操作将梯度路由给更大的输入。乘法门拿取输入激活数据,对它们进行交换,然后乘以梯度。


    从上例可知:

    加法门单元把输出的梯度相等地分发给它所有的输入,这一行为与输入值在前向传播时的值无关。这是因为加法操作的局部梯度都是简单的+1,所以所有输入的梯度实际上就等于输出的梯度,因为乘以1.0保持不变。上例中,加法门把梯度2.00不变且相等地路由给了两个输入。

    取最大值门单元对梯度做路由。和加法门不同,取最大值门将梯度转给其中一个输入,这个输入是在前向传播中值最大的那个输入。这是因为在取最大值门中,最高值的局部梯度是1.0,其余的是0。上例中,取最大值门将梯度2.00转给了z变量,因为z的值比w高,于是w的梯度保持为0。

    乘法门单元相对不容易解释。它的局部梯度就是输入值,但是是相互交换之后的,然后根据链式法则乘以输出值的梯度。上例中,x的梯度是-4.00x2.00=-8.00。

    非直观影响及其结果。注意一种比较特殊的情况,如果乘法门单元的其中一个输入非常小,而另一个输入非常大,那么乘法门的操作将会不是那么直观:它将会把大的梯度分配给小的输入,把小的梯度分配给大的输入。在线性分类器中,权重和输入是进行点积w^Tx_i,这说明输入数据的大小对于权重梯度的大小有影响。例如,在计算过程中对所有输入数据样本x_i乘以1000,那么权重的梯度将会增大1000倍,这样就必须降低学习率来弥补。这就是为什么数据预处理关系重大,它即使只是有微小变化,也会产生巨大影响。对于梯度在计算线路中是如何流动的有一个直观的理解,可以帮助读者调试网络。

    用向量化操作计算梯度

    上述内容考虑的都是单个变量情况,但是所有概念都适用于矩阵和向量操作。然而,在操作的时候要注意关注维度和转置操作。

    矩阵相乘的梯度:可能最有技巧的操作是矩阵相乘(也适用于矩阵和向量,向量和向量相乘)的乘法操作:

    # 前向传播
    W = np.random.randn(5, 10)
    X = np.random.randn(10, 3)
    D = W.dot(X)
    
    # 假设我们得到了D的梯度
    dD = np.random.randn(*D.shape) # 和D一样的尺寸
    dW = dD.dot(X.T) #.T就是对矩阵进行转置
    dX = W.T.dot(dD)
    
    

    提示:要分析维度!注意不需要去记忆dWdX的表达,因为它们很容易通过维度推导出来。例如,权重的梯度dW的尺寸肯定和权重矩阵W的尺寸是一样的,而这又是由XdD的矩阵乘法决定的(在上面的例子中XW都是数字不是矩阵)。总有一个方式是能够让维度之间能够对的上的。例如,X的尺寸是[10x3],dD的尺寸是[5x3],如果你想要dW和W的尺寸是[5x10],那就要dD.dot(X.T)

    使用小而具体的例子:有些读者可能觉得向量化操作的梯度计算比较困难,建议是写出一个很小很明确的向量化例子,在纸上演算梯度,然后对其一般化,得到一个高效的向量化操作形式。

    小结

    • 对梯度的含义有了直观理解,知道了梯度是如何在网络中反向传播的,知道了它们是如何与网络的不同部分通信并控制其升高或者降低,并使得最终输出值更高的。

    • 讨论了分段计算在反向传播的实现中的重要性。应该将函数分成不同的模块,这样计算局部梯度相对容易,然后基于链式法则将其“链”起来。重要的是,不需要把这些表达式写在纸上然后演算它的完整求导公式,因为实际上并不需要关于输入变量的梯度的数学公式。只需要将表达式分成不同的可以求导的模块(模块可以是矩阵向量的乘法操作,或者取最大值操作,或者加法操作等),然后在反向传播中一步一步地计算梯度。

    在下节课中,将会开始定义神经网络,而反向传播使我们能高效计算神经网络各个节点关于损失函数的梯度。换句话说,我们现在已经准备好训练神经网络了,本课程最困难的部分已经过去了!ConvNets相比只是向前走了一小步。

    参考文献

    反向传播笔记全文翻译完

    展开全文
  • 梯度下降和反向传播算法讲解

    千次阅读 2019-10-22 16:19:07
    在讲梯度下降之前,先向大家推荐一门课程《数值分析》,有的书也将它称为《计算方法》。 数值分析(numerical analysis),为数学的一个分支,是研究分析用计算机求解数学计算问题的数值计算方法及其理论的学科。它...
  • 反向传播梯度的计算

    千次阅读 2019-06-29 18:55:04
    适用pytorch中Variable()函数中的backward()自动计算梯度 手动实现梯度计算(缺点:计算网络复杂时容易出错,难以检查) # -*- coding: utf-8 -*- #@Time :2019/6/29 18:36 #@Author :XiaoMa import torch as t ...
  • 反向传播是优化神经网络参数的方法,深层网络由许多线性层和非线性层堆叠而来,因此整个深度网络可以视为是一个复合的非线性多元函数。 我们最终的目的是希望这个非线性函数很好的完成输入到输出之间的映射,也就是...
  • 使用keras举例说明: 网络结构如下: loss定义如下: ...网络具有两个输出,分别都要计算loss,那么在计算梯度反向传播的时候,就会有以下问题: 整个网络进行几次梯度更新,1次还是2次? VGG网络
  • 1.1 正向传播1.2 反向传播二.梯度消失如何产生?2.1 数学角度2.2 激活函数角度三.结论 一.神经网络如何传播? 1.1 正向传播 如下图所示,两个输入值X1X_1X1​和X2X_2X2​,以第一层的第一个神经元f1(e)f_1(e)f1​(e)...
  • 梯度下降法与反向传播

    万次阅读 2017-11-09 20:16:02
    梯度下降法与反向传播主要内容:梯度下降法 最优化 梯度下降 反向传播 梯度与偏导 链式法则 直观理解 Sigmoid 例子 1. 梯度下降(Gradient descent)初始权重不要都置为0,可用高斯分布。 随机初始化的目的是使对称...
  • 梯度反向传播求解示例

    千次阅读 2017-06-23 13:02:28
    深度学习中进行网络的训练的时候,常常采用梯度反向传递的方式对网络中的参数进行调整,那么具体是怎么实现的呢?我用一个简单的例子进行推导求解。 如下图,这里采用的是两层网络,损失函数采用的是平方差损失函数...
  • 在机器学习算法中,误差反向传播梯度下降是模型收敛的关键技术,作者将以单隐层模型为例说明误差反向传播梯度下降的工作原理。 各种算法的单隐层模型结构大同小异 正向传播 假设:主要模型参数有3个,输入...
  • 反向传播当有激活函数的时候传播的方式如下:复合表达式、链式法则、反向传播链式法则:将偏导数相乘。对于一个符合表达式:# -*- coding: utf-8 -*- """ Created on Fri Dec 23 17:24:24 2016@author: CrazyVertigo...
  • 反向传播过程需要对每一个 z j L , j = 1 , 2 , ⋯   , N z_j^L, j=1, 2, \cdots, N z j L ​ , j = 1 , 2 , ⋯ , N 求导数。 (1) 当 j = k j=k j = k 时: (3) ∂ J ∂ z j L = ∂ J ∂ z k L = ∂ J...
  • 最近在学习深度学习中的梯度下降与反向传播方面的知识。偶有心得,特此记录。若有不足之处,烦请指正赐教。  在训练阶段,深度神经网络经过前向传播之后,得到的预测值与先前给出真实值之间存在差距。我们可以使用...
  • 反向传播梯度下降的关系

    千次阅读 2020-06-26 08:42:54
    1 梯度下降法(Gradient Descent Algorithm) 梯度下降法是一种通用的优化算法,中心思想是沿着目标函数梯度的方向更新参数值以希望达到目标函数最小(或最大)。梯度下降法是深度学习网络最常用的优化算法。除了...
  • 神经网络梯度反向传播公式

    千次阅读 2019-08-19 21:03:13
    三层神经网络的 BP 公式
  • 这篇文章讲一下RNN的反向传播算法BPTT,及RNN梯度消失和梯度爆炸的原因。 BPTT RNN的反向传播,也称为基于时间的反向传播算法BPTT(back propagation through time)。对所有参数求损失函数的偏导,并不断调整这些...
  • 针对最基本的全连接+激活函数这类型的网络结构中每一个节点处反向传播梯度的计算以及权重增量,从而能够直观理解sigmoid当激活函数时为什么会发生梯度消失的状况; 增加对卷积层和池化层中权重节点的梯度计算及...
  • 文件内描述了BF神经网络的基本原理(英文),看不懂可以自行百度找中文,网上资料很...资料里面重点是使用反向传播算法在MATLAB上实现了函数y=sin(2piX1)*sin(2piX2)的拟合。附带有MATLAB的(.m)文件,可以直接运行。
  • loss.backward() 反向传播,计算当前梯度; optimizer.step() 根据梯度更新网络参数 简单的说就是进来一个batch的数据,计算一次梯度,更新一次网络 使用梯度累加是这么写的: for i,(images,target) in enumerate...
  • PyTorch教程-2:PyTorch中反向传播梯度追踪与计算 基本原理 torch.Tensor类具有一个属性 requires_grad 用以表示该tensor是否需要计算梯度,如果该属性设置为True的话,表示这个张量需要计算梯度,计算梯度的张量...
  • PyTorch: 梯度下降及反向传播 . 以一个最简单的线性回归模型为例: 损失函数 在模型训练中,损失函数用来衡量预测值与真实值之间的误差,数值越小表示误差越小。一个常见的选择是平方函数。 它在评估索引为 i...
  • 反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。 该方法对网络中所有权重计算损失函数的梯度。 这个梯度...
  • 2.反向传播算法(BP算法) 1.为什么要梯度优化 上一节介绍过,我们的第一个神经网络示例中,每个神经层都用下述方法对输入数据进行 变换。 output = relu(dot(W, input) + b) 在这个表达式中,W 和 b 都是张量,均...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,403
精华内容 23,361
关键字:

反向梯度传播方法