zoukankan      html  css  js  c++  java
  • BP浅谈

    之前一直对BP的理解不透彻,这可不行,这个可是超经典的广泛应用在ML中的求偏导的方法。本博来自《神经网络与机器学习》P86页。

    在用到bp的地方我们都是为了使用梯度下降法,并求出他的偏导数,如图:(图 1 来自ng的ufldl),但是如何求得J(W,b)关于W和b的导数确实比较难,所以才有了BP的出现。下面都是讲解如何求得alpha后面的那项,当求出了后面的,我们就很容易的进行权值的更新了。




    首先,考虑一个单独的神经元,此时没有隐藏层。只是为了说明BP的数学原理,务必搞懂之后才能看下面的,不然会看得更糊。

    图中可以发现几个需要记住的公式,在推导过程中容易遗忘,这时候需要回头并记住,而且不要被公式迷惑了,这里是对一个神经元,所以如果可以直接把 n 和 j 都忽略的看,否则有可能眼晕:

    (公式1-诱导局部域) ;

                     (公式2-激活函数);

                     (公式3-单样本瞬时损失函数);

         (公式4-单样本全网络损失函数;)(公式5-所有样本全网络损失函数)。


    在这其中m是指的神经元,而不只偏置单元。偏置单元出现的地方都会有0出现。

    根据高数中的微分链式规则:

    (公式6-链式规则)。

    看这里就需要用到前面的公式1-4.。相信其中的三个大家一眼就看得出来,可是在第三个的时候却有些犯难,因为这里我们都并未给出激活函数是什么,只是用公式2代替:

    (公式7-略)

    所以最后得到的结果如下图:

    (公式8-单样本损失函数关于权值的偏导)

    在权值更新的过程中后面的项是

    (公式9-权值更新项),

    这里请与图 1 中进行比对,前面的那个其实就是alpha,(因为图1 在书中没找到公式,从ufldl中借鉴,图1 只是给个直观理解,和全文没半毛钱关系,这里就是学习率)。从公式9中可以看出,前面的负号是为了在权空间中梯度下降。这里将这个此时最终的公式进行规范化,使得容易在输出层和隐藏层中统一起来。

    公式10-规范化权值更新项

    公式11-局域梯度)。

    公式11需要强烈记住,其实

    公式10就可以看出这是最需要记住的,前面的公式1-9都是为了得出这个公式,这时候假设j是输出层,或者是隐藏层,就可以发现公式10中只有局域梯度是需要注意的,而学习率和激活函数是没有疑惑的地方的。


    情况1  神经元j是输出节点

    这里其实局域梯度中前面的单样本损失函数就是 真实结果 - 期望结果(就是模型算出来的标签 - 我们之前人为给定的标签)。而公式11中后面的那个求导函数就是关于诱导局部域的导数(如果采用的是逻辑函数sigmoid,那么这里其实就是sigmoid(vj)(1-sigmoid(vj)))(但是这里尤为注意的是,在最后的权值更新中需要加上:

    (公式12- 局域诱导域关于权值的导数。)

    ,因为公式11是关于局部诱导域的偏导数,而不是关于权值的偏导数,当然了,加上的时候其实发现这里公式12的结果是yi,也就是这是来自前层的一个激活值,但是在 j 层 其实就是输入层。

    情况2  神经元j是隐藏层节点

    (图2有隐藏层的神经元图)

    当j代表的是隐藏层,这里就是BP的重头戏,也就是为什么BP的优势在此,(公式13-隐藏层神经元的局部梯度)

    公式13中通过再次使用链式法则,先对当前神经元求导,然后转接到当前神经元对局部诱导域的求导。而后面的当前神经元对局部诱导域的求导可以使用公式1带入,即是 此隐藏层的上一层的激活值。这里直接对当前神经元求导是很困难的,所以再次可以通过链式规则,将过程铺到后面层即 从当前层到输出层,因为输出层的局部梯度知道,可以从这里找突破口,

    (公式14-输出层的单样本瞬时能量函数)

    (公式15-关于隐藏单元的偏导函数),

    其中的

    (公式16-输出层的单样本损失函数关于输出层的局部诱导域的偏导),

    其实公式16,完全可以轻松理解,因为这是与前面公式6中的一部分,只是那时候是关于y的求导,这里是关于局部诱导域的求导。(公式17-公式13的部分结果)

    最后得到结果如公式17,,这里是只有一层隐藏层的情况,所以 j 层的后面就是 k (输出) 层,所以不需要联想中间有多少,当懂得了原理后在进行扩展即可。

    所以当j是隐藏层的时候,他的局部梯度:

    公式18-隐藏层的局部梯度



    总结:看完上面的说明,其实是需要在纸上一个公式一个公式的抄下来的,不然因为采用的符号太多会眼晕,其实我们对bp的理解在 j 不是隐藏层的时候是很好理解的,但是当 j 是隐藏层的时候就犯难了,其实有个直观的描述:假设此时已经完成了前向传导,那么对于公式11来说,假设一个有着【3 4 5 6】的神经网络模型来说(四层网络,每层的神经元个数),sum(6(i) -exp(i))的差距是100 ,那么对于整个网络来说其实误差就是100,在通过往前传导到倒数第二层,那么5(1)其实接受到6(1)-6(6)的误差,他们乘以与5(1)的权值,那么这就是传导到这个点的误差,即cost(5(1)) = 6(1)×W(61,51)+6(2)×W(62,51)+6(3)×W(63,51)+。。。+6(6)×W(66,51)。直观的说,那整个网络的误差100,因为倒数第二层与输出层的权值的调整,会使得这一层产生的误差减小(特别注明,必须先传递好各层的误差之后算好梯度之后,在最后才能对整个网络的权值进行更新,而不是更新一层,传递一层。),那么剔除输出层,让倒数第二层作为输出层,那么误差有可能就是80了,所以越往前穿,误差越小,能够调整的范围越小,这就是为什么BP不合适用在深度网络中,有论文说明当超过7层的时候,第一层的权值其实已经接受不到误差了,那么也就不能调整了。


    (附加)BP涉及的参数

    激活函数:主要的原则就是必须可以微分,而且最好是单调的。一般就涉及两个,一个是

    sigmoid(theta‘ * x)=

    他的导数是:sigmoid(theta' * x)  ×【1 - sigmoid(theta' * x)】;另一个是

    tanh (theta’ * x) = ,

    他的导数是:1 - 【tanh(theta‘ * x)】^2;


    学习率

            学习率是控制着每次迭代的步长的大小,大了的话会造成震荡,这里很形象的就是一个碗的形状当你从碗的一边往下快到局部最小值的附近的时候,因为学习率很大,他会跳到另一边,而这时候应该从另一边往下吧,他又会跳到这一边的上面,这就是在局部最小值附近不断的徘徊。 而这么说其实当学习率越小越好,但是这是需要花费时间代价的,越小,那么时间就越长,(聪明的你肯定知道有自适应了吧,开始快速下降,快到了局部最小值的时候让他变得很小,即能满足时间又能保证精度。)

    动量

         这个

    (公式19-有动量的权值更新项)

    这里是前面说的权值更新项,看后面发现那就是上面所求的,而这里的alpha就是动量项了,就是当前的权值更新项是由上一次的权值更新项乘以动量项加上当前的更新部分。通过这个递推公式加起来得

    ,(公式20-公式19的另一种表示)

    ,公式20显示,要想权值更新项收敛,就需要动量项要在【0 1】之间。

    将公式20的局部梯度带入得(公式21-公式20的另一种表述),这里可以看出当下一个梯度方向和上一个梯度方向一样,这个有着动量的权值更新项会使得在稳定的下降方向上加速下降;当下一个梯度方向与上一个梯度方向相反时,这个有着动量的权值更新项会使得在方向上数量会减少,所以权值的调整不大,这使得权值更新具有一定的稳定性。这也使得他有益于防止学习过程停在误差曲面的局部最小值上。

    停止准则

     那么迭代多少次,就不需要进行权值的更新呢,一般有两种方法:

     (1) 当梯度向量的欧式范数达到了一个充分小的梯度阈值时,就认为BP已经收敛,但是这个方法需要较长的学习时间,而且需要计算梯度向量。

      (2)当每一回合的均方误差变化的绝对速率足够小时,我们认为BP已经收敛。(这就是需要计算误差函数的每次迭代后的比率,一方面我觉得是不是需要都要计算一次前向传播?)推荐每次速率为0.1%-1%就认为误差已经差不多够了,但是这个准则一般会导致学习过程的过早终止(这很好理解,在误差曲面图中,有可能有些地方的梯度的确很小,但是却还没到达局部最小值区域)。

    不过 这里我还是推荐ng的方法:每次操作后,都将学习曲线显示出来,可以人为的观察是否收敛。

     对于训练来说,每次的epoch中的样本在输入的时候顺序都必须是随机的,而不是简单的一个数据集的循环输入,这样的随机排布可以打破上下文联想,而且动量和学习率随着训练迭代次数的增加也需要进行调整(通常是减少的)。


  • 相关阅读:
    Spring使用Jackson处理json数据
    手工搭建web项目
    购物车模块
    C# ——利用反射动态加载dll
    C# —— 利用Marshal.GetDelegateForFunctionPointer 来转换一个函数指针为一个委托
    C# —— GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。
    c#——IntPtr
    C#-StructLayoutAttribute(结构体布局)
    C#报错——传递数组对象报错“未将对象引用设置到对象的实例”
    C#——保留小数点,强转
  • 原文地址:https://www.cnblogs.com/shouhuxianjian/p/4529220.html
Copyright © 2011-2022 走看看