循环神经网络(recurrent neural network)或RNN(Rumelhart et al.,1986c)是一类用于处理序列数据的神经网络。就像卷积网络是专门用于处理网格化数据 X(如一个图像)的神经网络,循环神经网络是专门用于处理序列的神经网络。正如卷积网络可以很容易地扩展到具有很大宽度和高度的图像,以及处理大小可变的图像,循环网络可以扩展到更长的序列(比不基于序列的特化网络长得多)。大多数循环网络也能处理可变长度的序列。
从多层网络出发到循环网络,我们需要在模型的不同部分共享参数。参数共享使得模型能够扩展到不同形式的样本(这里指不同长度的样本)并进行泛化。当信息的特定部分会在序列内多个位置出现时,这样的共享尤为重要。考虑这两句话:“I went to Nepal in 2009’’ 和“In 2009, I went to Nepal.” 如果我们让一个机器学习模型读取这两个句子,并提取叙述者去Nepal的年份,无论 “2009年’’ 是作为句子的第六个单词还是第二个单词出现,我们都希望模型能认出 “2009年’’ 作为相关资料片段。假设我们要训练一个处理固定长度句子的前馈网络。传统的全连接前馈网络会给每个输入特征分配一个单独的参数,所以需要分别学习句子每个位置的所有语言规则。相比之下,循环神经网络在几个时间步内共享相同的权重,不需要分别学习句子每个位置的所有语言规则。
卷积的输出是一个序列,其中输出中的每一项是相邻几项输入的函数。参数共享的概念体现在每个时间步中使用的相同卷积核。循环神经网络以不同的方式共享参数。输出的每一项是前一项的函数。输出的每一项对先前的输出应用相同的更新规则而产生。
1、展开计算图
考虑动态系统的经典形式:
其中称为系统的状态。容易看出,这样的表达式是循环的。对有限时间步,次应用这个定义可以展开这个图。例如,我们展开,可以得到:
以这种方式重复应用定义,展开等式,就能得到不涉循环的表达。现在我们可以使用传统的有向无环计算图呈现这样的表达。
作为另一个例子,让我们考虑由外部信号驱动的动态系统:
可以看到,当前状态包含了整个过去序列的信息。为了表明状态是网络的隐藏单元,我们使用变量代表状态重写式:
展开计算图得到:
当训练循环网络根据过去预测未来时,网络通常要学会使用 作为过去序列(直到)与任务相关方面的有损摘要。此摘要一般而言一定是有损的,因为其映射任意长度的序列到一固定长度的向量 。根据不同的训练准则,摘要可能选择性地精确保留过去序列的某些方面。
2、循环神经网络
循环神经网络中一些重要的设计模式包括以下几种:
- 每个时间步都有输出,并且隐藏单元之间有循环连接的循环网络。
- 每个时间步都产生一个输出,只有当前时刻的输出到下个时刻的隐藏单元之间有循环连接的循环网络。
- 隐藏单元之间存在循环连接,但读取整个序列后产生单个输出的循环网络。
任何图灵可计算的函数都可以通过这样一个有限维的循环网络计算,在这个意义上图 10.3 的循环神经网络是万能的。
现在我们研究图10.3中RNN的前向传播公式。这个图没有指定隐藏单元的激活函数。我们假设使用双曲正切激活函数。此外,图中没有明确指定何种形式的输出和损失函数。我们假定输出是离散的,表示离散变量的常规方式是把输出作为每个离散变量可能值的非标准化对数概率。然后,我们可以应用softmax函数后续处理后,获得标准化后概率的输出向量。RNN 从特定的初始状态开始前向传播。从到的每个时间步,我们应用以下更新方程:
其中的参数的偏置向量和连同权重矩阵、和,分别对应于输入到隐藏、隐藏到输出和隐藏到隐藏的连接。这个循环网络将一个输入序列映射到相同长度的输出序列。
与序列配对的的总损失就是所有时间步的损失之和。例如,为
给定后的负对数似然,则
其中需要读取模型输出向量中对应于的项。
关于各个参数计算这个损失函数的梯度是计算成本很高的操作。梯度计算涉及执行一次前向传播(如在图 10.3 展开图中从左到右的传播),接着是由右到左的反向传播。运行时间是,并且不能通过并行化来降低,因为前向传播图是固有循序的。因此隐藏单元之间存在循环的网络非常强大但训练代价也很大。应用于展开图且代价为的反向传播算法称为通过时间反向传播(back-propagation through time, BPTT)。
2.1、导师驱动过程和输出循环网络
仅在一个时间步的输出和下一个时间步的隐藏单元间存在循环连接的网络(图10.4)确实没有那么强大(因为缺乏隐藏到隐藏的循环连接)。因为输出单元明确地训练成匹配训练集的目标,它们不太能捕获关于过去输入历史的必要信息,除非用户知道如何描述系统的全部状态,并将它作为训练目标的一部分。消除隐藏到隐藏循环的优点在于,任何基于比较时刻的预测和时刻的训练目标的损失函数中的所有时间步都解耦了。因此训练可以并行化,即在各时刻分别计算梯度。因为训练集提供输出的理想值,所以没有必要先计算前一时刻的输出。
由输出反馈到模型而产生循环连接的模型可用导师驱动过程(teacher forcing)进行训练。训练模型时,导师驱动过程不再使用最大似然准则,而在时刻接收真实值作为输入。我们可以通过检查两个时间步的序列得知这一点。条件最大似然准则是:
在这个例子中,同时给定迄今为止的序列和来自训练集的前一值,我们可以看到在时刻时,模型被训练为最大化的条件概率。因此最大似然在训练时指定正确反馈,而不是将自己的输出反馈到模型。如下图所示:
2.2、计算循环神经网络的梯度
这部分花书上的公式乱糟糟的,虽然作者说要给读者一些“直观”,但至少我看得很没有耐心,因为连配图都没有……只有一堆公式……所以这部分我选择放弃花书,通过查阅博客学习。以下来自this website:
首先RNN的一些计算公式如下(和花书表示稍有不同):
以为例,计算其对的偏导:
这里,表示外积。
可以看到只取决于当前时间步的值,但求的情况则不同:
注意这里是依赖于的,而又依赖于和。所以求导时我们不能把当作常数,而要再次利用链式法则:
从这里我们就能看出为什么BPTT训练的代价很大。
2.3、作为有向图模型的循环网络
将整个序列的联合分布分解为一系列单步的概率预测是捕获关于整个序列完整联合分布的一种方法。当我们不把过去的值反馈给下一步作为预测的条件时,那么有向图模型不包含任何从过去到当前的边。在这种情况下,输出与给定的序列是条件独立的。当我们反馈真实的值(不是它们的预测值,而是真正观测到或生成的值)给网络时,那么有向图模型包含所有从过去到当前的边。下图所示RNN完全图的解释基于排除并忽略模型中的隐藏单元。
举一个简单的例子,让我们考虑对标量随机变量序列建模的RNN,也没有额外的输入。在时间步的输入仅仅是时间步的输出。该RNN定义了关于变量的有向图模型。我们使用链式法则参数化这些观察值的联合分布:
因此,根据这样一个模型,一组值的负对数似然为:
其中:
图模型中的边表示哪些变量直接依赖于其他变量。许多图模型的目标是省略不存在强相互作用的边以实现统计和计算的效率。例如,我们通常可以作Markov假设,即图模型应该只包含从到的边,而不是包含整个过去历史的边。然而,在一些情况下,我们认为整个过去的输入会对序列的下一个元素有一定影响。当我们认为的分布可能取决于遥远过去 (在某种程度) 的的值,且无法通过捕获的影响时,RNN将会很有用。
更有趣的是,将隐藏单元视为随机变量,从而产生RNN的图模型结构。在图模型中包括隐藏单元预示 RNN 能对观测的联合分布提供非常有效的参数化。如下图所示:
在图模型中结合节点可以用作过去和未来之间的中间量,从而将它们解耦。遥远过去的变量可以通过其对的影响来影响变量。该图的结构表明可以在时间步使用相同的条件概率分布有效地参数化模型,并且当观察到全部变量时,可以高效地评估联合分配给所有变量的概率。
在循环网络中使用的参数共享的前提是相同参数可用于不同时间步的假设。也就是说,假设给定时刻的变量后,时刻变量的条件概率分布是平稳的(stationary),这意味着之前的时间步与下个时间步之间的关系并不依赖于。原则上,可以使用作为每个时间步的额外输入,并让学习器在发现任何时间依赖性的同时,在不同时间步之间尽可能多地共享。相比在每个使用不同的条件概率分布已经好很多了,但网络将必须在面对新时进行推断。
2.4、基于上下文的RNN序列建模
之前,我们已经讨论了将的向量序列作为输入的RNN。另一种选择是只使用单个向量作为输入。当是一个固定大小的向量时,我们可以简单地将其看作产生序列RNN的额外输入。将额外输入提供到RNN的一些常见方法是:
在每个时刻作为一个额外输入
作为初始状态
结合两种方式
第一个也是最常用的方法如下图所示:
输入和每个隐藏单元向量之间的相互作用是通过新引入的权重矩阵参数化的,这是只包含序列的模型所没有的。同样的乘积在每个时间步作为隐藏单元的一个额外输入。我们可以认为的选择(确定值),是有效地用于每个隐藏单元的一个新偏置参数。权重与输入保持独立。
RNN还可以接收向量序列作为输入,而不是仅接收单个向量作为输入。我们可以在时刻的输出到时刻的隐藏单元添加连接,该模型就可以代表关于序列的任意概率分布。
3、双向RNN
在许多应用中,我们要输出的的预测可能依赖于整个输入序列。例如,在语音识别中,由于协同发音,当前声音作为音素的正确解释可能取决于未来几个音素,甚至潜在的可能取决于未来的几个词,因为词与附近的词之间的存在语义依赖:如果当前的词有两种声学上合理的解释,我们可能要在更远的未来(和过去)寻找信息区分它们。这在手写识别和许多其他序列到序列学习的任务中也是如此。
双向循环神经网络(双向RNN)为满足这种需要被发明 (Schuster and Paliwal,1997)。他们在需要双向信息的应用中非常成功 (Graves, 2012)。
顾名思义,双向RNN结合时间上从序列起点开始移动的RNN和另一个时间上从序列末尾开始移动的RNN。下图是一个典型的双向RNN,其中代表通过时间向前移动的子RNN的状态,代表通过时间向后移动的子 RNN的状态。这允许输出单元能够计算同时依赖于过去和未来且对时刻的输入值最敏感的表示,而不必指定周围固定大小的窗口。
4、基于编码-解码的序列到序列架构
上面讨论的RNN都是将一个序列映射到另一个等长序列。如何训练RNN,使其将输入序列映射到不一定等长的输出序列呢?这在许多场景中都有应用,如语音识别、机器翻译,其中训练集的输入和输出序列的长度通常不相同(虽然它们的长度可能相关)。
用于映射可变长度序列到另一可变长度序列最简单的RNN架构最初由Choet al. (2014a) 提出,之后不久由Sutskever et al. (2014) 独立开发,并且第一个使用这种方法获得翻译的最好结果。前一系统是对另一个机器翻译系统产生的建议进行评分,而后者使用独立的循环网络生成翻译。这些作者分别将该架构称为编码-解码或序列到序列架构,如下图所示:
这个想法非常简单:
(1)编码器(encoder)或读取器(reader)或输入(input)RNN处理输入序列。编码器输出上下文(通常是最终隐藏状态的简单函数)。
(2)解码器(decoder)或写入器(writer) 或输出(output)RNN则以固定长度的向量(如图10.9)为条件产生输出序列。
这种架构对比本章前几节提出的架构的创新之处在于长度和可以彼此不同,而之前的架构约束。在序列到序列的架构中,两个RNN共同训练以最大化(关于训练集中所有和对的平均)。编码器RNN的最后一个状态通常被当作输入的表示并作为解码器RNN 的输入。
5、深度循环网络
大多数RNN中的计算可以分解成三块参数及其相关的变换:
从输入到隐藏状态
从前一隐藏状态到下一隐藏状态
从隐藏状态到输出
根据图10.3中的RNN架构,这三个块都与单个权重矩阵相关联。换句话说,当网络被展开时,每个块对应一个浅的变换。能通过深度MLP内单个层来表示的变换称为浅变换。通常,这是由学成的仿射变换和一个固定非线性表示组成的变换。
Graves et al. (2013) 第一个展示了将 RNN 的状态分为多层的显著好处,如下图。我们可以认为,在图10.13 (a)所示层次结构中较低的层起到了将原始输入转化为对更高层的隐藏状态更合适表示的作用ascanu et al. (2014a) 更进一步提出在上述三个块中各使用一个单独的 MLP(可能是深度的),如图10.13 (b)所示。考虑表示容量,我们建议在这三个步中都分配足够的容量,但增加深度可能会因为优化困难而损害学习效果。
6、递归神经网络
递归神经网络代表循环网络的另一个扩展,它被构造为深的树状结构而不是RNN的链状结构,因此是不同类型的计算图。递归网络的典型计算图如图所示。
递归网络已成功地应用于输入是数据结构的神经网络 (Frasconiet al., 1997, 1998),如自然语言处理 (Socher et al., 2011a,c, 2013a) 和计算机视觉(Socher et al., 2011b)。
递归网络的一个明显优势是,对于具有相同长度的序列,深度(通过非线性操作的组合数量来衡量)可以急剧地从减小为,这可能有助于解决长期依赖。
7、长期依赖的挑战
学习循环网络长期依赖的根本问题是,经过许多阶段传播后的梯度倾向于消失(大部分情况)或爆炸(很少,但对优化过程影响很大),即使我们假设循环网络是参数稳定的(可存储记忆,且梯度不爆炸),但长期依赖的困难来自比短期相互作用指数小的权重(涉及许多Jacobian相乘)。
循环网络涉及相同函数的多次组合,每个时间步一次。这些组合可以导致极端非线性行为,如图所示。
这个问题是针对循环网络的。在标量情况下,想象多次乘一个权重。该乘积消失还是爆炸取决于的幅值。然而,如果每个时刻使用不同权重非循环网络,情况就不同了。如果初始状态给定为1,那么时刻的状态可以由给出。假设的值是随机生成的,各自独立,且有0均值方差。乘的方差就为。为了获得某些期望的方差,我们可以选择单个方差为权重。因此,非常深的前馈网络通过精心设计的比例可以避免梯度消失和爆炸问题,如 Sussillo (2014) 所主张的。
8、克服长期依赖的方法
花书上接下来的内容主要介绍克服长期依赖问题的方法。这部分内容因为书上也没有细讲,所以这里只是记录下各模型的大致思想。
8.1、回声状态网络
从到的循环权重映射以及从到的输入权重映射是循环网络中最难学习的参数。避免这种困难的方法是设定循环隐藏单元,使其能很好地捕捉过去输入历史,并且只学习输出权重。 回声状态网络(echo state network)独立地提出了这种想法。
ESN被称为储层计算(reservoir computing)(Lukoševičius and Jaeger, 2009),因为隐藏单元形成了可能捕获输入历史不同方面的临时特征池。
储层计算循环网络类似于核机器,这是思考它们的一种方式:它们将任意长度的序列(到时刻的输入历史)映射为一个长度固定的向量(循环状态),之后可以施加一个线性预测算子(通常是一个线性回归)以解决感兴趣的问题。
8.2、渗漏单元和其他多时间尺度的策略
处理长期依赖的一种方法是设计工作在多个时间尺度的模型,使模型的某些部分在细粒度时间尺度上操作并能处理小细节,而其他部分在粗时间尺度上操作并能把遥远过去的信息更有效地传递过来。
增加从遥远过去的变量到目前变量的直接连接是得到粗时间尺度的一种方法。梯度可能关于时间步数呈指数消失或爆炸。(Linet al., 1996) 引入了延时的循环连接以减轻这个问题。现在导数指数减小的速度与相关而不是。既然同时存在延迟和单步连接,梯度仍可能成指数爆炸。这允许学习算法捕获更长的依赖性,但不是所有的长期依赖都能在这种方式下良好地表示。
获得导数乘积接近 1 的另一方式是设置线性自连接单元,并且这些连接的权重接近 1。
我们对某些值应用更新累积一个滑动平均值 ,其中是一个从到线性自连接的例子。当接近 1 时,滑动平均值能记住过去很长一段时间的信息,而当接近 0,关于过去的信息被迅速丢弃。线性自连接的隐藏单元可以模拟滑动平均的行为。这种隐藏单元称为渗漏单元(leaky unit)。
处理长期依赖另一种方法是在多个时间尺度组织RNN状态的想法 (El Hihi and Bengio, 1996),信息在较慢的时间尺度上更容易长距离流动。这个想法与之前讨论的时间维度上的跳跃连接不同,因为它涉及主动删除长度为一的连接并用更长的连接替换它们。以这种方式修改的单元被迫在长时间尺度上运作。而通过时间跳跃连接是添加边。收到这种新连接的单元,可以学习在长时间尺度上运作,但也可以选择专注于自己其他的短期连接。
8.3、长短期记忆和其他门控RNN
实际应用中最有效的序列模型称为门控RNN(gated RNN)。包括基于长短期记忆(long short-term memory)和基于门控循环单元(gated recurrent unit)的网络。
引入自循环的巧妙构思,以产生梯度长时间持续流动的路径是初始长短期记忆(long short-term memory, LSTM)模型的核心贡献 (Hochreiter and Schmidhuber,1997)。其中一个关键扩展是使自循环的权重视上下文而定,而不是固定的 (Gerset al., 2000)。门控此自循环(由另一个隐藏单元控制)的权重,累积的时间尺度可以动态地改变。在这种情况下,即使是具有固定参数的LSTM,累积的时间尺度也可以因输入序列而改变,因为时间常数是模型本身的输出。