Skip to content

NLP与循环神经网络 - 了解

前言

CNN 等传统神经网络的局限在于:将固定大小的向量作为输入(比如一张图片),然后输出一个固定大小的向量(比如不同分类的概率)。其实在图像处理中,相邻的像素点大概率互相关联,因为它们描述的都是同一个物体的一部分。

但是在文本中,尤其是在一个句子中,前一个单词对于当前单词的词性推断其实是有很大影响的,例如:

  • 我要去游戏了。(「游戏」一词是动词)
  • 这个游戏很好玩。(「游戏」一词是名词)

并且句子中每个单词的词性、表达的含义也远比图像复杂得多,例如“水份”一词放在不同的场景下表达的意思也不同,不像计算机视觉一样直观。

也就是说,在传统的卷积神经网络中,输入和输出都是相对确定的,卷积核被设定好大小以后,其对整个图像的每个像素都适用,并且上一个输出结果对下一个输出结果没有任何影响。

但是在文本中,当我们理解一句话的意思时,孤立理解每个单词的意思是不够的,我们需要处理的是这些词语连接起来的完整内容。

一般的,在自然语言处理领域,我们的文本信息都是时间序列数据。所谓时间序列数据,是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度。

因此,在使用传统神经网络处理自然语言时,我们会遇到如下几个问题:

  • 输入和输出长度不定:输入文本序列和输出的文本序列不可能是等长的;
  • 不同位置的词信息学到的特征不共享:比如有这样一个文本序列「卡拉是条狗」和「有一条狗叫卡拉」。其中,「卡拉」是一个名字,但是出现在不同的地方,即使模型能够学习识别出第一个是名字,但一旦换了位置,模型可能就无法识别出其含义,要重新去学习。
  • 参数量巨大,隐藏层参数过多:输入网络的特征,往往是 one-hot(独热编码)或者 embedding 向量,维度过大。如果输入文本序列过长,则导致向量巨大,致使隐藏层参数过多,增加计算复杂度。
  • 无法提现出时序上的“前因后果”:训练的数据没办法体现出特征的前因后果。

因此,当我们在理解一句话意思时,孤立的理解这句话的每个词不足以理解整体意思,我们通常需要处理这些词连接起来的整个序列; 当我们处理视频的时候,我们也不能只单独的去分析每一帧,而要分析这些帧连接起来的整个序列。为了解决一些这样类似的问题,能够更好的处理序列的信息,RNN 就由此诞生了。

一、词向量与独热编码

1、通俗解释

词向量表示是将自然语言文本转换为计算机可以处理的向量形式。

一般的词向量表示,就是独热编码。

假设词典中有 5 个单词,分别是:apple、bag、cat、dog 和 elephant。那么,通过独热编码的方式表示词向量,就如下所示:

单词1 列2 列3 列4 列5 列
apple10000
bag01000
cat00100
dog00010
elephant00001

用向量表示如下所示: 每一个维度对应一个单词

但是,通过独热编码来描述单词,会有一些问题:

  • 单词不断增加,则向量维度也随之增加;
  • 组成的矩阵稀疏。

在词向量表示中,通常会使用 词袋模型(Bag of Words Model)或者分布式表示(Distributional Representation) 等方法。

其中,分布式表示方法是一种由 Geoffrey Hinton 提出的技术,它通过在大规模语料库上训练神经网络来实现词向量的表示。语义分析关注句子的意义,其目标是将自然语言表示转换为一种计算机可以理解的形式。这通常涉及实体识别、关系抽取和指代消解等任务。在语义分析中,通常会使用词向量的平均值、加权平均值或者递归神经网络(Recursive Neural Network)等方法来表示句子的语义信息。

二、RNN 概述

循环神经网络(Recurrent Neural Networks, RNN) ,也叫递归神经网络。是一种常用的神经网络结构,它源自于 1982 年由 Saratha Sathasivam 提出的霍普菲尔德网络,其主要对序列数据进行建模(序列数据可以是音频,文本等)

RNN 之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。

在上图中,神经网络 A(包含若干层)的输入向量位 xt ,输出向量为 ht ,把神经网络 A 看作一个函数 f ,其中的权重为 W ,那么 RNN 本质上就是一个递推函数:

它允许许网络将这一步的输出传递到下一步作为输入。可能有点难理解,其实它和普通的神经网络没什么不同。可以把递归神经网络看作同一个神经网络的多个副本,每个副本的输入都不同,而且前一个副本的输出也会作为后一个副本的输入。

把递归神经网络展开来看就如下所示:

为神经网络 A 完全相同,所以在实现的时候只需要实现一个神经网络即可。这种链式结构表示了递归神经网络用于序列形式的数据,每一步就输入序列的不同元素,即执行一个副本。

理论上,RNN 能够对任何长度的序列数据进行处理。但是在实践中,为了降低复杂性往往假设当前的状态只与前面的几个状态相关。其特有的循环概念及其最重要的结构——长短时记忆网络,使得它在处理和预测序列数据的问题上有着良好的表现。

传统神经网络(包括 CNN),输入和输出都是互相独立的。

但有些任务,后续的输出和之前的内容是相关的。例如:我是中国人,我的母语是__。这是一道填空题,需要依赖之前的输入。

RNN 引入“记忆”的概念,也就是输出需要依赖之前的输入序列,并把关键输入记住。循环来源于其每个元素都执行相同的任务。它并⾮刚性地记忆所有固定长度的序列,而是通过隐藏状态来存储之前时间步的信息。

RNN 跟传统神经网络最大的区别在于每次都会将前一次的输出结果,带到下一次的隐藏层中,一起训练。如下图所示:

三、基本结构

基本循环神经网络结构:一个输入层、一个隐藏层和一个输出层

  • x:输入层的值
  • s:隐藏层的值
  • o:输出层的值
  • U:输入层到隐藏层的权重矩阵
  • V:隐藏层到输出层的权重矩阵
  • W:隐藏层到隐藏层的权重矩阵

循环神经网络的隐藏层的值 s 不仅仅取决于当前这次的输入 x ,还取决于上一次隐藏层的值 s 。

权重矩阵 W 就是隐藏层上一次的值作为这一次的输入的权重。

把上图展开来,就是如下的形式:

上图中,各个表示如下所示:

  • xt:代表不同时间序列下的输入;
  • ot:代表不同序列下的输出;
  • st:代表当前序列下的中间状态,也就是隐藏状态输出,会传递到下一时刻;
  • O:代表隐藏层的一个 Cell Unit(细胞单元);
  • U/V/W:所有单元的权重参数共享

举个简单的例子,有一个输入文本时I Love You!,那么:

  • xt1代表的就是单词I的向量;
  • xt代表的就是单词Love的向量;
  • xt+1 代表的就是单词You的向量;
  • ......

权重矩阵 W 在每个序列时刻都是不变的。我们注意到,RNN 之所以可以解决序列问题,是因为它可以记住每一时刻的信息,每一时刻的隐藏层不仅由该时刻的输入层决定,还由上一时刻的隐藏层决定

初始状态下:

然后,st 的计算如下所示,当前时刻的输入和上一时刻的中间状态,通过激活函数 f 得到,计算公式如下:

最后,输出层通过中间状态 st 通过激活函数 g 计算得到,公式如下:

其中,ot 代表 t 时刻的输出,st 代表 t 时刻的隐藏层的值( st 的取值不仅仅取决于当前序列的输入 xt ,还取决于上一个细胞状态 st1)。f 为激活函数,一般是 tanh、relu,g 也是激活函数,一般为 sigmoid、softmax。

所以,我们可以把 ot 计算分解开来。

t 时刻的输出 ot 的值,是受前面历次输入值 xtxt1xt+1...的影响的。

值得注意的一点是,在整个训练过程中,每一时刻所用的都是同样的 U\V\W 矩阵

四、数学推导 - 可忽略

4.1 矩阵运算表示


例如一句话「我昨天上学迟到了」,输入到网络当中的是一个个分词结果,每个词的输入都是一个时刻。

通常,s0 时刻,输入是一个开始的标识符号Start,最后一个时刻 s6,隐层状态输出是一个结束符号End

而且,每个词语都是以词向量的形式输入。

对于网络中 t 时刻的公式中,中间状态 st 的表示如下(可忽略偏置 ba,激活函数使用 Relu):

那么,我们就能够得到如下矩阵公式:

矩阵 U 的维度是 n × m,矩阵 W 的维度是 n x n,其中 m 是词向量的维度,n 表示输入 s 的维度(可人为指定的一个长度,用来指定细胞状态的输出大小)。

输出值 ot 的标识如下(可忽略偏置 by ,激活函数使用 Softmax):

那么,我们就能够得到如下矩阵公式:

矩阵 V 的维度是 m×n,这样输出的结果就是一个 m 维度的词向量。

4.2 交叉熵损失

如果要训练 RNN 网络,则需要定义其损失,对于 RNN 网络,我们将损失函数定义为标准的逻辑回归损失(即交叉熵损失)

总损失的定义是:一整个序列(一个句子)作为训练实例,总误差就是各个时刻词的误差之和

对于一个序列中的一个词,其交叉熵损失的计算公式如下所示:

其中,ot表示 t 时刻上输出正确的词,ot^ 表示 t 时刻上预测出来的词。

那么,最终的交叉熵损失为如下的求和:

然后,通过反向传播的方式来计算模型中的参数,并使用梯度下降法来更新参数。

4.3 BPTT 算法

BPTT(back-propagation through time)算法是常用的训练 RNN 的方法,其本质还是 BP 算法,只不过 RNN 处理时间序列数据,所以要基于时间反向传播,故叫随时间反向传播

BPTT 的中心思想和 BP 算法相同,沿着需要优化的参数的负梯度方向不断寻找更优的点直至收敛。需要寻优的参数有三个,分别是 U、V、W。

与 BP 算法不同的是,其中 W 和 U 两个参数的寻优过程需要追溯之前的历史数据,参数 V 相对简单只需关注目前,那么我们就来先求解参数 V 的偏导数,如下所示:

W 和 U 的偏导的求解由于需要涉及到历史数据,其偏导求起来相对复杂。

为了简化推导过程,我们假设只有三个时刻,那么在第三个时刻 L 对 W,L 对 U 的偏导数分别为:

可以观察到,在某个时刻的对 W 或是 U 的偏导数,需要追溯这个时刻之前所有时刻的信息。

根据上面两个式子得出 L 在 t 时刻对 W 和 U 偏导数的通式:

整体的偏导公式就是将其按时刻再一一加起来。

BP 算法只考虑了上下层级之间梯度的纵身传播;而 BPTT 同时考虑了层级间的纵向传播和时间上的横向传播,同时在两个方向上进行参数优化。

五、RNN 举例

假设现在我们已经训练好了一个 RNN,我们假设每个单词的特征向量是二维的,也就是输入层的维度是二维,且隐藏层也假设是二维,输出也假设是二维,所有权重的值都为 1 且没有偏差且所有激活函数都是线性函数,如下图所示。

现在输入一个序列 x 到该模型中,我们来一步步求解出输出序列。

如下图中,a1a2 ​可以看做每一时刻存下来的值。

首先,当我们输入第一个序列 [1,1],我们来计算隐藏层的值,也就是绿色神经元的值,当然初始时 a1a2 是没有存值的,因此初始值为 0。

隐藏层计算公式为:

因为所有权重都是 1,所以中间状态 s1 的计算结果是:

所以,我们得到隐藏层的结果是 s1 = [2,2],然后计算输出层的值。

输出层计算公式为:

权重也都为 1,所以计算结果是:

最终,我们得到输出层为 y = [4,4]。

此时,我们的中间时刻记忆中 a1a2 的值就是 [2,2]。

然后,我们再次输入下一个向量 [1,1]。

中间状态 s2 的值是:

此时,我们的中间时刻记忆中 a1a2 的值就是 [6,6]。

然后,输出 o2 的值是:

最终,我们得到输出层为 y = [12,12]。

此时,我们的中间时刻记忆中 a1a2 的值就是 [6,6]。

我们可以发现,由于 a_{1}a_{2}$ 的不同,所以即使当我们的输入相同向量的时候,最终的输出结果也是不同的

同理,我们继续输入第三个向量 [2,2]。

中间状态 s3 的值是:

此时,我们的中间时刻记忆中 a1a2 的值就是 [16,16]。

然后,输出 o3 的值是:

最终,我们得到输出层为 y=[32,32]。

由此,我们得到了最终的输出序列为:

至此,一个完整的 RNN 结构我们已经经历了一遍,我们注意到,每一时刻的输出结果都与上一时刻的输入有着非常大的关系,如果我们将输入序列换个顺序,那么我们得到的结果也将是截然不同,这就是 RNN 的特性,可以处理序列数据,同时对序列也很敏感

六、总结 RNN

所以,可以使用循环神经网络处理槽填充这件事。例如,当用户说「在 6 月 1 日抵达上海」。其中,「抵达」一词就变成了一个输入向量,神经网络的隐藏层的输出为向量 a1a1 是产生「抵达」属于每一个槽填充的概率 y1

然后,把 a1 存储到记忆单元里面,再把「上海」一词作为输入向量,此时 RNN 就会考虑「上海」和记忆单元中的 a1(抵达一词),并求得 a2,再根据 a1,就可以求出「上海」属于每个槽填充的概率 y2

TIP

这里不是两个网络,这是同一个网络在两个不同的时间点被使用了两次,所以用相同的颜色表示,即它们的权重相同。

有了记忆元以后,输入同一个单词,希望输出不同的问题就有可能被解决。

如上图所示,同样是输入“上海”这个单词,但是因为红色“上海”前接了“离开”,绿色“上海”前接了“抵达”,“离开”和“抵达”的向量不一样,隐藏层的输出会不同,所以存在记忆元里面的值会不同。虽然 x2 的值是一样的,因为存在记忆元里面的值不同,所以隐藏层的输出会不同,所以最后的输出也就会不一样。

七、RNN 常见结构

7.1 vector-to-sequence 结构

有时我们要处理的问题输入是一个单独的值,输出是一个序列。此时,有两种主要建模方式:

方式一:可只在其中的某一个序列进行计算,比如序列第一个进行输入计算,其建模方式如下。

方式二:把输入信息 X 作为每个阶段的输入,其建模方式如下。

其主要的应用场景是:

  • 根据图像生成文字描述,输入为图像的特征,输出为一段句子;
  • 根据图像生成语音或音乐,输入为图像特征,输出为一段语音或音乐。

7.2 sequence-to-vector 结构

有时我们要处理的问题输入是一个序列,输出是一个单独的值,此时通常在最后的一个序列上进行输出变换,其建模如下所示。

其主要的应用场景是:

  • 输入一段文字,判断其所属类别;
  • 输入一个句子,判断其情感倾向;
  • 输入一段视频,判断其所属类别

7.3 Encoder-Decoder 结构

原始的 sequence-to-sequence 结构的 RNN 要求序列等长,然而我们遇到的大部分问题序列都是不等长的,如机器翻译中,源语言和目标语言的句子往往并没有相同的长度。

因此,Encoder-Decoder 结构能够对不等长的输入序列进行处理,然后进行训练。

其建模步骤如下。

步骤一:将输入数据编码成一个上下文向量 c,这部分称为 Encoder(编码),得到 c 有多种方式:

  • c = h4 :把 Encoder 的最后一个隐状态赋值给 c;
  • c = q(h4) :对最后的隐状态做一个变换得到 c;
  • c=q(h1, h2, h3, h4):对所有的隐状态做变换得到 c。

其示意如下所示:

步骤二:用另一个 RNN 网络(我们将其称为 Decoder)对其进行解码。

方法一是将步骤一中的 c 作为初始状态输入到 Decoder,示意图如下所示:

方法二是将 c 作为 Decoder 的每一步输入,示意图如下所示:

其主要的应用场景是:

  • 机器翻译,输入一种语言文本序列,输出另外一种语言的文本序列;
  • 文本摘要,输入文本序列,输出这段文本序列摘要;
  • 阅读理解,输入文章,输出问题答案;
  • 语音识别,输入语音序列信息,输出文字序列。

八 模型特点

  1. RNN 主要用于处理序列数据。对于传统神经网络模型,从输入层到隐含层再到输出层,层与层之间一般为全连接,每层之间神经元是无连接的。但是传统神经网络无法处理数据间的前后关联问题。例如,为了预测句子的下一个单词,一般需要该词之前的语义信息。这是因为一个句子中前后单词是存在语义联系的。
  2. RNN 中当前单元的输出与之前步骤输出也有关,因此称之为循环神经网络。具体的表现形式为当前单元会对之前步骤信息进行储存并应用于当前输出的计算中。隐藏层之间的节点连接起来,隐藏层当前输出由当前时刻输入向量和之前时刻隐藏层状态共同决定。
  3. 标准的 RNN 结构图,图中每个箭头代表做一次变换,也就是说箭头连接带有权值。
  4. 在标准的 RNN 结构中,隐层的神经元之间也是带有权值的,且权值共享。
  5. 理论上,RNN 能够对任何长度序列数据进行处理。但是在实践中,为了降低复杂度往往假设当前的状态只与之前某几个时刻状态相关。

总结就两点

  • 处理时序数据
  • 中间状态,带有记忆功能

九、模型问题

9.1 梯度消失/爆炸

当序列太长时,容易导致梯度消失。参数更新只能够捕捉到局部依赖关系,没法再捕捉序列之间的长期关联或依赖关系。比如,「The cat, which ate already, ......, was full」,这句话中,就是后面的是was还是were,要看前面是cat还是cats,但是一旦中间的这个which句子很长,cat的信息传不到was这里来。对was的更新没有任何帮助,这就是 RNN 一个很大的不足,容易导致梯度消失

首先来看 tanh 函数的函数及导数图如下所示:

sigmoid 函数的函数及导数图如下所示:

从上图观察可知,sigmoid 函数的导数范围是 (0,0.25],tanh 函数的导数范围是(0,1],他们的导数最大都不大于 1。

RNN 的激活函数是嵌套在里面的,如果选择激活函数为 tanh 或 sigmoid,把激活函数放进去,拿出中间累乘的那部分可得:

基于上式,会发现累乘会导致激活函数导数的累乘,如果取 tanh 或 sigmoid 函数作为激活函数的话,那么必然是一堆小数在做乘法,结果就是越乘越小。

随着时间序列的不断深入,小数的累乘就会导致梯度越来越小直到接近于 0,这就是“梯度消失“现象。

实际使用中,会优先选择 tanh 函数,原因是 tanh 函数相对于 sigmoid 函数来说梯度较大,收敛速度更快且引起梯度消失更慢。

梯度消失是在无限的利用历史数据而造成,但是 RNN 的特点本来就是能利用历史数据获取更多的可利用信息,解决 RNN 中的梯度消失方法主要有:

  • 选取更好的激活函数,如 Relu 激活函数。ReLU 函数的左侧导数为 0,右侧导数恒为 1,这就避免了“梯度消失“的发生。但恒为 1 的导数容易导致“梯度爆炸“,但设定合适的阈值可以解决这个问题。
  • 加入 BN 层,其优点包括可加速收敛、控制过拟合,可以少用或不用 Dropout 和正则、降低网络对初始化权重不敏感,且能允许使用较大的学习率等。
  • 改变传播结构,LSTM 结构可以有效解决这个问题。

9.2 长期依赖问题

在 RNN 中,每个输出由当前输入和之前的信息共同决定,这个思路是很巧妙的,但是会带来一个问题。

RNN 是一种死板的逻辑,越晚的输入影响越大,越早的输入影响越小,且无法改变这个逻辑。

短期的记忆影响较大,但是长期的记忆影响就很小,这就是 RNN 存在的短期记忆问题,无法处理很长的输入序列。

有时,我们只需要最近的信息来作为当前预测任务的输入,对于一个语言模型,它要根据前面的单词预测后面的单词。例如,这句话 the clouds are in the ___ ,我们只需要预测最后的词是sky

在这样的场景中,相关的信息和预测的词位置之间的间隔是非常小的,RNN 可以学会使用先前的信息。

在这个 RNN 中,输入和输出数据如表。

对于sky这个词的输出,主要是theclouds这两个词起了重要的作用。

但是同样会有一些更加复杂的场景。假设我们试着去预测一段很长的文本,I grew up in France. I am 10 years old, I like Chinese food. I speak fluent _____,预测这段文本最后的词。(很显然,应该填 France

通过最近的信息,机器知道下一个词可能是一种语言的名字,但是如果要弄清楚具体是什么语言,则需要参考更久远更前面的相关信息,也就是France

这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。不幸的是,在这个间隔不断增大时(一般 8~10 个步长信息就会丢失),RNN 会丧失学习到连接如此远的信息的能力。

在理论上,RNN 绝对可以处理这样的长期依赖问题。人们可以仔细挑选参数来解决这类问题中的最初级形式,但在实践中,RNN 肯定不能够成功学习到这些知识。Bengio 等人对该问题进行了深入的研究,他们发现一些使训练 RNN 变得非常困难的相当根本的原因。然而,幸运的是,LSTM 并没有这个问题!

十、LSTM 网络

Long Short-term Memory,长时间(的)短期记忆, 一般就叫做 LSTM,是一种 RNN 特殊的类型,可以学习长期依赖信息。由于 RNN 的短期记忆问题,后来又出现了基于 RNN 的优化算法—LSTM。

LSTM 由 Hochreiter 和 Schmidhuber 在 1997 年被提出,并在近期被 Alex Graves 进行了改良和推广。在很多问题,LSTM 都取得相当巨大的成功,并得到了广泛的使用。LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为,而非需要付出很大代价才能获得的能力。

从上图中可以看出,LSTM 有三个门:输入门、遗忘门和输出门。

  • 输入门:决定输入的数据是否存到记忆单元中
  • 遗忘门:决定记忆单元中的数据是否遗忘掉还是继续保留
  • 输出门:决定记忆单元中哪些数据输出

10.1 网络架构对比

所有 RNN 都具有重复模块的结构。在标准的 RNNs 中,这个重复的模块只有一个非常简单的结构,例如单个 tanh 层,如下图所示。

LSTMs 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。

其实,LSTMs 主要多了一个控制参数 C,这个也叫做细胞状态。它能够决定什么样的信息会被保留,什么样的会被遗忘。

10.2 网络详解

下面对 LSTM 网络进行详细说明,首先说明一下图中使用的图标,如下:

上图中,每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。粉色的圈代表 pointwise 的操作,诸如向量的和,而黄色的矩阵就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。

LSTM 的关键就是细胞状态(cell state),水平线在图上方贯穿运行,也就是贯穿每个重复结构的上面这条信息流(flow)。细胞状态类似于传送带,直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。这条 flow 其实就承载着之前所有状态的信息,每当 flow 流经一个重复结构 A 的时候,都会有相应的操作来决定舍弃什么旧的信息以及添加什么新的信息。

LSTM 有通过精心设计对信息增减进行控制的结构,称作为“门”。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个按位的乘法操作。Sigmoid 层输出 0 到 1 之间的数值,描述每个部分有多少量可以通过。0 代表“不许任何量通过”,1 就指“允许任意量通过”!

LSTM 拥有三个门,来保护和控制细胞状态,分别是遗忘门 (forget gate)、输入门 (input gate)、输出门 (output gate)。

10.2.1 遗忘门

作用对象:细胞状态 。

作用:将细胞状态中的信息选择性的遗忘。

操作步骤:该门会读取上一状态的输出 ht1​ 和状态输入信息 xt,通过 Sigmoid 激活函数,输出一个在 0 到 1 之间的数值,然后上一细胞状态 Ct1 中的数字相乘后,确定舍弃(保留)多少信息。1 表示“完全保留”,0 表示“完全舍弃”。示意图如下:

主要参数说明如下:

  • Wf:遗忘门的权重矩阵,决定什么值丢弃
  • [ht1, xt]:把两个向量连接成一个更长的向量
  • bf:遗忘门的偏置项
  • σ:sigmoid 激活函数

如果输入的维度是 dx,隐藏层的维度是 dh,单元状态的维度是 dc(通常 dc = dh),则遗忘门的权重矩阵 Wf 维度是 dc × (dh + dx)。

事实上,权重矩阵 Wf 是由两个矩阵拼接而成的:

  • 一个是 Wfh :它对应着输入项 ht1,其维度是 dc × dh
  • 一个是 Wfx :它对应着输入项 xt,其维度是 dc × dx

权重矩阵 Wf 与输入输出向量的计算,可以写为:

10.2.2 输入门

作用对象:细胞状态

作用:输入门决定了要往 cell state 中保存什么新的信息,将新的信息选择性的记录到细胞状态中。

操作步骤:其通过输入上一状态的输出 ht1​ 、当前状态输入信息 xt​ 到一个 Sigmoid 函数中,产生一个介于 0 到 1 之间的数值 it 来确定我们需要保留多少的新信息。

同时,一个 tanh 层会通过上一状态的输出 ht1、当前状态输入信息 xt 来创建一个新的候选值向量,得到一个将要加入到 cell state 中的候选新信息 Ct~

主要参数说明如下:

  • it:要保留下来的新信息
  • Ct~:候选新信息

现在计算当前时刻的单元状态。它是由上一次的单元状态按元素乘以遗忘门,丢弃掉我们确定需要丢弃的信息;然后把当前输入的单元状态按元素乘以输入门,将两个积加和,这就是新的候选值:

主要参数说明如下:

  • Ct:前一阶段的信息和当前信息加起来

10.2.3 输出门

作用对象:隐藏层

作用:利用新的控制参数 C 产生输出

操作步骤:输出门决定了要从 cell state 中输出什么信息。这个输出将会基于我们的细胞状态,但是也是一个过滤后的版本,会先有一个 Sigmoid 函数产生一个介于 0 到 1 之间的数值 ot 来确定我们需要输出多少 cell state 中的信息。cell state 的信息再与 ot 相乘时首先会经过一个 tanh 层进行“激活”(非线性变换)。得到的就是这个 LSTM block 的输出信息 ht

十一、LSTM 举例

假设我们的 LSTMs 只有一个细胞,输入数据是一个三维的向量,输出数据是一维的数值,如下图所示。

输入、细胞状态和输出之间的关系是这样的:

  • x2 = 1 时,添加 x1 到记忆细胞中;
  • x2 = -1 时,将记忆细胞中的值重置为 0;
  • x3 = 1 时,将记忆细胞中的值输出;

接下来,我们就用上述的记忆细胞实际运算一下。

输入的三维向量经过线性变化后,得到了 (x1, x2, x3)。然后将 (x1, x2, x3) 乘以相应的权重再加上偏置,即可得到一个结果(权重和偏置,均是通过训练数据用梯度下降算法学到的)。

我们假设,已经学习到的权重和偏置,如下图所示。

从图中可以看出:

  • 最底部,x1 的权重为 1,所以直接将 x1 作为输入,也就是要保留的新信息。

  • 输入门中,x2 的权重为 100,偏置为-10。当 x2 > 1 时,结果是正值,输入门通道被打开。否则,-10 通过 sigmoid 函数后会接近 0,输入门通道被关闭。

  • 遗忘门中,x2 的权重为 100,偏置为 10,只有当 x2 是很大的负数,遗忘门才会关闭。

  • 输出门中,x3 的权重为 100,偏置为-10,只有当 x3 是很大的正值时,通道才打开,平时则关闭。

为了方便计算,我们将输入记忆细胞的 g 函数和输出记忆细胞的 h 函数都看做是线性函数,记忆细胞中初始值为 0。

右下角是我们依次输入的三维向量 (x1, x2, x3)。

第一次,输入的向量是 (3,1,0)

  • 输入门打开,将要存到记忆细胞中的值为 3
  • 遗忘门打开,则存到遗忘门中的数值为 0 × 1 + 3 = 3(0 是细胞状态初始值)
  • 输出门关闭,则记忆细胞中的值不输出

第二次,输入的向量是 (4,1,0)

  • 输入门打开,将要存到记忆细胞中的值为 4
  • 遗忘门打开,则存到遗忘门中的数值为 3 × 1 + 4 = 7
  • 输出门关闭,则记忆细胞中的值不输出

第三次,输入的向量是 (2,0,0)

  • 输入门关闭,将要存到记忆细胞中的值为 0
  • 遗忘门打开,则存到遗忘门中的数值为 7 × 1 + 0 = 7
  • 输出门关闭,则记忆细胞中的值不输出

第四次,输入的向量是 (1,0,1)

  • 输入门关闭,将要存到记忆细胞中的值为 0
  • 遗忘门打开,则存到遗忘门中的数值为 7 × 1 + 0 = 7
  • 输出门打开,则记忆细胞中的值 7 输出

第五次,输入的向量是 (3,-1,0)

  • 输入门关闭,将要存到记忆细胞中的值为 0
  • 遗忘门关闭,则存到遗忘门中的数值为 0 × 7 + 0 = 0,则记忆细胞中的值被清除
  • 输出门关闭,则记忆细胞中的输出为 0

最终,输出的结果是 (0,0,0,7,0)。

以上就是 LSTMs 的运算实例,其实际情况远比这复杂的多,其输入的维度往往是数千维,权重也更为复杂。但其本质原理,仍是三个门在控制信息的保留和清除。

十二、应用场景

12.1 语言模型与文本生成

语言模型与文本生成,Language Modeling and Generating Text,给定一组单词序列,需要根据前面单词预测每个单词出现的可能性。语言模型能够评估某个语句正确的可能性,可能性越大,语句越正确。另一种应用便是使用生成模型预测下一个单词的出现概率,从而利用输出概率的采样生成新的文本。

12.2 机器翻译

机器翻译(Machine Translation)是将一种源语言语句变成意思相同的另一种源语言语句,如将英语语句变成同样意思的中文语句。与语言模型关键的区别在于,需要将源语言语句序列输入后,才进行输出,即输出第一个单词时,便需要从完整的输入序列中进行获取。

12.3 语音识别

语音识别(Speech Recognition)是指给定一段声波的声音信号,预测该声波对应的某种指定源语言语句以及计算该语句的概率值。

12.4 图像描述生成

图像描述生成,Generating Image Descriptions,同卷积神经网络一样,RNN 已经在对无标图像描述自动生成中得到应用。CNN 与 RNN 结合也被应用于图像描述自动生成。

12.5 股票预测

基于时间序列的股票预测。 这种形式的 NLG 使用模板驱动模式来显示输出。以足球比赛得分板为例。数据动态地保持更改,并由预定义的业务规则集(如 if / else 循环语句)生成。

Released under the MIT License.