在此之前,我们已经学习了前馈网络的两种结构——多层感知器卷积神经网络,这两种结构有一个特点,就是假设输入是一个独立的没有上下文联系的单位,比如输入是一张图片,网络识别是狗还是猫。但是对于一些有明显的上下文特征的序列化输入,比如预测视频中下一帧的播放内容,那么很明显这样的输出必须依赖以前的输入, 也就是说网络必须拥有一定的”记忆能力”。为了赋予网络这样的记忆力,一种特殊结构的神经网络——递归神经网络(Recurrent Neural Network)便应运而生了。网上对于RNN的介绍多不胜数,这篇《Recurrent Neural Networks Tutorial》对于RNN的介绍非常直观,里面手把手地带领读者利用Python实现一个RNN语言模型,强烈推荐。为了不重复作者 Denny Britz的劳动,本篇将简要介绍RNN,并强调RNN训练的过程与多层感知器的训练差异不大(至少比CNN简单),希望能给读者一定的信心——只要你理解了多层感知器,理解RNN便不是事儿:-)。

RNN的基本结构

首先有请读者看看我们的递归神经网络的容貌: 
 
乍一看,好复杂的大家伙,没事,老样子,看我如何慢慢将其拆解,正所谓见招拆招,我们来各个击破。 
上图左侧是递归神经网络的原始结构,如果先抛弃中间那个令人生畏的闭环,那其实就是简单”输入层=>隐藏层=>输出层”的三层结构,我们在多层感知器的介绍中已经非常熟悉,然而多了一个非常陌生的闭环,也就是说输入到隐藏层之后,隐藏层还会给自己也来一发,环环相扣,晕乱复杂。 
我们知道,一旦有了环,就会陷入“先有蛋还是先有鸡”的逻辑困境,为了跳出困境我们必须人为定义一个起始点,按照一定的时间序列规定好计算顺序,做到有条不紊,于是实际上我们会将这样带环的结构展开成一个序列网络,也就是上图右侧被“unfold”之后的结构。先别急着能理解RNN,我们来点轻松的,先介绍这样的序列化网络结构包含的参数记号:

  • 网络某一时刻的输入xt,和之前介绍的多层感知器的输入一样,xt是一个n维向量,不同的是递归网络的输入将是一整个序列,也就是x=[x0,...,xt−1,xt,xt+1,...xT],对于语言模型,每一个xt将代表一个词向量,一整个序列就代表一句话。
  • ht代表时刻t的隐藏状态
  • ot代表时刻t的输出
  • 输入层到隐藏层直接的权重由U表示,它将我们的原始输入进行抽象作为隐藏层的输入
  • 隐藏层到隐藏层的权重W,它是网络的记忆控制者,负责调度记忆。
  • 隐藏层到输出层的权重V,从隐藏层学习到的表示将通过它再一次抽象,并作为最终输出。

RNN的Forward阶段

上一小节我们简单了解了网络的结构,并介绍了其中一些记号,是时候介绍它具体的运作过程了。首先在t=0的时刻,U,V,W都被随机初始化好,h0通常初始化为0,然后进行如下计算:

s1=Ux1+Wh0h1=f(s1)o1=g(Vh1)

这样时间就向前推进,此时的状态h1作为时刻0的记忆状态将参与下一次的预测活动,也就是

s2=Ux2+Wh1h2=f(s2)o2=g(Vh2)

,以此类推

st=Uxt+Wht−1ht=f(Uxt+Wht−1)ot=g(Vht)

其中f可以是tanh,relu,logistic任君选择,g通常是softmax也可以是其他,也是随君所欲。 
值得注意的是,我们说递归神经网络拥有记忆能力,而这种能力就是通过W将以往的输入状态进行总结,而作为下次输入的辅助。可以这样理解隐藏状态:

h=f(现有的输入+过去记忆总结)

RNN的Backward阶段

上一小节我们说到了RNN如何做序列化预测,也就是如何一步步预测出o0,o1,....ot−1,ot,ot+1.....,接下来我们来了解网络的知识U,V,W是如何炼成的。 
其实没有多大新意,我们还是利用在之前讲解多层感知器卷积神经网络用到的backpropagation方法。也就是将输出层的误差Cost,求解各个权重的梯度∇U,∇V,∇W,然后利用梯度下降法更新各个权重。现在问题就是如何求解各个权重的梯度,其它的所有东西都在之前介绍中谈到了,所有的trick都可以复用。 
由于是序列化预测,那么对于每一时刻t,网络的输出ot都会产生一定误差et,误差的选择任君喜欢,可以是cross entropy也可以是平方误差等等。那么总的误差为E=∑tet,我们的目标就是要求取

∇U=∂E∂U=∑t∂et∂U∇V=∂E∂V=∑t∂et∂V∇W=∂E∂W=∑t∂et∂W

我们知道输出ot=g(Vst),对于任意的Cost函数,求取∇V将是简单的,我们可以直接求取每个时刻的∂et∂V,由于它不存在和之前的状态依赖,可以直接求导取得,然后简单地求和即可。我们重点关注∇W,∇U的计算。 
回忆之前我们介绍多层感知器的backprop算法,我们知道算法的trick是定义一个δ=∂e∂s,首先计算出输出层的δL,再向后传播到各层δL−1,δL−2,....,那么如何计算δ呢?先看下图: 
 
之前我们推导过,只要关注当前层次发射出去的链接即可,也就是

δht=(VTδot+WTδht+1).∗f′(st)

只要计算出所有的δot,δht,就可以通过以下计算出∇W,∇U:

∇W=∑tδht×ht∇U=∑tδht×xt

其中×表示两个向量的外积。这样看来,只要你熟悉MLP的backprop算法,RNN写起程序来和MLP根本没有多大差异!手写naive的demo至少比CNN容易很多。

RNN的训练困难

虽然上一节中,我们强调了RNN的训练程序和MLP没太大差异,虽然写程序容易,但是训练起来却是千难万阻。为什么呢?因为我们的网络是根据输入而展开的,输入越长,展开的网络越深,那么对于“深度”网络训练有什么困难呢?最常见的是“gradient explode”和“gradient vanish”。这种问题在RNN中如何体现呢?为了强调这个问题,我们模仿Yoshua Bengio的论文《On the difficulty of training recurrent neural networks》的推导,重写一下RNN的梯度求解过程,为了推导方便,我们人为地为W,U打上标签Wt,Ut,即认为当确定好时间长度T,RNN就变成普通的MLP。打上标签后的RNN变成如下: 
 
假如对于时刻t+1产生的误差et+1,我们想计算它对于W1,W2,....,Wt,Wt+1的梯度,可以如下计算:

∂et+1∂Wt+1=∂et+1∂ht+1∂ht+1∂Wt+1
∂et+1∂Wt=∂et+1∂ht+1∂ht+1∂ht∂ht∂Wt
∂et+1∂Wt−1=∂et+1∂ht+1∂ht+1∂ht∂ht∂ht−1∂ht−1∂Wt−1
......

反复运用链式法则,我们可以求出每一个∇W1,∇W2,....,∇Wt,∇Wt+1,需要注意的是,实际RNN模型对于W,U都是不打标签的,也就是在不同时刻都是共享同样的参数,这样可以大大减少训练参数,和CNN的共享权重类似。对于共享参数的RNN,我们只需将上述的一系列式子抹去标签并求和,就可以得到Yoshua Bengio论文中所推导的梯度计算式子:

∂et∂W=∑1≤k≤t∂et∂ht∏k<i≤t∂hi∂hi−1∂+hk∂W

其中∂+hk∂W代表不利用链式法则直接求导,也就是假如对于函数f(h(x)),对其直接求导结果如下:

∂f(h(x))∂x=f′(h(x))

也就是将h(x)看成常数了。网上许多RNN教程都用Yoshua Bengio类似的推导,却省略了这个小步骤,使得初学者常常搞得晕头转向,摸不着头脑。论文中证明了:

||∏k<i≤t∂hi∂hi−1||≤ηt−k

从而说明了这是梯度求导的一部分环节是一个指数模型,当η<1时,就会出现”gradient vanish”问题,而当η>1时,“gradient explode”也就产生了。为了克服这样的问题,LSTM和GRU模型便后续被推出了。有趣的是,正是因为训练深度网络的困难,才导致神经网络这种古老模型沉寂了几十年,不过现在硬件的发展,训练数据的增多,神经网络重新得以复苏,并以重新以深度学习的外号杀出江湖。

参考引用

《Recurrent Neural Networks Tutorial》 
《On the difficulty of training recurrent neural networks》

递归神经网络(RNN)简介(转载)的更多相关文章

  1. lecture7-序列模型及递归神经网络RNN(转载)

    Hinton 第七课 .这里先说下RNN有recurrent neural network 和 recursive neural network两种,是不一样的,前者指的是一种人工神经网络,后者指的是 ...

  2. lecture7-序列模型及递归神经网络RNN

    Hinton 第七课 .这里先说下RNN有recurrent neural network 和 recursive neural network两种,是不一样的,前者指的是一种人工神经网络,后者指的是 ...

  3. RNN模型(递归神经网络)简介

    有些任务可以通过MLP多层感知器的神经网络,CNN卷积神经网络解决,因为那些任务内部的每一个前后无关联,无顺序,如MNIST手写数字子集,CIFAR子集等. 但是在自然语言处理中,每个字的前后有语义联 ...

  4. 深度学习原理与框架-递归神经网络-RNN网络基本框架(代码?) 1.rnn.LSTMCell(生成单层LSTM) 2.rnn.DropoutWrapper(对rnn进行dropout操作) 3.tf.contrib.rnn.MultiRNNCell(堆叠多层LSTM) 4.mlstm_cell.zero_state(state初始化) 5.mlstm_cell(进行LSTM求解)

    问题:LSTM的输出值output和state是否是一样的 1. rnn.LSTMCell(num_hidden, reuse=tf.get_variable_scope().reuse)  # 构建 ...

  5. 递归神经网络(RNN,Recurrent Neural Networks)和反向传播的指南 A guide to recurrent neural networks and backpropagation(转载)

    摘要 这篇文章提供了一个关于递归神经网络中某些概念的指南.与前馈网络不同,RNN可能非常敏感,并且适合于过去的输入(be adapted to past inputs).反向传播学习(backprop ...

  6. 循环神经网络(RNN, Recurrent Neural Networks)介绍(转载)

    循环神经网络(RNN, Recurrent Neural Networks)介绍    这篇文章很多内容是参考:http://www.wildml.com/2015/09/recurrent-neur ...

  7. 递归神经网络之理解长短期记忆网络(LSTM NetWorks)(转载)

    递归神经网络 人类并不是每时每刻都从头开始思考.正如你阅读这篇文章的时候,你是在理解前面词语的基础上来理解每个词.你不会丢弃所有已知的信息而从头开始思考.你的思想具有持续性. 传统的神经网络不能做到这 ...

  8. 【神经网络篇】--RNN递归神经网络初始与详解

    一.前述 传统的神经网络每个输入节点之间没有联系, RNN (对中间信息保留): 由图可知,比如第二个节点的输入不仅依赖于本身的输入U1,而且依赖上一个节点的输入W0,U0,同样第三个节点依赖于前两个 ...

  9. 递归神经网络(Recursive Neural Network, RNN)

    信息往往还存在着诸如树结构.图结构等更复杂的结构.这就需要用到递归神经网络 (Recursive Neural Network, RNN),巧合的是递归神经网络的缩写和循环神经网络一样,也是RNN,递 ...

随机推荐

  1. 1、ViewModel类的构建和INoyifyPropertyChanged的应用

    public class SampleItem : INotifyPropertyChanged { public SampleItem() { } private string title; pub ...

  2. bzoj 3687 bitset的运用

    题目大意: 小呆开始研究集合论了,他提出了关于一个数集四个问题:1. 子集的异或和的算术和.2. 子集的异或和的异或和.3. 子集的算术和的算术和.4. 子集的算术和的异或和.目前为止,小呆已经解决了 ...

  3. Rhel6-hadoop分布式部署配置文档

    理论基础: Hadoop 分布式文件系统架构 HDFS 负责大数据存储 MapReduce 负责大数据计算 namenode  master守护进程 datanode  slaves上负责存储的进程 ...

  4. [vijos P1626] 爱在心中

    做完Victoria的舞会3,挑了vijos里强连通分量里面难度值最低的题目,也就是这道.先把第一小问做了,纯Tarjan,只是我学的时候的标程是用邻接表的,这题数据小于是用了邻接矩阵,两者之间的切换 ...

  5. Section 1.4 Arithmetic Progressions

    寒假的第一天,终于有空再写题目了,专心备战了.本想拿usaco上的题目练手热身,结果被磕住了T T.其实这是一道穷举题,一开始我在穷举a,b,但是怎么优化就是过不了Test 8,后来参照NOCOW上的 ...

  6. K2上海总部技术培训分享笔记

    第一部门 WinDdg 入门指南 1.NGen.exe --> native code 预编译,省去了.NET程序编译器JIT过程,是程序第一次运行也非常快. NGen 参考资料:http:// ...

  7. js和C#中的编码和解码

    同一个字符串,用URL编码和HTML编码,结果是完全不同的. JS中的URL编码和解码.对 ASCII 字母和数字及以下特殊字符无效: - _ . ! ~ * ' ( ) ,/?:@&=+$# ...

  8. Bootstrap非常简单实用的web前端开发框架

    今天无意间用firebug看网站的代码发现了Bootstrap,之前从来没有听说过这个东东,于是对它产生了好奇感,通过百度我了解到了Bootstrap是一款非常简单,强悍,实用,移动设备端优先使用的这 ...

  9. 100个iOS开发/设计面试题汇总

    常见问题 你昨天/这周学习了什么? 你为什么热衷于软件开发? 你对哪一种控制系统比较熟悉? 是否参与过GitHub项目? 是否参与过GitHub或其他同类型网站的iOS开源项目? 请描述一下你的iOS ...

  10. yum源的更新问题

    我们知道在linux下安装软件的方法有多种多样,其中利用yum的方式来安装较为简单,但需要等待的时间比较长.下面介绍一下如何更新yum的源的问题. 首先需要保证的是linux的机器能上网.然后按照下面 ...