seq2seq模型_CS224n笔记[7]:整理了12小时,只为让你20分钟搞懂Seq2seq

3f4d671f27cb6b0467a28be7eaea8409.png

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的主要思想就是从大量的数据中学习一个概率模型

,其中x是源语言(source language),y是目标语言(target language),即x翻译成y的概率有多大。在翻译时,我们只需要通过求
就行了,即找到概率最大的那个y,就是x的最佳翻译了。

这么一想,是不是感觉跟之前介绍过的语言模型(LM)挺像的?LM是根据一句话的前面几个词,给出下一个词的概率。这里的SMT则是根据source文本给出target文本的概率。但不要搞混淆,这里的x和y不是单个词,而是一句话。我们对

通过贝叶斯公式进行转换,可以得到:

这里由于我们是要找出使得上式最大的y,因此只跟x相关的分母可以被省去。跟上面这个公式的变换,我们发现SMT真的跟语言模型是有关的:

就是求y这个句子的概率,这就是一个
「语言模型」(LM)。而后者
则被称为
「翻译模型」(TM)。LM可以通过目标语言的语料进行训练,TM则需要通过 「平行语料」(parallel corpus,即源和目标两种语言的互相对照的语料,比如“罗塞塔石碑”,上面刻有一份古埃及的诏书的三个语言的版本)进行训练。

cb263ebd9daba65ff2b0116c29473eb4.png

有人(我)就奇怪了,原本的

不就是一个翻译模型吗?经过这么一分解,不仅还有一个翻译模型,还多了一个语言模型!这不是越搞越复杂吗?其实不是这样的,翻译模型和语言模型,各自有所偏重。翻译模型通过大量的平行语料,学习到的主要是两种语言之间的对应关系,而语言模型则侧重于学习一种语言内部的语法结构,不同词汇是怎么流畅地组合成句子的。原本的公式只有一个翻译模型,会导致我们训练出来的模型在翻译结果的语言通畅性方面很差。因此,我们经过公式变换,将一个TM任务转化成TM+LM两种任务,可以模型学习的结果更好。

对于TM的学习,一般我们会进一步进行分解,考虑两种语言之间的各种对齐方式(alignment),即在原有的翻译模型上,引入一个隐变量a,得到

,可以理解为给定句子y,按照对齐方式a翻译成x的概率。

具体什么是对齐方式alignment呢?它的意思就是在两种语言A和B之间,A的词是跟B的词怎么对应的。很明显,这种对应关系可以是一对一、一对多、多对一、多对多的。比方下图:

ec834477f1bc50f78feaecc7835a51d3.png

这里例子展示了一个法语句子和英语句子词语对齐关系,其中法语词entarte,英文翻译是“hit me with a pie”,英文中根本没有一个词可以直接表示这个含义。中英文中这样的例子更加常见了,有些英文单词可以用一个汉字对应,但也有很多单词需要两个甚至多个汉字对应。另外,同一个词,在不同的语境下,对齐的词和数量都有可能不同,比如“牛”可以对应“cow”也可以对应“awesome”,“cool”可以对应“酷”也可以对应“凉快”。因此,对齐,alignment,是一个十分复杂的东西,学习

也是很麻烦,这里我也不太了解,就不细讲了。

在学习了LM和TM这两个模型之后,是不是就完事儿了呢?当然没有,别忘了公式里还有一个argmax,我们要找出最佳的翻译是什么。根据LM和TM寻找最佳y的过程,就称为“decoding”,即解码。

2c23c90325a6a7e69126facc159b7b47.png

一个最直接的方法就是,遍历所有可能的y,选择概率最大的那个,当然就是最佳的翻译。明显,这种方式带来的开销是我们无法忍受的。如果学习过CRF或者HMM,我们应该知道对于这种解码的过程,我们一般使用动态规划、启发式搜索的方法来处理。在SMT中具体怎么解码,我们这里也暂时不做深入的研究。

统计机器翻译——SMT,在深度学习时代之前,风光无限,一直是机器翻译的巅峰技术。但是,SMT的门槛也是很高的,那些表现优异的SMT模型,通常都是极其复杂的,里面涉及到大量的特征工程,海量的专家知识,无数的资源积累,繁多的功能模块,还需要庞大的人力去维护。这也是我根本不想去深入了解这个技术的原因。

幸好,在深度学习时代,我们有了更好的方法:神经机器翻译(Neural Machine Translation,NMT)。

神经机器翻译(NMT)

深度学习的“可恨之处”在于,它把那些需要大量人力的工作都吃掉了,导致行业专家和搬砖工人门纷纷下岗。NMT就是这样,企图就是用一个简洁的神经网络结构,就把机器翻译这么大的一个工程给包下来。 我画了一个形象生动的图来示意SMT和NMT的区别:

0ea2cb850a4cd5a18f9a607ac5311985.png

NMT使用的神经网络结构,是一种被称为sequence-to-sequence的结构,即seq2seq。它还有另外一个常见的名字:Encoder-Decoder结构。这种结构一般都是由两个RNN组成。下面我画了一个抽象的示意图:

cb5107234d17ecdea56c33a54c02beb3.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

这张图,展示了在「训练时」,seq2seq内部的详细结构。

在Encoder端,我们将source文本的词序列先经过embedding层转化成向量,然后输入到一个RNN结构(可以是普通RNN,LSTM,GRU等等)中。另外,这里的RNN也可以是多层、双向的。经过了RNN的一系列计算,最终隐层的输入,就作为源文本整体的一个表示向量,称为「context vector」

Decoder端的操作就稍微复杂一些了。首先,Decoder的输入是什么呢?Decoder的输入,训练和测试时是不一样的! 「在训练时,我们使用真实的目标文本,即“标准答案”作为输入」(注意第一步使用一个特殊的<start>字符,表示句子的开头)。每一步根据当前正确的输出词、上一步的隐状态来预测下一步的输出词。

下图则展示了在「预测时」,seq2seq的内部结构:

3408011f8666b188cff6bd15f077b1ed.png

预测时,Encoder端没什么变化,在Decoder端,由于此时没有所谓的“真实输出”或“标准答案”了,所以只能「自产自销:每一步的预测结果,都送给下一步作为输入」,直至输出<end>就结束。如果你对我之前写的笔记很熟悉的话,会发现,「这时的Decoder就是一个语言模型」。由于这个语言模型是根据context vector来进行文本的生成的,因此这种类型的语言模型,被称为“条件语言模型”:Conditional LM。正因为如此,在训练过程中,我们可以使用一些预训练好的语言模型来对Decoder的参数进行初始化,从而加快迭代过程。

为什么训练和预测时的Decoder不一样?

很多人可能跟我一样,对此感到疑惑:为什么在训练的时候,不能直接使用这种语言模型的模式,使用上一步的预测来作为下一步的输入呢?

389ae1007e5a6914f1479d7faaa07142.png

我们称这两种模式,根据标准答案来decode的方式为「teacher forcing」,而根据上一步的输出作为下一步输入的decode方式为「free running」

其实,free running的模式真的不能在训练时使用吗?——当然是可以的!从理论上没有任何的问题,又不是不能跑。但是,在实践中人们发现,这样训练太南了。因为没有任何的引导,一开始会完全是瞎预测,正所谓“一步错,步步错”,而且越错越离谱,这样会导致训练时的累积损失太大(「误差爆炸」问题,exposure bias),训练起来就很费劲。这个时候,如果我们能够在每一步的预测时,让老师来指导一下,即提示一下上一个词的正确答案,decoder就可以快速步入正轨,训练过程也可以更快收敛。因此大家把这种方法称为teacher forcing。所以,这种操作的目的就是为了使得训练过程更容易。

这就好比我们考驾照时,很多教练为了让我们快速通关,会给我们在场地上画上各种标记,告诉我们你看到某个标记就执行某个动作(说白了就是作弊手段)。这种方法很有效,我们在练车的时候,死记住这些作弊技巧,很容易在训练场顺利倒车、侧方停车。但这种方法在我们上考场的时候就会暴露出问题了——考场上可没人给你做标记!因此很多人明明在下面自己练车的时候很顺,以上考场就挂了。这也是teacher forcing方法的一个弊端:预测时我们没有老师给你做标记了!纯靠自己很可能挂掉。

所以,更好的办法,更常用的办法,是老师只给适量的引导,学生也积极学习。即我们设置一个概率p,每一步,以概率p靠自己上一步的输入来预测,以概率1-p根据老师的提示来预测,这种方法称为「计划采样」(scheduled sampling):

119767bfa0f56c50a674d366a72216be.png

这是种什么感觉呢?就拿我们来刷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

这种Greedy的方式,简单快速,但是既然叫“贪心”,肯定会有问题,那就是「每一步最优,不一定全局最优」,这种方式很可能“捡了芝麻,丢了西瓜”。

改进的方法,就是使用「Beam Search」方法:每一步,多选几个作为候选,最后综合考虑,选出最优的组合。

下面我们来具体看看Beam Search的操作步骤:

  • 首先,我们需要设定一个候选集的大小beam size=k;
  • 每一步的开始,我们从每个当前输入对应的所有可能输出,计算每一条路的“序列得分”;
  • 保留“序列得分”最大的k个作为下一步的输入;
  • 不断重复上述过程,直至结束,选择“序列得分”最大的那个序列作为最终结果。

这里的重点就在于这个“序列得分”的计算。

我们使用如下的score函数来定义「序列得分」

这个score代表了当前到第t步的输出序列的一个综合得分,越高越好。其中

类似于前面我们写的第t步的交叉熵损失的负数。所以这个score越到,就意味着到当前这一步为止,输出序列的累积损失越小。

再多描述不如一张图直观,我用下图描绘一个极简的案例(只有3个词的语料,k=2):

327ca0e77f025d32de80c360fdec4ac6.png

本来想贴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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值