循环神经网络(RNN)浅析

2024-05-05 22:41

1. 循环神经网络(RNN)浅析

RNN是两种神经网络模型的缩写,一种是递归神经网络(Recursive Neural Network),一种是循环神经网络(Recurrent Neural Network)。虽然这两种神经网络有着千丝万缕的联系,但是本文主要讨论的是第二种神经网络模型——循环神经网络(Recurrent Neural Network)。
  
 循环神经网络是指一个随着时间的推移,重复发生的结构。在自然语言处理(NLP),语音图像等多个领域均有非常广泛的应用。RNN网络和其他网络最大的不同就在于RNN能够实现某种“记忆功能”,是进行时间序列分析时最好的选择。如同人类能够凭借自己过往的记忆更好地认识这个世界一样。RNN也实现了类似于人脑的这一机制,对所处理过的信息留存有一定的记忆,而不像其他类型的神经网络并不能对处理过的信息留存记忆。
  
 循环神经网络的原理并不十分复杂,本节主要从原理上分析RNN的结构和功能,不涉及RNN的数学推导和证明,整个网络只有简单的输入输出和网络状态参数。一个典型的RNN神经网络如图所示:
  
 
  
                                          
 由上图可以看出:一个典型的RNN网络包含一个输入x,一个输出h和一个神经网络单元A。和普通的神经网络不同的是,RNN网络的神经网络单元A不仅仅与输入和输出存在联系,其与自身也存在一个回路。这种网络结构就揭示了RNN的实质:上一个时刻的网络状态信息将会作用于下一个时刻的网络状态。如果上图的网络结构仍不够清晰,RNN网络还能够以时间序列展开成如下形式:
                                          
 等号右边是RNN的展开形式。由于RNN一般用来处理序列信息,因此下文说明时都以时间序列来举例,解释。等号右边的等价RNN网络中最初始的输入是x0,输出是h0,这代表着0时刻RNN网络的输入为x0,输出为h0,网络神经元在0时刻的状态保存在A中。当下一个时刻1到来时,此时网络神经元的状态不仅仅由1时刻的输入x1决定,也由0时刻的神经元状态决定。以后的情况都以此类推,直到时间序列的末尾t时刻。
  
 上面的过程可以用一个简单的例子来论证:假设现在有一句话“I want to play basketball”,由于自然语言本身就是一个时间序列,较早的语言会与较后的语言存在某种联系,例如刚才的句子中“play”这个动词意味着后面一定会有一个名词,而这个名词具体是什么可能需要更遥远的语境来决定,因此一句话也可以作为RNN的输入。回到刚才的那句话,这句话中的5个单词是以时序出现的,我们现在将这五个单词编码后依次输入到RNN中。首先是单词“I”,它作为时序上第一个出现的单词被用作x0输入,拥有一个h0输出,并且改变了初始神经元A的状态。单词“want”作为时序上第二个出现的单词作为x1输入,这时RNN的输出和神经元状态将不仅仅由x1决定,也将由上一时刻的神经元状态或者说上一时刻的输入x0决定。之后的情况以此类推,直到上述句子输入到最后一个单词“basketball”。
  
 接下来我们需要关注RNN的神经元结构:
                                          
 上图依然是一个RNN神经网络的时序展开模型,中间t时刻的网络模型揭示了RNN的结构。可以看到,原始的RNN网络的内部结构非常简单。神经元A在t时刻的状态仅仅是t-1时刻神经元状态与t时刻网络输入的双曲正切函数的值,这个值不仅仅作为该时刻网络的输出,也作为该时刻网络的状态被传入到下一个时刻的网络状态中,这个过程叫做RNN的正向传播(forward propagation)。注:双曲正切函数的解析式如下:
                                          
 双曲正切函数的求导如下:
                                          
 双曲正切函数的图像如下所示:
                                          
 这里就带来一个问题:为什么RNN网络的激活函数要选用双曲正切而不是sigmod呢?(RNN的激活函数除了双曲正切,RELU函数也用的非常多)原因在于RNN网络在求解时涉及时间序列上的大量求导运算,使用sigmod函数容易出现梯度消失,且sigmod的导数形式较为复杂。事实上,即使使用双曲正切函数,传统的RNN网络依然存在梯度消失问题,无法“记忆”长时间序列上的信息,这个bug直到LSTM上引入了单元状态后才算较好地解决。
  
 这一节主要介绍与RNN相关的数学推导,由于RNN是一个时序模型,因此其求解过程可能和一般的神经网络不太相同。首先需要介绍一下RNN完整的结构图,上一节给出的RNN结构图省去了很多内部参数,仅仅作为一个概念模型给出。
                                          
 上图表明了RNN网络的完整拓扑结构,从图中我们可以看到RNN网络中的参数情况。在这里我们只分析t时刻网络的行为与数学推导。t时刻网络迎来一个输入xt,网络此时刻的神经元状态st用如下式子表达:
                                          
 t时刻的网络状态st不仅仅要输入到下一个时刻t+1的网络状态中去,还要作为该时刻的网络输出。当然,st不能直接输出,在输出之前还要再乘上一个系数V,而且为了误差逆传播时的方便通常还要对输出进行归一化处理,也就是对输出进行softmax化。因此,t时刻网络的输出ot表达为如下形式:
                                          
 为了表达方便,笔者将上述两个公式做如下变换:
                                          
 以上,就是RNN网络的数学表达了,接下来我们需要求解这个模型。在论述具体解法之前首先需要明确两个问题:优化目标函数是什么?待优化的量是什么?
  
 只有在明确了这两个问题之后才能对模型进行具体的推导和求解。关于第一个问题,笔者选取模型的损失函数作为优化目标;关于第二个问题,我们从RNN的结构图中不难发现:只要我们得到了模型的U,V,W这三个参数就能完全确定模型的状态。因此该优化问题的优化变量就是RNN的这三个参数。顺便说一句,RNN模型的U,V,W三个参数是全局共享的,也就是说不同时刻的模型参数是完全一致的,这个特性使RNN得参数变得稍微少了一些。
  
 不做过多的讨论,RNN的损失函数选用交叉熵(Cross Entropy),这是机器学习中使用最广泛的损失函数之一了,其通常的表达式如下所示:
                                          
 上面式子是交叉熵的标量形式,y_i是真实的标签值,y_i*是模型给出的预测值,最外面之所以有一个累加符号是因为模型输出的一般都是一个多维的向量,只有把n维损失都加和才能得到真实的损失值。交叉熵在应用于RNN时需要做一些改变:首先,RNN的输出是向量形式,没有必要将所有维度都加在一起,直接把损失值用向量表达就可以了;其次,由于RNN模型处理的是序列问题,因此其模型损失不能只是一个时刻的损失,应该包含全部N个时刻的损失。
  
 故RNN模型在t时刻的损失函数写成如下形式:
                                          
 全部N个时刻的损失函数(全局损失)表达为如下形式:
                                          
 需要说明的是:yt是t时刻输入的真实标签值,ot为模型的预测值,N代表全部N个时刻。下文中为了书写方便,将Loss简记为L。在结束本小节之前,最后补充一个softmax函数的求导公式:
                                          
 由于RNN模型与时间序列有关,因此不能直接使用BP(back propagation)算法。针对RNN问题的特殊情况,提出了BPTT算法。BPTT的全称是“随时间变化的反向传播算法”(back propagation through time)。这个方法的基础仍然是常规的链式求导法则,接下来开始具体推导。虽然RNN的全局损失是与全部N个时刻有关的,但为了简单笔者在推导时只关注t时刻的损失函数。
  
 首先求出t时刻下损失函数关于o_t*的微分:
                                          
 求出损失函数关于参数V的微分:
                                          
 因此,全局损失关于参数V的微分为:
                                          
 求出t时刻的损失函数关于关于st*的微分:
                                          
 求出t时刻的损失函数关于s_t-1*的微分:
                                          
 求出t时刻损失函数关于参数U的偏微分。注意:由于是时间序列模型,因此t时刻关于U的微分与前t-1个时刻都有关,在具体计算时可以限定最远回溯到前n个时刻,但在推导时需要将前t-1个时刻全部带入:
                                          
 因此,全局损失关于U的偏微分为:
                                          
 求t时刻损失函数关于参数W的偏微分,和上面相同的道理,在这里仍然要计算全部前t-1时刻的情况:
                                          
 因此,全局损失关于参数W的微分结果为:
                                          
 至此,全局损失函数关于三个主要参数的微分都已经得到了。整理如下:
                                          
 接下来进一步化简上述微分表达式,化简的主要方向为t时刻的损失函数关于ot的微分以及关于st*的微分。已知t时刻损失函数的表达式,求关于ot的微分:
                                          
 softmax函数求导:
                                          
 因此:
                                          
 又因为:
                                          
 且:
                                          
 有了上面的数学推导,我们可以得到全局损失关于U,V,W三个参数的梯度公式:
                                          
 由于参数U和W的微分公式不仅仅与t时刻有关,还与前面的t-1个时刻都有关,因此无法写出直接的计算公式。不过上面已经给出了t时刻的损失函数关于s_t-1的微分递推公式,想来求解这个式子也是十分简单的,在这里就不赘述了。
  
 以上就是关于BPTT算法的全部数学推导。从最终结果可以看出三个公式的偏微分结果非常简单,在具体的优化过程中可以直接带入进行计算。对于这种优化问题来说,最常用的方法就是梯度下降法。针对本文涉及的RNN问题,可以构造出三个参数的梯度更新公式:
                                          
 依靠上述梯度更新公式就能够迭代求解三个参数,直到三个参数的值发生收敛。
  
 这是笔者第一次尝试推导RNN的数学模型,在推导过程中遇到了非常多的bug。非常感谢互联网上的一些公开资料和博客,给了我非常大的帮助和指引。接下来笔者将尝试实现一个单隐层的RNN模型用于实现一个语义预测模型。

循环神经网络(RNN)浅析

2. 循环神经网络(RNN)的应用

 循环神经网络(RNN)是目前深度学习最有前景的工具之一,它解决了传统神经网络不能共享从数据中共享位置的特征的问题。目前,RNN已经有了不少有意思的应用:
    语音识别 :输入的语音数据,生成相应的语音文本信息。比如微信的语音转文字功能。
    机器翻译 :不同语言之间的相互转换。像有道翻译、腾讯翻译官等。最近微软据说实现了中翻英媲美人类的水平
    音乐生成 :使用RNN网络生成音乐,一般会用到RNN中的LSTM算法(该算法可以解决RNN网络中相距较远的节点梯度消失的问题)。下面这个github项目实现了jazz音乐的生成。    deepjazz 
    文本生成 :利用RNN亦可以生成某种风格的文字。有兴趣的可以看一下一下两个github项目    numpy实现字符层面的文本生成器     keras实现特定作家风格的文本 
    情感分类 :输入文本或者语音的评论数据,输出相应的打分数据。
    DNA序列分析 :输入的DNA序列,输出蛋白质表达的子序列。
    视频行为识别 :识别输入的视频帧序列中的人物行为。
    实体名字识别 :从文本中识别实体的名字。

3. 循环神经网络(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所决定的,而这种单向的按照时序进行传播的方式没有利用到后面的信息。因此诞生了双向循环网络
                                           双向循环神经网络示意图
   双向循环神经网络实际上就是简单的双层循环神经网络,只不过第二层网络的传播方式为按时序的逆向传播,其传播公式为:     
     
     

循环神经网络(RNN)简介

4. 循环神经网络(RNN)——处理序列样本

循环神经网络(Recurrent Neural Network,RNN)具有记忆功能,他可以发现样本之间的序列关系,是处理序列样本的首选模型。循环神经网络大量应用在数值、文本、声音、视频处理等领域。
  
 循环神经网络模型是一个具有记忆功能的模型。它可以发现样本之间的相互关系,多用于处理带有序列特征的样本数据。
  
 RNN模型有很多种结构,其最基本的结构是将全连接网络的输出节点复制一份并传回到输入节点中,与输入数据一起进行下一次运算。这种神经网络将数据从输入层又传回到输出层,形成了循环结构,所以被叫做循环神经网络。
  
 通过RNN模型,可以将上一个序列的样本输出结果与下一个序列样本一起输入模型中进行运算,使模型所处理的特征信息中,既含有该样本之前序列的信息,又含有该样本自身的数据信息,从而使网络具有记忆功能。
  
 在实际开发中,所使用的RNN模型还会基于上述的原理做更多的结构改进,使得网络的记忆功能更强。
  
 在深层网络结构中,还会在RNN模型基础上结合全连接网络、卷积网络、等组成拟合能力更强的模型。

5. 入门 | 一文简述循环神经网络

入门 | 一文简述循环神经网络
本文简要介绍了什么是循环神经网络及其运行原理,并给出了一个 RNN 实现示例。
什么是循环神经网络(RNN)?它们如何运行?可以用在哪里呢?本文试图回答上述这些问题,还展示了一个 RNN 实现 demo,你可以根据自己的需要进行扩展。
 
循环神经网络架构
基础知识。Python、CNN 知识是必备的。了解 CNN 的相关知识,是为了与 RNN 进行对比:RNN 为什么以及在哪些地方比 CNN 更好。
我们首先从「循环」(Recurrent)这个词说起。为什么将其称为循环?循环的意思是:
经常或重复出现
将这类神经网络称为循环神经网络是因为它对一组序列输入重复进行同样的操作。本文后续部分将讨论这种操作的意义。
我们为什么需要 RNN?
也许你现在想的是,已经有像卷积网络这样表现非常出色的网络了,为什么还需要其他类型的网络呢?有一个需要用到 RNN 的特殊例子。为了解释 RNN,你首先需要了解序列的相关知识,我们先来讲一下序列。
序列是相互依赖的(有限或无限)数据流,比如时间序列数据、信息性的字符串、对话等。在对话中,一个句子可能有一个意思,但是整体的对话可能又是完全不同的意思。股市数据这样的时间序列数据也是,单个数据表示当前价格,但是全天的数据会有不一样的变化,促使我们作出买进或卖出的决定。
当输入数据具有依赖性且是序列模式时,CNN 的结果一般都不太好。CNN 的前一个输入和下一个输入之间没有任何关联。所以所有的输出都是独立的。CNN 接受输入,然后基于训练好的模型输出。如果你运行了 100 个不同的输入,它们中的任何一个输出都不会受之前输出的影响。但想一下如果是文本生成或文本翻译呢?所有生成的单词与之前生成的单词都是独立的(有些情况下与之后的单词也是独立的,这里暂不讨论)。所以你需要有一些基于之前输出的偏向。这就是需要 RNN 的地方。RNN 对之前发生在数据序列中的事是有一定记忆的。这有助于系统获取上下文。理论上讲,RNN 有无限的记忆,这意味着它们有无限回顾的能力。通过回顾可以了解所有之前的输入。但从实际操作中看,它只能回顾最后几步。
本文仅为了与人类大体相关联,而不会做任何决定。本文只是基于之前关于该项目的知识做出了自己的判断(我甚至尚未理解人类大脑的 0.1%)。
何时使用 RNN?
RNN 可用于许多不同的地方。下面是 RNN 应用最多的领域。
1. 语言建模和文本生成
给出一个词语序列,试着预测下一个词语的可能性。这在翻译任务中是很有用的,因为最有可能的句子将是可能性最高的单词组成的句子。
2. 机器翻译
将文本内容从一种语言翻译成其他语言使用了一种或几种形式的 RNN。所有日常使用的实用系统都用了某种高级版本的 RNN。
3. 语音识别
基于输入的声波预测语音片段,从而确定词语。
4. 生成图像描述
RNN 一个非常广泛的应用是理解图像中发生了什么,从而做出合理的描述。这是 CNN 和 RNN 相结合的作用。CNN 做图像分割,RNN 用分割后的数据重建描述。这种应用虽然基本,但可能性是无穷的。
5. 视频标记
可以通过一帧一帧地标记视频进行视频搜索。
深入挖掘
本文按照以下主题进行。每一部分都是基于之前的部分进行的,所以不要跳着读。
前馈网络循环网络循环神经元基于时间的反向传播(BPTT)RNN 实现
前馈网络入门
前馈网络通过在网络的每个节点上做出的一系列操作传递信息。前馈网络每次通过每个层直接向后传递信息。这与其他循环神经网络不同。一般而言,前馈网络接受一个输入并据此产生输出,这也是大多数监督学习的步骤,输出结果可能是一个分类结果。它的行为与 CNN 类似。输出可以是以猫狗等作为标签的类别。
前馈网络是基于一系列预先标注过的数据训练的。训练阶段的目的是减少前馈网络猜类别时的误差。一旦训练完成,我们就可以用训练后的权重对新批次的数据进行分类。
 
一个典型的前馈网络架构
还有一件事要注意。在前馈网络中,无论在测试阶段展示给分类器的图像是什么,都不会改变权重,所以也不会影响第二个决策。这是前馈网络和循环网络之间一个非常大的不同。
与循环网络不同,前馈网络在测试时不会记得之前的输入数据。它们始终是取决于时间点的。它们只会在训练阶段记得历史输入数据。
循环网络
也就是说,循环网络不仅将当前的输入样例作为网络输入,还将它们之前感知到的一并作为输入。
我们试着建立了一个多层感知器。从简单的角度讲,它有一个输入层、一个具备特定激活函数的隐藏层,最终可以得到输出。
 
多层感知器架构示例
如果在上述示例中的层数增加了,输入层也接收输入。那么第一个隐藏层将激活传递到下一个隐藏层上,依此类推。最后到达输出层。每一个隐藏层都有自己的权重和偏置项。现在问题变成了我们可以输入到隐藏层吗?
 
每一层都有自己的权重(W)、偏置项(B)和激活函数(F)。这些层的行为不同,合并它们从技术层面上讲也极具挑战性。为了合并它们,我们将所有层的权重和偏置项替换成相同的值。如下图所示:
 
现在我们就可以将所有层合并在一起了。所有的隐藏层都可以结合在一个循环层中。所以看起来就像下图:
 
我们在每一步都会向隐藏层提供输入。现在一个循环神经元存储了所有之前步的输入,并将这些信息和当前步的输入合并。因此,它还捕获到一些当前数据步和之前步的相关性信息。t-1 步的决策影响到第 t 步做的决策。这很像人类在生活中做决策的方式。我们将当前数据和近期数据结合起来,帮助解决手头的特定问题。这个例子很简单,但从原则上讲这与人类的决策能力是一致的。这让我非常想知道我们作为人类是否真的很智能,或者说我们是否有非常高级的神经网络模型。我们做出的决策只是对生活中收集到的数据进行训练。那么一旦有了能够在合理时间段内存储和计算数据的先进模型和系统时,是否可以数字化大脑呢?所以当我们有了比大脑更好更快的模型(基于数百万人的数据训练出的)时,会发生什么?
另一篇文章(https://deeplearning4j.org/lstm.html)的有趣观点:人总是被自己的行为所困扰。
我们用一个例子来阐述上面的解释,这个例子是预测一系列字母后的下一个字母。想象一个有 8 个字母的单词 namaskar。
namaskar(合十礼):印度表示尊重的传统问候或姿势,将手掌合起置于面前或胸前鞠躬。
如果我们在向网络输入 7 个字母后试着找出第 8 个字母,会发生什么呢?隐藏层会经历 8 次迭代。如果展开网络的话就是一个 8 层的网络,每一层对应一个字母。所以你可以想象一个普通的神经网络被重复了多次。展开的次数与它记得多久之前的数据是直接相关的。
 
循环神经网络的运作原理
循环神经元
这里我们将更深入地了解负责决策的实际神经元。以之前提到的 namaskar 为例,在给出前 7 个字母后,试着找出第 8 个字母。输入数据的完整词汇表是 {n,a,m,s,k,r}。在真实世界中单词或句子都会更复杂。为了简化问题,我们用的是下面这个简单的词汇表。
 
在上图中,隐藏层或 RNN 块在当前输入和之前的状态中应用了公式。在本例中,namaste 的字母 n 前面什么都没有。所以我们直接使用当前信息推断,并移动到下一个字母 a。在推断字母 a 的过程中,隐藏层应用了上述公式结合当前推断 a 的信息与前面推断 n 的信息。输入在网络中传递的每一个状态都是一个时间步或一步,所以时间步 t 的输入是 a,时间步 t-1 的输入就是 n。将公式同时应用于 n 和 a 后,就得到了一个新状态。
用于当前状态的公式如下所示:
 
h_t 是新状态,h_t-1 是前一个状态。x_t 是时间 t 时的输入。在对之前的时间步应用了相同的公式后,我们已经能感知到之前的输入了。我们将检查 7 个这样的输入,它们在每一步的权重和函数都是相同的。
现在试着以简单的方式定义 f()。我们使用 tanh 激活函数。通过矩阵 W_hh 定义权重,通过矩阵 W_xh 定义输入。公式如下所示:
 
上例只将最后一步作为记忆,因此只与最后一步的数据合并。为了提升网络的记忆能力,并在记忆中保留较长的序列,我们必须在方程中添加更多的状态,如 h_t-2、h_t-3 等。最后输出可以按测试阶段的计算方式进行计算:
其中,y_t 是输出。对输出与实际输出进行对比,然后计算出误差值。网络通过反向传播误差来更新权重,进行学习。本文后续部分会对反向传播进行讨论。
基于时间的反向传播算法(BPTT)
本节默认你已经了解了反向传播概念。如果需要对反向传播进行深入了解,请参阅链接:?http://cs231n.github.io/optimization-2/?。
现在我们了解了 RNN 是如何实际运作的,但是在实际工作中如何训练 RNN 呢?该如何决定每个连接的权重呢?如何初始化这些隐藏单元的权重呢?循环网络的目的是要准确地对序列输入进行分类。这要靠误差值的反向传播和梯度下降来实现。但是前馈网络中使用的标准反向传播无法在此应用。
与有向无环的前馈网络不同,RNN 是循环图,这也是问题所在。在前馈网络中可以计算出之前层的误差导数。但 RNN 的层级排列与前馈网络并不相同。
答案就在之前讨论过的内容中。我们需要展开网络。展开网络使其看起来像前馈网络就可以了。
 
展开 RNN
在每个时间步取出 RNN 的隐藏单元并复制。时间步中的每一次复制就像前馈网络中的一层。在时间步 t+1 中每个时间步 t 层与所有可能的层连接。因此我们对权重进行随机初始化,展开网络,然后在隐藏层中通过反向传播优化权重。通过向最低层传递参数完成初始化。这些参数作为反向传播的一部分也得到了优化。
展开网络的结果是,现在每一层的权重都不同,因此最终会得到不同程度的优化。无法保证基于权重计算出的误差是相等的。所以每一次运行结束时每一层的权重都不同。这是我们绝对不希望看到的。最简单的解决办法是以某种方式将所有层的误差合并到一起。可以对误差值取平均或者求和。通过这种方式,我们可以在所有时间步中使用一层来保持相同的权重。
RNN 实现
本文试着用 Keras 模型实现 RNN。我们试着根据给定的文本预测下一个序列。
代码地址:?https://gist.github.com/09aefc5231972618d2c13ccedb0e22cc.git?
该模型是 Yash Katariya 建的。我对该模型做了一些细微的改动以适合本文的要求。

入门 | 一文简述循环神经网络

6. 循环神经网络

  为什么卷积神经网络不会出现严重的数值问题呢?    卷积神经网络中每一层的权重矩阵 W 是不同的,并且在初始化时它们是独立同分布的,因此可以相互抵消,在多层之后一般不会出现严重的数值问题。   循环神经网络采用 ReLu 激活函数,只有当 W 的取值在单位矩阵附近时才能取得比较好的效果,因此需要将 W 初始化为单位矩阵。
   Seq2Seq 模型最基础的解码方法是贪心法,即选取一种度量标准后,每次都在当前状态下选择最佳的一个结果,直到结束。贪心法的计算代价低,适合作为基准结果与其他方法相比较。贪心法获得的是一个局部最优解,由于实际问题的复杂性,该方法往往不能取得最好的结果。    集束搜索: 是一种启发式算法,会保存 beam size 个当前的较佳选择,然后解码时每一步根据保存的选则进行下一步扩展和排序,接着选择前 b 个进行保存,循环迭代,知道结束时选择最佳的一个作为解码的结果。 b 往往选择一个适中的范围,以 8-12 为佳。    
                                           
    Seq2Seq 模型引入注意力机制是为了解决什么问题?为什么选用了双向的循环神经网络模型?    编码时输入序列的全部信息压缩到了一个向量中,随着序列增长,句子越前面的词的信息丢失越严重。同时,Seq2Seq 模型的输出序列中,常常会损失部分输入序列信息,这是解码时,当前词及对应的源语言词的上下文信息和位置信息在编解码过程中丢失了。 引入注意力机制,解决上述问题 。使用双向的循环神经网络进行建模,可以获取前后文的信息。

7. 循环神经网络

 花书中关于RNN的内容记录于 https://www.jianshu.com/p/206090600f13 。
   在前馈神经网络中,信息的传递是单向的,这种限制虽然使得网络变得更容易学习,但在一定程度上也减弱了神经网络模型的能力。在生物神经网络中,神经元之间的连接关系要复杂的多。 前馈神经网络可以看作是一个复杂的函数,每次输入都是独立的,即网络的输出只依赖于当前的输入。但是在很多现实任务中,网络的输入不仅和当前时刻的输入相关,也和其过去一段时间的输出相关 。因此,前馈网络难以处理时序数据,比如视频、语音、文本等。时序数据的长度一般是不固定的,而前馈神经网络要求输入和输出的维数都是固定的,不能任意改变。因此,当处理这一类和时序相关的问题时,就需要一种能力更强的模型。
    循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络。在循环神经网络中,神经元不但可以接受其它神经元的信息,也可以接受自身的信息,形成具有环路的网络结构。 和前馈神经网络相比,循环神经网络更加符合生物神经网络的结构。循环神经网络已经被广泛应用在语音识别、语言模型以及自然语言生成等任务上。循环神经网络的参数学习可以通过 随时间反向传播算法 来学习。
   为了处理这些时序数据并利用其历史信息,我们需要让网络具有短期记忆能力。而前馈网络是一个静态网络,不具备这种记忆能力。
   一种简单的利用历史信息的方法是建立一个额外的延时单元,用来存储网络的历史信息(可以包括输入、输出、隐状态等)。比较有代表性的模型是延时神经网络。
   延时神经网络是在前馈网络中的非输出层都添加一个延时器,记录最近几次神经元的输出。在第  个时刻,第  层神经元和第  层神经元的最近  次输出相关,即:
     
    延时神经网络在时间维度上共享权值,以降低参数数量。因此对于序列输入来讲,延时神经网络就相当于卷积神经网络 。
    自回归模型(Autoregressive Model,AR) 是统计学上常用的一类时间序列模型,用一个变量  的历史信息来预测自己:
     
   其中  为超参数,  为参数,  为第  个时刻的噪声,方差  和时间无关。
    有外部输入的非线性自回归模型(Nonlinear Autoregressive with ExogenousInputs Model,NARX) 是自回归模型的扩展,在每个时刻  都有一个外部输入  ,产生一个输出  。NARX通过一个延时器记录最近几次的外部输入和输出,第  个时刻的输出  为:
     
   其中  表示非线性函数,可以是一个前馈网络,  和  为超参数。
   循环神经网络通过使用带自反馈的神经元,能够处理任意长度的时序数据。
   给定一个输入序列  ,循环神经网络通过下面   公式更新带反馈边的隐藏层的活性值  :
     
   其中  ,  为一个非线性函数,也可以是一个前馈网络。
                                           从数学上讲,上式可以看成一个动力系统。动力系统(Dynamical System)是一个数学上的概念,指 系统状态按照一定的规律随时间变化的系统 。具体地讲,动力系统是使用一个函数来描述一个给定空间(如某个物理系统的状态空间)中所有点随时间的变化情况。因此, 隐藏层的活性值  在很多文献上也称为状态(State)或隐状态(Hidden States) 。理论上,循环神经网络可以近似任意的非线性动力系统。
   简单循环网络(Simple Recurrent Network,SRN)是一个非常简单的循环神经网络,只有一个隐藏层的神经网络。
   在一个两层的前馈神经网络中,连接存在相邻的层与层之间,隐藏层的节点之间是无连接的。而 简单循环网络增加了从隐藏层到隐藏层的反馈连接 。
   假设在时刻  时,网络的输入为  ,隐藏层状态(即隐藏层神经元活性值)   不仅和当前时刻的输入  相关,也和上一个时刻的隐藏层状态  相关: 
     
   其中  为隐藏层的净输入,  是非线性激活函数,通常为Logistic函数或Tanh函数,  为状态-状态权重矩阵,  为状态-输入权重矩阵,  为偏置。上面两式也经常直接写为:
     
    如果我们把每个时刻的状态都看作是前馈神经网络的一层的话,循环神经网络可以看作是在时间维度上权值共享的神经网络 。下图给出了按时间展开的循环神经网络。
                                           由于循环神经网络具有短期记忆能力,相当于存储装置,因此其计算能力十分强大。 前馈神经网络可以模拟任何连续函数,而循环神经网络可以模拟任何程序。 
   定义一个完全连接的循环神经网络,其输入为  ,输出为  :
     
   其中  为隐状态,  为非线性激活函数,  和  为网络参数。
    这样一个完全连接的循环神经网络可以近似解决所有的可计算问题 。
   循环神经网络可以应用到很多不同类型的机器学习任务。根据这些任务的特点可以分为以下几种模式: 序列到类别模式、同步的序列到序列模式、异步的序列到序列模式 。
   序列到类别模式主要用于序列数据的分类问题:输入为序列,输出为类别。比如在文本分类中,输入数据为单词的序列,输出为该文本的类别。
   假设一个样本  为一个长度为  的序列,输出为一个类别  。我们可以将样本  按不同时刻输入到循环神经网络中,并得到不同时刻的隐藏状态  。我们可以将  看作整个序列的最终表示(或特征),并输入给分类器  进行分类:
     
   其中  可以是简单的线性分类器(比如Logistic 回归)或复杂的分类器(比如多层前馈神经网络)
   除了将最后时刻的状态作为序列表示之外,我们还可以对整个序列的所有状态进行平均,并用这个平均状态来作为整个序列的表示:
     
                                           同步的序列到序列模式 主要用于序列标注(Sequence Labeling)任务,即每一时刻都有输入和输出,输入序列和输出序列的长度相同 。比如词性标注(Partof-Speech Tagging)中,每一个单词都需要标注其对应的词性标签。
   输入为序列  ,输出为序列  。样本  按不同时刻输入到循环神经网络中,并得到不同时刻的隐状态  。每个时刻的隐状态  代表当前和历史的信息,并输入给分类器  得到当前时刻的标签  。
     
                                           异步的序列到序列模式也称为 编码器-解码器(Encoder-Decoder)模型,即输入序列和输出序列不需要有严格的对应关系,也不需要保持相同的长度。 比如在机器翻译中,输入为源语言的单词序列,输出为目标语言的单词序列。
   在异步的序列到序列模式中,输入为长度为  的序列  ,输出为长度为  的序列  。经常通过 先编码后解码 的方式来实现。先将样本  按不同时刻输入到一个循环神经网络(编码器)中,并得到其编码  。然后再使用另一个循环神经网络(解码器)中,得到输出序列  。为了建立输出序列之间的依赖关系,在解码器中通常使用非线性的自回归模型。
     
   其中  分别为用作编码器和解码器的循环神经网络,  为分类器,  为预测输出  的向量表示。
                                           循环神经网络的参数可以通过梯度下降方法来进行学习。给定一个训练样本  ,其中  为长度是  的输入序列,  是长度为  的标签序列。即在每个时刻  ,都有一个监督信息  ,我们定义时刻  的损失函数为:
     
   其中  为第  时刻的输出,  为可微分的损失函数,比如交叉熵。那么整个序列上损失函数为:
     
   整个序列的损失函数  关于参数  的梯度为:
     
   即每个时刻损失  对参数  的偏导数之和。
   循环神经网络中存在一个递归调用的函数  ,因此其计算参数梯度的方式和前馈神经网络不太相同。在循环神经网络中主要有两种计算梯度的方式: 随时间反向传播(BPTT)和实时循环学习(RTRL)算法。 
    随时间反向传播(Backpropagation Through Time,BPTT) 算法的主要思想是通过类似前馈神经网络的错误反向传播算法来进行计算梯度。
    BPTT算法将循环神经网络看作是一个展开的多层前馈网络,其中“每一层”对应循环网络中的“每个时刻”。在“展开”的前馈网络中,所有层的参数是共享的,因此参数的真实梯度是将所有“展开层”的参数梯度之和 。
   因为参数  和隐藏层在每个时刻  的净输入  有关,因此第  时刻的损失函数  关于参数  的梯度为:
     
   其中  表示“直接”偏导数,即公式  中保持  不变,对  求偏导数,得到:
     
   其中  为第  时刻隐状态的第  维;  除了第  个值为  外,其余都为  的行向量。
   定义误差项  为第  时刻的损失对第  时刻隐藏神经层的净输入  的导数,则:
     
   从而:
     
   写成矩阵形式为:
     
   由此得到整个序列的损失函数  关于参数  的梯度:
     
   同理可得,  关于权重  和偏置  的梯度为:
     
   在BPTT算法中,参数的梯度需要在一个完整的“前向”计算和“反向”计算后才能得到并进行参数更新。如下图所示。
                                            与反向传播的BPTT算法不同的是,实时循环学习(Real-Time Recurrent Learning)是通过前向传播的方式来计算梯度。 
   假设循环神经网络中第  时刻的状态  为:
     
   其关于参数  的偏导数为:
     
   RTRL算法从第1 个时刻开始,除了计算循环神经网络的隐状态之外,还依次前向计算偏导数  。
   两种学习算法比较:
   RTRL算法和BPTT算法都是基于梯度下降的算法,分别通过前向模式和反向模式应用链式法则来计算梯度。 在循环神经网络中,一般网络输出维度远低于输入维度,因此BPTT算法的计算量会更小,但BPTT算法需要保存所有时刻的中间梯度,空间复杂度较高。RTRL算法不需要梯度回传,因此非常适合于需要在线学习或无限序列的任务中 。
   循环神经网络在学习过程中的主要问题是由于 梯度消失或爆炸问题 ,很难建模长时间间隔(Long Range)的状态之间的依赖关系。
   在BPTT算法中,我们有:
     
   如果定义  ,则:
     
   若  ,当  时,  ,会造成系统不稳定,称为梯度爆炸问题;相反,若  ,当  时,  ,会出现和深度前馈神经网络类似的梯度消失问题。
   虽然简单循环网络理论上可以建立长时间间隔的状态之间的依赖关系,但是由于梯度爆炸或消失问题,实际上只能学习到短期的依赖关系。这样,如果t时刻的输出  依赖于  时刻的输入  ,当间隔  比较大时,简单神经网络很难建模这种长距离的依赖关系,称为 长程依赖问题(Long-Term dependencies Problem) 。
   一般而言,循环网络的梯度爆炸问题比较容易解决,一般 通过权重衰减或梯度截断来避免。 权重衰减是通过给参数增加  或  范数的正则化项来限制参数的取值范围,从而使得  。梯度截断是另一种有效的启发式方法,当梯度的模大于一定阈值时,就将它截断成为一个较小的数。
   梯度消失是循环网络的主要问题。除了使用一些优化技巧外,更有效的方式就是改变模型,比如让  ,同时使用  ,即:
     
   其中  是一个非线性函数,  为参数。
   上式中,  和  之间为线性依赖关系,且权重系数为1,这样就不存在梯度爆炸或消失问题。但是,这种改变也丢失了神经元在反馈边上的非线性激活的性质,因此也降低了模型的表示能力。
   为了避免这个缺点,我们可以采用一种更加有效的改进策略:
     
   这样  和  之间为既有线性关系,也有非线性关系,并且可以缓解梯度消失问题。但这种改进依然存在两个问题:
   为了解决这两个问题,可以通过引入 门控机制 来进一步改进模型。
   为了改善循环神经网络的长程依赖问题,一种非常好的解决方案是引入门控机制来控制信息的累积速度,包括 有选择地加入新的信息,并有选择地遗忘之前累积的信息 。这一类网络可以称为基于门控的循环神经网络(Gated RNN)。本节中,主要介绍两种基于门控的循环神经网络: 长短期记忆网络和门控循环单元网络。 
    长短期记忆(Long Short-Term Memory,LSTM)网络 是循环神经网络的一个变体,可以有效地解决简单循环神经网络的梯度爆炸或消失问题。
   在  基础上,LSTM网络主要改进在以下两个方面:
     
   其中  和  三个门(gate)来控制信息传递的路径;  为向量元素乘积;  为上一时刻的记忆单元;  是通过非线性函数得到的候选状态:
     
   在每个时刻  ,LSTM网络的内部状态  记录了到当前时刻为止的历史信息。
   在数字电路中,门(Gate)为一个二值变量{0, 1},0代表关闭状态,不许任何信息通过;1代表开放状态,允许所有信息通过。LSTM网络中的“门”是一种“软”门,取值在(0, 1) 之间,表示 以一定的比例运行信息通过 。LSTM网络中三个门的作用为:
   (1)遗忘门  控制上一个时刻的内部状态  需要遗忘多少信息。   (2)输入门  控制当前时刻的候选状态  有多少信息需要保存。   (3)输出门

循环神经网络

8. 分析RNN和NN(神经网络)的区别。

4.从处理输入来说,RNN可以用于处理单独的一个一个的输入。但是,当我们处理序列信息时,即前面的输入跟后面的输入是有关系的,普通的神经网络(NN)模型就无法实现了。【摘要】
分析RNN和NN(神经网络)的区别。【提问】
区别有好几方面,1.从名字上来说:RNN是循环神经网络,NN是神经网络【回答】
2.从定义上来说,传统的神经网络模型(左图),输入层(input layer)到隐藏层(hidden layer),隐藏层再到输出层(output layer),层与层之间是全连接的,但是隐藏层节点之间是无连接的。循环神经网络(右图),隐藏层节点之间是有连接的。【回答】
【回答】
3.从基本结构来看,在RNN中,每一层都共享参数U、V、W,降低了网络中需要学习的参数,提高学习效率。【回答】
U是输入层到隐藏层的权重矩阵。​ V是隐藏层到输出层的权重矩阵。【回答】
4.从处理输入来说,RNN可以用于处理单独的一个一个的输入。但是,当我们处理序列信息时,即前面的输入跟后面的输入是有关系的,普通的神经网络(NN)模型就无法实现了。【回答】