自然语言处理是研究和实现人与计算机之间用自然语言进行有效通信的各种理论和方法。本文主要介绍深度学习在自然语言处理中的应用。
自然语言处理简介
自然语言处理是研究和实现人与计算机之间用自然语言进行有效通信的各种理论和方法。具体的任务包括:
- 问答系统(如Siri、Alexa和Cortana的功能)
- 情感分析(判断某个句子表达的是正面还是负面情绪)
- 图像-文字映射(看图写话)
- 机器翻译(语言之间相互翻译)
- 语音识别
- 句子成分分析
- 命名实体识别
传统的NLP方法需要借助大量语言学的领域知识。理解音素和词素等术语是基本功,有专门的语言培训课程。我们先来看看传统的NLP方法是如何理解下面这个词语:
假设我们的目标是从该词提取出一些信息(情感偏向、词意等等)。根据语言学知识,该词可以分割为下面三部分:
我们知道前缀”un”表示相反或是反面意思,后缀”ed”表明了词的时态(过去式)。再通过识别词干”interest”的意思,我们就很容易推导出这个单词的含义和情感偏向了。似乎很简单对吧?但是,当真正去梳理英语里的所有前缀和后缀时,你会发现所有前缀和后缀组合很多很多,只有非常资深的语言学家才能理解它们的含义。
深度学习的介入
深度学习本质上还是一种表示学习的方法。例如,CNN模型就是用一系列滤波器的组合来将对象划分到不同类别。因此,作者认为我们也可以借用同样的方法来表示单词。
本文概述
作者按照构建深度神经网络模型的基本顺序来撰写本文,然后结合近期的研究论文来讨论一些实际应用。也许,部分读者在读完全文之后还存在为啥要用RNN模型,或者为啥LSTM网络会有效等等问题。但是,作者的初衷是希望大家对深度学习在自然语言处理领域的应用能有一个感性的认识。
词向量
既然深度学习方法喜欢用数学符号,那我们就把每个单词表示为一个d维的向量。假设 d=6。
该用什么数值来表示这个向量呢?我们希望这个向量能够表示词语的含义或者语义。一种方法是创建共现矩阵。假设现在有一句话:
我们希望将句子中的每个单词都表示为一个向量:
共现矩阵的每个元素表示一个词与另一个词在整篇文档中相邻出现的次数。具体来说如下图所示:
我们可以将共现矩阵的每一行当做词向量的初始值:
读者们请注意,仅仅观察这个简单的矩阵,我们就能够获取很多有用的信息。例如,“love”和“like”两个单词与名词性的单词共现次数都是1(NLP和dogs),而且它们都与单词“I”共现一次。这就意味着这两个单词很有可能属于动词。若我们手中的数据集足够大,大家可以想象“like”与“love”的相似度会越来越高,同理其它近义词的词向量也会越来越相似,因为它们总是在相近的上下文中出现。
尽管我们找到了一个好的入手点,但是需要注意到这种向量表示方式的维度会随着语料集的增长而呈线性增长。假如我们有一百万个单词(在NLP问题中并不算太多),就会得到一个 1000,000 x 1000,000 的矩阵,而且这个矩阵非常的稀疏。从存储效率来说,这显然不是一种好的表示方法。目前已经有许多不错的词向量表示方法了,其中最著名的就是word2vec。
Word2Vec
词向量方法的基本思想就是让向量尽可能完整地表示该词所包含的信息,同时让向量维度保持在一个可控的范围之内(合适的维度是25~1000维之间)。
Word2vec的思想是预测某个中心词附近其它词语出现的概率。还是以之前的句子“I love NLP and I like dogs.”为例。我们首先观察该句子的前三个单词。因此窗口的宽度就是 m=3:
接着,我们的目标就是根据中心词“love”,预测它左右可能出现的词。怎么实现呢?当然先要定一个优化目标函数。假设确定了一个中心词,我们定的这个函数要使得周围词语出现的对数概率值最大:
这个函数很重要,作者强调一定要认真理解。还是以“love”作为中心词为例,目标函数的含义就是累加左侧“I”,“love”和右侧“NLP”,“love”四个单词的对数概率值。变量T表示训练语句的数量。下面的式子是对数函数的公式:
Vc是中心词的词向量。每个单词有两种表示向量(Uo和Uw)—— 一个用于此单词作为中心词的场景,另一个用于此单词不是中心词的场景。我们采用随机梯度下降方法训练词向量。这个过程是最令人费解的,如果读者对上述解释看得云里雾里,作者还向大家推荐了两篇拓展阅读文章,第一篇 (https://dzone.com/articles/natural-language-processing-adit-deshpande-cs-unde) 和第二篇 (https://www.youtube.com/watch?v=D-ekE-Wlcds)。
一句话总结:在给出中心词的情况下,Word2vec的目标就是使得上下文词语的对数函数值最大,优化方法通常是SGD。
word2vec方法最吸引眼球的效果就是其能够发现词向量之间存在的线性关系。经过训练,词向量似乎可以捕捉到不同的语法和语义概念:
真是不可思议,如此简单的目标函数和优化方法就能够捕捉到这种线性关系。
循环神经网络
(Recurrent Neural Networks)
好了,现在我们已经得到了词向量,接下去就要把它们融入到循环神经网络模型中。RNN现在已经是NLP任务最常用的方法之一。RNN模型的优势之一就是可以有效利用之前传入网络的信息。下图就是RNN模型的简单示意图:
上图底部,输入的x是该词的词向量。每个向量x对应一个隐层的向量h。下图橙色框内的是一个输入单元:
每个单元的隐层向量是当前输入词向量和上一个隐层状态的函数,计算公式如下:
如果你仔细观察,会发现公式中有两个上标不同的权重矩阵Whx和Whh,分别与输入的词向量和上一次的隐藏状态相乘。这两个权重矩阵是网络的所有单元共享的。
这就是RNN模型的关键。仔细思考这个过程,它和传统的两层神经网络差别非常大。在传统的两层神经网络中,每层的权重矩阵各不相同(W1和W2),而在递归算机网络中,整个序列共享同一个权重矩阵。
具体到某个单元,它的输出值y是h和Ws的乘积,即另一个权值矩阵:
我们再来回顾一下RNN的优点。RNN与传统NN的最大区别在于RNN输入的是一个序列(这里就是一系列单词)。像CNN模型的输入也只是一张单一的图片,而RNN的输入既可以是一句简短的句子,也可以是一篇5个段落的文章。输入序列的顺序也会极大影响训练效果。理想情况下,隐藏状态有望捕捉过去的信息(历史输入内容)。
门控递归单元
(Gated Recurrent Units)
我们再来介绍门控递归单元。这种门控单元的目的是为RNN模型在计算隐层状态时提供一种更复杂的方法。这种方法将使我们的模型能够保持更久远的信息。为什么保持长期依赖是传统循环神经网络存在的问题呢?因为在误差反向传播的过程中,梯度沿着RNN模型由近及远往回传播。如果初始梯度是一个很小的数值(例如 < 0.25),那么在传播到第三个或第四个模块时,梯度将几乎消失(多级梯度连乘),因此较靠前的单元的隐藏状态得不到更新。
在传统的RNN模型中,隐藏状态向量的计算公式如下:
而GRU采取了另一种计算方式。计算过程被分为三块:更新门,重置门和一个新的记忆存储器。两个门都是输入词向量与上一步隐藏状态的函数:
其实,关键的差别之处就在于不同的门有不同的权重矩阵,通过公式中的上标加以区分。更新门的符号是Wz和Uz,重置门的符号是WT和UT。
新存储器的计算公式如下:
式子中的空心点表示逐元素相乘 (https://en.wikipedia.org/wiki/Hadamard_product_%28matrices%29)。
如果仔细观察公式,大家会发现如果重置门单元的输出值接近于0,那么整一项的值都接近于0,相当于忽略了ht-1步的状态。此时,模型只考虑当前的输入词向量xt。
h(t)的最终形式如下公式所示:
h(t)函数由三部分组成:更新门,重置门和一个记忆存储器。当zt接近于1时,新的隐藏状态ht几乎完全依赖于上一次的状态,因为(1-zt)接近0,后一项的乘积也接近于0。当zt接近于0时,情况则相反。
长短期记忆单元
(Long Short-Term Memory Units)
如果大家已经理解了GRU的原理,那么就能很容易理解LSTM。LSTM同样也是由多个门控模块组成:
显然,LSTM引入的信息更多。由于LSTM可以被看作是GRU思路的引申,因此,作者不打算再做太深入的分析,读者若想要理解每一扇门和每一个公式的来龙去脉,Chris Olah撰写了一篇精彩的文章 (http://colah.github.io/posts/2015-08-Understanding-LSTMs/)。这是目前为止介绍LSTM的最精彩的教程,一定会对大家理解各个单元的原理有着很大的帮助。
LSTM和GRU对比
我们先来探讨两者的相似之处。原作者认为,这两种模型都具有保持序列数据长期信息依赖的特殊能力。长期信息指的是两个词语或者短语之间间隔很远,但是它们之间的关系对理解句子又至关重要。LSTM和GRU都是通过门控模块来捕捉或是选择性忽略这些依赖关系。
两者的差异之处在于门的数量,GRU有两扇门,LSTM有三扇门。门的数量也会影响到输入单词之间的非线性关系,并且影响最终的计算结果。GRU也不具有LSTM模型的记忆单元。
写在阅读论文之前
要提醒大家一点,NLP领域还有很多很多其它种类的深度学习模型,有时候递归神经网络和卷积神经网络也会用在NLP任务中,但没有RNN这么广泛。
不错,我们现在已经对深度学习在自然语言处理领域的应用有了清晰的认识,接下来一起就读几篇论文吧。NLP领域的方向很多(例如机器翻译、问答系统等等),我们可以挑选阅读的文献也很多,作者从中挑选了三篇具有代表性的。
记忆网络(Memory Networks)
原作者挑选的第一篇论文 (http://colah.github.io/posts/2015-08-Understanding-LSTMs/) 是问答领域非常有影响力的一篇文章。此文的作者是Jason Weston, Sumit Chopra, 和 Antoine Bordes,此文介绍了一类称作记忆网络的模型。
直观的想法是,为了准确地回答一个文本的问题,我们需要以某种方式来存储初始信息。如果问大家,“RNN指的是什么”?认真阅读了文章前半部分的读者一定能够回答。只不过大家可能要花几秒钟的时间去前文中查找相关段落。我们暂且不知道人类大脑执行这一行为的机制是什么,但一般认为大脑中有一块区域来存储这些信息。
此篇文章所介绍的记忆网络独特之处在于它有一块可以读写的关联记忆区域。CNN模型、强化学习以及传统的神经网络都没有这种记忆功能。也许是因为问答系统重度依赖长期的上下文信息,比如要追溯事件发生的时间线。对于CNN和强化学习而言,它们通过训练不同的滤波器或是状态到行为的映射关系,已经将“记忆”体现在权值矩阵中。乍一看,RNN和LSTM符合要求,但是一般也无法记忆历史的输入内容(对于问答系统至关重要)。
网络结构
我们一起看看网络是如何处理初始输入内容的。和大多数机器学习算法一样,此方法首先也是将输入内容映射成特征表示。映射的方法可以是词向量、成分标注或者语法分析等等。
下一步,根据特征表示I(x)更新记忆内容m,以反馈新输入内容x引入的信息。
我们可以把m看成是若干个mi组成的数组。每个独立的mi又可以视为m、特征表示I(x)和其本身的函数G。记忆内容的更新是通过G函数完成。第三步和第四步是读取记忆信息,根据问题生成特征表示o,然后将其解码输出得到最终的答案r。
函数R可以是一个RNN模型,将特征表示转化为我们人类可读的文字答案。
针对第三步,我们希望O模块输出的特征表示是最匹配该问题的答案。那么,这个问题将与各个记忆单元逐一比较,计算它们之间的匹配得分。
最后,用argmax函数选出得分最高的一项(或者多项)。计算得分的方法就是将问题的embedding向量与各个记忆单元的特征表示向量相乘(细节请参见论文 https://arxiv.org/pdf/1410.3916v11.pdf)。这个过程与计算两个词向量的相似度类似。输出的表示特征o再被送入RNN或是LSTM模型,生成最终我们可读的答案。
整个训练过程属于监督式学习,训练数据包括问题、原始语料、经过标记的答案。目标函数如下图所示:
更多的相关资料可以参见下面几篇论文:
- End-to-End Memory Networks https://arxiv.org/pdf/1503.08895v5.pdf
- Dynamic Memory Networks https://arxiv.org/pdf/1506.07285v5.pdf
- Dynamic Coattention Networks https://arxiv.org/pdf/1611.01604v2.pdf
情感分析的树形LSTM模型
下一篇论文 (https://arxiv.org/pdf/1503.00075v3.pdf) 主要内容是介绍情感分析的方法,分析某个短语是否包含正面或是负面的情绪。《心理学大辞典》中认为:“情感是人对客观事物是否满足自己的需要而产生的态度体验”。LSTM是目前情感分析最常用的网络结构。Kai Sheng Tai, Richard Socher, 和 Christopher Manning所发表的这篇论文介绍了一种新颖的方法将LSTM网络串联成非线性的结构。
这种非线性排列的动机源自自然语言所具有的属性,即词语序列构成短语。而词语的排列顺序不同,构成的短语含义也不相同,甚至与单个词语的含义完全相反。为了体现这一特点,LSTM单元构成的网络必须呈树状结构排列,不同的单元受其子节点的影响。
网络结构
树形LSTM与标准型网络结构的差异之一是后者的隐藏状态是当前输入与上一步隐藏状态的函数,而前者的隐藏状态则是当前输入与其子节点的隐藏状态的函数。
由于网络结构的改变,训练的方法也有所变化,具体细节可以参考这篇文章 (https://arxiv.org/pdf/1503.00075v3.pdf)。作者的关注点在于为何这种模型的效果比线性LSTM更好。
基于树形的结构,每个独立单元的状态与其所有子节点的隐藏状态都相关。这一点很重要,因为因为每个节点可以区别对待其子节点。在训练过程中,网络模型能学到某些特殊单词(比如“not”和“very”)对整句话的情感分析相当重要。若模型能给予这部分节点更大的权重,最终取得的效果也将更好。
神经机器翻译
作者挑选的最后一篇论文 (https://arxiv.org/pdf/1609.08144v2.pdf) 是关于机器翻译的。该文的作者是谷歌的机器学习大牛们,Jeff Dean, Greg Corrado, Orial Vinyals等人,这篇文章介绍了支撑谷歌翻译服务的基础系统。该系统相比之前谷歌所用的系统,翻译的平均错误率降低了60%。
传统的自动翻译方法包括多种短语匹配方法。这种方法需要大量的语言学的领域知识,而且最终其设计方案被证明过于脆弱,缺乏泛化能力。传统方法存在的问题之一,就是它会试图一块一块地翻译输入的句子。事实证明,最有效的方法(即神经机器翻译的技术)是一次翻译整个句子,从而译文显得更自然流畅。
网络结构
该论文介绍了一种深度LSTM神经网络,包括8个编码和解码层,实现端到端的训练过程。这套系统可以拆分为三部分:编码RNN,解码RNN和注意力模块。从宏观来说,编码器将输入的句子表示为向量的形式,解码器生成输出表示,注意力模块则是在解码阶段告诉解码器该聚焦哪部分内容(这就是利用句子整体语境的思想来源):
论文的剩余部分主要讨论大规模部署这套系统所面临的挑战,包括计算资源消耗、延迟,以及高并发量等等。
总结
笔者认为,今后深度学习会在客户服务机器人、机器翻译以及复杂的问答系统发挥作用。特别感谢Richard Socher以及斯坦福CS224D课程 (http://cs224d.stanford.edu/index.html) 老师提供的精彩课堂和幻灯片。