神经网络那些事儿(二)

上一篇中,我们看到了神经网络是怎样使用梯度下降算法来学习它们的权值和偏置。然而,我们还有一些没有解释:我们没有讨论怎样计算损失函数的梯度。本篇中将解释著名的BP算法,它是一个快速计算梯度的算法。

反向传播算法(Backpropagation algorithm,BP)是在1970s提出的,但是它的重要性直到一篇著名的1986年的论文才被接受。论文是David Rumelhart,Geoffrey Hinton,以及Ronald Williams合写的。这篇论文描述了几种神经网络,其中的反向传播算法工作得更快比早期的学习算法,这使得使用神经网络能够解决之前不能解决的问题。今天,反向传播算法已经是神经网络中最核心的算法。

BP算法的核心是网络中的损失函数C分别关于任何权值w(或者偏置b)的偏导数

神经网络那些事儿(二)的表达式。这个表达式告诉我们当我们改变权值和偏置的时候损失函数变化得有多快。BP算法不仅是一个快速学习的算法,它实际上给出了更细节的关于权值和偏置改变网络的全部行为是怎样变化的。

热身:一个基于矩阵快速计算神经网络输出的方法

在讨论反向传播之前,让我们先热身一下,看一下一个快速基于矩阵的计算神经网络输出的算法。我们实际上已经简短地看见了这个算法在上一张快结束的时候。特别地,这是熟悉在反向传播中用到的符号的一种很自然的方法。

我们将使用

神经网络那些事儿(二)来表示第(l-1)层的第k个神经元到第l层的第j个神经元之间连接的权值。例如下图中的神经网络那些事儿(二)表示第3层的第2个神经元与第2层的第4个神经元之间的连接的权值:

神经网络那些事儿(二)

那么,对于偏置和激活,我们使用一个相似的符号。显然地,我们使用

神经网络那些事儿(二)表示第l层的第j个神经元。并且,我们使用神经网络那些事儿(二)来表示第l层的第j个神经元的激活。就像下图一样:

神经网络那些事儿(二)

我们能发现第l层的第j个神经元的激活

神经网络那些事儿(二)和第l-1层的激活有关系,正如下面的式子:

神经网络那些事儿(二)

这里的和表示第l-1层的所有神经元k。为了把表达式写成一个矩阵形式,我们为每层l定义了一个权值矩阵

神经网络那些事儿(二)。权值矩阵神经网络那些事儿(二)的元素仅仅是和第l层的神经元连接的权值,即,第j行和第j列的元素是神经网络那些事儿(二)。类似地,对于每一层l,我们定义一个偏置向量神经网络那些事儿(二)。偏置向量的元素仅仅是值神经网络那些事儿(二),第l层的每个神经元的一个元素。最后,我们定义了一个激活向量神经网络那些事儿(二),它的组成是激活神经网络那些事儿(二)。接下来我们要做的是向量化一个函数,例如神经网络那些事儿(二)。简单地说,如果我们有函数神经网络那些事儿(二),那么f的向量化形式有这样的结果:

神经网络那些事儿(二)

所以我们能够把(23)式写成:

神经网络那些事儿(二)

这样写不仅在符号上简单许多,而且有助于你从总体上理解这个式子:第l层的激活就是等于前一层(l-1)的激活和与l层神经元相连接的权值的积再加上该层的偏置,然后应用sigmoid函数。最关键的是,许多线性代数库计算基于矩阵的形式会非常快。

当使用等式(25)来计算

神经网络那些事儿(二),我们计算了一个中间量神经网络那些事儿(二)沿着这种方式。这个量表明是足够有用的而值得重新命名:我们把神经网络那些事儿(二)称作到第l层神经元的权重输入(weighted input)。等式(25)有时候会写成权重输入(weighted input)的形式,正如神经网络那些事儿(二)。然后需要注意的是:神经网络那些事儿(二)神经网络那些事儿(二)这样的组成,即,神经网络那些事儿(二)只是第l层的神经元j的到激活函数的权重输入。

关于损失函数我们需要的两个假设

BP算法的目标就是计算损失函数C关于任何网络中的权重w或者偏置b的偏导数

神经网络那些事儿(二)神经网络那些事儿(二)。这里还是以二次损失函数为例子。即:

神经网络那些事儿(二)

这里的n是训练样本的总数;对所有单个训练样本x取和;y=y(x)是相应的期望输出;L表示层数;

神经网络那些事儿(二)是输入为x的网络的激活向量神经网络那些事儿(二)

第一个假设就是损失函数可以被写成

神经网络那些事儿(二),单个的训练样本的损失函数为神经网络那些事儿(二)。我们始终遵循这种假设。

我们需要这个假设的理由是因为反向传播实际上让我们做的是计算单个的训练样本的偏导数

神经网络那些事儿(二)神经网络那些事儿(二)。然后通过平均所有的训练样本来计算神经网络那些事儿(二)神经网络那些事儿(二)。实际上,我们可以假设训练样本x已经被固定,然后丢弃x下标,把损失神经网络那些事儿(二)写成神经网络那些事儿(二)

第2个假设是损失可以被写成一个神经网络的输出的函数:

神经网络那些事儿(二)

例如,二次损失函数满足这个需求,因为单个训练样本x的二次损失可能被写成:

神经网络那些事儿(二)

Hadamard积,

神经网络那些事儿(二)

反向传播算法是基于普通的线性代数操作-像向量相加,用矩阵乘以一个向量。但是其中有一个操作用的比较少。假设s和t是两个维数一样的向量。那么我们使用

神经网络那些事儿(二)来表示两个元素的按位相乘。因此,神经网络那些事儿(二)的组成为神经网络那些事儿(二)。例如:

神经网络那些事儿(二)

这种按位相乘有时被称为Hadamard 积。好的矩阵库通常提供了Hadamard积的快速的实现,这对于实现反向传播信手拈来。

反向传播背后的四个等式

反向传播是关于理解在一个网络改变损失函数时,权重和偏置是怎样变化的。最终,这个意味着计算偏导数

神经网络那些事儿(二)神经网络那些事儿(二)。但是为了计算那些,我们首先引进一个中间变量,神经网络那些事儿(二),我们把它称为第l层的第j个神经元的error。BP将给出一个计算error 神经网络那些事儿(二)的过程,然后关联神经网络那些事儿(二)神经网络那些事儿(二)神经网络那些事儿(二)

为了理解error是如何定义的,想象我们的神经网络中有一个精灵:

神经网络那些事儿(二)

这个精灵坐在第l层的第j个神经元上。当神经元的输入进来时,精灵扰乱神经元的操作。它增加了一个小的变化

神经网络那些事儿(二)到神经元的权重输入,所以输出不再是神经网络那些事儿(二),而是神经网络那些事儿(二)。这个变化传播到网络中后面的层,最终导致损失函数改变了一个量神经网络那些事儿(二)

现在,这个精灵是一个好的精灵,并且正在帮助你改进损失函数,也就是他们正尝试找到一个

神经网络那些事儿(二)使得损失函数更小。假设神经网络那些事儿(二)有一个很大的值(要么是正的要么是负的,指绝对值)。那么,精灵能够通过选择神经网络那些事儿(二)有和神经网络那些事儿(二)相反的符号来使损失函数减小得十分多。相反,如果神经网络那些事儿(二)接近于0,那么精灵就不能通过扰乱权重输入神经网络那些事儿(二)来改进损失函数。到目前为止,精灵能够告诉我们,神经元已经相当接近最优了。因此,存在一个启发式神经网络那些事儿(二)是神经元的error的一个度量。于是我们定义层l的的神经元j的error 神经网络那些事儿(二)为:

神经网络那些事儿(二)

按照我们的传统,我们使用

神经网络那些事儿(二)来表示和层l关联的error向量。反向传播将告诉我们计算每层的神经网络那些事儿(二)方法,然后把这些errors关联到我们真实感兴趣的量神经网络那些事儿(二)神经网络那些事儿(二)

你可能想知道为什么精灵正在改变权重输入

神经网络那些事儿(二)。当然,想象精灵正在改变输出激活神经网络那些事儿(二),然后使用神经网络那些事儿(二)来度量我们的error,这样也许会更自然。事实上,如果你这样做了将和下面的讨论的结果是差不多的。但是,它将使陈述BP变得稍微有点代数上更复杂。因此,我们将坚持神经网络那些事儿(二)作为我们error的度量。

攻克计划:

BP是基于四个基础的等式。这些等式一起给了我们一个计算error(你可以将其翻译为残差)

神经网络那些事儿(二)和损失函数的梯度的方法。

输出层残差 神经网络那些事儿(二) 的一个等式

神经网络那些事儿(二)的组成由下面的式子给定:

神经网络那些事儿(二)

这是一个很自然的式子。右边的第一项,

神经网络那些事儿(二),仅仅是度量作为第j个输出激活的一个函数,损失函数变化得有多快。例如,如果C不依赖于一个特定输出神经元j很多的话,那么神经网络那些事儿(二)将是很小的,这也正是我们所期望的。右边的第二项,神经网络那些事儿(二)是度量激活函数神经网络那些事儿(二)在点神经网络那些事儿(二)上改变得有多快。我们能够发现,(BP1)中的所有项都很容易计算。特别是,我们计算神经网络那些事儿(二)同时也在计算网络的行为,并且计算神经网络那些事儿(二)也只是一个很小的花费。神经网络那些事儿(二)的真实形式将取决于损失函数的形式。然而,被提供的损失函数是已知的,会存在一点小麻烦在计算神经网络那些事儿(二)的时候。例如,如果我们使用二次损失函数,那么神经网络那些事儿(二),因此神经网络那些事儿(二),它是很容易被计算的。

等式(BP1)是一个

神经网络那些事儿(二)分量方式的表达式。它是一个完美的表达式,但是不是我们想要的基于矩阵的BP表达式。然而,把它写成一个矩阵的形式也是简单的:

神经网络那些事儿(二)

这里,

神经网络那些事儿(二)被定义为偏导数神经网络那些事儿(二)组成的一个向量。你可以把它想象成表达C关于输出激活的一个变化率。所以,神经网络那些事儿(二),最后基于矩阵的形式为:

神经网络那些事儿(二)

用下一层中的残差 神经网络那些事儿(二) 表示的残差 神经网络那些事儿(二) 的一个等式

:特别地

神经网络那些事儿(二)

假设我们知道残差

神经网络那些事儿(二)在第神经网络那些事儿(二)层。当我们应用转置权值矩阵神经网络那些事儿(二)时,我们可以直观地把这个想成让残差向后穿过网络,从而给了我们某种度量第l层的输出的残差的方法。当使用Hadamard积神经网络那些事儿(二)时,它通过第l层的激活函数把残差向后移动,给出了到达l层的权重输入的残差神经网络那些事儿(二)

组合BP2和BP1,我们能计算网络中的任何层的残差

神经网络那些事儿(二)。我们首先通过BP1来计算神经网络那些事儿(二),然后应用等式BP2来计算神经网络那些事儿(二),然后再次使用等式BP2计算神经网络那些事儿(二),等等,用这样的方式反向穿过网络。

网络中损失函数关于任何偏置的变化率的一个等式:

特别地:

神经网络那些事儿(二)

也就是,残差

神经网络那些事儿(二)实际上等于变化率神经网络那些事儿(二)。这个信息很有用,因为BP1和BP2已经告诉我们怎样计算神经网络那些事儿(二)。我们能够重写BP3:

神经网络那些事儿(二)

损失函数关于任何权值的变化率的一个等式:

特别地:

神经网络那些事儿(二)

这告诉我们怎样利用量

神经网络那些事儿(二)神经网络那些事儿(二)来计算偏导数神经网络那些事儿(二),前面两个量我们已经知道怎么计算了。可以重写为下面的形式:

神经网络那些事儿(二)

其中

神经网络那些事儿(二)是权重为w输入的神经元的激活,神经网络那些事儿(二)是从权重w的神经元的输出残差。可以简化为下面的图形:

神经网络那些事儿(二)

等式(32)的一个很好的结果是当激活

神经网络那些事儿(二)很小的时候,神经网络那些事儿(二),梯度项神经网络那些事儿(二)也将趋向于很小。在这种情况下,我们将说权重学习得很慢,意味着在梯度下降过程中改变得很多。换句话说,BP4的一个结果就是从低-激活神经元输出的权重学习得很慢。

从BP1-BP4中也可以看到其他的信息。先看看输出层。考虑(BP1)中的

神经网络那些事儿(二)项。回忆上一章中的sigmoid函数的图,当神经网络那些事儿(二)接近0或1的时候,神经网络那些事儿(二)函数变得很平坦。当这个发生的时候,我们可以得到神经网络那些事儿(二)。所以如果输出神经元是低激活(神经网络那些事儿(二))或者高激活(神经网络那些事儿(二)),那么最后一层中的权重将学习得很慢。这种情况下,通常是说输出神经元已经饱和了,并且权重已经停止学习了(或者学习得很慢)。相似的结论对于输出神经元中的偏置也是成立的。

对于非输出层我们也能获得一些相似的信息。特别是,注意BP2中的项

神经网络那些事儿(二)。这意味着如果神经元接近饱和,则神经网络那些事儿(二)可能变小。反过来,这也意味着输入到一个饱和神经元的任何权重也将学习得很慢。

可以总结出来,我们已经知道,如果输入神经元是低-激活或者输出神经元已经饱和了,也就是要么是高激活,要么是低激活,那么一个权重将学习得很慢。刚才观测到的这些信息没有太多的让人惊讶。但是,它们依旧帮助提升当一个神经网络学习的时候发生了什么我们的思维模型。

四个基础等式的证明

我们将证明四个基础等式(BP1)-(BP4)。所有四个等式都是多元微积分的链式法则的结果。首先看(BP1)等式吧,它给出的是输出残差,

神经网络那些事儿(二)。为了证明这个等式,回忆定义:

神经网络那些事儿(二)

应用链式法则,我们可以重写使用关于输出激活的偏导数来表示

上面的偏导数:

神经网络那些事儿(二)

和表示所有输出层中的神经元k。当然,第k个神经元仅仅取决于当k=j时的第j个神经元的输入权值

神经网络那些事儿(二)的输出激活神经网络那些事儿(二)。因此当神经网络那些事儿(二) 时,神经网络那些事儿(二)项就消失了。所以可以简化前面的等式为:

神经网络那些事儿(二)

因为

神经网络那些事儿(二),右边的第2项能够被写成神经网络那些事儿(二),等式就变成:

神经网络那些事儿(二)

这便是BP1的形式。接下来BP2和BP3的证明留给读者自己思考。

反向传播算法

BP算法为我们提供了一个计算损失函数梯度的方法。写成一个算法的形式:

  1. 输入 x:为输入层设置相应的激活神经网络那些事儿(二)
  2. 前向:对于每个l=2,3,…,L计算神经网络那些事儿(二) 以及神经网络那些事儿(二)
  3. 输出残差神经网络那些事儿(二) :计算向量神经网络那些事儿(二)
  4. 反向传播残差:对于每个l=L-1,L-2,…,2计算神经网络那些事儿(二)
  5. 输出:损失函数的梯度为神经网络那些事儿(二)神经网络那些事儿(二)

我们从最后一层开始向后计算残差向量

神经网络那些事儿(二),这可能看起来我们正在向后穿过网络是奇怪的。但是,如果你思考反向传播的证明,反向移动是由于损失是网络的输出的一个函数的事实所导致的。为了理解损失怎样随着早先的权重和偏置变化的,我们需要重复应用链式法则,层层向后计算来获得可用表达式信息。反向传播算法计算的是单个训练样本的梯度,即神经网络那些事儿(二)。实践中,通常把反向传播和一个像随机梯度这样的学习算法组合,在随机梯度算法中我们计算许多训练样本的梯度。特别地,给定一个含有m个训练样本的mini-batch,下面的算法应用了一个基于mini-batch的梯度下降学习算法:
  1. 输入一个训练样本的集合
  2. 对于每个训练样本x:设置相应的输入激活神经网络那些事儿(二) ,然后执行下面的步骤:
  3. 前向:对于每个l=2,3,…,L计算神经网络那些事儿(二) 以及神经网络那些事儿(二)
  4. 输出残差神经网络那些事儿(二) :计算向量神经网络那些事儿(二)
  5. 反向传播残差:对于每个l=L-1,L-2,…,2计算神经网络那些事儿(二)
  6. 梯度下降:对于每个l=L,L-1,…,2依据规则神经网络那些事儿(二) 更新权重,依据规则神经网络那些事儿(二) 更近偏置。

当然,实践中为了实现随机梯度下降,你也需要一个外层循环来产生训练样本的mini-batches,以及一个外层循环单步执行训练的多个epochs。

反向传播代码实现:

关于代码的分析,请看我的下一篇文章《神经网络代码分析》。

转载 http://www.gumpcs.com/index.php/archives/962

Original: https://www.cnblogs.com/chenying99/p/5023815.html
Author: 刺猬的温驯
Title: 神经网络那些事儿(二)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551369/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Linux find 配合 rm 命令安全批量删除文件

    可以先运行: find . -name "*.log" 确认通配符匹配到的文件是你想删除的文件。再命令执行删除: find . -name "*.lo…

    技术杂谈 2023年6月21日
    0105
  • es index template

    建一个索引的步骤 1:先创建轮滚策略 2:创建模板 3:创建索引 创建轮滚策略 创建索引模板 根据模板创建索引 创建索引后,如果要观察轮滚效果,可以手动滚动 修改mapping后数…

    技术杂谈 2023年7月10日
    083
  • 编程思想与算法leetcode_二分算法详解

    二分算法通常用于有序序列中查找元素: 思路很简单,细节是魔鬼。 一.有序序列中是否存在满足某条件的元素 首先,二分查找的框架: 其次,最基本的查找有序序列中的一个元素 循环的条件为…

    技术杂谈 2023年7月25日
    065
  • 设计模式 11 外观模式

    外观模式(Facade Pattern)属于 结构型模式 在生活中,经常遇到这样的情况:办理一个业务,需要找很多部门签字盖章,这些部门往往距离较远,无奈只得四处奔波。这时候相信所有…

    技术杂谈 2023年7月25日
    071
  • 什么是拦截器?拦截器如何配置?

    今天这篇文章来介绍一下拦截器在SpringBoot中的如何自定义及如何配置的,拦截器的具体作用和应用场景。 SpringBoot版本 本文基于的Spring Boot的版本是2.6…

    技术杂谈 2023年6月21日
    089
  • 测试执行和软件缺陷

    测试执行 1.基本概念 测试执行就是执行测试用例、提交Bug 单、测试结论的评估和总结等一系列测试活动,测试执行不仅包含测试用例的执行,还包括其它测试活动. 2.注意事项 (1) …

    技术杂谈 2023年7月25日
    076
  • jQuery.fn.extend() 与 jQuery.extend()

    jQuery.fn如何扩展。 jQuery插件 $.fn(object)与$.extend(object) jQuery提供了两个方法帮助开发插件 $.extend(object)…

    技术杂谈 2023年5月31日
    0114
  • 这个定时任务,从3min优化到200ms。老板,我尽力了!

    近期,数据中心系统负荷大,mysql服务器的CPU动辄高达90%以上。代码和数据表存在很大优化空间。 这里分享一个定时任务批量处理数据的优化过程。 先介绍定时任务 先介绍下面2张数…

    技术杂谈 2023年7月11日
    072
  • 验证token

    去测试登陆时,请求头一定要带token(authorization)信息,不然401错误。 Original: https://www.cnblogs.com/145Mirro-r…

    技术杂谈 2023年6月21日
    0101
  • 阿里云CentOS 7无外网IP的ECS访问外网(配置网关服务器)

    说明: 1、必须要有一台机器具有外网IP的ECS。 2、如果不想配置具有外网IP的ECS时,可以购买NAT网关,但需要钱,贵。下面会说明NAT网关的配置。 3、最后吐槽一下阿里云V…

    技术杂谈 2023年5月31日
    077
  • 对工作分配问题的求解

    工作分配问题是一个典型的回溯问题,利用回溯思想能很准确地得到问题的解。我们就针对如下一个案例做一个系统的分析: 问题描述 有 (n) 份工作要分配给 (n) 个人来完成,每个人完成…

    技术杂谈 2023年5月31日
    089
  • 自己动手写线程池——向JDK线程池进发

    自己动手写线程池——向JDK线程池进发 前言 在前面的文章自己动手写乞丐版线程池中,我们写了一个非常简单的线程池实现,这个只是一个非常简单的实现,在本篇文章当中我们将要实现一个和J…

    技术杂谈 2023年7月23日
    084
  • Delphi自写组件:可设置颜色的按钮

    unit ColorButton; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls,…

    技术杂谈 2023年5月31日
    068
  • nodejs集群

    nodejs集群 单个 Node.js 实例运行在单个线程中。 为了充分利用多核系统,有时需要启用一组 Node.js 进程去处理负载任务。 集群中的Master 现在让我们详细了…

    技术杂谈 2023年5月31日
    087
  • 《重构:改善既有代码的设计》 读书笔记 第三章

    第三章 代码的坏味道 3.1 神秘命名 命名是编程中很难的事情,所以最常用的重构手段就是去改个名字。 如果你发现改名很难,那就说明代码设计有问题。 3.2 重复代码 同一类的两个函…

    技术杂谈 2023年6月1日
    082
  • 方法重载

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    技术杂谈 2023年7月11日
    0121
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球