乾明 编译整理 量子位 报道 | 公众号 QbitAI
要说当前人工智能研究中哪个架构最火,Transformer绝对能占其一。
不论是各处霸榜的谷歌BERT、OpenAI最近的强大NLP模型GPT-2,还是DeepMind击败星际2顶尖职业玩家的AlphaStar,背后都有 Transformer的身影。
那么,它是如何工作的?
最近,毕业于MIT的开发者Giuliano Giacaglia发表了一篇博客文章,通过动画图解的形式,解读了 Transformer的工作原理,对于想要了解相关内容的人来说,是一篇不错的入门文章。
Transformer的问世,是为了解决序列转换以及神经机器翻译的问题。
它能用来处理各种seq2seq的任务,比如语音识别、文本-语音转换等等。
△序列转换过程,绿色是输入,蓝色是模型,紫色是输出。
对于执行序列转换的模型来说,必须要有某种形式的记忆。
比如说翻译下面的这个句子:
“The Transformers”是一个日本的硬核朋克乐队。这支乐队成立于1968年,当时正值日本音乐史上的鼎盛时期
在这个例子中,第二句中的“乐队”一词,指代的是第一句中介绍的乐队“The Transformers”。
作为人类,当你在第二句中读到这个词的时候,你知道它就是在指“The Transformers”乐队。
这对机器翻译来说非常重要,有很多情况下,句子中的一个单词,是在代指前面句子中的单词。
想要更好的翻译这样的句子,模型就需要找出单词之间的依赖和联系。
用来处理这一问题的,正是循环神经网络(RNN)和卷积神经网络(CNN)。
这两个网络各有各的特性,在开始解释Transformer之前,先来回顾下这两种网络架构和相应的缺点。
循环神经网络
循环神经网络中具有循环架构,可以让信息持久存在。
△输入表示为x_t
在上图中,我们能够看到神经网络A的一部分,处理输入x_t和输出h_t。循环的存在,允许信息从一个步骤传递到下一个步骤。
我们可以从不同的角度来看待这一循环。一个循环神经网络,可以被看作由多个网络A组成,每个网络向后传递一条消息。如果把循环神经网络展开,就会是这样子的:
这种链式特性表明,循环神经网络显然与序列和列表有关。
这样的话,如果想翻译某些文本,就可以将这个文本中的单词设置为输入。循环神经网络就会将前面的单词信息传递给下一个网络,下一个网络可以使用和处理这些信息。
下图显示了seq2seq模型使用循环神经网络的工作原理。每个单词都是单独处理的,通过将隐藏状态传递给解码器来生成结果句子,然后生成输出。
长期依赖的问题
假设要做一个可以根据前面的单词预测下一个单词的模型。
如果用它预测句子“the clouds in the sky”的下一个单词,就不需要太多上下文信息了。很明显,下一个词将是sky。
在这种情况下,相关信息和需要用到它的地方之间的距离很小,循环神经网络可以学习使用过去的信息,找出这个句子的下一个单词。
但有些情况下,我们需要更多的上下文。比如要预测“ “I grew up in France… I speak fluent …”文本中的最后一个词是什么。
最近的信息表明,下一个单词可能是一种语言,但如果想缩小范围,就需要France的上下文信息了。
当相关信息与需要信息的地方之间的差距离非常大时,循环神经网络就基本没用了。这是因为,在循环神经网络中,信息是逐步逐步传递的,链条越长,信息沿着链条丢失的可能性就越大。
理论上,循环神经网络可以学习这种长期的依赖关系。但在实践中,它们似乎并没有学会。LSTM是一种特殊类型的循环神经网络,被用来解决这类问题。
长短期记忆(LSTM)
在安排一天的日程时,我们会先按照当前的情况安排。如果有什么重要的事情,我们可以取消一些会议,安排这些重要的事情。
但循环神经网络并不会这样做。无论什么时候添加新的信息时,它都会通过应用一个函数来完全转换现有的信息,以至于整个信息都被修改了,而不会考虑什么是重要的,什么不是重要的。
LSTM通过乘法和加法对信息进行小的修改。在LSTM中,信息通过一种称为单元状态的机制传递。通过这种机制,LSTM可以选择性地记住重要的事情,或者忘记不重要的事情。
LSTM的内部构造如下图所示:
每个单元,将x_t (句子到句子转换的情况下是一个单词)、前一个单元状态和前一个单元的输出作为输入。它操纵这些输入,并基于它们产生新的单元状态和输出。
在单元状态下,翻译时句子中对翻译单词很重要的信息,可以从一个单词传递到另一个单词。
LSTM的问题
一般来说,循环神经网络遇到的问题,LSTM上也会出现。比如在句子很长的时候,LSTM也不太管用。
背后的原因是,保持上下文信息与当前被处理单词联系的可能性,会随着距离的增加呈指数级下降。
这意味着,当句子很长时,模型经常会忘记序列中距离位置较远的内容。
循环神经网络和 LSTM 的另一个问题是,处理句子的工作很难并行化,必须要逐单词处理。不仅如此,还没有长期和短期依赖的模型。
综上所述,LSTM和循环神经网络一共存在三个问题:
- 顺序计算抑制了并行化
- 没有对长期和短期依赖关系的明确建模
- 位置之间的“距离”是线性的
注意力(Attention)
为了解决其中一些问题,研究人员创造了一种关注特定单词的技术。
就我自己而言,在翻译一个句子的时候,我会特别注意自己正在翻译的单词。
如果要描述自己所在的房间,我会先扫一眼,看看周围都有啥东西。
神经网络可以通过注意力机制来实现同样的行为,把注意力集中在给定信息的子集上。
使一个循环神经网络,可以参与到另一个循环神经网络的输出中。
在每一步,它都将注意力集中在另一个循环神经网络中的不同位置。
对于循环神经网络来说,不仅仅是将整个句子编码为隐藏状态,每个单词都会有一个对应的隐藏状态,这个隐藏状态一直传递到解码阶段。
然后,在循环神经网络的每个步骤中使用隐状态进行解码。下面的动图展示了运作原理:
△绿色是编码阶段,紫色是解码阶段。
它背后的想法是,一个句子中的每个单词,都可能有相关的信息。因此,为了使解码更加精确,需要利用注意力机制关注输入的每一个单词。
为了在用于序列转换的循环神经网络中引入注意力机制,编码和解码主要分为两个步骤。
如上图所示,绿色步骤是编码阶段,紫色步骤是解码阶段。
编码阶段负责创建隐藏状态。
在没有引入注意力机制之前,只是将一个隐藏状态传递给解码器。现在它要将句子中每个“单词”产生的所有隐藏状态传递到解码阶段。
每个隐藏状态都在解码阶段使用,来找出网络应该注意的地方。
例如,当把“Je suis étudiant” (我是学生)这个句子翻译成英语时,在解码的步骤,要看不同的单词。
下面这个动图,就展示了每个隐藏状态的权重,颜色越深,权重越高。
但是,上面讨论过的一些问题,使用引入注意力机制的循环神经网络也没法解决。
比如并行处理输入(单词)是不可能的。
如果有大量文本需要翻译的话,这会大幅度增加翻译时间。
卷积神经网络(CNN)
卷积神经网络有助于解决这些问题,它能够:
并行化(每层)
利用位置的依赖关系
位置之间的距离是呈对数的
一些用于序列转换的流行神经网络,比如Wavenet、Bytenet,都是卷积神经网络。
△Wavenet的架构。
卷积神经网络之所以能够并行工作,是因为可以同时处理输入的每个单词,并且也不一定依赖于要翻译的前面的单词。
不仅如此,卷积神经网络的输出单词和输入之间的“距离”是以 log (N)函数的顺序排列的,大致如上面的动图所示。
这比一个循环神经网络的输出和输入之间的距离呈指数级变化要“友好”得多。
但卷积神经网络的问题在于,它不一定能够解决句子翻译中的依赖问题。
这就是Transformer被创造出来的原因,它是注意力机制和卷积神经网络的结合体。
Transformer
为了解决并行化问题,Transformer尝试将卷积神经网络与注意力模型相结合起来。
在Transformer中,使用的自注意力机制(self-attention),提高了从一个序列转换到另一个序列的速度。
Transformer是由六个编码器和六个解码器组成的。
编码器和解码器,各自之间也都非常相似。 每个编码器由两层组成:自注意力和前馈神经网络。
编码器的输入,首先经过一个自注意力层。
这有助于编码器在编码特定单词时,查看输入句子中的其他单词。
解码器中也有这两层,但在它们之间有一个注意力层,帮助解码器专注于输入句子的相关部分。
自注意力
接下来,就要开始研究各种向量/张量了,看它们如何在这些组件之间流动,从而将训练模型的输入转化为输出。
正如自然语言处理应用的通常情况一样,首先使用嵌入算法将每个输入单词转换成一个向量。
每个单词被嵌入到大小为512的向量中,用上图中的简单方块来表示。
嵌入只发生在最底层的编码器中。所有编码器共有的抽象信息是,它们接收到一个大小为512的向量列表。
在底层的编码器中,这是词嵌入,但在其他编码器中,它是下层编码器的输出。输入序列中的词都进行嵌入之后,每个单词都会经过编码器两层架构中的每一层。
这就凸显出了Transformer的一个关键属性,即每个位置的单词,在编码器中通过它自己的路径传递。
在自注意力层,这些路径之间存在依赖关系。但是,前馈神经网络层没有这些依赖关系,因此各种路径可以在流经前馈神经网络层时并行执行。
接下来,以一个更短的句子为例,看看编码器的每个子层中发生了什么。
首先,是如何用用向量计算自注意力,然后再看看它实际上是如何使用矩阵实现的。
△找出句子中单词之间的关系,并给予正确的权重。
计算自注意力的第一步,是从编码器的每个输入向量中创建三个向量。
在当前的例子中,是每个单词的嵌入。
因此,对于每个单词,分别创建一个Query向量、一个Key向量和一个 Value向量。
这些向量是通过将嵌入乘以在训练过程中训练的三个矩阵来创建的。
请注意,这些新向量在维数上比嵌入向量小。
它们的维数是64,而嵌入和编码器输入/输出向量的维数是512。
它们不一定要更小,这是一个让多头注意力的大部分计算恒定的架构选择。
用WQ权重矩阵乘以x1得到q1,即与该单词关联的Query向量。
最终在输入句子中为每个单词创建一个Query、一个Key和一个Value的映射。
什么是Query、Key和Value向量?它们是对计算和思考注意力有用的抽象概念。
在下面计算注意力的环节,就会知道这些向量所扮演的角色。
计算自注意力的第二步是计算分数。
假设要计算这个例子中第一个单词“Thinking”的自注意力,需要将输入句子中的每个单词与这个单词进行比较打分。
分数决定了在某个位置编码一个单词时,对输入句子其他部分的关注程度。
计算分数的方法,是取要评分单词的Query向量与Key向量的点积。
所以如果处理位置 #1中单词的自我注意力,第一个得分是q1和k1的点积。
第二个得分是q1和 k2的点积。
第三步和第四步,是将得分除以8 ,然后通过softmax传递结果。
Softmax将分数标准化,这样它们都是正数,加起来等于1。
这个softmax分数,决定了每个单词在这个位置有多重要。
显然,在这个位置的单词,将有最高的softmax分数,但是有时候注意与当前单词相关的另一个单词是很有用的。
第五步是将每个Value向量乘以softmax得分(准备求和)。
这一步是保持要关注的单词的值不变,屏蔽掉不相关的单词(例如,用0.001这样的小数字与它们相乘)。
第六步是对加权Value向量求和。然后产生自注意力层的输出(第一个单词)。
自注意力计算到此结束。
由此产生的向量是可以发送给前馈神经网络的向量。
然而,在实际实现中,为了更快的处理,这种计算是以矩阵形式进行的。
多头注意力(Multihead attention)
Transformer基本上就是这样工作的。还有一些其他的细节,可以让它们运作得更好。
例如,Transformer使用了多头注意力的概念,使其不仅仅在一个维度上注意彼此。
背后的想法是,每当翻译一个单词时,可能会根据你所问的问题类型,对每个单词给予不同的注意力。下图显示了这意味着什么。
例如,当你在翻译“I kicked the ball”这个句子中的 “kicked”时,你可能会问“Who kicked”。
根据答案的不同,这个单词翻译成另一种语言时可能会有所不同。或者也可以问其他问题,比如“Did what?”等等。
位置编码
Transformer的另一个重要步骤,是在对每个单词进行编码时添加位置编码,这是有必要的,因为每个单词的位置都与翻译结果相关。
-完-
原文链接:
https://medium.com/@giacaglia/transformers-141e32e69591
— 完 —