NLP学习系列05丨RNN基础机构

一、传统机器学习中的序列模型

在传统的机器学习领域当然有不少模型是针对序列进行建模的。最经典的要数“隐马尔科夫 模型”(Hidden Markov Model),有时候又简称为 HMM。在比较长的一段时间里, HMM 都是常用的对序列建模的缺省(Default)模型。

HMM 的一个最基本的假设是:当前的序列数据是根据一些隐含的状态产生的。具体来 说,HMM 的架构是这样的。我们认为每个时间点都有一个对应的隐含状态。这个隐含状态只与当前这个时间点之前的时间点所对应的隐含状态有关联。更加简单的假设,也是经常使用的假设,则认为当前时间点的隐含状态,仅仅与之前最直接相邻的一个时间点的隐含状态有关,而和之前所有时间点的隐含状态都没有关系了。这类似于说今天的天气仅仅与昨天有关,和昨天之前的天气状态都没有任何关系,显然这是一个很强的假设。

从时间轴这个角度来说,HMM 是构建了一个隐含状态的一阶马尔科夫链条。这里,“一 阶”是指每个状态仅与当前最邻近的状态有关。当我们构建好了隐含状态以后,就可以在这 个基础上对数据进行建模了。

HMM 假定,每个时间点的数据都是从这个时间点的隐含状态产生的,而时间点所对应的 数据之间并不直接产生关系。也就是说,我们假定产生数据的原因是隐含状态,而隐含状态 已经通过一个链条给串联起来了,这样我们就不需要针对数据进行串联了。

HMM 虽然理解起来相对比较直观,但在实际应用中存在不少问题。比如,这个模型的表现力有限。我们刚才说了,一个普通的 HMM 假定了隐含状态的一阶性质,使得我们不能 对比较长的序列进行建模,因为模型无法对其中所有的隐含状态的转换进行建模,一阶无法表达这样的关系。当然,HMM 有一阶以上的表达,但这也就带来了 HMM 的一个普遍的 问题,就是训练方法比较复杂。对于一个现实问题而言,HMM 的建模会相对比较复杂,从而让训练方法更加繁复。这也就是为什么 HMM 不能适用于大规模问题的一个主要的原因。

2.RNN的基本架构

在 HMM 的基础上,我们再来看一下 RNN 的基本思想。

首先,我们需要指出的是,RNN 并不是一个模型的称呼,而是一个框架。具体在这个框架内部,根据不同的需求,我们可以构造出非常不一样的模型。

第二,RNN 的一大优势是它根植于深度学习的大范畴中。RNN 的模型都可以算是特殊的深度学习模型。所以,深度学习模型的很多优化算法或者整体的计算方式也都可以无缝嫁接到 RNN 上。从这一点来看,RNN 比传统的 HMM 就有很大的相对优势。

通常来说,一个 RNN 有一个输入序列 X 和输出序列 Y,这两个序列都随着时间的变化而变化。也就是说,每一个时间点,我们都对应这一个 X 和一个 Y。和 HMM 类似的是, RNN 也假定 X 和 Y 都不独立发生变化,而他们的变化和关系都是通过一组隐含状态来控制的。

具体来说,时间 T 时刻的隐含状态有两个输入,一个输入是时间 T 时刻之前所有的隐含状态,一个输入是当前时刻,也就是时间 T 时刻的输入变量 X。时间 T 时刻的隐含状态根据这两个输入,会产生一个输出,这个输出就是 T 时刻的 Y 值。也就是说,T 时刻的输出是根据之前所有的隐含状态和这个时刻的输入决定的。在一些简化的情况下,并不是每一个时刻都有输出的信息。比如我们需要对一个句子进行分类,这个时候,一个输出变量只在整个句子结束的时候出现。那么,在这样的情况下,Y 仅仅在最后的一个时刻出现。

这个 RNN 的参数也就是这些隐含状态。从原理上来说,可以根据标准的深度学习框架的流程加以学习。

RNN 的整个框架还可以看作是一个加码解码的过程。从已知的序列到中间隐含状态,这是一个加码的流程,而从隐含状态到最后的输出序列,这是一个解码的过程。具体的 RNN 针对这个加码解码的过程有更加详细的分工。

二、基于门机制的RNN架构:LSTM与GRU

所有的深度学习模型都依赖一个叫作“反向传播”(Back-Propagation)的算法来计算参数的“梯度”,从而用于优化算法。但是,RNN 的基本架构存在一个叫作“梯度爆炸”或 者“梯度消失”的问题。在传统的 RNN 模型下,这两种梯度异常都会造成优化算法的迭代无法进行,从而导致我们无法学习到模型的参数。

想要在现实的数据中使用 RNN,我们就必须解决梯度异常这一问题。而在解决梯度异常这个问题的多种途径中,有一类途径现在变得很流行,那就是尝试在框架里设计“门机制”(Gated Mechanism)。

这个门机制的由来主要是着眼于一个问题,那就是在我们刚才介绍的简单的 RNN 模型中, 隐含变量从一个时间点到另一个时间点的变化,是“整个向量”变换为另外的“整个向 量”。研究人员发现,我们可以限制这个向量的变化,也就是说我们通过某种方法,不是让 整个向量进行复制,而是让这个隐含向量的部分单元发生变化。

如果要达到这样的效果,我们就必须设计一种机制,使得这个模型知道当前需要对隐含向量 的哪些单元进行复制,哪些单元不进行复制而进行变化。我们可以认为,进行复制的单元是 它们被屏蔽了“进行转换”这一操作,也可以认为它们被“门”阻挡了,这就是“门机 制”的来源。

从逻辑上思考,如何设计“门机制”从而起到这样的作用呢?一种方式就是为隐含变量引入 一个伴随变量G。这个伴随变量拥有和隐含变量一样的单元个数,只不过这个伴随变量的取 值范围是 0 或者 1,0 代表不允许通过,1 代表可以通过。这其实就是门机制的一个简单实 现。我们只需要利用这个向量和隐含向量相应单元相乘,就能实现控制这些单元的目的。当 然,这只是一个逻辑上的门机制,实际的门机制要有更多细节,也更加复杂。

基于门机制的 RNN 架构都有哪些呢?这里介绍两个比较流行的,分别是 LSTM 和 GRU。 我们这里不对这些模型展开详细的讨论,而是给你一个直观的介绍,帮助你从宏观上把握这 些模型的核心思想。

LSTM的思路是把隐含状态分为两个部分。一部分用来当作“存储单元”(Memory Cells),另外一部分当作“工作单元”(Working Memory)。存储单元用来保留信息, 并且用来保留梯度,跨越多个时间点。这个存储单元是被一系列的门控制,这些门其实是数学函数,用来模拟刚才我们说的门的机制。对于每一步来说,这些门都要决定到底需要多少信息继续保留到下一个时间点。

总体来说,LSTM 模型的细节很多,也很复杂。虽然 LSTM 已经成为了一种典型而且成功 的 RNN 模型,但是实践者们还是觉得这个模型可以简化,于是就催生了 GRU 模型。

GRU模型的核心思想其实就是利用两套门机制来决定隐含单元的变化。一个门用于决定哪些单元会从上一个时间点的单元里复制过来,并且形成一个临时的隐含状态,另外一个门则控制这个临时状态和过去状态的融合。GRU 在结构上大大简化了 LSTM 的繁复,在效果上依然能够有不错的表现。

三、RNN在自然语言处理中有哪些应用场景?

1.简单分类场景

我们首先来聊一种简单的分类场景。在这种场景下,RNN 输入一个序列的文字,然后根据 所有这些文字,做一个决策,或者叫作输出一个符号。这类应用是文本挖掘和分析中最基本的一个场景。

在绝大多数的“简单分类”任务中,传统的文字表达,例如“词包”(Bag of Word)或者“N 元语法”(Ngram),经常都能有不错的表现。也就是说,在很多这类任务中,文字的顺序其实并不是很重要,或者说词序并没有携带更多的语义信息

然而,实践者们发现,在一些场景中,如果利用 RNN 来对文字序列进行建模,会获得额外的效果提升。比如有一类任务叫作“句子级别的情感分类”(Sentence-Level Sentiment Classification),这类任务常常出现在分析商品的评论文本(Review)这个场景。这时候,我们需要对每一个句子输出至少两种感情色彩的判断,褒义或者贬义,正面或者负面。比如,我们在分析电影评价的时候,就希望知道用户在某一个句子中是否表达了对电影“喜爱”或者“不喜爱”的情绪。

面对这样句子级别的情感分析,一种比较通行的利用 RNN 建模的方式是:把每一个单词作为一个输入单元,然后把一个句子当作一个序列输入到一个 RNN 中去,RNN 来维持一个隐含的状态

对于这类应用,不是每一个隐含状态都有一个输出,而是在句子结束的时候,利用最后的隐含状态来产生输出。对于这类任务而言,输出的状态就是一个二元判断,那么我们需要利用最后的隐含状态来实现这个目的。一般来说,在深度模型的架构中,这个步骤是利用最后的隐含状态,然后经过多层感知网络,最后进行一个二元或者多元的分类。这其实是一个标准的分类问题的构建。

在有的应用中,研究者们发现可以利用两个 RNN 建立起来的链条,从而能够更进一步地提升最后的分类效果。在我们刚才描述的建模步骤里,RNN 把一个句子从头到尾按照正常顺序进行了输入并归纳。另外一种建模方式是利用 RNN 去建模句子的逆序,也就是把整个句子倒过来,学习到一个逆序的隐含状态。接下来,我们把顺序的最后隐含状态和逆序的最后隐含状态串联起来,成为最终放入分类器需要学习的特性。这种架构有时候被称作“双向模型”。

当我们从句子这个层级到文档这个层级时,比如希望对文档进行情感分类,仅仅利用我们刚才讲的 RNN 的结构就会显得有点“捉襟见肘”了。一个重要的阻碍就是 RNN 很难针对特别长的序列直接建模。这个时候,就需要我们把整个文档拆分成比较小的单元,然后针对小的单元利用 RNN 进行建模,再把这些小单元的 RNN 结果当作新的输入串联起来。

在实际拆分的时候,我们可以把文章分成一个一个的句子,然后每个句子可以用刚才我们在 句子层级的建模方式进行建模;在句子的层级下,还可能再把句子拆分成比如短语这样的单元。这种把一个比较大的文档进行拆分,并且通过 RNN 对不同级别的数据进行建模的形式 就叫作“层次式”(Hierarchical)RNN 建模

2.特性提取器

在更多的场景中,RNN 其实已经扮演了文本信息特性提取器的角色,特别是在很多监督学 =习任务中,隐含状态常常被用来当作特性处理。尤其要说明的是,如果你的任务对文字的顺 序有一定要求,RNN 往往就能成为这方面任务的利器,我们这里举几个例子。

首先可以想到的一个任务就是,在自然语言处理中很常见的“词类标注”(Part-OfSpeech Tagging),或者简称POS 标注。简单来说,POS 标注就是针对某一个输入句 子,把句子里的词性进行分析和标注,让大家知道哪些是动词,哪些是名词,哪些是形容词 等等。我们可以很容易地想到,在这样的标注任务中,一个词到底是名词还是动词,在很多 的语言场景中,是需要对整个句子的语境进行分析的,也就是说,整个句子的顺序和词序是 有意义的。

针对 POS 标注这类任务,一种已经尝试过的架构,就是利用我们刚才介绍过的双向 RNN 来对句子进行建模。双向 RNN 的好处是,我们可以构建的隐含信息是包含上下文的,这样 就更加有助于我们来分析每个词的词性。

和句子分类的任务类似的是,利用双向 RNN 对句子进行扫描之后,我们依然需要建立分类器,对每一个位置上的词语进行分类。这个时候,依然是同样的思路,我们把当前的隐含状 态当作是特性,利用多层感知网络,构建多类分类器,从而对当前位置的词性进行决策。

除了 POS 标注这样的任务以外,针对普通的文档分类,RNN 也有一定的效果。这里我们 所说的文档分类,一般是指类似把文档分为“艺术”、“体育”或“时政”等主题类别。人们从实践中发现,在这样的通用文档分类任务中,RNN 和另外一类重要的深度模型,“卷积神经网络”(CNN)结合起来使用效果最好。我们这里不展开对 CNN 的原理进行讲 解,只是从大的逻辑上为你讲一下这种分类方法的核心思路。

在计算机视觉中,通常认为 CNN 可以抓住图像的“位置”特征。也就是说,CNN 非常善于挖掘一个二维数据结构中局部的很多变化特征,从而能够有效形成对这些数据点的总结。 那么,如果我们把文档的文字排列也看作是某种情况下的一种图案,CNN 就可以发挥其作 用来对文字的上下文进行信息提取。然后当 CNN 对文字的局部信息进行提取之后,我们再 把这些局部信息当作输入放入 RNN 中,这样就能更好地利用 RNN 去对文章的高维度的特征进行建模。