Temp
A High-Level Look
首先将这个模型看成是一个黑箱操作。在机器翻译中,就是输入一种语言,输出另一种语言。

那么拆开这个黑箱,我们可以看到它是由编码组件、解码组件和它们之间的连接组成。

编码组件部分由一堆编码器(encoder)构成(论文中是将6个编码器叠在一起——数字6没有什么神奇之处,你也可以尝试其他数字)。解码组件部分也是由相同数量(与编码器对应)的解码器(decoder)组成的。

所有的编码器在结构上都是相同的,但它们没有共享参数。每个编码器都可以分解成两个子层。

从编码器输入的句子首先会经过一个自注意力(self-attention)层,这层帮助编码器在对每个单词编码时关注输入句子的其他单词。自注意力层的输出会传递到前馈(feed-forward)神经网络中。每个位置的单词对应的前馈神经网络都完全一样(译注:另一种解读就是一层窗口为一个单词的一维卷积神经网络)。
解码器中也有编码器的自注意力(self-attention)层和前馈(feed-forward)层。除此之外,这两个层之间还有一个注意力层,用来关注输入句子的相关部分(和seq2seq模型的注意力作用相似)。
Bringing The Tensors Into The Picture
像大部分NLP应用一样,我们首先将每个输入单词通过词嵌入算法转换为词向量。
每个单词都被嵌入为512维的向量,我们用这些简单的方框来表示这些向量。
词嵌入过程只发生在最底层的编码器中。所有的编码器都有一个相同的特点,即它们接收一个向量列表,列表中的每个向量大小为512维。在底层(最开始)编码器中它就是词向量,但是在其他编码器中,它就是下一层编码器的输出(也是一个向量列表)。向量列表大小是我们可以设置的超参数——一般是我们训练集中最长句子的长度。
将输入序列进行词嵌入之后,每个单词都会流经编码器中的两个子层。
接下来我们看看Transformer的一个核心特性,在这里输入序列中每个位置的单词都有自己独特的路径流入编码器。在自注意力层中,这些路径之间存在依赖关系。而前馈(feed-forward)层没有这些依赖关系。因此在前馈(feed-forward)层时可以并行执行各种路径。
Encoding
如上述已经提到的,一个编码器接收向量列表作为输入,接着将向量列表中的向量传递到自注意力层进行处理,然后传递到前馈神经网络层中,将输出结果传递到下一个编码器中。

输入序列的每个单词都经过自编码过程。然后,他们各自通过前向传播神经网络——完全相同的网络,而每个向量都分别通过它。
Self-Attention at a High Level
参考Attention is All You Need 这篇论文,让我们精炼一下它的工作原理。
例如,下列句子是我们想要翻译的输入句子:
The animal didn’t cross the street because it was too tired
这个“it”在这个句子是指什么呢?它指的是street还是这个animal呢?这对于人类来说是一个简单的问题,但是对于算法则不是。
当模型处理这个单词“it”的时候,自注意力机制会允许“it”与“animal”建立联系。
随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。
如果你熟悉RNN(循环神经网络),回忆一下它是如何维持隐藏层的。RNN会将它已经处理过的前面的所有单词/向量的表示与它正在处理的当前单词/向量结合起来。而自注意力机制会将所有相关单词的理解融入到我们正在处理的单词中。
当我们在编码器#5(栈中最上层编码器)中编码“it”这个单词的时,注意力机制的部分会去关注“The Animal”,将它的表示的一部分编入“it”的编码中。
Tips
那接下来,不侷限于 Transformer ,讲一些训练这种 Sequence To Sequence Model 的Tips
Copy Mechanism
在我们刚才的讨论里面,我们都要求 Decoder 自己产生输出,但是对很多任务而言,也许 Decoder 没有必要自己创造输出出来,它需要做的事情,也许是从输入的东西里面复製一些东西出来
像这种复製的行为在哪些任务会用得上呢,一个例子是做聊天机器人

人对机器说:你好 我是库洛洛,
机器应该回答说:库洛洛你好 很高兴认识你
对机器来说,它其实没有必要创造库洛洛这个词汇,这对机器来说一定会是一个非常怪异的词汇,所以它可能很难,在训练资料里面可能一次也没有出现过,所以它不太可能正确地产生这段词汇出来
但是假设今天机器它在学的时候,它学到的是看到输入的时候说我是某某某,就直接把某某某,不管这边是什么复製出来说某某某你好
那这样子机器的训练显然会比较容易,它显然比较有可能得到正确的结果,所以复製对于对话来说,可能是一个需要的技术 需要的能力
Summarization
或者是在做摘要的时候,你可能更需要 Copy 这样子的技能

摘要就是,你要训练一个模型,然后这个模型去读一篇文章,然后产生这篇文章的摘要
那这个任务完全是有办法做的,你就是收集大量的文章,那每一篇文章都有人写的摘要,然后你就训练一个,Sequence-To-Sequence 的 Model,就结束了
你要做这样的任务,只有一点点的资料是做不起来的,有的同学收集个几万篇文章,然后训练一个这样的,Sequence-To-Sequence Model,发现结果有点差
你要训练这种,你要叫机器说合理的句子,通常这个 百万篇文章 是需要的,所以如果你有百万篇文章,那些文章都有人标的摘要,那有时候你会把,直接把文章标题当作摘要,那这样就不需要花太多人力来标,你是可以训练一个,直接可以帮你读一篇文章,做个摘要的模型
对摘要这个任务而言,其实从文章里面直接复製一些资讯出来,可能是一个很关键的能力,那 Sequence-To-Sequence Model,有没有办法做到这件事呢,那简单来说就是有,那我们就不会细讲
最早有从输入复製东西的能力的模型,叫做 Pointer Network

那这个过去上课是有讲过的,我把录影 (opens new window)放在这边给大家参考,好 那后来还有一个变形,叫做 Copy Network,那你可以看一下这一篇,Copy Mechanism,就是 Sequence-To-Sequence,有没有问题,你看 Sequence-To-Sequence Model,是怎么做到从输入复製东西到输出来的
Guided Attention
机器就是一个黑盒子,有时候它里面学到什么东西,你实在是搞不清楚,那有时候它会犯非常低级的错误
这边举的例子是语音合成
你完全可以就是训练一个,Sequence-To-Sequence 的 Model,Transformer 就是一个例子
- 收集很多的声音,文字跟声音讯号的对应关係
- 然后接下来告诉你的,Sequence-To-Sequence Model ,看到这段中文的句子,你就输出这段声音
- 然后就没有然后,就 硬 Train 一发 就结束了,然后机器就可以学会做语音合成了
像这样的方法做出来结果,其实还不错,

举例来说我叫机器连说 4 次发财,看看它会怎么讲,机器输出的结果是:发财 发财 发财 发财
就发现很神奇,我输入的发财是明明是同样的词汇,只是重复 4 次,机器居然自己有一些抑扬顿挫,它怎么学到这件事,不知道,它自己训练出来就是这个样子
那你让它讲 3 次发财也没问题,那它讲 2 次发财也没问题,让它讲 1 次发财,它不念“发”
不知道为什么这样子,就是你这个 Sequence-To-Sequence Model,有时候 Train 出来就是,会产生莫名其妙的结果,也许在训练资料里面,这种非常短的句子很少,所以机器不知道要怎么处理这种非常短的句子,你叫它念发财,它把发省略掉只念财,你居然叫它念 4 次的发财,重复 4 次没问题,叫它只念一次,居然会有问题,就是这么的奇怪
当然其实这个例子并没有那么常出现,就这个用 Sequence-To-Sequence,Learn 出来 TTS,也没有你想像的那么差,这个要找这种差的例子也是挺花时间的,要花很多时间才找得到这种差的例子,但这样子的例子是存在的
所以怎么办呢
我们刚才发现说机器居然漏字了,输入有一些东西它居然没有看到,我们能不能够强迫它,一定要把输入的每一个东西通通看过呢
这个是有可能的,这招就叫做 Guided Attention

像语音辨识这种任务,你其实很难接受说,你讲一句话,今天辨识出来,居然有一段机器没听到,或语音合成你输入一段文字,语音合出来居然有一段没有念到,这个人很难接受
那如果是其它应用,比如说 Chat Bot,或者是 Summary,可能就没有那么严格,因为对一个 Chat Bot 来说,输入后一句话,它就回一句话,它到底有没有把整句话看完,其实你 Somehow 也不在乎,你其实也搞不清楚
但是对语音辨识 语音合成,Guiding Attention,可能就是一个比较重要的技术
Guiding Attention 要做的事情就是,要求机器它在做 Attention 的时候,是有固定的方式的,举例来说,对语音合成或者是语音辨识来说,我们想像中的 Attention,应该就是由左向右

在这个例子里面,我们用红色的这个曲线,来代表 Attention 的分数,这个越高就代表 Attention 的值越大
我们以语音合成为例,那你的输入就是一串文字,那你在合成声音的时候,显然是由左念到右,所以机器应该是,先看最左边输入的词汇产生声音,再看中间的词汇产生声音,再看右边的词汇产生声音
如果你今天在做语音合成的时候,你发现机器的 Attention,是颠三倒四的,它先看最后面,接下来再看前面,那再胡乱看整个句子,那显然有些是做错了,显然有些是,Something is wrong,有些是做错了,
所以 Guiding Attention 要做的事情就是,强迫 Attention 有一个固定的样貌,那如果你对这个问题,本身就已经有理解知道说,语音合成 TTS 这样的问题,你的 Attention 的分数,Attention 的位置都应该由左向右,那不如就直接把这个限制,放进你的 Training 里面,要求机器学到 Attention,就应该要由左向右
那这件事怎么做呢,有一些关键词汇我就放在这边,让大家自己 Google 了,比如说某某 Mnotonic Attention,或 Location-Aware 的 Attention,那这个部分也是大坑,也不细讲,那就留给大家自己研究
Beam Search
Beam Search ,我们这边举一个例子,在这个例子里面我们假设说,我们现在的这个 Decoder就只能产生两个字,一个叫做 A 一个叫做 B
那对 Decoder 而言,它做的事情就是,每一次在第一个 Time Step,它在 A B 里面决定一个,然后决定了 A 以后,再把 A 当做输入,然后再决定 A B 要选哪一个

那举例来说,它可能选 B 当作输入,再决定 A B 要选哪一个,那在我们刚才讲的 Process 里面,每一次 Decoder 都是选,分数最高的那一个
我们每次都是选Max 的那一个,所以假设 A 的分数 0.6,B 的分数 0.4,Decoder 的第一次就会输出 A,然后接下来假设 B 的分数 0.6,A 的分数 0.4,Decoder 就会输出 B,好,然后再假设把 B 当做 Input,就现在输入已经有 A 有 B 了,然后接下来,A 的分数 0.4,B 的分数 0.6,那 Decoder 就会选择输出 B,所以输出就是 A 跟 B 跟 B
那像这样子每次找分数最高的那个 Token,每次找分数最高的那个字,来当做输出这件事情叫做, Greedy Decoding
但是 Greedy Decoding,一定是更好的方法吗,有没有可能我们在第一步的时候,先稍微捨弃一点东西

比如说第一步虽然 B 是 0.4,但我们就先选 0.4 这个 B,然后接下来我们选了 B 以后,也许接下来的 B 的可能性就大增,就变成 0.9,然后接下来第三个步骤,B 的可能性也是 0.9
如果你比较红色的这一条路,跟绿色这条路的话,你会发现说绿色这一条路,虽然一开始第一个步骤,你选了一个比较差的输出,但是接下来的结果是好的
这个就跟那个天龙八部的真龙棋局一样,对不对,先堵死自己一块,结果接下来反而赢了
那所以我,如果我们要怎么找到,这个最好的绿色这一条路呢,也许一个可能是,爆搜所有可能的路径,但问题是我们实际上,并没有办法爆搜所有可能的路径,因为实际上每一个转捩点可以的选择太多了,如果是在对中文而言,我们中文有 4000 个字,所以这个树每一个地方分叉,都是 4000 个可能的路径,你走两三步以后,你就无法穷举
所以怎么办呢,有一个演算法叫做 Beam Search ,它用比较有效的方法,找一个 Approximate,找一个估测的 Solution,找一个不是很精准的,不是完全精准的 Solution,这个技术叫做 Beam Search,那这个也留给大家自己 Google,好
那这个 Beam Search 这个技术,到底有没有用呢,有趣的事就是,**它有时候有用,有时候没有用,**你会看到有些文献告诉你说,Beam Search 是一个很烂的东西
举例来说这篇 Paper 叫做,The Curious Case Of Neural Text Degeneration,那这个任务要做的事情是,Sentence Completion,也就是机器先读一段句子,接下来它要把这个句子的后半段,把它完成,你给它一则新闻,或者是一个故事的前半部,哇 它自己发挥它的想像创造力,把这个文章,把故事的后半部把它写完

那你会发现说,Beam Search 在这篇文章里面,一开头就告诉你说,Beam Search 自己有问题:如果你用 Beam Search 的话,会发现说机器不断讲重复的话,它不断开始陷入鬼打墙 无穷迴圈,不断说重复的话
如果你今天不是用 Beam Search,有加一些随机性,虽然结果不一定完全好,但是看起来至少是比较正常的句子,所以有趣的事情是,有时候对 Decorder 来说,没有找出分数最高的路,反而结果是比较好的
这个时候你又觉得乱乱的 对不对,就是刚才前一页投影片才说,要找出分数最高的路,现在又要讲说找出分数最高的路不见得比较好,到底是怎么回事呢
那其实这个就是要,看你的任务的本身的特性
就假设一个任务,它的答案非常地明确
举例来说,什么叫答案非常明确呢,比如说语音辨识,说一句话辨识的结果就只有一个可能,就那一串文字就是你唯一可能的正确答案,并没有什么模糊的地带
对这种任务而言,通常 Beam Search 就会比较有帮助,那什么样的任务
你需要机器发挥一点创造力的时候,这时候 Beam Search 就比较没有帮助,
举例来说在这边的 Sentence Completion,给你一个句子,给你故事的前半部,后半部有无穷多可能的发展方式,那这种需要有一些创造力的,有不是只有一个答案的任务,往往会比较需要在 Decoder 里面,加入随机性,还有另外一个 Decoder,也非常需要随机性的任务,叫做语音合成,TTS 就是语音合成的缩写
这也许就呼应了一个英文的谚语,就是要接受没有事情是完美的,那真正的美也许就在不完美之中,对于 TTS 或 Sentence Completion 来说,Decoder 找出最好的结果,不见得是人类觉得最好的结果,反而是奇怪的结果,那你加入一些随机性,结果反而会是比较好的
Optimizing Evaluation Metrics?
在作业里面,我们评估的标准用的是,BLEU Score,BLEU Score 是你的 Decoder,先产生一个完整的句子以后,再去跟正确的答案一整句做比较,我们是拿两个句子之间做比较,才算出 BLEU Score
但我们在训练的时候显然不是这样,训练的时候,每一个词汇是分开考虑的,训练的时候,我们 Minimize 的是 Cross Entropy,Minimize Cross Entropy,真的可以 Maximize BLEU Score 吗

不一定,因为这两个根本就是,它们可能有一点点的关联,但它们又没有那么直接相关,它们根本就是两个不同的数值,所以我们 Minimize Cross Entropy,不见得可以让 BLEU Score 比较大
所以你发现说在助教的程式里面,助教在做 Validation 的时候,并不是拿 Cross Entropy 来挑最好的 Model,而是挑 BLEU Score 最高的那一个 Model,所以我们训练的时候,是看 Cross Entropy,但是我们实际上你作业真正评估的时候,看的是 BLEU Score,所以你 Validation Set,其实应该考虑用 BLEU Score
那接下来有人就会想说,那我们能不能在 Training 的时候,就考虑 BLEU Score 呢,我们能不能够训练的时候就说,我的 Loss 就是,BLEU Score 乘一个负号,那我们要 Minimize 那个 Loss,假设你的 Loss 是,BLEU Score乘一个负号,它也等于就是 Maximize BLEU Score
但是这件事实际上没有那么容易,你当然可以把 BLEU Score,当做你训练的时候,你要最大化的一个目标,但是 BLEU Score 本身很复杂,它是不能微分的,
这边之所以採用 Cross Entropy,而且是每一个中文的字分开来算,就是因为这样我们才有办法处理,如果你是要计算,两个句子之间的 BLEU Score,这一个 Loss,根本就没有办法做微分,那怎么办呢
这边就教大家一个口诀,遇到你在 Optimization 无法解决的问题, 用 RL 硬 Train 一发 就对了这样,遇到你无法 Optimize 的 Loss Function,把它当做是 RL 的 Reward,把你的 Decoder 当做是 Agent,它当作是 RL,Reinforcement Learning 的问题硬做
其实也是有可能可以做的,有人真的这样试过,我把 Reference 列在这边给大家参考,当然这是一个比较难的做法,那并没有特别推荐你在作业里面用这一招
Scheduled Sampling
那我们要讲到,我们刚才反覆提到的问题了,就是训练跟测试居然是不一致的
测试的时候,Decoder 看到的是自己的输出,所以测试的时候,Decoder 会看到一些错误的东西,但是在训练的时候,Decoder 看到的是完全正确的,那这个不一致的现象叫做, Exposure Bias

假设 Decoder 在训练的时候,永远只看过正确的东西,那在测试的时候,你只要有一个错,那就会一步错 步步错,因为对 Decoder 来说,它从来没有看过错的东西,它看到错的东西会非常的惊奇,然后接下来它产生的结果可能都会错掉
所以要怎么解决这个问题呢
有一个可以的思考的方向是,给 Decoder 的输入加一些错误的东西,就这么直觉,你不要给 Decoder 都是正确的答案,偶尔给它一些错的东西,它反而会学得更好,这一招叫做, Scheduled Sampling ,它不是那个 Schedule Learning Rate,刚才助教有讲 Schedule Learning Rate,那是另外一件事,不相干的事情,这个是 Scheduled Sampling

Scheduled Sampling 其实很早就有了,这个是 15 年的 Paper,很早就有 Scheduled Sampling,在还没有 Transformer,只有 LSTM 的时候,就已经有 Scheduled Sampling,但是 Scheduled Sampling 这一招,它其实会伤害到,Transformer 的平行化的能力,那细节可以再自己去了解一下,所以对 Transformer 来说,它的 Scheduled Sampling,另有招数跟传统的招数,跟原来最早提在,这个 LSTM上被提出来的招数,也不太一样,那我把一些 Reference 的,列在这边给大家参考

好 那以上我们就讲完了,Transformer 和种种的训练技巧,这个我们已经讲完了 Encoder,讲完了 Decoder,也讲完了它们中间的关係,也讲了怎么训练,也讲了种种的 Tip
上图是transformer的一个详细结构,相比本文一开始结束的结构图会更详细些,接下来,我们会按照这个结构图讲解下decoder部分。可以看到decoder部分其实和encoder部分大同小异,不过在最下面额外多了一个masked mutil-head attetion,这里的mask也是transformer一个很关键的技术,我们一起来看一下。
Mask
mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。
其中,padding mask 在所有的 scaled dot-product attention 里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到。
Padding Mask
什么是 padding mask 呢?因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。
具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0!
而我们的 padding mask 实际上是一个张量,每个值都是一个Boolean,值为 false 的地方就是我们要进行处理的地方。
Sequence mask
文章前面也提到,sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 $ t $ 的时刻,我们的解码输出应该只能依赖于 $ t $ 时刻之前的输出,而不能依赖 $t $ 之后的输出。因此我们需要想一个办法,把 $ t $ 之后的信息给隐藏起来。
那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。
- 对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。
- 其他情况,attn_mask 一律等于 padding mask。
编码器通过处理输入序列开启工作。顶端编码器的输出之后会变转化为一个包含向量
在完成编码阶段后,则开始解码阶段。解码阶段的每个步骤都会输出一个输出序列(在这个例子里,是英语翻译的句子)的元素
接下来的步骤重复了这个过程,直到到达一个特殊的终止符号,它表示transformer的解码器已经完成了它的输出。每个步骤的输出在下一个时间步被提供给底端解码器,并且就像编码器之前做的那样,这些解码器会输出它们的解码结果 。另外,就像我们对编码器的输入所做的那样,我们会嵌入并添加位置编码给那些解码器,来表示每个单词的位置。
而那些解码器中的自注意力层表现的模式与编码器不同:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置。在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。
这个“编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵。
The Final Linear and Softmax Layer
解码组件最后会输出一个实数向量。我们如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是Softmax层。
线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的、被称作对数几率(logits)的向量里。
不妨假设我们的模型从训练集中学习一万个不同的英语单词(我们模型的“输出词表”)。因此对数几率向量为一万个单元格长度的向量——每个单元格对应某一个单词的分数。
接下来的Softmax 层便会把那些分数变成概率(都为正数、上限1.0)。概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出。

这张图片从底部以解码器组件产生的输出向量开始。之后它会转化出一个输出单词。
Recap Of Training
既然我们已经过了一遍完整的transformer的前向传播过程,那我们就可以直观感受一下它的训练过程。
在训练过程中,一个未经训练的模型会通过一个完全一样的前向传播。但因为我们用有标记的训练集来训练它,所以我们可以用它的输出去与真实的输出做比较。
为了把这个流程可视化,不妨假设我们的输出词汇仅仅包含六个单词:“a”, “am”, “i”, “thanks”, “student”以及 “eos”(end of sentence的缩写形式)。
我们模型的输出词表在我们训练之前的预处理流程中就被设定好。
一旦我们定义了我们的输出词表,我们可以使用一个相同宽度的向量来表示我们词汇表中的每一个单词。这也被认为是一个one-hot 编码。所以,我们可以用下面这个向量来表示单词“am”:
Loss function
比如说我们正在训练模型,现在是第一步,一个简单的例子——把“merci”翻译为“thanks”。
这意味着我们想要一个表示单词“thanks”概率分布的输出。但是因为这个模型还没被训练好,所以不太可能现在就出现这个结果。
因为模型的参数(权重)都被随机的生成,(未经训练的)模型产生的概率分布在每个单元格/单词里都赋予了随机的数值。我们可以用真实的输出来比较它,然后用反向传播算法来略微调整所有模型的权重,生成更接近结果的输出。
你会如何比较两个概率分布呢?我们可以简单地用其中一个减去另一个。更多细节请参考交叉熵和KL散度。
交叉熵:https://colah.github.io/posts/2015-09-Visual-Information/
KL散度:https://www.countbayesie.com/blog/2017/5/9/kullback-leibler-divergence-explained
但注意到这是一个过于简化的例子。更现实的情况是处理一个句子。例如,输入“je suis étudiant”并期望输出是“i am a student”。那我们就希望我们的模型能够成功地在这些情况下输出概率分布:
每个概率分布被一个以词表大小(我们的例子里是6,但现实情况通常是3000或10000)为宽度的向量所代表。
第一个概率分布在与“i”关联的单元格有最高的概率;
第二个概率分布在与“am”关联的单元格有最高的概率;
以此类推,第五个输出的分布表示“eos”关联的单元格有最高的概率.
依据例子训练模型得到的目标概率分布
在一个足够大的数据集上充分训练后,我们希望模型输出的概率分布看起来像这个样子:
我们期望训练过后,模型会输出正确的翻译。当然如果这段话完全来自训练集,它并不是一个很好的评估指标(参考:交叉验证,链接https://www.youtube.com/watch?v=TIgfjmp-4BA)。注意到每个位置(词)都得到了一点概率,即使它不太可能成为那个时间步的输出——这是softmax的一个很有用的性质,它可以帮助模型训练。
因为这个模型一次只产生一个输出,不妨假设这个模型只选择概率最高的单词,并把剩下的词抛弃。这是其中一种方法(叫贪心解码)。另一个完成这个任务的方法是留住概率最靠高的两个单词(例如I和a),那么在下一步里,跑模型两次:其中一次假设第一个位置输出是单词“I”,而另一次假设第一个位置输出是单词“me”,并且无论哪个版本产生更少的误差,都保留概率最高的两个翻译结果。然后我们为第二和第三个位置重复这一步骤。这个方法被称作集束搜索(beam search)。在我们的例子中,集束宽度是2(因为保留了2个集束的结果,如第一和第二个位置),并且最终也返回两个集束的结果(top_beams也是2)。这些都是可以提前设定的参数。
Advanced
我希望通过上文已经让你们了解到Transformer的主要概念了。如果你想在这个领域深入,我建议可以走以下几步:阅读Attention Is All You Need,Transformer博客和Tensor2Tensor announcement,以及看看Łukasz Kaiser的介绍,了解模型和细节。
Attention Is All You Need:https://arxiv.org/abs/1706.03762
Transformer博客:https://ai.googleblog.com/2017/08/transformer-novel-neural-network.html
Tensor2Tensor announcement:https://ai.googleblog.com/2017/06/accelerating-deep-learning-research.html
Łukasz Kaiser的介绍:https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb
接下来可以研究的工作:
Depthwise Separable Convolutions for Neural Machine Translation
https://arxiv.org/abs/1706.03059
One Model To Learn Them All
https://arxiv.org/abs/1706.05137
Discrete Autoencoders for Sequence Models
https://arxiv.org/abs/1801.09797
Generating Wikipedia by Summarizing Long Sequences
https://arxiv.org/abs/1801.10198
Image Transformer
https://arxiv.org/abs/1802.05751
Training Tips for the Transformer Model
https://arxiv.org/abs/1804.00247
Self-Attention with Relative Position Representations
https://arxiv.org/abs/1803.02155
Fast Decoding in Sequence Models using Discrete Latent Variables
https://arxiv.org/abs/1803.03382
Adafactor: Adaptive Learning Rates with Sublinear Memory Cost
https://arxiv.org/abs/1804.04235