㈠ 解读反向传播算法(BackPropagation)
冒泡~周末愉快鸭!
举个例子:
如下图所示,这是 带有一个隐层的三层神经网络 ,
-小女孩→隐藏层节点
-小黄帽→输出层节点
-哆啦A梦→误差
小女孩左侧接受输入信号,经过隐层节点产生输出结果,哆啦A梦则指导参数往更优的方向调整。 由于哆啦A梦可以直接将误差反馈给小黄帽,所以与小黄帽直接相连的左侧参数矩阵可以直接通过误差进行参数优化(实纵线);而与小女孩直接相连的左侧参数矩阵由于不能得到哆啦A梦的直接反馈而不能直接被优化(虚棕线)。但由于反向传播算法使得哆啦A梦的反馈可以被传递到小女孩那进而产生间接误差,所以与小女孩直接相连的左侧权重矩阵可以通过间接误差得到权重更新,迭代几轮,误差会降低到最小。( 也就是说小男孩得到的是直接误差,小女孩是间接误差 )
接下来将用例子演示整个过程
假设有下图这样一个带权值的网络层,第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间连接的权重,激活函数我们默认为sigmoid函数。
通过前向传播我们得到输出值为[0.75136079 , 0.772928465],与实际值[0.01 , 0.99]相差还很远,接下来我们对误差进行反向传播,更新权值,重新计算输出。
3.输入层---->隐含层的权值更新:
在上文计算总误差对w5的偏导时,是从out(o1)---->net(o1)---->w5,但是在隐含层之间的权值更新时,是out(h1)---->net(h1)---->w1,而out(h1)会接受E(o1)和E(o2)两个地方传来的误差,所以这个地方两个都要计算。
根据BP算法的过程演示,可以得到BP算法的一般过程:
1. 正向传播FP(求损失)
此过程中,我们根据输入的样本、给定的初始化权重值W和偏置项的值b, 计算最终输出值以及输出值与实际值之间的损失值。( 注意:如果损失值不在给定的范围内则进行接下来反向传播的过程, 否则停止W,b的更新。 )
2.反向传播BP(回传误差)
将输出以某种形式通过隐层向输入层逐层反传,并将误差分摊给各层的所有单元,从而获得各层单元的误差信号,此误差信号即作为修正各单元权值的依据。( 主要为: ①隐层到输出层的参数W的更新 ②从输入层到隐层的参数W的更新。 )
Ending~理解计算和公式还是很重要的鸭!
㈡ 循环神经网络(RNN)简介
循环神经网络英文名称为 ( Recurrent Neural Network, RNN ),其通过使用带自反馈的神经元,能够处理任意长度的 时序 数据。
给定输入时序序列
式中, 表示一段时序数据, 为时间长度
以一段英文段落为例,其时序数据可以表示为:
若是一段视频,将其每一帧通过CNN网络处理得到相应的编码向量
循环神经网络通过以下公式更新隐藏层的活性值
循环神经网络图示
RNN的基本模型如下图所示,为便于理解,图中将RNN的模型展开,按照时序方向对其前向传播流程进行介绍
RNN的基本模型
利用数学表达式整个过程可以变得更加清晰,RNN的前向传播公式如下:
将上述过程整合到一个RNN cell中,可以表示为如下图所示的过程:
RNN的前向传播示意图
缺陷:
没有利用到模型后续的信息,可以通过双向RNN网络进行优化
RNN主要有两种计算梯度的方式:随时间反向传播(BPTT)和实时循环学习法(RTRL)算法
本文中主要介绍随时间反向传播的方法 ( BackPropagation Through Time )
RNN的损失函数与任务有关,对于同步的序列对序列任务,其loss可以用交叉熵公式表示
然后通过BPTT算法便可以进行梯度的反向传播计算
梯度爆炸的解决方法:梯度修剪
梯度消失的解决方法:增加长程依赖 LSTM,GRU
GRU的基本思路:增加相关门(Relate Gate)和更新门(Update Gate),进而使得RNN单元具有记忆能力
首先从数学角度对GRU的前向传播过程进行介绍,具体公式如下:
公式中各变量的含义:
将上述数学公式转化为图像,可得
GRU Cell的前向传播流程
LSTM意为长短时记忆网络 (Long Short-Term Memory Network,LSTM) ,可以有效地解决简单神经网络的梯度消失和爆炸问题
在LSTM中,与GRU主要有两点不同
同样,先从数学公式入手,对LSTM的前向传播过程进行了解
基于数学公式的过程,可将LSTM CELL的前向传播过程总结为(图片借用于nndl):
LSTM Cell的前向传播示意图
从上图中可以看出,LSTM在前向传播的过程中传输了两个状态:内部状态 以及外部状态 ,在整个传播过程中 外部状态(隐状态) 每个时刻都会被重写,因此可以看作一种 短时记忆 ,而 内部状态 可以在某个时刻捕捉一些关键信息,并将此信息保存一段时间间隔,可以看作一种 长时记忆 (长的短时记忆)
此外,在LSTM网络初始化训练的时候,需要手动将遗忘门的数值设置的大一些,否则在参数初始化的时候,遗忘门的数据会被初始化为一个很小的值,前一时刻的内部状态 大部分都会丢失,这样网络很难获取到长距离的依赖信息,并且相邻时间间隔的梯度会非常小,导致 梯度弥散 问题,因此遗忘门的 偏置变量 的初始值 一般很大,取 1或2
将 设置为1即可,但是长度非常的大的时候会造成记忆单元的饱和,降低性能
三个门不仅依赖于 和 ,也依赖于
将两者合并为一个门,即:
首先,我们要理解什么是深层的RNN,对于单个的RNN cell,若将其在时间维度上展开,其深度与时间维度的长度成正比,但若将一个RNN cell看作为单个从 的映射函数,则单个cell实际上是很浅显的一层,因此深层循环神经网络要做的就是把多个RNN cell组合起来,换句话说,就是增加从输入 到输出 的路径,使得网络的深度更深。
如何增加从输入 到输出 的路径呢?两种途径:
堆叠循环神经网络示意图
将网络带入到实际应用场景中:假如我们要翻译一段句子
在这里,is和are实际上是由后面的Lucy和they所决定的,而这种单向的按照时序进行传播的方式没有利用到后面的信息。因此诞生了双向循环网络
双向循环神经网络示意图
双向循环神经网络实际上就是简单的双层循环神经网络,只不过第二层网络的传播方式为按时序的逆向传播,其传播公式为:
㈢ 读懂反向传播算法(bp算法)
反向传播算法可以说是神经网络最基础也是最重要的知识点。基本上所以的优化算法都是在反向传播算出梯度之后进行改进的。同时,也因为反向传播算法是一个递归的形式,一层一层的向后传播误差即可,很容易实现(这部分听不懂没关系,下面介绍)。不要被反向传播吓到,掌握其核心思想就很容易自己手推出来。
我们知道神经网络都是有一个loss函数的。这个函数根据不同的任务有不同的定义方式,但是这个loss函数的目的就是计算出当前神经网络建模出来输出的数据和理想数据之间的距离。计算出loss之后,根据反向传播算法就可以更新网络中的各种参数以此使loss不断下降,即可使输出的数据更加理想。
所以,现在的任务是,已知一个网络的loss之后,如何根据loss来更新参数呢?具体点即如何更新网络节点中的权重w和偏差b的值呢?
这里我们采用的是全连接神经网络进行说明。
要想把这个过程说清楚,首先需要将神经网络中各个参数用文字表达清楚。定义的就是w和b在网络中的准确位置。
对于 表示的是神经网络中第 层第k个节点到神经网络中第 层第j个节点之间的权重。注意w的下标是首位表示的是节点后层节点的位置,末尾表示是前层节点的位置。理解这样的表达方式在后面的计算中会很好理解。
同理,对于b的表示:
b的表示相比于w要简单一些,符号 表示第l层网络在第j个节点的偏置。无论w还是b的表示,上标都是表示层数。并且 和 表示都是第l层网络第j个节点的参数。所以该节点的输出可以表示为:
神经网络输出之后会经过一个激活函数,这用激活函数用 表示,则经过激活函数输出为:
至此,根据上面符号 、 、 、 。我们可以对于神经网络里面每一个数据准确的表示了。
给定一个损失函数之后,用 表示,说白了反向传播就是求∂C/∂w和∂C/∂b,然后将这个值乘以和对应的w,b进行相减就可以实现一次的参数更新了。为什么这样的操作就可以优化网络,减小loss值呢?
来源于导数的概念和速度相关。∂C/∂w和∂C/∂b相当于loss值C相对于w和v变化的速度。如果∂C/∂w是正的,则增大w,C也会增大,如果希望C减小的话,应该减小w;并且∂C/∂w的绝对值越大,表示w对C的值影响越大,w稍微有一点变化,C就会有大幅变化。如果要优化C变小,w应该对应的减少多少呢?也没有一个确定的答案。这里通过变化的速度和学习率相乘作为一个减小的值。通过多轮迭代。最终是希望c达到最小点。而当函数落入最小值的时候,无论是局部最小还是全局最小,其周围一定是平滑的。所以此时∂C/∂w和∂C/∂b将会变得很小甚至为0,即参数不在更新了。当函数在局部最小点处参数不在更新出现梯度消失的问题时,目前也有各种trick进行解决。不是这里的重点。
为了好说明,这里定义一个很简单的损失函数C:
接下来就是有意思的阶段了。这里还是利用上一节中∂C/∂w和∂C/∂b的解释。如果我们想要求出∂C/∂w和∂C/∂b的值,即具体的 、 对C影响速率的值,我们找一个中间变量∂C/∂ 。因为我们知道:
我们定义:
当我们知道了 值之后,我们根据 式子可以很容易求出 。
利用导数的链式法则:
很容易推出来不是?同理可以求出:
可以看出通过媒介 很容易求出∂C/∂w和∂C/∂b。那么我们现在来理解一下 到底是什么意思,以及如何求出来每一个l层j节点的 值。
根据定义:
可以看出来 就是 对于C的影响大小(联系之前说的导数和速率的关系)。而 是第 层第 个神经元未进过激活函数之前的输出。所以我们可以理解 为网络中第 层第 个神经元对loss的影响。所以很直观的看法就是我们先求出单个神经元对loss值得影响,然后再计算该神经元内部参数对于loss的影响。
ok,如果我们已经理解了为什么要引入 变量以及如何利用该变量计算具体参数的梯度后,接下来我们就可以看看如何获得 值。反向传播的名字我想也就是通过计算 的方式而来的。是一层一层递归而来的。
既然说是递归的方式,我们来思考一下 和 之间有什么关系,如果找到这个关系之后,我们就可以默认我们如果知道最后一层网络节点的 值,我们就可以获得倒数第二层网络节点的 值,倒数第三层,倒数第四层,……以此推类即可获得整个网络的每个节点的 值。至此我们的反向传播也基本完成了。
所以最重要的有两点:
先看问题1,直接根据求导的链式法则就可以找出两个的关系,具体公式如下,可以多看看手写一下,思路上也很简单。
觉得这样的链式公式还是很直观的,如果不好理解,可以自己画一个神经网络图,连上节点与节点之间的线,标上参数,然后推一下应该就能理解了。
这里的 都表示的未经过激活函数的神经元的输出。 表示激活函数。因为:
所以:
带入上式就可以得出:
至此就找出了 和 之间的关系了。
(还能简化,根据最开始我们定义的 )。
理解起来就是网络中前面一层某一个神经元对于loss的影响与该层的后一层所有的神经元对loss的影响、该神经元的输出大小、该神经元与后一层神经元连接的权重有关系的,并且是一个累加的效应。这样的理解也是非常直观合乎常理的。
现在万事具备,只差问题2了。即假设最后一层网络是L,最后一层 如何计算得出。最后一层的 值就像一个导火索,一旦有了开始,就可以利用我们之前推出来的: 公式进行反向传播了(反向传播还是很形象的不是?)。现在解决这个问题。这个问题就是和损失函数具体怎么定义有关系了。不过我们先不考虑C的具体形式,根据通用的链式法则我们可以得到:
这里需要注意的是最后一层激活函数使用的是哪种。最后一层激活函数在计算某一个神经元的输出时可能会结合其他节点的输出来计算。比如softmax激活函数,其输出的是一个概率值【0,1】。输出大小就是结合输出所有的值。
现在我们来考虑两个具体的损失函数,并且采用之前定义的均方误差损失函数 :
求导为:
因为sigmoid输出的值仅仅和输入的x值有关 。所以 当 时值为0.所以:
根据上面,BP推导有三部曲,先求出 ,再根据 分别求出 、 。总结公式如下:
启动上面反传的导火索是最后一层的 值,计算公式为:
根据最后一层不同类型的激活函数不同对待。