编者按:年初疫情在家期间开始大量阅读NLP领域的经典论文,在学习《Attention Is All You Need》时发现了一位现居日本的数据科学家LeeMeng写的Transformer详解博客,理论讲解+代码实操+动画演示的写作风格,在众多文章中独树一帜,实为新手学习Transformer的上乘资料,在通读以及实操多遍之后,现在将其编辑整理成简体中文分享给大家。由于原文实在太长,为了便于阅读学习,这里将其分为四个部分:
- 透过机器翻译理解Transformer(一):关于机器翻译
- 透过机器翻译理解Transformer(二):师傅引进门,修行在个人—建立输入管道
- 透过机器翻译理解Transformer(三):理解 Transformer 之旅:跟着多维向量去冒险
- 透过机器翻译理解Transformer(四):打造 Transformer:叠叠乐时间
在涉及代码部分,强烈推荐大家在Google的Colab Notebooks中实际操作一遍,之所以推荐Colab Notebooks是因为1).这里有免费可以使用的GPU资源;2). 可以避免很多安装包出错的问题
本节目录
-
- 前言
-
- 一些你需要具备的先验基础知识
-
- 机器翻译近代史
- 3.1 统计机器翻译-SMT:基于短语的翻译
- 3.2 神经机器翻译:Encoder-Decoder 模型
- 3.3 Encoder-Decoder 模型 + 注意力机制
- 3.4 Transformer:Seq2Seq 模型 + 自注意力机制
-
- 总结
1. 前言
机器翻译的研究之所以如此重要且迷人,是因为它将有机会让未来任何人都不受语言的限制,获得世界上任何他或她想要的信息与知识。
在透过机器翻译理解Transformer系列文章的第一部分,我们会先花点时间来回顾神经机器翻译里面的一些重要概念。接着在具备这些概念以及其他背景知识的前提之下,使用 TensorFlow 2 来实现作一个可以将英文句子翻译成中文的神经网络架构:Transformer。
这是一个非常简化的示意图。 Transformer 实际上是一种基于自注意力机制的 Seq2Seq 模型,近年在图像描述、聊天机器人、语音识别以及机器翻译等NLP各大领域大发异彩。但因为其结构相对复杂,到现在还是有种现象:
了解 Transformer 相关技术的人已经用了好一阵子并且用得很开心,而不知道的人还是不知道。
当然这并不仅限于 Transformer,因为深度学习牵涉的研究范围实在太广了。透过这篇文章,我希望能帮助你开始了解神经机器翻译以及 Transformer 的相关知识。
在我们完整实现并训练出一个Transformer 以后,除了可以英翻中以外,我们还能清楚地了解其是如何利用强大的注意力机制(我们在Encoder-Decoder 模型+ 注意力机制一节会仔细探讨此概念)来做到精准且自然的翻译。
除了翻译出来的中文正确无误以外,从上图我们可以发现一些很有趣的现象。
给定左侧的英文,Transformer 在生成其对应的中文翻译时都会给每个英文词汇不同的「注意程度」。小方格越亮则代表模型在生成某个中文文字时放越多的注意力在左侧对应的英文词汇上。
仔细看会发现这个已经训练好的 Transformer 在翻译:
「必」、「须」时会关注「must」
「希」、「望」时会关注「hope」
「公」、「民」时会关注「citizens」
乍看之下好像稀松平常,但事实上我们在训练模型时并不会告诉它这些词汇之间的对应关系或是任何语言学的知识。我们就只是喂给它多组相同意思的中英句子,并让它自己学会怎么做翻译。
在英翻中的情境下,神经网络要做的事情就是读入左侧的英文句子,接着生成右侧的中文句子(繁体中文对英文的翻译资料集稀少,此文将以简体为例)
2. 一些你需要具备的先验基础知识
在文中我会尽量言简意赅地介绍所有你需要了解的深度学习概念,并附上相关链接供参考。但就像在众多武侠小说中都有提过的重要准则:
武功修习有先后顺序,勿求一步登天。
尽管在 2017 年就已被提出,本文即将探讨并实现的 Transformer 仍然算是相当进阶的神经网络架构。因此具备以下的基础知识能帮助你更顺利地理解本文内容:
一点点卷积神经网络的概念
清楚理解循环神经网络的运算方式
基本的自然语言处理知识
基本的线性代数如矩阵相乘运算
希望这样的要求没把你吓跑,因为事实上你大约需要好几倍的相关知识来成功实现一个完整的 Transformer。尽管在实现前你会看到一些额外要求,本文的前半部分还是相当平易近人的,还请放心阅读。
当你想要深入了解某些细节的时候,可以参考这节附上的链接或是文内说明概念时附上的图片来源。
想更深入了解文中讲述的各种概念,点击相关的「图片来源」就对了。
前言很长,但好戏才在后头。如果你已经准备好进入神经机器翻译的世界的话,现在就让我们正式开始这趟旅程吧!
3. 机器翻译近代史
鉴往知来。了解一点机器翻译的历史以及 Transformer 是怎么跑出来的会对实现它很有帮助。
机器翻译(Machine Translation)本身的概念最早可追溯到 17 世纪。从那时开始,人们尝试并研究了各式各样的方法,写了一大堆规则、搜集了数以万计的翻译结果来尝试自动化翻译。随着时代演进,我们有了:
基于规则的机器翻译 RBMT
基于范例的机器翻译 EBMT
统计机器翻译 SMT
-
近年的神经机器翻译 NMT
很多远古时代的东西我们不会讨论,而 NMT 当然就是本文的重点了。不过在讲解NMT之前让我们非常简短地看一下 SMT。
3.1 统计机器翻译-SMT:基于短语的翻译
机器翻译的历史很长,但一直要到 21 世纪初期统计机器翻译(Statistical Machine Translation,简称 SMT)技术成熟以后,机器翻译的质量才稍微使人满意。其中最知名的例子当属 Google 在 2006 年发布的 SMT 翻译系统。
不限于 Google,当时不少最先进的 SMT 系统都采用了基于短语的机器翻译(Phrase-Based MT) 的算法。 PBMT 最大的特色是先将来源语言(Source Language)的句子切成短语或是词汇,接着大致上独立地将这些词汇翻译成目标语言(Target Language)。
PBMT 的翻译结果相较于早年基于规则(Rule-Based)的方法已经进步很多,但仍然需要大量的平行语料、对齐语料来取得较好的结果。且因为是以短语为单位在做翻译,这些短语拼凑出来的句子仍然不够自然。如果你有用过早年的 Google 翻译,应该还能隐约记得当年那些充斥着「机械感」的翻译结果。
3.2 神经机器翻译:Encoder-Decoder 模型
顾名思义,神经机器翻译 NMT 即代表使用神经网络(Neural Network)来做机器翻译。不管是英文、法文还是中文,一个自然语言的句子基本上可以被视为一个有时间顺序的序列数据(Sequence Data)。而我们知道 RNN 很适合用来处理有时间关系的序列数据。给定一个向量序列,RNN 就是回传一个一样长度的向量序列作为输出。
当我们把源语言以及目标语言的句子都视为一个独立的序列以后,机器翻译事实上就是一个序列生成(Sequence Generation)任务:对一个输入序列(源语言)做些有意义的转换与处理以后,输出一个新的序列(目标语言)。
而在深度学习时代,我们一般会使用以 RNN 为基础的 Encoder-Decoder 架构(又被称作 Sequence to Sequence / Seq2Seq 模型)来做序列生成(图片来源):
Seq2Seq 模型里头 Encoder 跟 Decoder 是各自独立的 RNN。 Encoder 把输入的句子做处理后所得到的隐状态向量(图中的Hidden State#3
)交给 Decoder 来生成目标语言。
你可以想像两个语义相同的法英句子虽然使用的语言、语序不一样,但因为它们有相同的语义,Encoder 在将整个法文句子浓缩成一个嵌入空间(Embedding Space)中的向量后,Decoder 能利用隐含在该向量中的语义信息来重新生成具有相同意义的英文句子。
这样的模型就像是在模拟人类做翻译的两个主要过程:
(Encoder)解译来源文字的文意
(Decoder)重新编译该文意至目标语言
当然人类在做翻译时有更多步骤、也会考虑更多东西,但 Seq2Seq 模型的表现已经很不错了。
有些人阅读到这里可能会问:
如果我们利用 Seq2Seq 模型将多种语言的句子都转换到某个嵌入空间里头,该空间会长成什么样子呢?是相同语言的句子靠得比较近,还是不同语言但拥有同语义的句子会靠得比较近呢?
这是一个很好的研究问题。
而如果我们试着把这个问题可视化,则结果可能长得像这样:
图中的点代表不同句子,不同颜色则代表不同语言。如果结果是左边,代表神经网络并没有创出一个「语义」空间,而只是把不同语言都投射到该嵌入空间里头的不同位置,接着才在该空间里进行不同语言之间的转换(中转英、英转法etc.)。
我们比较想要的是右边的情况:无关语言,只要句子的语义接近,彼此的距离就相近的语义空间。
而Google 在2016 年的研究结果发现,在此空间里头语言相异但拥有同语义的句子之间的距离d1
,要比同语言但不同语义的句子之间的距离d2
要小得多(即d1 << d2
)。换句话说,在此空间中同语义的句子会靠得比较近,我们实际得到的空间比较像右边。
而如果我们将这些句子做 t-SNE
,甚至可以得到这样的结果(图片来源):
该研究告诉我们,只要对自然语言做正确的转换,就能将语言相异但同语义的句子都转换成彼此距离相近的语义向量,并以此做出好的翻译。
以下是随意挑选出来的一组句子,它们在该空间里的距离相近:
英文: From low-cost pharmacy brand moisturizers to high-priced cosmetics brand moisturizers, competition is fierce.
日文: 低価格の薬品ブランドの保湿剤から高価な百貨店の化粧品ブランドのためには, 競争が激しい
韩文: 싸구려백화점화장품브랜드 moisturizers 에 저렴한약국브랜드 moisturizers 에서 , 경쟁이큰있습니다
这些句子都代表着类似的意思:「从低价的保湿剂到高价的化妆品牌,竞争都十分激烈」。
如果你想进一步了解这个视觉化结果,可以阅读 Google Brain 的详细解说或是上 Embedding Projector 自己试看看。
另外值得注意的是,机器翻译本身是一种有条件的序列生成任务(Conditional Sequence Generation):给定一个特定的输入句子(文字序列),依此条件输出另外一个句子(文字序列)。
3.3 Encoder-Decoder 模型 + 注意力机制
好啦,你现在应该已经了解如何使用 Seq2Seq 模型来做 NMT 了,不过现在让我们再次回顾一下它的运行方式。这次我们把用 RNN 实现的 Encoder / Decoder 在每个时间点做的事情从左到右一字排开:
基本款的 Seq2Seq 模型表现得不错,但其实有可以改善的地方。你有看出来了吗?上图的输入句子只有 3 个词汇,但如果我们想输入一个很长的句子呢
我们前面曾提过 Seq2Seq 模型里的一个重要假设是Encoder 能把输入句子的语义 / 文本脉络全都压缩成一个固定维度的语义向量。之后 Decoder 只要利用该向量里头的信息就能重新生成具有相同意义,但不同语言的句子。
但你可以想像当我们只有一个向量的时候,是不太可能把一个很长的句子的所有信息打包起来的。
这时候怎么办呢?
与其只把Encoder 处理完句子产生的最后「一个」向量交给Decoder 并要求其从中萃取整句话的信息,不如将Encoder 在处理每个词汇后所生成的「所有」输出向量都交给Decoder,让Decoder自己决定在生成新序列的时候要把「注意力」放在Encoder 的哪些输出向量上面。
这事实上就是注意力机制(Attention Mechanism)的中心思想:提供更多信息给 Decoder,并透过类似资料库存取的概念,令其自行学会该怎么提取信息。两篇核心论文分别在 2014 年 9 月及 2015 年 8 月放出,概念不难但威力十分强大。
以下就是将注意力机制加到 Seq2Seq 模型后的结果:
你可以拉回去跟没有注意力机制的 Seq2Seq 模型比较一下差异。
现在你会看到 Encoder 把处理完每个词汇所产生的向量都交给 Decoder 了。并且透过注意力机制,Decoder 在生成新序列的每个元素时都能动态地考虑自己要看哪些Encoder的向量(还有决定从中该撷取多少信息),因此这种运用注意力机制的Seq2Seq 架构又被称作动态的条件序列生成(Dynamic Conditional Generation)。
实际构想并证明其有效的研究者们十分厉害,且其概念也挺符合人类直觉的,对吧?
为了方便读者理解,上面动画实际上隐藏了一些细节:
呈现算好的注意力程度而不是计算过程
Encoder / 跟 Decoder 的实际架构
既然是深度学习,Encoder / Decoder 一般来说都是由多个 LSTM / GRU 等 RNN Layers 所叠起来的。而注意力机制在这种情境下实际的运行方式如下:
左右两边分别是 Encoder 与 Decoder ,纵轴则是多层的神经网络区块 / 层。
虽然上张动画是法翻英(这边是英翻法),但该动画也是以一样的概念将图中的注意力权重(attention weights )可视化化出来(注意力权重和为 1)。
现在让我们看一下注意力机制的实际计算步骤。在 Decoder 的每个时间点,我们都会进行注意力机制以让 Decoder 从 Encoder 取得语境信息:
拿 Decoder 当下的红色隐状态向量
ht
跟 Encoder 所有蓝色隐状态向量hs
做比较,利用score
公式计算出ht
对每个hs
的注意程度以此注意程度为权重,加权平均所有 Encoder 隐状态
hs
以取得上下文向量context vector
将此上下文向量与 Decoder 隐状态结合成一个注意向量
attention vector
并作为该时间点的输出该注意向量
attention vector
会作为 Decoder 下个时间点的输入
定义 score
公式的方式不少,现在就先让我们假设有这么一个公式。
至此为止,你应该已经能够看懂注意力机制的计算公式(图片来源):
而之所以称为注意力权重(attention weights),是因为注意力机制可以被视为是一个学习源语言和目标语言每一个单词之间关系的小型神经网络,而这些权重是该神经网络的参数。
我们在后面的章节会实际看到,在训练还没开始前,这些权重都是随机且无意义的。是通过训练,神经网络才知道该为这些权重赋予什么值。
你也会发现我在文中提及多次的「注意力程度」就是这里的「注意力权重」,而前者是一种拟人化的说法。你可以想像这些权重值让当下的 Decoder 晓得该放多少关注在 Encoder 个别的隐状态身上,并依此从它们身上取得上下文信息(步骤 2)。
而事实上神经网络并没有意识,因此也不会有感知层次上的「注意力」。它学到的是让注意力机制产生最好结果的「参数权重」,而不是我们人类想像的「注意力程度」。只有人类可以赋予神经网络里头的计算意义。
有点扯远了,毕竟这里应该没有人文学系的读者。
让我们拉回注意力机制。
将此机制加入 Seq2Seq 模型后,NMT 系统的翻译水准再次起飞。 Google 在 2016 年推出的 Google Neural Machine Translation system(GNMT) 是一个知名的案例。除了注意力机制以外,GNMT 在 Encoder 跟 Decoder 都采用了多达 8 层的 LSTM 神经网络,让更多人见识到深度学习的威力。
跟 Google 10 年前推出的 PBMT 系统比起来,翻译错误率平均下降了 60 %(图片来源)。
上图为 GNMT 做中翻英的过程。 Encoder 跟 Decoder 之间的线条代表注意力(Attention),线条越粗代表下面的 Decoder 在生成某英文字时越关注上方的某些中文字。模型自己学会在翻译时该看来源句子中的哪些信息。
因为其卓越的翻译品质,在 GNMT 推出的那段时间,搭配注意力机制的 Seq2Seq 模型基本上就是拿来做 NMT 系统的不二选择。
当年 Google 导入 GNMT 时释出了 8 个语言之间的对应翻译,涵盖了约 1/3 的世界人口以及超过 35 % 的 Google 翻译查询,是机器翻译发展的一个重要里程碑。
3.4 Transformer:Seq2Seq 模型 + 自注意力机制
好酒沉瓮底,万众瞩目的时刻来了。
标题已经破梗。你已经知道我们将探讨本文主角 Transformer,且理论上越后面出来的 BOSS 越强。
但你现在可能在想:
Seq2Seq 模型搭配注意力机制感觉已经很猛了,难道还有什么可以改善的吗?
答案是肯定的 Yes。
不过这次问题不是出在 Encoder 跟 Decoder 中间交换的信息不够,也不是 Seq2Seq 架构本身有什么问题,问题是出在我们是用 RNN 来实现 Encoder 以及 Decoder。
循环神经网络 RNN 时常被拿来处理序列数据,但其运作方式存在着一个困扰研究者已久的问题:无法有效地并行运算。以一个有 4 个元素的输入序列为例:
[a1, a2, a3, a4]
要获得最后一个时间点的输出向量 b4 得把整个输入序列跑过一遍才行:
Google 在 2017 年 6 月的一篇论文:Attention Is All You Need 里参考了注意力机制,提出了自注意力机制(Self-Attention mechanism)。这个机制不只跟 RNN 一样可以处理序列数据,还可以并行运算。
以刚刚的输入序列 a[] 为例:
[a1, a2, a3, a4]
一个自注意力层(Self-Attention Layer)可以利用矩阵运算在等同于 RNN 的一个时间点内就回传所有 bi
,且每个 bi
都包含了整个输入序列的信息。相比之下,RNN 得经过四个时间点依序看过 [a1, a2, a3, a4]
以后才能取得序列中最后一个元素的输出b4
。
虽然我们还没讲到实际的运行过程,但在给定一个输入序列的情境下,自注意力机制的基本思想就是:
在建立序列中每个元素的 repr. 时,同时去「注意」并撷取同个序列中其他元素的语义信息。接着将这些语义信息合并成上下文信息并当作自己的 repr. 回传。
repr. 为 representation 缩写,在本文的机器翻译情境里头,其意味着可以用来描述某个词汇、句子意涵的多维实数张量。
虽然我们一直强调自注意力机制的并行能力,如果你还记得我们在上一节讲述的注意力机制,就会发现在 Seq2Seq 架构里头自注意力机制跟注意力机制讲的根本是同样一件事情:
注意力机制让Decoder 在生成输出元素的 repr. 时关注 Encoder 的输出序列,从中获得上下文信息
自注意力机制让Encoder在生成输入元素的 repr. 时关注自己序列中的其他元素,从中获得上下文信息
自注意力机制让Decoder在生成输出元素的 repr. 时关注自己序列中的其他元素,从中获得上下文信息
我们发现一个非常重要的模式:
注意力机制跟自注意力机制都是让序列 q 关注序列 k 来将上下文信息 v 汇总到序列 q 的 repr. 里头,只是使用的序列不同。
这也是为何在后面实现时我们只需要一个注意力函数就好了。总之透过新设计的自注意力机制以及原有的注意力机制,Attention Is All You Need 论文作者们打造了一个完全不需使用 RNN 的 Seq2Seq 模型:Transformer。以下是 Transformer 中非常简化的 Encoder-Decoder 版本,让我们找找哪边用到了(自)注意力机制:
在 Transformer 里头,Decoder 利用注意力机制关注 Encoder 的输出序列(Encoder-Decoder Attention),而 Encoder 跟 Decoder 各自利用自注意力机制关注自己处理的序列(Self-Attention)。无法并行运算的 RNN 完全消失,名符其实的 Attention is all you need.
以下则是 Transformer 实际上将英文句子翻译到法文的过程:
以 Transformer 实现的 NMT 系统基本上可以分为 6 个步骤:
Encoder 为输入序列里的每个词汇产生初始的 repr. (即词向量),以空圈表示
利用自注意力机制将序列中所有词汇的语义信息各自汇总成每个词汇的 repr.,以实圈表示
Encoder 重复 N 次(图中N=3)自注意力机制,让每个词汇的 repr. 彼此持续修正以完整纳入上下文语义
Decoder 在生成每个法文字时也运用了自注意力机制,关注自己之前已生成的元素,将其语义也纳入之后生成的元素
在自注意力机制后,Decoder 接着利用注意力机制关注 Encoder 的所有输出并将其信息纳入当前生成元素的 repr.
Decoder 重复步骤 4, 5 以让当前元素完整包含整体语义
上面动画的 N 为 3,代表着 Encoder 与 Decoder 的层数。这是一个可以依照任务调整的超参数。
如果你看懂这张图的信息流动,就等于了解 Transformer 的核心思想了,恭喜!如果仍然有不明了的地方,可以搭配我上面的说明多看几遍动画或是直接阅读 Google AI 博客的原文介绍。
4. 总结
自注意力机制解开了 RNN 加在 GPU 上的拘束器。作者们用了 8 个 NVIDIA P100 GPU,花了 3 天半训练了一个 Transformer,而该模型在 WMT 2014 英法 / 英德翻译都取得了最高水准的成绩。
跟其他模型相比,这训练时间跟其创造的优异成绩在当时可以说是逆天的存在。自此「大注意力时代」展开,该论文至今超过 13800 次引用,所有研究领域都被自注意力机制相关的论文洗了一波。
没能赶上开心洗论文的最佳时机也别伤心难过,对我们来说仍然有个十分重要的信息:
多数以 RNN 做过的研究,都可以用自注意力机制来取代;多数用 Seq2Seq 架构实现过的应用,也都可以用 Transformer 来替换。模型训练速度更快,结果可能更好。
这也是我决定写这篇文章的理由之一。虽然本文是以机器翻译的角度来介绍 Transformer,但事实上只要是能用 RNN 或 Seq2Seq 模型进行的研究领域,你都会看到已经有大量跟(自)注意力机制或是 Transformer 有关的论文了:
文本摘要(Text Summarization)
图像描述(Image Captioning)
阅读理解(Reading Comprehension)
语音识别(Voice Recognition)
语言模型(Language Model)
聊天机器人(Chat Bot)
其他任何可以用 RNN 的潜在应用
当然不是每个人都喜欢或需要看论文。如果你只是想要应用 Transformer 也没问题。但是如果你接下来想往深度学习领域发展(尤其是自然语言处理这块),了解(自)注意力机制以及 Transformer 的运作方式几乎可以说是必经之路。就算没打算自己手刻 Transformer,你现在应该也稍微能够体会现代的神经网络到底对自然语言做些什么了。
至此本文的第一部分结束。在后面我们将实现一个能进行英翻中的 Transformer。等等会说明一项要你完成的事情,不过现在先离开位置喝点东西、让眼睛跟脑袋休息一下吧!