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

2024-05-18 14:10

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

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

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

2. 浅谈LSTM循环神经网络

姓名:程祖晗
  
 学号:19021210938
  
 【嵌牛导读】人工神经网络(ANN)由大量相互连接的神经元或称节点组成,这些节点经过网络中的大量加权连接,将数据进行相互通信,实现了神经网络的记忆特性。在常规的神经网络中,各个层之间的所有神经元彼此连接,但层间神经元不连接,即不能对前后位置具有一定关系的系列化数据进行更有效的分析,无法学习序列数据中前后样本的内在关联。为了优化此问题,多方研究提出了循环神经网络,且为了解决长距离依赖的问题,出现了长短期记忆网络(LSTM)。本篇就LSTM循环神经网络进行简单的讲解。
  
 【嵌牛鼻子】LSTM循环神经网络
  
 【嵌牛正文】LSTM循环神经网络应用了门控算法,即增加了一个状态  来保存长期的状态,此算法在学习时既能掌握长距离依赖又能选择性地遗忘信息防止过载。因此在当前时刻下,LSTM 的单个神经元中共有三个输入,分别是当前时刻网络的输入值  、LSTM 隐含层上一时刻的输出值  以及上一时刻的单元状态  。现研究其模型的建立过程。
  
 LSTM是改进的循环神经网络,如图1所示,  为输入样本,  为输出样本,  为LSTM单元输出。  分别为样本个数,输出样本个数及神经元个数。即:
                                          
 模型中需要初始化的参数有  、  、  、  、  。
  
 遗忘门限  决定了当前时刻的神经元状态  中保存了多少上一时刻的神经元状态  :
                                          
 输入门限  决定了当前时刻网络的输入  有多少保留到当前时刻的神经元状态  ,同时计算当前输出的神经元状态  。
                                          
 输出门限  限制了神经元状态  对  的作用:
                                          
 最后输出的预测结果为:  ,其中  为偏移量。
  
 与 WNN 不同,RNN 的反向误差值包括两个方面:一个是沿时间的反向传播,即当前时刻开始后的每个时刻的误差;一个是将层间的误差值传递。设 LSTM 单元的输出值为  ,定义  时刻的误差项为:
                                          
 (1)误差项沿时间的反向传递
  
 根据上式得到  时刻的  ,即
                                          
 因此  。且由前向计算可知:
                                          
 (2)层间传递
  
 假设当前为第  层,定义  层的误差项为:
                                          
 
  
                                          
 因此  
  
 由前可计算出各权值对应的梯度值,如下所示:
                                          
 设置学习率  ,则示例如下所示:
                                          
 模型建立完成,可利用此模型完成对数据的预测,其结果比常规的神经网络更精确。
  
 参考: http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 
  
 https://zybuluo.com/hanbingtao/note/541458

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)浅析

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模型用于实现一个语义预测模型。

5. 快速理解RNN(LSTM,GRU)结构原理

 RNN主要用来解决序列问题,强调的是先后顺序,在NLP中引申出上下文的概念,一个翻译问题,这个词的含义可能和前后的单词形成的这个组合有联系(Skip-gram),也可能是它之前的所有单词都有联系(Attention),并且,借助RNN的state这样的记忆单元,使得一个序列位置的输出在数学上和之前的所有序列的输入都是有关系的。当然原始的RNN由于梯度的乘性问题,前面的序列的影响近乎为0,这个后面又用LSTM来修正为加性问题。RNN的数学基础可以认为是马尔科夫链,认为后续的值是有前者和一些参数的概率决定的。
                                           
                                                                                                                                                                                                                     
                                                                                                                                                                                                           seq2seq模型,另外会有新文章介绍。
   普通的RNN在长文本的情况下,会学不到之前的信息,例如:the clouds are in the  sky  预测sky是可以预测准确的,但是如果是很长的文本,如:我出生在中国,......,我讲的是 中文 这个时候就存在长时依赖问题,LSTM可以通过输入们,遗忘门,输出们来解决这个问题。
                                                                                   刚开始接触LSTM时有点懵,这个结构怎么这么复杂,但其实先理解LSTM做了什么来解决长时依赖问题,就很容易 记住这个结构了。   LSTM通过忘记们来决定从上个隐状态记忆中忘记哪些信息,通过输入们来决定输入哪部分信息,通过输出们来决定输出哪部分信息,这样来解决长时依赖问题,下面来介绍下LSTM的具体结构信息。
                                           LSTM相比RNN hidden status还引入了细胞状态来记录信息。细胞状态通过门结构 gate来添加新的记忆和删除旧的记忆信息
   
                                                               
                                           这一步是通过忘记门来忘记部分cell state中的记忆信息
   
                                                               
                                           将需添加的新信息加入到经过忘记门后的cell state中,生成新的cell state
   
                                                     
                                           GRU的结构如下,主要包含重置门和更新门,把GRU看着LSTM的变体,相当于取消了LSTM中的cell state,只使用了hidden state,并且使用update gate更新门来替换LSTM中的输入们和遗忘门,取消了LSTM中的输出门,新增了reset gate重置门。这样做的好处是在达到LSTM相近的效果下,GRU参数更少,训练的计算开销更小,训练速度更快。
   由于GRU参数更少,收敛快,通常在数据集够大的情况下,选择LSTM效果应该会更好。   通常情况下LSTM和GRU两者效果相差不大,GRU训练更快,所以一般会先选择使用GRU进行训练和调参,当无法再继续优化时可以把GRU替换成LSTM来看看是否有提高。
                                            完全图解RNN、RNN变体、Seq2Seq、Attention机制     Understanding LSTM Networks     序列预测问题,CNN、RNN各有什么优势? 

快速理解RNN(LSTM,GRU)结构原理