![3f4d671f27cb6b0467a28be7eaea8409.png](https://i-blog.csdnimg.cn/blog_migrate/fbbe01b06ea87cc641e679599c1e6e5d.jpeg)
CS224n笔记[7]:机器翻译和seq2seq
作者:郭必扬
今天主要介绍机器翻译的简单发展历史和方法,由此引入seq2seq框架,我们会一起深入讨论seq2seq框架中的各种细节,并配合精美的结构图、流程图辅助大家理解。
本文约5000字,阅读约20分钟
目录:
- 机器翻译
- 传统机器翻译,SMT
- 神经机器翻译,NMT
- Seq2seq
- Seq2seq结构详解
- 为什么训练和预测时的Decoder不一样?
- Seq2seq的损失函数
- Decoding和Beam Search
- 总结
- NMT的优缺点
- 机器翻译的评价指标
一、机器翻译
传统机器翻译
早期的(1950s)机器翻译的思路十分简单,通过设置大量的翻译规则,构建一个大型的双语对照表,来将源语言翻译成目标语言。这个固然简单,也自然效果很一般。因此我们不展开描述。
后来(1990s-2010s)我们有了更为先进复杂的机器翻译技术——「统计机器翻译」(Statistical Machine Translation, SMT)。
SMT的主要思想就是从大量的数据中学习一个概率模型
这么一想,是不是感觉跟之前介绍过的语言模型(LM)挺像的?LM是根据一句话的前面几个词,给出下一个词的概率。这里的SMT则是根据source文本给出target文本的概率。但不要搞混淆,这里的x和y不是单个词,而是一句话。我们对
则
这里由于我们是要找出使得上式最大的y,因此只跟x相关的分母可以被省去。跟上面这个公式的变换,我们发现SMT真的跟语言模型是有关的:
![cb263ebd9daba65ff2b0116c29473eb4.png](https://i-blog.csdnimg.cn/blog_migrate/e849210a0889137f6283f6efeda9fc62.jpeg)
有人(我)就奇怪了,原本的
对于TM的学习,一般我们会进一步进行分解,考虑两种语言之间的各种对齐方式(alignment),即在原有的翻译模型上,引入一个隐变量a,得到
具体什么是对齐方式alignment呢?它的意思就是在两种语言A和B之间,A的词是跟B的词怎么对应的。很明显,这种对应关系可以是一对一、一对多、多对一、多对多的。比方下图:
![ec834477f1bc50f78feaecc7835a51d3.png](https://i-blog.csdnimg.cn/blog_migrate/a0ba9ed0db1286ef983b80134094b635.png)
这里例子展示了一个法语句子和英语句子词语对齐关系,其中法语词entarte,英文翻译是“hit me with a pie”,英文中根本没有一个词可以直接表示这个含义。中英文中这样的例子更加常见了,有些英文单词可以用一个汉字对应,但也有很多单词需要两个甚至多个汉字对应。另外,同一个词,在不同的语境下,对齐的词和数量都有可能不同,比如“牛”可以对应“cow”也可以对应“awesome”,“cool”可以对应“酷”也可以对应“凉快”。因此,对齐,alignment,是一个十分复杂的东西,学习
在学习了LM和TM这两个模型之后,是不是就完事儿了呢?当然没有,别忘了公式里还有一个argmax,我们要找出最佳的翻译是什么。根据LM和TM寻找最佳y的过程,就称为“decoding”,即解码。
![2c23c90325a6a7e69126facc159b7b47.png](https://i-blog.csdnimg.cn/blog_migrate/2e17bda1849cb970df879ede272a0a4a.png)
一个最直接的方法就是,遍历所有可能的y,选择概率最大的那个,当然就是最佳的翻译。明显,这种方式带来的开销是我们无法忍受的。如果学习过CRF或者HMM,我们应该知道对于这种解码的过程,我们一般使用动态规划、启发式搜索的方法来处理。在SMT中具体怎么解码,我们这里也暂时不做深入的研究。
统计机器翻译——SMT,在深度学习时代之前,风光无限,一直是机器翻译的巅峰技术。但是,SMT的门槛也是很高的,那些表现优异的SMT模型,通常都是极其复杂的,里面涉及到大量的特征工程,海量的专家知识,无数的资源积累,繁多的功能模块,还需要庞大的人力去维护。这也是我根本不想去深入了解这个技术的原因。
幸好,在深度学习时代,我们有了更好的方法:神经机器翻译(Neural Machine Translation,NMT)。
神经机器翻译(NMT)
深度学习的“可恨之处”在于,它把那些需要大量人力的工作都吃掉了,导致行业专家和搬砖工人门纷纷下岗。NMT就是这样,企图就是用一个简洁的神经网络结构,就把机器翻译这么大的一个工程给包下来。 我画了一个形象生动的图来示意SMT和NMT的区别:
![0ea2cb850a4cd5a18f9a607ac5311985.png](https://i-blog.csdnimg.cn/blog_migrate/65a873cfcd5c142527fbf5cc2298690d.png)
NMT使用的神经网络结构,是一种被称为sequence-to-sequence的结构,即seq2seq。它还有另外一个常见的名字:Encoder-Decoder结构。这种结构一般都是由两个RNN组成。下面我画了一个抽象的示意图:
![cb5107234d17ecdea56c33a54c02beb3.png](https://i-blog.csdnimg.cn/blog_migrate/bdacc58ebf0ada270d2c103a907f3b6b.png)
从这个抽象示意图上看,seq2seq的结构的Encoder部分读取输入文本,在机器翻译中即源语言文本,通过Encoder编码成一个表示向量,即context vector,然后交给Decoder来进行解码,翻译成目标语言。在训练和预测时,我们都可以使用这样的结构,没有其他的花里胡哨的东西,因此总体上看起来比SMT要简洁明了得多。
上面这张图还是太抽象了,下面让我们深入seq2seq结构的内部,看看我们如何使用这个结构来进行训练和预测。
二、seq2seq
这里说个题外话,seq2seq我之前一直读/sek-tu:-sek/
,后来听了网课,发现正确的读法应该是/si:k-tu:-si:k/
,毕竟sequence的读音是/si:kwəns/
。读正确的读音,也让我们讨论技术的时候也更有底气不是?
seq2seq结构详解
我们把前面那张抽象图展开,可以看到内部的结构是这样的:
❝ One hour later(辛苦画图中)......
❞
![5156f630d41f8747cf9e587c4c6e17bf.png](https://i-blog.csdnimg.cn/blog_migrate/550c63eac6eb1c6985c9fe70a45847e2.jpeg)
这张图,展示了在「训练时」,seq2seq内部的详细结构。
在Encoder端,我们将source文本的词序列先经过embedding层转化成向量,然后输入到一个RNN结构(可以是普通RNN,LSTM,GRU等等)中。另外,这里的RNN也可以是多层、双向的。经过了RNN的一系列计算,最终隐层的输入,就作为源文本整体的一个表示向量,称为「context vector」。
Decoder端的操作就稍微复杂一些了。首先,Decoder的输入是什么呢?Decoder的输入,训练和测试时是不一样的! 「在训练时,我们使用真实的目标文本,即“标准答案”作为输入」(注意第一步使用一个特殊的<start>
字符,表示句子的开头)。每一步根据当前正确的输出词、上一步的隐状态来预测下一步的输出词。
下图则展示了在「预测时」,seq2seq的内部结构:
![3408011f8666b188cff6bd15f077b1ed.png](https://i-blog.csdnimg.cn/blog_migrate/85279875ba101f0ecd6ef39290b47582.jpeg)
预测时,Encoder端没什么变化,在Decoder端,由于此时没有所谓的“真实输出”或“标准答案”了,所以只能「自产自销:每一步的预测结果,都送给下一步作为输入」,直至输出<end>
就结束。如果你对我之前写的笔记很熟悉的话,会发现,「这时的Decoder就是一个语言模型」。由于这个语言模型是根据context vector来进行文本的生成的,因此这种类型的语言模型,被称为“条件语言模型”:Conditional LM。正因为如此,在训练过程中,我们可以使用一些预训练好的语言模型来对Decoder的参数进行初始化,从而加快迭代过程。
为什么训练和预测时的Decoder不一样?
很多人可能跟我一样,对此感到疑惑:为什么在训练的时候,不能直接使用这种语言模型的模式,使用上一步的预测来作为下一步的输入呢?
![389ae1007e5a6914f1479d7faaa07142.png](https://i-blog.csdnimg.cn/blog_migrate/bda2466e86022e6f2cf5860eb412d836.jpeg)
我们称这两种模式,根据标准答案来decode的方式为「teacher forcing」,而根据上一步的输出作为下一步输入的decode方式为「free running」。
其实,free running的模式真的不能在训练时使用吗?——当然是可以的!从理论上没有任何的问题,又不是不能跑。但是,在实践中人们发现,这样训练太南了。因为没有任何的引导,一开始会完全是瞎预测,正所谓“一步错,步步错”,而且越错越离谱,这样会导致训练时的累积损失太大(「误差爆炸」问题,exposure bias),训练起来就很费劲。这个时候,如果我们能够在每一步的预测时,让老师来指导一下,即提示一下上一个词的正确答案,decoder就可以快速步入正轨,训练过程也可以更快收敛。因此大家把这种方法称为teacher forcing。所以,这种操作的目的就是为了使得训练过程更容易。
这就好比我们考驾照时,很多教练为了让我们快速通关,会给我们在场地上画上各种标记,告诉我们你看到某个标记就执行某个动作(说白了就是作弊手段)。这种方法很有效,我们在练车的时候,死记住这些作弊技巧,很容易在训练场顺利倒车、侧方停车。但这种方法在我们上考场的时候就会暴露出问题了——考场上可没人给你做标记!因此很多人明明在下面自己练车的时候很顺,以上考场就挂了。这也是teacher forcing方法的一个弊端:预测时我们没有老师给你做标记了!纯靠自己很可能挂掉。
所以,更好的办法,更常用的办法,是老师只给适量的引导,学生也积极学习。即我们设置一个概率p,每一步,以概率p靠自己上一步的输入来预测,以概率1-p根据老师的提示来预测,这种方法称为「计划采样」(scheduled sampling):
![119767bfa0f56c50a674d366a72216be.png](https://i-blog.csdnimg.cn/blog_migrate/aa8204add7e1cbc304edcd97d8880517.jpeg)
这是种什么感觉呢?就拿我们来刷LeetCode来说吧,完全不看答案的话,对于我来说的话就太难了。。。做题的进度会灰常慢,如果我完全看答案写,那也没啥意义,过几天就忘了,所以最好的方式就是自己也思考,遇到太难的时候就看看答案,这样我们又能保证进度,又能有学习效果。
另外有一个小细节:在seq2seq的训练过程中,decoder即使遇到了<end>
标识也不会结束,因为训练的时候并不是一个生成的过程 ,我们需要等到“标准答案”都输入完才结束。
seq2seq的损失函数
前面我们详细介绍了seq2seq的内部的结构,明白了内部结构,想知道是怎么训练的就很容易了。
在上面的图中,我们看到decoder的每一步产生隐状态后,会通过一个projection层映射到对应的词。那怎么去计算每一步的损失呢?实际上,这个projection层,通常是一个softmax神经网络层,假设词汇量是V,则会输出一个V维度的向量,每一维代表是某个词的概率。映射的过程就是把最大概率的那个词找出来作为预测出的词。
在计算损失的时候,我们使用交叉熵作为损失函数,所以我们要找出这个V维向量中,正确预测对应的词的那一维的概率大小
其中T代表Decoder有多少步,[EOS]代表‘end of sentence’这个特殊标记,本来想打<end>
跟前面保持一致的,因为LaTeX里面显示的问题,我替换了一下。
Decoding和Beam search
前面画的几个图展示的预测过程,其实就是最简单的decoding方式——「Greedy Decoding」,即每一步,都预测出概率最大的那个词,然后输入给下一步。
![2aeab301c572d1e618f68ad0acfd0622.png](https://i-blog.csdnimg.cn/blog_migrate/cb5a3dc3e6a9e19033f64477cb75ec96.png)
这种Greedy的方式,简单快速,但是既然叫“贪心”,肯定会有问题,那就是「每一步最优,不一定全局最优」,这种方式很可能“捡了芝麻,丢了西瓜”。
改进的方法,就是使用「Beam Search」方法:每一步,多选几个作为候选,最后综合考虑,选出最优的组合。
下面我们来具体看看Beam Search的操作步骤:
- 首先,我们需要设定一个候选集的大小beam size=k;
- 每一步的开始,我们从每个当前输入对应的所有可能输出,计算每一条路的“序列得分”;
- 保留“序列得分”最大的k个作为下一步的输入;
- 不断重复上述过程,直至结束,选择“序列得分”最大的那个序列作为最终结果。
这里的重点就在于这个“序列得分”的计算。
我们使用如下的score函数来定义「序列得分」:
这个score代表了当前到第t步的输出序列的一个综合得分,越高越好。其中
再多描述不如一张图直观,我用下图描绘一个极简的案例(只有3个词的语料,k=2):
![327ca0e77f025d32de80c360fdec4ac6.png](https://i-blog.csdnimg.cn/blog_migrate/39425b6832ea9b420881cbbf8e687265.jpeg)
本来想贴CS224N上的图,发现上面省去了一些细节容易造成误解。在每一步,我们都会去对所有的可能输出,计算一次score,假设beam size为k,词汇量为V,那么每一步就需要分出k×V个分支并逐一计算score。所以在图中我们可以看到除了第一步,后面每一步都是分出来2×3=6支。然后综合这k×V个score的结果,只选择其中最大的k个保留。
最后还有一个问题:由于会有多个分支,所以很有可能我们会遇到多个<end>
标识,由于分支较多,如果等每一个分支都遇到<end>
才停的话,可能耗时太久,因此一般我们会设定一些规则,比如已经走了T步,或者已经积累了N条已完成的句子,就终止beam search过程。
在search结束之后,我们需要对已完成的N个序列做一个抉择,挑选出最好的那个,那不就是通过前面定义的score函数来比较吗?确实可以,但是如果直接使用score来挑选的话,会导致那些很短的句子更容易被选出。因为score函数的每一项都是负的,序列越长,score往往就越小。因此我们可以使用长度来对score函数进行细微的调整:对每个序列的得分,除以序列的长度。根据调整后的结果来选择best one。
Beam Search的使用,往往可以得到比Greedy Search更好的结果,道理很容易理解,高手下棋想三步,深思熟虑才能走得远。
NMT的优缺点、评价方式
上面我们花了大量时间基本介绍清楚了神经机器翻译以及seq2seq的结构细节。最后我们对NMT稍作总结,并补充一些小细节。
NMT的优缺点
NMT相比于SMT,最大的优点当然就如前面所说的——简洁。我们不需要什么人工的特征工程,不需要各种复杂的前后组件,就是一个端到端的神经网络,整个结构一起进行优化。
另外,由于使用了深度学习的方法,我们可以引入很多语义特征,比如利用文本的相似度,利用文本内隐含的多层次特征,这些都是统计学方法没有的。
但是,没有什么东西是绝对好或绝对差的,NMT也有其不足。它的不足也是跟深度学习的黑箱本质息息相关。NMT的解释性差,难以调试,难以控制,我们谁也不敢保证遇到一个新的文本它会翻译出什么奇怪的玩意儿,所以NMT在重要场合使用是有明显风险的。
NMT的评价
机器翻译的效果如何评价呢?——「BLEU」指标。
BLEU,全称是Bilingual Evaluation Understudy,它的主要思想是基于N-gram等特征来比较人工翻译和机器翻译结果的相似程度。详情我不赘述,毕竟写这篇文章时我也还没有自己动手去做一个NMT。等之后做这一块的时候我再详细讨论吧。
好了,再不结束,不光你们要烦了,我也要烦了(•́へ•́╬)。关于seq2seq的基本知识点,我应该已经讲得很清楚了,你们觉得呢?
>欢迎订阅我的Hello NLP系列文章(不断更新中):
CS224n笔记[1]:Word2Vec从何而来
CS224n笔记[2]:Word2Vec算法推导&实现
CS224n笔记[3]:共现矩阵、SVD与GloVe词向量
CS224n笔记[4]:自然语言中的依存分析(Dependency Parsing)
CS224n笔记[5]:语言模型(LM)和循环神经网络(RNNs)
CS224n笔记[6]:更好的我们,更好的RNNs
CS224n笔记[7]:机器翻译和seq2seq>我的其他高赞文章,总有一款是你的菜:
何时能懂你的心——图卷积神经网络(GCN)
GraphSAGE:我寻思GCN也没我牛逼
【DL笔记8】如果你愿意一层一层剥开CNN的心
【DL笔记6】从此明白了卷积神经网络(CNN)
一条龙搞定情感分析:文本预处理、加载词向量、搭建RNN
Docker,救你于「深度学习环境配置」的苦海>更多精彩,欢迎订阅我的公众号:SimpleAI