这篇文章可以参考:

循环神经网路?

zybuluo.com
图标

前面探讨了前馈神经网路及其在神经语言模型和文本分类中的应用。在语言模型的例子中,我们看到这样的网路可以被训练成在给定前一个单词有限上下文的序列中预测下一个单词,这种方法让人想起马尔可夫语言建模方法。这些模型通过接受一个固定大小的令牌窗口作为输入来运行;较长的序列是通过在输入上滑动这个窗口进行增量预测来处理的,最终的结果是跨越输入的一系列预测。图9.1演示了这种方法,窗口大小为3。在这里,我们预测下一个单词会出现在窗户下面。接下来的单词是通过将窗口向前滑动一个单词来预测的。

不幸的是,滑动窗口方法有很多问题。首先,它具有马尔可夫方法的主要弱点,因为它限制了可以从中提取信息的上下文;上下文窗口之外的任何内容都不会影响正在作出的决策。这是有问题的,因为有许多语言任务需要访问信息,而这些信息可以任意地远离正在处理的点。其次,窗口的使用使得网路难以学习由选区等现象引起的系统模式。举个例子,在图9.1中这句话the ground在不同的窗口中出现两次:一次,如图所示,在第一和第二位置的窗口,在前面的步骤中第二和第三个插槽,因此迫使网路学习两种不同的模式单一成分。本章的主题是递归神经网路,这是一类通过将序列显式地处理为序列来解决这些问题的网路,允许我们处理可变长度的输入,而不需要使用任意固定大小的窗口。

递归神经网路是指在网路连接中包含一个循环的网路。也就是说,一个单元的值直接或间接地依赖于它自己作为输入的输出的任何网路。一般来说,这样的网路很难推理和训练。然而,在一般的递归网路中,有一些受约束的体系结构,它们在应用于语言问题时被证明是非常有用的。在本节中,我们将介绍一类称为简单递归网路(SRNs)或Elman网路的递归网路。这些网路本身是有用的。9.2抽象地说明了SRN的循环结构。与普通的前馈网路一样,表示当前输入元素xt的输入向量乘以一个权重矩阵,然后通过一个激活函数来计算一层隐藏单元的激活值。这个隐藏层依次用于计算相应的输出yt。序列是通过每次向网路显示一个元素来处理的。与feedht的关键区别

Elman之后的简单递归神经网路(Elman, 1990)。隐藏层包含一个循环连接作为其输入的一部分。也就是说,隐藏层的激活值取决于当前输入以及前一个时间步中隐藏层的激活值。

正向网路位于图中用虚线表示的循环链路上。该链接使用隐藏层在前一点的激活值来增加到隐藏层的输入前一个timestep中的隐藏层提供了一种内存或上下文形式,用于编码早期处理并通知在稍后的时间点要做出的决策。重要的是,体系结构不会对前面的上下文施加固定长度限制;前一隐藏层中包含的上下文包含扩展到序列开头的信息。添加这个时间维度使得循环网路看起来比非循环体系结构更加奇特。但实际上,它们并没有那么大的不同。给定一个输入向量和前一个时间步的隐含层的值,我们仍然执行标准的前馈计算。要了解这一点,请考虑图9.3,它阐明了递归式的性质,以及它是如何影响隐层的计算的。最重要的增加在于新的权重集U,它将前一个时间步的隐藏层连接到当前隐藏层。这些权重决定了网路在计算当前输入的输出时应该如何利用过去的上下文。与网路中的其他权重一样,这些连接将通过反向传播进行训练。

Inference in Simple RNNs

SRN中的正向推理(将输入序列映射为输出序列)与我们已经看到的前馈网路几乎相同。为了要计算输入xt的输出yt,我们需要隐层ht的激活值。为了计算这个值,计算输入的点积xt的权重矩阵W,和隐藏的点积层从之前的时间步 h_{t-1} 与权重矩阵V,我们把这些值加起来,他们通过一个合适的激活函数,g,到达当前的激活值隐藏层,ht。一旦我们得到了隐藏层的值,我们就进行通常的计算来生成输出向量。

在通常遇到的软分类情况下,查找yt由一个「softmax」计算组成,该计算为可能的输出类提供一个规范化的概率分布。

简单递归网路的时序性可以通过及时展开网路来说明,如图9.4所示。在这样的图中,每个时间步骤都复制了不同层次的单元,以说明它们会随著时间的推移而具有不同的值。然而,权重本身在不同的时间步骤中共享。最后,时间t的计算需要时间t1的隐含层的值,这就要求从序列的开始到结束采用增量推理演算法,如图9.5所示。

Training

正如我们在前馈网路中所做的那样,我们将使用训练集、损失函数和反向传播来调整这些递归网路中的权重集。如图9.3所示,我们现在有3组权值需要更新:W,从输入层到隐藏层的权值:U,从前一层到当前隐藏层的权值,最后V,从隐藏层到输出层的权值。在继续之前,让我们先回顾一下一些符号。假设一个网路有一个输入层x和一个非线性的激活函数g,我们将用一个 a^{[i]} 来表示来自第i层的激活值,这是将g应用到该层输入的加权和 z^{[i]} 的结果。一个简单的两层前馈网路,将W和V分别作为第一组和第二组权值,其特征如下:

图9.4说明了我们在前馈网路中不用担心反向传播的两个注意事项。首先,要计算t时刻输出的损失函数,我们需要t-1时刻的隐层。其次,t时刻的隐含层同时影响t时刻的输出和t+1时刻的隐含层(从而影响t+1时刻的输出和损失)由此可见,要评估 h_t 产生的误差,我们需要知道它对当前输出和下一个输出的影响。考虑我们在图9.4中所示的情况,在时间2检查输入/输出对。我们需要计算什么梯度来更新权重U,V和W ?让我们首先回顾一下如何计算更新V所需的梯度(此计算与前馈网路相同)。为了复习第7章,我们需要计算损失函数L对权重v的导数。然而,由于损失不是直接用权重表示的,我们使用链式法则来间接地得到它。

第一项就是损失函数的导数对网路输出,也就是输出的激活层。第二项是网路输出的导数对中间网路激活z,这是一个功能的激活函数g我们的应用程序的最后一个任期链式法则的导数是网路激活对权重V,也就是当前隐藏层 h_t 的激活值。

在这里,使用前两个术语来定义 delta 是很有用的,delta 是一个损失项,表示标量损失中有多少是由输出层中的每个单元引起的。

因此,我们需要更新权值矩阵V的最终梯度为:

继续,我们需要为权重矩阵计算相应的梯度W和U:

误差在SRN中的反向传播。ti向量表示训练数据序列中每个元素的目标。红色箭头显示了计算U、V和W在第2时刻的更新所需的反向传播误差流。汇聚在h2上的两个入射箭头表示需要对这些误差进行求和。

在这里,我们遇到了来自前馈网路的第一个实质性变化。t时刻的隐藏状态会导致t时刻的输出和相关误差,以及t+1时刻的输出和误差。因此,隐含层的误差项 delta _h 必须是当前输出的误差项和下一个时间步的误差项之和。

给定这个隐含层的总误差项,我们可以用链式法则计算权重U和W的梯度:

这些梯度为我们提供了通过普通反向传播更新矩阵U和W所需的信息

我们尚未完成,我们仍然需要将比例权重(计算误差项)分配回先前的隐藏层 h_{t-1} 以用于进一步处理:

函数BACKPROPTHROUGHTIME(sequence, network)返回用于权重更新的梯度
前向传递以收集损失
后向传递计算误差项并评估

通过时间反向传播训练。正向传递在每个时间步长计算所需的损失值。后向传递使用前向传递的值计算梯度。

这涉及到根据U中的权重按比例将误差从 delta _h 反向传播到 h_{t-1}

此时,我们已经拥有了为三组权重中的每一组执行权重更新所需的所有梯度。注意,在这个简单的例子中,不需要将误差通过W反向传播到输入x,因为假设输入的训练数据是固定的。如果我们希望更新我们的输入字或字元嵌入,我们也会将误差反向传播到它们。我们将在9.5节中进一步讨论这个问题。综上所述,所有这些考虑导致了在SRNs中训练权重的两步演算法。在第一个步骤中,我们执行正向推理,计算ht、yt和每一步的时间损失,保存每一步隐藏层的值,以备下一个步骤使用。在第二阶段,我们反向处理序列,计算所需的误差项梯度,计算并保存误差项,以便在每一步后退时在隐藏层中使用。不幸的是,为序列的每一项分别计算梯度和更新权重将非常耗时。相反,就像我们在第7章中使用的小批量训练一样,我们将在序列上增量地积累权重的梯度,然后使用这些累积的梯度执行权重更新。

Deep Networks: Stacked and Bidirectional RNNs

递归网路实际上是非常灵活的。将展开计算图的前馈特征与向量作为公共输入和输出相结合,可以将复杂网路视为模块,并以创造性的方式进行组合。介绍在使用RNNs进行语言处理时使用的两种比较常见的网路体系结构。

Stacked RNNs

到目前为止,在我们的示例中,RNNs的输入由单词或字元嵌入序列(向量)组成,而输出则是用于预测单词、标记或序列标签的向量。然而,没有什么能阻止我们使用从一个RNN到另一个RNN的整个输出序列作为输入序列。堆叠的RNNs由多个网路组成,其中一层的输出作为下一层的输入,如图9.10所示。堆叠的RNNs由多个网路组成,其中一层的输出作为下一层的输入,如图9.10所示。

堆叠的循环网路。 较低层的输出用作较高层的输入,最后一个网路的输出用作最终输出

在许多任务中已经证明,堆叠的RNNs可以胜过单层网路。这种成功的一个原因与网路能够在不同的抽象层上诱导表示有关。就像人类视觉系统的早期阶段检测到边缘,然后用于寻找更大的区域和形状一样,堆叠网路的初始层可以诱导表示,作为进一步层表示的有用抽象,而进一步层表示可能证明很难在单个RNN中诱导。

双向RNNs

在一个简单的递归网路中,给定时刻t的隐藏状态表示网路所知道的关于序列到该时刻的所有信息。也就是说,在t时刻的隐藏状态是一个函数的结果,这个函数的输入从开始到t时刻。我们可以把它看作是当前时间左边网路的上下文

其中 h_{t}^{forward} 对应于t时刻的正常隐藏状态,表示网路从序列到该点所收集到的所有信息(从0到t时刻)。当然,在基于文本的应用程序中,我们可以同时访问整个输入序列。我们可能会问,利用当前输入右侧的上下文是否也有帮助。恢复这类信息的一种方法是使用我们讨论过的同一种网路,按照输入序列反向训练一个递归网路。使用这种方法,t时刻的隐藏状态现在表示关于当前输入右侧序列的信息。

这里,隐藏状态 h_{t}^{backward} 表示从t到序列末尾我们所知道的关于序列的所有信息。将这些网路放在一起就得到了一个双向的RNN。Bi-RNN由两个独立的递归网路组成,一个是从头到尾处理输入,另一个是从尾到头处理输入。然后,我们可以将两个网路的输出组合成一个单一的表示,该表示在每个时间点同时捕获输入的左上下文和右上下文。在向前和向后方向上训练独立的模型,正向计算和反向计算不共享权重,两个模型训练完成以后再融合模型,最终的输出取决于正向和反向计算的加和

Figure 9.11 一个双向RNN。在向前和向后方向上训练独立的模型,每个模型在每个时间点的输出连接起来表示在那个时间点的状态。围绕著正向和反向网路的盒子强调了这个架构的模块化本质。

图9.11说明了一个双向网路,其中前向和后向传递的输出被连接在一起。 组合前向和后向上下文的其他简单方法包括逐元素加法或乘法。 因此,每个时间步的输出捕获当前输入的左侧和右侧的信息。在序列标记应用中,这些串联的输出可以作为局部标记决策的基础。

双向RNNs也被证明是非常有效的序列分类。从图9.10可以看出,对于序列分类,我们使用RNN的最终隐藏状态作为后续前馈分类器的输入。这种方法的一个困难之处在于,最终状态自然地反映了更多关于句子结尾的信息,而不是句子开头的信息。双向RNNs为这一问题提供了一个简单的解决方案;如图9.12所示,我们简单地将前向和后向传递的最终隐藏状态组合起来,并将其作为后续处理的输入。同样,连接是组合这两个输出的常用方法,但也使用元素级别的求和、乘法或平均。

LSTMs and GRUs

可参考这篇文章:

LSTM?

zybuluo.com
图标

在实践中,要训练简单的rns来完成需要网路利用远离当前处理点的信息的任务是相当困难的。尽管可以访问前面的整个序列,但以隐藏状态编码的信息往往是相当局部的(梯度消失),与输入序列的最新部分和最近的决策更相关。然而,通常情况下,远程信息对许多语言应用程序来说是至关重要的。

Figure 9.12 一种用于序列分类的双向RNN。前向和后向传递的最后隐藏单元组合起来表示整个序列。这个组合表示作为后续分类器的输入。

在语言模型的上下文中考虑以下示例

(9.8) The flights the airline was cancelling were full.

为「was」后面的「airline」分配高概率是很简单的,因为was为单一协议提供了强大的本地上下文。然而,给「were」分配一个合适的概率是相当困难的,这不仅是因为复数的「flights」相当遥远,而且因为更近的上下文包含单数成分。理想情况下,网路应该能够保留关于多个「航班」的远程信息,直到需要时,同时正确处理序列的中间部分。

SRN无法传递关键信息的一个原因是SRN中的隐藏层,以及确定隐藏层中的值的权重,被要求同时执行两个任务:提供对在当前上下问下做出决定,并更新和推进对未来决策有用的信息。成功训练简单循环网路的第二个困难来自于需要通过隐藏层反向传播训练误差。由于t时刻的隐含层参与了计算,所以会影响下一个时间步的损失。因此,在训练的后向遍历过程中,隐层会受到重复的点积的影响,由序列的长度决定这个过程的一个常见结果是梯度要么被驱动到零要么饱和。分别称为消失梯度或爆炸梯度的情况。为了解决这些问题,设计了更复杂的网路体系结构来显式地管理随时间推移维护上下文信息的任务。这些方法将上下文视为一种需要显式管理的内存单元。更具体地说,网路需要忘记不再需要的信息,并根据以后的决策需要记住信息。

Long Short-Term Memory

图9.13 单个LSTM内存单元显示为计算图形

长短时记忆(LSTM)网路将上下文管理问题分为两个子问题:从上下文中删除不再需要的信息,以及添加可能需要用于以后决策的信息。该方法的关键是学习如何管理此上下文,而不是将策略硬编码到体系结构中。LSTMs通过使用专门的神经单元来实现这一点,这些神经单元使用控制信息进出组成网路层的单元的门。这些门是通过使用在上下文层上按顺序操作的附加权重集来实现的。

可改为:

简单记为:ifog,ct

Figure 9.14 用于前馈、简单递归网路(SRN)、长短时记忆(LSTM)和门递归单元的基本神经单元。

GRUs(门控递归单元)

虽然LSTMs相对容易部署,但它为我们的网路引入了大量的参数,因此带来了更大的训练负担。门控循环单元(GRUs)试图通过将LSTMs的遗忘和添加门折叠到一个具有一组权重的更新门中来减轻这种负担

可简单记为:rzhh

参考:

零基础入门深度学习(7) - 递归神经网路?

zybuluo.com
图标

LSTMs和GRUs中使用的神经单元明显比基本的前馈网路复杂得多。幸运的是,这种复杂性在很大程度上被封装在基本的处理单元中,允许我们维护模块性,并可以轻松地尝试不同的体系结构。要了解这一点,请考虑图9.14,它说明了与每种单元相关的输入/输出和权重。在最左边,(a)是基本的前馈单元h = g(Wx+b)。一个单独的权重集和一个单独的激活函数决定了它的输出,当排列在一个层中时,层中的单元之间没有连接。接下来,(b)表示SRN中的单元。现在有两个输入和附加的权重。但是,仍然有一个单独的激活函数和输出。当设置为一个层时,每个单元的隐藏层作为下一个单元的输入。幸运的是,LSTM和GRU单元增加的复杂性封装在单元本身中。除了基本经常性单位(b)之外,唯一额外的外部复杂性是额外的上下文向量输入和输出的存在。这种模块化是LSTM和GRU单元强大和广泛应用的关键。具体来说,LSTM和GRU单元可以替换到第9.3节中描述的任何网路架构中。而且,与SRNs一样,利用门控单元的多层网路可以展开成深度前馈网路,并按照通常的方式进行反向传播训练。

序列标记RNN,它接受用字元级词嵌入增强的分散式词嵌入。

Words, Characters and Byte-Pairs(单词、字元和位元组对)

到目前为止,我们假设网路的输入要么是预先训练的,要么是经过训练的单词嵌入。正如我们所看到的,基於单词的嵌入非常善于发现单词之间的分布(语法和语义)相似性。然而,任何基於单词的方法都存在一些重要的问题:

  • 对于某些语言和应用程序,词典实在太大,无法实际地将每个可能的单词表示为嵌入。需要一些用更小的比特组成单词的方法。
  • 无论辞汇量有多大,我们总是会遇到一些不认识的单词,这是由于新单词进入语言,拼写错误和从其他语言中借用
  • 对于许多应用程序来说,低於单词级别的形态学信息显然是一个重要的信息来源。基於单词的方法对这种规则视而不见。
Figure 9.16 Bi-RNN接受单词字元序列,并发出从序列的正向和反向传递派生的嵌入。网路本身是在一个更大的终端应用程序上下文中训练的,在这个应用程序中,损失将一直传播到字元向量嵌入。

我们可以通过使用来自组成单词的字元(一个又一个的字母)的嵌入来扩展输入单词表示,从而克服其中的一些问题。图9.15说明了词性标注上下文中的一种方法。图的上部由一个RNN组成,它接受一个输入序列,并为输入的每个元素在标记上输出一个softmax分布。注意,这个RNN可以是任意复杂的,由堆叠和/或双向网路层组成。这个网路的输入由普通的单词嵌入组成,其中包含丰富的字元信息。具体地说,每个输入由普通单词嵌入的连接和双向RNN派生的嵌入组成,双向RNN接受每个单词的字元序列作为输入,如图下半部分所示。输入中每个单词的字元序列通过一个双向RNN运行,该RNN由两个独立的RNNs组成,一个处理从左到右的序列,另一个处理从右到左的序列。将从左到右和从右到左网路的最终隐藏状态连接起来,表示每个单词的复合字元级表示。关键是,这些字元嵌入是在整个任务的上下文中训练的;词性「softmax」层的损失会一直传播到字元嵌入。

推荐阅读:

相关文章