• 第五周反向传播算法


    关于第5周反向传播算法的一些争论与思考

    小耿 2015-03-16 16:58

    第5周介绍了神经网络的反向传播算法。由于介绍得比较简要,很多地方没有讲透(众:You can you up!),后来C站论坛里有几个网友开始争论其中的公式有点奇怪,究竟是讲错了还是另有原因(最后结论似乎应该是没讲错)。全程围观的耿先生记录了相关的一些要点。

    背景:

    反向传播算法就是说好比你有一个神经网络,输入层 -> 隐藏层 -> 输出层酱紫。我们现在把所有系数初始化,把训练集里的 x 都代入到输入层,经过层层计算最后得到一组输出值。这时候我们就可以和实际的值 y 作比较,计算cost函数。假设我们用的是逻辑回归来研究分类问题,那么cost函数就应该是:

    (摘自课程维基页。下同)

    学 过前几周应该会知道这个公式是怎么来的。前半部分和前几周逻辑回归的cost函数区别在于多了一个 K。因为逻辑回归最后的结果是一个输出值,0 到 1 之间。而上述神经网络最后的结果是一排值,每一个都是 0 到 1 之间,所以多了一次求和。后半部分其实就是把所有的统统求平方加起来。

    cost函数有了之后我们就可以使用梯度下降法,那么就需要计算梯度gradient。这就要用到反向传播算法了。简单来说就是,我们从最后的输出层的值(可以叫或者叫)开始,计算每一个值的值。这个值描述了当前的计算结果和实际结果 y 之间的偏差量error。

    对于输出层,课程告诉我们,就等于。争论就发生在这里,我们下面会详细说是什么争论。现在先把背景知识介绍完。

    对于其它层,则需要从后一层的,倒推前一层的。公式是:

    这个公式体现了什么思想呢?我们说了表现了每一个结点的值与实际值之间的偏差。对于输出层看似很好理解,减一下得到的就是偏差。不过实际上这里面暗藏玄机。详见下文(此处为悬念1)。

    而 对于中间层,所谓“偏差”应该这么理解:对于后一层某一个结点上出现的偏差,前一层的每一个结点都要承担一部分责任,所以我们可以把后一层结点的偏差量按 照系数比例分配给前一层的结点。同时,前一层的某一个结点,对后一层的每一个节点都承担着责任,那么它的“总责任”就是这些所有的小责任之和。如果你仔细 想想这个矩阵乘法的计算过程,会发现正好就是上面说的这个责任分配与求和的过程。

    但是后面乘的 g' 项是从哪里来的呢?我们先不说,详见下文(此处为悬念2)。我们只要知道,由于这里用的是逻辑回归,g(z)函数就是逻辑函数。g' 是指对它求导。求导之后我们会发现:,而根据定义又有,所以我们就把上式展开为:

    这样我们就得到了每一层的。之后再用前一层的“每一个”结点的值 a,乘以后一层的“每一个”结点的,就得到了一个矩阵。写成公式是。这个矩阵的规模和前后两层之间的系数矩阵是一致的,因为它们都是由前一层的每一个结点指向后一层的每一个结点。这个矩阵有什么意义呢?实际上,前一层的结点 i 的值,乘以后一层结点 j 的,得到的就是cost函数对于的偏微分。为什么呢?详见下文(悬念3)。总之,这其实就是我们要求的梯度。

    注意,上面这部分(从“简单来说就是……”那句话往后)是针对“一条”输入数据所进行的计算。而我们的训练集里通常有很多条,比如有 m 条数据。我们针对每一条都进行上述计算,最后把每一条的都累加起来再除以 m,得到的就是我们真正需要的梯度矩阵。然后就可以使用梯度下降法寻找最优了。

    争议:

    在C站课程论坛上,有人发了一个帖子,指出输出层的计算公式有问题。课程给出的公式是:

    Andrew Ng在这里并没有详细解释这个计算公式是怎么来的。实际上它是cost函数求导求出来的,具体求法详见下文(悬念4)。该贴楼主和楼主的小伙伴认为 Andrew Ng犯了一个错误,误将线性回归的cost函数用在了逻辑回归计算中。因为逻辑回归的cost函数是长最上面那个鬼样子。为了便于看清楚我们将它简化一下 (忽略求和,忽略后半部分项):

    对它求导后得到的应该是:

    (注意。)

    而只有线性回归的cost函数:

    求导之后才能得到:

    几位TA觉得他们说的好有道理无法反驳,只能不断地说我信任Prof Ng男神是不会错的!最后还是楼主的小伙伴自己发了个帖子指出了真正的问题出在哪里。

    原来还是他们理解错了公式。并非简单地对cost函数求导就可以。它真正的计算方法是:详见下文(众:你去死吧!)……

    真相:

    问题的焦点集中在了真正的计算公式上面。维基百科“反向传播算法”页面给出了这个过程。我们下面来看看到底是怎么求的。我们之前留下的悬念1、2、3、4,也将一次性解决。

    让我们回到我们的初心。这一切究竟是为了什么?啊!是为了求cost函数对于每一个的偏微分,也就是求:

    (其中分母上的那坨东东是指:第 l 层的结点 i,指向其下一层也就是 l+1 层的结点 j 的系数。)

    (评论中有人指出这里似乎 i 和 j 的意义弄反了。我查了一下似乎是反了,表示前一层结点的字母应该写在后面。如果第 l 层是结点 i,第 l+1 层是结点 j,的下标应该是 j,i 这样子。如果这里反了的话上面背景部分的倒数第二段估计也弄反了。如果你需要参考这篇文章里的公式,请留意一下这个问题。我暂时先不改了。)

    再回顾一下我们计算输出值时的一些定义:

    为了使用这些定义,我们可以将上面的偏微分式子展开为:

    (此处使用技能:链式法则x2)

    把求一次偏微分变成了求三次偏微分。

    右边这三项,我们先看最后一项。根据定义我们知道:

    所以:

    JOB DONE...........33%

    顺便说一句,右边前两项的乘积,就是课程里引入的值!这就回答了悬念 3 提出的问题:为什么得到后一层的值之后,要乘以前一层的 a 值来得到偏微分?答案是:因为它们分别是偏微分式子展开后的两个乘数。

    接下来我们看第二项:这不就是对sigmoid函数求导吗?之前我们遇到过的g'(z),它的出处原来是这里!

    我们经过计算后会得到这样一个式子:

    恰好,算出来也是这个式子,所以我们就用后面这个更好算的式子来计算了。这就是计算公式的后半部分,的来源。

    JOB DONE...........67%

    现在来到第一项偏微分。对于中间层的结点,这个偏微分并不好算。(也能算,需要继续使用链式法则展开成更多的项!最后算出来就是上面计算公式的前半部分。)但是我们只想知道关于最后输出层的情况。那就简单多了!上面争议部分中,那位楼主的小伙伴已经给出了cost函数对于输出层求偏微分的结果:

    JOB DONE...........100%

    那么说到底输出层的到底等于多少?

    等于前两项的乘积:

    原来地球是这个样子滴……

    结论:

    Andrew Ng给的公式没有错。他只是把复杂的推倒,不是,推导过程省略了。但是这样一来容易产生误解。很多人以为输出层的偏差量就是计算值减实际值这么简单,其实 是碰巧才这么简单的。还有很多人说为什么这个值和很多别的网站,包括维基百科上说的不一样啊?因为很多别的网站包括维基百科,cost函数用的是线性回归 的那种,。它的偏微分就和逻辑回归的cost函数有差别了。具体地说,就差在分母的那一项上。

    tl;nr:男神没搞错。微积分很复杂。而猫咪依旧是可爱的。

  • 相关阅读:
    Hystrix使用说明,配置参数说明
    服务限流 -- 自定义注解基于RateLimiter实现接口限流
    Java生产环境下问题排查
    Java垃圾回收(GC)机制详解
    RabbitMQ如何解决各种情况下丢数据的问题
    JWT如何在Spring Cloud微服务系统中在服务相互调时传递
    LeetCode 117th Weekly Contest 总结
    系统设计总结
    单调栈总结
    LeetCode 116th Weekly Contest 总结
  • 原文地址:https://www.cnblogs.com/sunshinewxz/p/5017614.html
Copyright © 2020-2023  润新知