谷歌、DeepMind和OpenAI都在用的Transformer是如何工作的?| 干货

2019-04-23 11:24:34 浏览数 (1)

乾明 编译整理 量子位 报道 | 公众号 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

0 人点赞