一文读懂: Transformer
本文旨在帮助不懂技术的朋友轻松搞懂Transformer 模型架构和思想,所以不含代码,纯讲解。
前言
Transformer模型之所以被称为“Transformer”,是因为它的核心功能是对输入数据的矩阵进行变换处理。(哈哈,目前没有中文名,不是变形金刚也不是翻译)
这种变换是通过计算矩阵内部各个向量之间的关系来实现的,目的是去除无效信息并加强有效信息。在这个过程中,组成矩阵的向量的值会发生变化,但形状保持不变。这样的变换使得模型能够更好地解决最终数学问题,计算最优解。
大模型爆红,一方面给互联网用户带来了更新鲜的体验,另一方面也让不少业内人士开始思考起 AI 企业的发展路径,以及 AIGC 在国内的可发展性。
BERT,GPT 的T也正是Transformer。那么GPT 的来源核心技术组成的Transformer究竟是什么来头?
Transformer模型的发展速度日新月异,一天一个样,混合或者魔改都有。
BERT和GPT的计算逻辑来自于一个名为transformer的算法,Transformer由论文《Attention Is All You Need》提出,现在是谷歌云TPU推荐的参考模型。
虽然transformer原本是聚焦在自然语言处理领域,但由于其出色的解释性和计算性能开始广泛地使用在AI各个领域,成为最近几年最流行的AI算法模型,无论是这篇论文还是transformer模型,都是当今AI科技发展的一个缩影。以此为前提,本文分析了这篇论文的核心要点和主要创新初衷。
在本文中,我将把模型简化一点,并逐一介绍里面的核心概念,希望让普通读者也能轻易理解。
在机器翻译任务上,Transformer表现超过了RNN和CNN,只需要编/解码器就能达到很好的效果,可以高效地并行化。
Transformer模型提出了自注意力机制(Self-attention),是一个重大改进。
标准Transformer模型
先来看,标准的Transformer模型是什么样的结构。

Transformer的核心部分,是右边的两个黑色实线框圈起来的两部分,左边是编码器(Encoder),右边是解码器(Decoder)。
下图是 Transformer 用于中英文翻译的整体结构:

可以看到 Transformer 由 Encoder 和 Decoder 两个部分组成,Encoder 和 Decoder 都包含 6 个 block。
之前序列处理主要的算法叫RNN(循环神经网络),它主要的实现逻辑是每个“字”计算之后将结果继承给第二个“字”。rnn算法的弊病是需要大量的串行计算,效率低。而且当遇到比较长的句子时,前面信息很有可能会被稀释掉,造成模型不准确,也就是对于长句子效果会衰减。这是这篇文章致力于要解决的问题,也就是说这篇文章有训练处更好的f()的方法。
在Transformer里,将每个字与句子中所有单词进行计算,算出这个词与每个单词的相关度,从而确定这个词在这个句子里的更准确意义。
在此处,要开始进入一些技术细节,在开始之前,我们有必要再熟悉一下机器学习领域最核心的一个概念——“向量”。在数字化时代,数学运算最小单位往往是自然数字。但在AI时代,这个最小单元变成了向量。这是数字化时代计算和智能化时代最重要的差别之一。
举个例子,比如,在银行,判断一个人的信用额度,我们用一个向量来表示

向量是一组数据的集合,也可以想象成在一个超高维度空间里的一个点。一个具体的信用额度向量,就是在8个特征组成的高维空间的一个点。数据在高维空间将展现更多的数学性质比如线性可分,容易让我们抓住更多隐藏的规律。
向量的加减乘除是计算机在进行样本训练是最主要的计算逻辑。
Transformer模型的主要目的就是,分成三步把一个词逐步定位到了一个高维空间,在这个过程中赋予这个单词比其它算法更优的信息。很多情况下这个高维空间有着不同的意义,一旦这个向量赋予的信息更准确更接近真实情况,后面的机器学习工作就很容易展开。还拿刚才信用额度向量举例子

这两个向量存在于两个不同的向量空间,主要的区别就是前者多了一个向量特征:“年薪”。可以思考一下如果判断一个人的信用额度,“年薪”是不是一个很重要的影响因子?
以上例子还是很简单的,只是增加了一个特征值,在transformer里就复杂很多,它是要把多个向量信息通过矩阵加减乘除综合计算,从而赋予一个向量新的含义。
transformer的三步走
- 1.编码(Embedding)
- 2. 定位 (Positional encoding)
- 3. 自注意力机制(Self-Attention)。
举个例子,比如,把句子Smart John is singing翻译成中文。
这是第一步:嵌入编码(Embedding)。
首先,要对句子每个词进行向量化。
例如“John”这个词,需要把“John”这个字母排列的表达转换成一个512维度的向量John,这样计算机可以开始认识它。
再次,第二步: 定位(Positional encoding),利用以下公式(这是这篇论文的创新)

微调一个新的高维空间,生成一个新的向量。

这个标识的作用是:1.在这个新的向量里面每一位由原来的0和1表示,分别取代成由sin和cos表示,这个目的是可以通过sin和cos的定律,让这个新向量不仅表示John这个单词的意义,还可以表示John在Smart John is singing这个句子的位置信息。如果不理解,可以直接忽略,只要记住第二步是用来在“表达John这个词的向量”中,加入了John在句子中的位置信息。John已经不是一个孤立的词,而是一个具体句子中的一个词,虽然还不知道句子中其他词是什么含义。
如果第一步计算机理解了什么是John,第二步计算机理解了“* John**”。
最后,第三步:自注意力机制(Self-Attention),通过一个Attention(Q,K,V)算法,再次把John放到一个新的空间信息里,设为

在这个新向量里,不仅包含了John的含义,John在句子中位置信息,更包含了John和句子中每个单子含义之间的关系和价值信息。我们可以理解,John作为一个词是一个泛指,但Smart John就具体了很多,singing的Smart John就又近了一步。而且Attention (Q,K,V)算法,不是对一个单词周围做计算,是让这个单词跟句子里所有单词做计算。通过计算调整这个单词在空间里的位置。
这种方法,可以在一个超长句子中发挥优势,而且最关键的是一举突破了时序序列的屏障。以往对于图像和NLP算法的划分,很大程度上是由于NLP有很明显的时序特征,即每个单词和下一个以及在下一个有比较明显的时序关系。但Transformer打破了这种束缚,它更在意一个单词跟句子中每个单词的价值权重。这是Transformer可以用到everywhere的主要原因。

计算过程
理解了向量的重要性,回到计算过程 :
具体的计算过程,用翻译句子“我爱你”到“I love you”举例(这句更简单一些)。首先进行向量化并吸收句子位置信息,得到一个句子的初始向量组。

(由于样本每个句子长短不同,所以每个句子都会是一个512*512的矩阵,如果长度不够就用0来代替。这样在训练时,无论多长的句子,都可以用一个同样规模的矩阵来表示。当然512是超参,可以在训练前调整大小。)
接着,用每个字的初始向量分别乘以三个随机初始的矩阵WQ,Wk,Wv分别得到三个量Qx,Kx,Vx。下图以“我”举例。

然后,计算每个单词的attention数值,比如“我”字的attention值就是用“我”字的Q我分别乘以句子中其他单词的K值,两个矩阵相乘的数学含义就是衡量两个矩阵的相似度。然后通过一个SoftMax转换(大家不用担心如何计算),计算出它跟每个单词的权重,这个权重比例所有加在一起要等于1。再用每个权重乘以相对应的V值。所有乘积相加得到这个Attention值。

这个attention数值就是除了“我”字自有信息和位置信息以外,成功的得到了这个句子中每个单词的相关度信息。
可以发现,在所有注意力系数的计算逻辑中其实只有每个字的初始矩阵WQ,Wk,Wv是未知数(这三个矩阵是所有文字共享的)。那么可以把这个transformer简化成一个关于输入,输出和这个W矩阵的方程:其中X是输入文字信息,Y是翻译信息。

这里有必要再介绍一下机器学习的基础知识:
Transformer算法本质上是一个前馈神经网络模型,它的计算基础逻辑,不去管复杂的隐藏层,就是假设Y=f(x)=wx,(目标还是要算出一个f())然后随机设置一个w0,开始计算这个y=w0x的成本函数,然后再把w0变成w1,计算y=w1x的成本函数,以此类推计算出无数w(不是无数,也会收敛),然后比较哪个w的成本函数最小,就是我们训练出来的f()。那么在transformer里,这三个初始矩阵就是那个w0。
再回到transformer,在计算Attention之后,每个单词根据语义关系被打入了新的高维空间这就是Self-attention(自注意力机制)。
但在transformer里,并不是代入了一个空间,而是代入了多个高维空间,叫做多头注意力机制,(文章中没有给出更清晰的理论支持,为什么是多头)。

主要原因是在训练时效果很好。这也是AI科研论文的一个特点,常常凭借非常高的科研素养和敏感性,发现一些方向,并且通过测试确实有效,但不一定可以给出很完美的理论支撑。这往往也给后续研究者一些可以进一步完善的空间。
事实证明,如何提升Attention(Q,K,V)效率是transformer领域迭代最快的部分。之后的Bert算法提出预训练机制成为了主流,后面会做进一步介绍。
当然,也可以理解是把这个句子中的逻辑关系放到不同的高维空间去训练,目的就是希望抓取更多的信息,这一部分可以更加深刻理解科研人员对空间的应用。
除了以上内容,还有一些技术点比如Mask机制、layer norm、神经网络激函数饱和区控制等,由于篇幅关系以及属于技术细节就不一一介绍了。
相关技术内容:
Attention是什么?
Transformer最重要的部分,就是注意力机制Attention。想要深度理解Transformer和Attention的机制,就需要了解一下它产生的背景、在哪类问题下产生,以及最初是为了解决什么问题而产生。
首先从机器翻译领域的模型演进历史切入:
机器翻译是从RNN开始跨入神经网络机器翻译时代的,几个比较重要的阶段分别是: Simple RNN -> Contextualize RNN -> Contextualized RNN with attention -> Transformer(2017),下面来一一介绍。
Simple RNN:
我们来回顾一下RNN的结构

在这个encoder-decoder模型结构中,encoder将整个源端序列(不论长度)压缩成一个向量(encoder output),源端信息和decoder之间唯一的联系只是: encoder output会作为decoder的initial states的输入。这样带来一个显而易见的问题就是,随着decoder长度的增加,encoder output的信息会衰减。

【RNN模型有2个主要的问题】
- 效率问题:需要逐个词进行处理,后一个词要等到前一个词的隐状态输出以后才能开始处理。源端序列不论长短,都被统一压缩成一个固定维度的向量,并且显而易见的是这个向量中包含的信息中,关于源端序列末尾的token的信息更多,而如果序列很长,最终可能基本上“遗忘”了序列开头的token的信息。
- 如果传递距离过长还会有梯度消失、梯度爆炸和遗忘问题。第二个问题同样由RNN的特性造成: 随着decoder timestep的信息的增加,initial hidden states中包含的encoder output相关信息也会衰减,decoder会逐渐“遗忘”源端序列的信息,而更多地关注目标序列中在该timestep之前的token的信息。
为了缓解传递间的梯度和遗忘问题,设计了各种各样的RNN cell,著名的有LSTM和GRU:
LSTM (Long Short Term Memory)

GRU (Gated Recurrent Unit)

但是,引用网上一个博主的比喻,这么做就像是在给马车换车轮,为什么不直接换成汽车呢?
但是这样依然有一个问题: context对于每个timestep都是静态的(encoder端的final hidden states,或者是所有timestep的output的平均值)。但是每个decoder端的token在解码时用到的context真的应该是一样的吗?在这样的背景下,Attention就应运而生了:
Transformer
接下来就是我们本文要介绍的核心结构——Transformer。
它针对RNN的弱点进行重新设计,解决了RNN效率问题和传递中的缺陷等,在很多问题上都超过了RNN的表现。Transfromer的基本结构如下图所示,它是一个N进N出的结构,也就是说每个Transformer单元相当于一层的RNN层,接收一整个句子所有词作为输入,然后为句子中的每个词都做出一个输出。但是与RNN不同的是,Transformer能够同时处理句子中的所有词,并且任意两个词之间的操作距离都是1,这么一来就很好地解决了上面提到的RNN的效率问题和距离问题。

每个Transformer单元都有两个最重要的子层,分别是Self-Attention层与Feed Forward层,后面会对这两个层的详细结构做介绍。文章使用Transformer搭建了一个类似Seq2Seq的语言翻译模型,并为Encoder与Decoder设计了两种不同的Transformer结构。

Decoder Transformer相对于Encoder Transformer多了一个Encoder-Decoder Attention层,用来接收来自于Encoder的输出作为参数。最终只要按照下图的方式堆叠,就可以完成Transformer Seq2Seq的结构搭建。

举个例子介绍下如何使用这个Transformer Seq2Seq做翻译
- 首先,Transformer对原语言的句子进行编码,得到memory。
- 第一次解码时输入只有一个<SOS>标志,表示句子的开始。
- 解码器通过这个唯一的输入得到的唯一的输出,用于预测句子的第一个词。
- 第二次解码,将第一次的输出Append到输入中,输入就变成了<SOS>和句子的第一个词(ground truth或上一步的预测),解码生成的第二个输出用于预测句子的第二个词。以此类推(过程与Seq2Seq非常类似)

了解了Transformer的大致结构以及如何用它来完成翻译任务后,接下来就看看Transformer的详细结构:
Transformer的详细结构介绍

核心组件就是上面所提到的自注意力Self-Attention和Feed Forward Networks,但还有很多其他细节,接下来我们就开始逐个结构的来解读Transformer。
自注意力Self Attention
Self Attention就是句子中的某个词对于本身的所有词做一次Attention。算出每个词对于这个词的权重,然后将这个词表示为所有词的加权和。每一次的Self Attention操作,就像是为每个词做了一次Convolution操作或Aggregation操作。具体操作如下:
首先,每个词都要通过三个矩阵Wq, Wk, Wv进行一次线性变化,一分为三,生成每个词自己的query, key, vector三个向量。以一个词为中心进行Self Attention时,都是用这个词的key向量与每个词的query向量做点积,再通过Softmax归一化出权重。然后通过这些权重算出所有词的vector的加权和,作为这个词的输出。具体过程如下图所示

归一化之前需要通过除以向量的维度dk来进行标准化,所以最终Self Attention用矩阵变换的方式可以表示为

最终每个Self Attention接受n个词向量的输入,输出n个Aggregated的向量。
上文提到Encoder中的Self Attention与Decoder中的有所不同,Encoder中的Q、K、V全部来自于上一层单元的输出,而Decoder只有Q来自于上一个Decoder单元的输出,K与V都来自于Encoder最后一层的输出。也就是说,Decoder是要通过当前状态与Encoder的输出算出权重后,将Encoder的编码加权得到下一层的状态。
如何理解attention中的Q,K,V?
在 Attention 机制中,从广义上来说 、、三者做了一种类似上面所说的搜索运算,从而确定每个 token 与全部输入序列中其他 token 之间的语义关联度。
那么,一个序列中的每一个 token 的 Embedding 是如何派生出三个向量、、的呢?
直接用邱锡鹏老师PPT里的一张图就可以直观理解——假设D是输入序列的内容,完全忽略线性变换的话可以近似认为Q=K=V=D(所以叫做Self-Attention,因为这是输入的序列对它自己的注意力),于是序列中的每一个元素经过Self-Attention之后的表示就可以这样展现:

也就是说,The这个词的表示,实际上是整个序列加权求和的结果——权重从哪来?点积之后Softmax得到——这里Softmax(QK)就是求权重的体现。我们知道,向量点积的值可以表征词与词之间的相似性,而此处的“整个序列”包括The这个词自己(再一次强调这是Self-Attention),所以最后输出的词的表示,其“主要成分”就主要地包含它自身和跟它相似的词的表示,其他无关的词的表示对应的权重就会比较低。
实际上,我们把每个 token 的 Embedding 向量分别做三次线性投影(或称为线性变换),即与三个具有不同权重的矩阵 ,,相乘来获得 、、 向量。 而 ,, 就是 Transformer 大模型在预训练阶段时,通过神经网络反向传播来训练的权重(注意,这里提到的权重,是指神经网络中的连接权重),是 Transformer 大模型通过百万级的训练语料在 8 块 NVIDIA P100 GPU 上运算 3.5 天后的训练所得(当然,这是2017年的事情了,今天许多的多模态大模型中的 Transformer 架构在训练时往往采用至少百亿计的语料训练集,同时在几百甚至上千块至少是 A100 GPU 上,训练十几天才会完成)。
很多人会在这里感觉很迷惑 ,,这三个矩阵从何而来,因为很多介绍 Transformer 的文章在这里都只是一笔带过,仅仅说了一下 ,,这三个权重矩阵是随机初始化的,但并没有说明是在模型“训练阶段”随机初始化的,这造成了诸多的混淆。因为,不同于“训练阶段”,在“执行阶段”这三个矩阵是固定的,即 Transformer 神经网络架构中的固定的节点连接权重,是早经被训练好的(Pre-Trained)。比如说 GPT ,就是 Generative Pre-Trained Transformer。

注意,这里因为是把整句子拆成具体的单词 token 来讲解,所以为了理解起来方便,暂用向量来表达。但在实际的运算过程中是以矩阵的方式来运行的,以提高运行效率,即整个序列中所有 token 的 Embedding 向量都放在一起组成一个矩阵进行运算。所以,该矩阵的维度由输入序列的 token 数 ,与 Embedding 的维度(一般为512)决定。所以,该矩阵的形状为 。
Masked Attention
通过观察上面的结构图我们还可以发现Decoder与Encoder的另外一个不同,就是每个Decoder单元的输入层,要先经过一个Masked Attention层。那么Masked的与普通版本的Attention有什么区别呢?
Encoder因为要编码整个句子,所以每个词都需要考虑上下文的关系。所以每个词在计算的过程中都是可以看到句子中所有的词的。但是Decoder与Seq2Seq中的解码器类似,每个词都只能看到前面词的状态,所以是一个单向的Self-Attention结构。
Masked Attention的实现也非常简单,只要在普通的Self Attention的Softmax步骤之前,与(&)上一个下三角矩阵M就好了

Multi-Head Attention
Multi-Head Attention就是将上述的Attention做h遍,然后将h个输出进行concat得到最终的输出。这样做可以很好地提高算法的稳定性,在很多Attention相关的工作中都有相关的应用。Transformer的实现中,为了提高Multi-Head的效率,将W扩大了h倍,然后通过view(reshape)和transpose操作将相同词的不同head的k、q、v排列在一起进行同时计算,完成计算后再次通过reshape和transpose完成拼接,相当于对于所有的head进行了一个并行处理。
Position-wise Feed Forward Networks层
Encoder中和Decoder中经过Attention之后输出的n个向量(这里n是词的个数)都分别的输入到一个全连接层中,完成一个逐个位置的前馈网络。


Add & Norm层
是一个残差网络,将一层的输入与其标准化后的输出进行相加即可。Transformer中每一个Self Attention层与FFN层后面都会连一个Add & Norm层。

位置嵌入Positional Encoding
由于Transformer中既不存在RNN,也不同于CNN,句子里的所有词都被同等的看待,所以词之间就没有了先后关系。换句话说,很可能会带上和词袋模型相同的不足。为了解决这个问题,Transformer提出了Positional Encoding的方案,就是给每个输入的词向量叠加一个固定的向量来表示它的位置。文中使用的Positional Encoding如下:

其中pos是词在句子中的位置,i是词向量中第i位,即将每个词的词向量为一行进行叠加,然后针对每一列都叠加上一个相位不同或波长逐渐增大的波,以此来唯一区分位置。
Transformer 工作流程
Transformer的工作流程就是上面介绍的每一个子流程的拼接
- 输入的词向量首先叠加上Positional Encoding,然后输入至Transformer内
- 每个Encoder Transformer会进行一次Multi-head self attention->Add & Normalize->FFN->Add & Normalize流程,然后将输出输入至下一个Encoder中
- 最后一个Encoder的输出将会作为memory保留
- 每个Decoder Transformer会进行一次Masked Multi-head self attention->Multi-head self attention->Add & Normalize->FFN->Add & Normalize流程,其中Multi-head self attention时的K、V至来自于Encoder的memory。根据任务要求输出需要的最后一层Embedding。
- Transformer的输出向量可以用来做各种下游任务
GitHub链接:github.com/harvardnlp/a
Post Scriptum
虽然在Transformer文章中提出了一种自然语言翻译的模型,很多文章把这个模型称为Transformer。但我们还是倾向于将文章中利用Self-Attention的Encoder或Decoder的子结构称为Transformer。文中和源码中还包含了很多其他的一些优化例如学习率动态变化,Residual Dropout以及Label Smoothing在这里就不再赘述,有兴趣的朋友可以阅读相关参考文献进行了解。
最近,大量论文提出了新的Transformer“变种”,它们的根本目的都是加速模型的效率,但如果一篇篇去看,可能有点眼花缭乱。
变种后的Transformer模型
2种分类方法
按使用方法来分类的话,Transformer模型可以分成如下3类:
只用编码器:可用于分类
只用解码器:可用于语言建模
编码器-解码器:可用于机器翻译
但如果按这些变种的提高效率的原理,也就是“高效方法”来分类,那么Transformer模型的这些“变种”则可以被分成如下几类:

Fixed Patterns(固定模式):将视野限定为固定的预定义模式,例如局部窗口、固定步幅块,用于简化注意力矩阵;
Learnable Patterns(可学习模式):以数据驱动的方式学习访问模式,关键在于确定token相关性。
Memory(内存):利用可以一次访问多个token的内存模块,例如全局存储器。
Low Rank(低秩):通过利用自注意力矩阵的低秩近似,来提高效率。
Kernels(内核):通过内核化的方式提高效率,其中核是注意力矩阵的近似,可视为低秩方法的一种。
Recurrence(递归):利用递归,连接矩阵分块法中的各个块,最终提高效率。
可以看见,之前部分Transformer相关的研究都被分在上面的图像中了,非常清晰明了。
总结
总上面这些关于Transformer工作的发展中,我也整理出了一些关于深度学习发展趋势的个人心得:
- 1. 有监督模型向半监督甚至无监督方向发展
数据的规模的增长速度远远超过了数据的标注速度,这也就导致了大量无标签数据的产生。这些无标签的数据并非没有价值,相反,如果找到合适的“炼金术”,将可以从这些海量的数据中获取意想不到的价值。如何利用上这些无标签的数据来改善任务的表现变成了一个越来越无法轻视的问题。
- 2. 从少量数据复杂模型到大量数据简单模型
深度神经网络的拟合能力非常的强大,一个简单的神经网络模型就足以拟合任何函数。但无奈使用越简单的网络结构完成同一个任务,对数据量的要求也更高。数据量越是上升,数据质量越是提高,往往对模型的要求就会越会降低。数据量越大,模型就越容易捕捉到符合真实世界分布的特征。Word2Vec就是一个例子,它所使用的目标函数非常的简单,但是由于使用了大量的文本,于是训练出的词向量中就包含了许多有趣的特性。
- 3. 从专用模型向通用模型发展
GPT、BERT、MT-DNN、GPT-2都使用了经过预训练的通用模型来继续进行下游的机器学习任务,并不需要对模型本身再做太多的修改。如果一个模型的表达能力足够的强,训练时候使用的数据量足够的大,那么模型的通用性就会更强,就不需要针对特定的任务做太多的修改。最极端的情况就像是GPT-2这个样子,训练时甚至完全不需要知道后续的下游任务是什么,就能够训练出一个通用的多任务模型。
- 4. 对数据的规模和质量提高
大模型GPT、BERT、MT-DNN、GPT-2虽然先后刷榜,但是我认为成绩的提升中,数据规模的提升占有比结构调整更大的比重。随着模型的通用化和简单化,为提升模型的性能,今后更多的注意力将会从如何设计一个复杂、专用的模型转移到如何获取、清洗、精化出质量更加出众的、大量的数据上。数据的处理方式调整的作用将会大于模型结构调整的作用。
最后
Transformers是一种强大的深度学习架构,并成为主流的大模型基础架构并彻底改变了自然语言处理(NLP)领域。它们已被用于实现各种任务的最先进结果,包括语言翻译、文本分类和文本生成。Transformers的关键优势之一是它们的灵活性,因为通过改变其架构,它们可以适应广泛的任务和问题。然而,并非每个Transformer模型都是相同的;存在各种不同的架构,选择正确的模型对于获得最佳结果至关重要。
文章来源:知乎