入门级别的Transformer模型介绍
文章目录
- 前言
- 0.Transformer名称
- 1.Transformer的整体结构
- 2.自注意力机制
- 2.1整体概述
- 2.2处理流程
- 3.多头注意力机制
- 4.位置编码
- 5.掩码注意力
- 6.编解码注意力
- 7.残差连接与归一化
- 7.1残差连接
- 7.2归一化
- 结语
前言
在当今的人工智能领域,站在风口浪尖的莫过于大语言模型(Large Language Model,LLM)
,它使得自然语言处理
得到了更加广泛的关注!当谈到大语言模型,必不可少的就是它的开山之作GPT系列
,而GPT系列又是基于Transformer的解码器结构
,因此想要从事该方向,你必不可少要理解Transformer的基本结构。本篇博客主要介绍Transformer的基本结构,包括位置编码、多头自注意力机制、残差连接与归一化、掩码自注意力机制、编解码自注意力机制、全连接层、Softmax层等内容,具体实现任务选择机器翻译
,原始论文地址:Attention Is All You Need
0.Transformer名称
这里可能有人会困惑,为什么一篇中文的博客,还一直保留Transformer这个词,而不使用对应的中文翻译?
主要因为没有统一的叫法,专业人士主要以Transformer称呼,当然也有很多人采用现有的翻译软件的翻译结果称呼,此处以有道翻译为例:
部分翻译软件在翻译该部分时就换翻译成变压器
,还有部分人称呼其变形金刚
,基于上述原因,此处保留使用Transformer。
1.Transformer的整体结构
我们可以先站在上帝视角观看,不考虑transformer里面的具体结构,即把它当作一个黑盒模型
,只看输入与输出。在机器翻译中,它可以把句子从一种语言翻译成另一种语言。
图示实现的是从法语翻译成英文。
接着,我们拨开黑盒的第一层,可以看到,它包含一个编码器(Encoder)
和解码器(Decoder)
,以及它们之间存在着某种联系——编码器的输出是解码器的输入。
这里你可能对编码器和解码器这个名词有些许陌生,因此这里插入一段解释:
编码器(encoder)负责将可变长的输入序列(如图示的法语输入序列)转换为一个固定长度的编码表示;
解码器(decoder)将该固定编码表示转换为可变长度的输出序列(如图示的英语输出序列)。
细心的就可以发现,这里图示使用的是ENCODERS
和DECODERS
而不是单数,这是不是说明它不是由一个编码器和解码器组成,而是多个呢?
接着,我们拨开黑盒的第三层来一探究竟。编码器模块是由6个子编码器堆叠而来,同理,解码器也是由6个子解码器堆叠而来(至于为什么选择6个?这是一个超参数
,论文中做出解释是因为其他数量的性能没有6个效果更好)。同时也可以关注到,最后一层的编码器(Encoder)输出会作为输入给每一个解码器(Decoder)
接着,我们看一下每个子编码器的结构。
每个编码器的结构都是一样的,包括两层:自注意力层和全连接层
这里解释一下为什么将前馈神经网络翻译成了全连接层?
主要是因为我认为两者只是强调的重点不同,前馈神经网络强调前向传播,全连接强调当前层和下一层的全部节点相连,在具体实现过程中均可使用线性层来实现,后续阐述过程中,这两种称呼均值的是这里的前馈神经网络(FFN)
编码器的输入首先会进入一个自注意力层,主要功能为:当要编码某个特定词汇的时候,它会帮助编码器关注句子中的其他词汇。之后会具体阐述该部分是如何实现的。
自注意力层的输出会传递给一个前馈神经网络层,每个编码器组件都是在相同的位置使用结构相同的前馈神经网络。
接着,我们看子解码器的结构。
每个子解码器的结构也是一样的,包括自注意力层、编解码注意力层、全连接层,这里的自注意力层和之前的结构略有不同,应该称之为掩码注意力机制,后续会做进一步阐释。这里可以简单留个印象即可。
至于编解码注意力,是为了让解码器能够注意到输入句子中的相关部分,后续会做详细介绍。
最后,我们就可以打开Transformer的最后一层了,也就是论文中使用的一张图。
左侧编码器(多头自注意力机制+残差连接与归一化+前馈神经网络),右侧解码器(多头掩码注意力机制+残差连接与归一化+多头编解码注意力机制+前馈神经网络)。后续会逐一介绍该部分内容是如何设计的。
2.自注意力机制
2.1整体概述
注意力机制在视觉中就是把注意力集中到一些重要的点上。
而在自然语言方向,使得模型关注整个输入序列所有单词,帮助模型对本单词更好的编码。下面从宏观的角度考虑。
假设我们要翻译下边这句话:
”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”的编码中。
随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码
2.2处理流程
- 对编码器的每个输入向量都计算一个
query
、key
、value
向量。把输入的词嵌入向量与三个权重矩阵WQ、WK、WVW_Q、W_K、W_VWQ、WK、WV相乘,权重矩阵是模型训练阶段训练出来的。
注:这三个向量维度是64,比嵌入向量的维度小,嵌入向量、编码器的输入输出维度都是512。这三个向量不是必须比编码器输入输出的维数小,这样做主要是为了让多头注意力的计算更稳定。 - 计算注意力得分。通过
query
和key
的点乘积得出来的。当要计算第一个位置的注意力得分的时候就要将第一个单词的query和其他的key依次相乘,在这里就是q1∗k1、q1∗k2q_1*k_1、q_1*k_2q1∗k1、q1∗k2
- 将计算获得的注意力分数除以dk\sqrt{d_k}dk,dkd_kdk指的是key向量的维度,此处指的是64。
至于为什么这样操作?
为了将结果缩放到一个合适的范围,使softmax函数的输入值分布更加合理,避免梯度饱和问题,从而让模型能够更稳定的学习。如果没有这一缩放操作,就会导致梯度消失或梯度不稳定,注意力分布过于集中等问题。简言之,让梯度计算更稳定
。
- 将结果通过softmax归一化。softmax之后的注意力分数表示在计算当前位置时,其他单词受到的关注度的大小
- 将每个value向量乘以注意力分数,这是为了留下想要注意的单词的value,并把其他不相关的单词丢掉。
- 将上一步结果相加,输出本位置的注意力结果。
以上就是自注意力的计算。计算得到的向量直接传递给前馈神经网络。但为了处理更加迅速,实际使用矩阵进行计算的。接下来我们看一下怎么用矩阵计算。
- 计算Query、Key、Value矩阵。直接把输入的向量打包成一个矩阵X,再把它乘以训练好的WQ、WK、WVW_Q、W_K、W_VWQ、WK、WV。其中X矩阵每一行都代表输入句子中的一个词,整个矩阵代表输入的句子。
- 直接用矩阵处理,压缩之前的后续步骤
了解完之前的介绍后,可以再看下面论文中介绍该部分的图片。
除了Mask(opt.)
以外的部分如何处理,此处应该有了比较清晰的对应关系了。
下面是一个简单的计算案例的实现:
3.多头注意力机制
论文中使用的是多头注意力机制。
在多头注意力中同时使用多个不同的WQ、WK、WVW_Q、W_K、W_VWQ、WK、WV权重矩阵(论文中使用的是8个头部,因此会得到8个计算结果),每个权重都是随机初始化的。经过训练每个
WQ、WK、WVW_Q、W_K、W_VWQ、WK、WV都能将输入的矩阵映射到不同的表示子空间。不同子空间关注的角度不同。
多头注意力结果会得到多个注意力权重。
多头注意力的结果会进入一个前馈神经网络,它的输入需要的是单个矩阵(矩阵中的每一行向量对应一个单词),因此引入一个权重矩阵WOW_OWO,将多个注意力矩阵拼接起来,然后乘以一个附加权重矩阵WOW_OWO。
这里将整个处理流程放在一张图里,结果如下:
多头注意力从关注上下文不同侧面的角度,进一步增强了自注意力机制聚合上下文信息的能力
4.位置编码
- 对任何语言来说,句子中词汇的顺序和位置都是非常重要的。它们定义了语法,从而定义了句子的实际语义。RNN结构本身就涵盖了单词的顺序,RNN按顺序逐字分析句子,这就直接在处理的时候整合了文本的顺序信息。
- 但Transformer架构抛弃了循环机制,仅采用多头自注意机制。避免了RNN较大的时间成本。并且从理论上讲,它可以捕捉句子中较长的依赖关系。
- 由于句子中的单词同时流经Transformer的编码器、解码器堆栈,模型本身对每个单词没有任何位置信息的。因此,仍然需要一种方法将单词的顺序整合到模型中。
- 想给模型一些位置信息,一个方案是在每个单词中添加一条关于其在句子中位置的信息。我们称之为“信息片段”,即位置编码。
位置编码维度与原始编码维度一致。序列中每个单词所在的位置都对应一个实值向量。这个实值向量会与表示对应相加并送入到后续模块中做进一步处理。在训练过程中,模型会自动地学习如何利用这部分位置信息。为了得到不同位置对应的编码,Transformer使用不同频率的正余弦函数:
PE(pos,2i)=sin(pos10002id)PE(pos,2i)=sin(\frac{pos}{1000\frac{2i}{d}})PE(pos,2i)=sin(1000d2ipos)
PE(pos,2i+1)=cos(pos10002id)PE(pos,2i+1)=cos(\frac{pos}{1000\frac{2i}{d}})PE(pos,2i+1)=cos(1000d2ipos)
其中,pos表示单词所在位置,2i和2i+1表示位置编码向量中的对应维度,d则对应位置编码的总维度。
这是可能会有疑问:词嵌入向量和位置编码相加不会破坏原始单词的意思吗?
主要是因为正余弦函数的范围是在[-1,1],导出的位置编码与原始嵌入向量相加不会使得结果偏差过远而破坏原有单词的语义信息。
上图描述的是,一个句子有20个单词,词嵌入向量的维度是512。可以看到图像从中间一分为二,因为左半部分由正弦函数生成,而右半部分由余弦函数生成,然后将他们二者拼接起来,形成了每个位置的位置编码。
5.掩码注意力
传统的Encoder-Decoder:训练阶段使用了上下文
的信息,而测试阶段只使用上文信息。
掩码注意力:训练时模拟测试阶段,只使用上文信息,预测某个单词时,将其下文遮住
具体操作为:在计算得到注意力矩阵后,通过和Mask矩阵元素对应相乘即可。
6.编解码注意力
编码器首先处理输入序列,将最后一个编码器组件的输出转化为一组注意力向量K和V。每个解码器组件将在“Encoder-Decoder attention”层中使用编码器传来的K和V
,这有助于解码器将注意力集中在输入序列的适当位置。
在解码阶段,每一轮计算都只往外预测一个输出token,输出步骤会一直重复,直到遇见句子结束符,表明Transformer的解码器完成输出。
每一步的输出都会在下一个时间步作为底层解码器的输入,跟编码器一样,添加位置编码,指示单词的位置信息。
此处的编解码注意力层中的Q、K和V和之前的来源不同
,Q是从下层创建的(底层解码器输入的嵌入向量或下层decoder组件的输出),但其K和V是来自编码器最后一个组件的输出结果。
编码器是对整个输入序列进行编码,将其结果转换成K和V传给解码器,K和V包含整个句子的所有信息。解码器的输入是拼接之前编码器输出的单词,所以解码器造出来的Q仅包含已经输出的内容,因此每一个输出与encoder输入的上下文和decoder输入的上文有关
。
7.残差连接与归一化
7.1残差连接
此处主要借鉴何凯明
提出的残差网络,来避免梯度弥散和梯度爆炸,导致参数不能有效更新。
7.2归一化
归一化层:使得每一层的输入输出范围稳定在一个合理的范围内
LN(x)=gx−μσ+bLN(x)=g\frac{x-μ}{\sigma}+bLN(x)=gσx−μ+b
其中μ和σ\mu和\sigmaμ和σ代表均值和方差,用于将数据平移缩放到均置为0,方差为1的标准分布,g和b是可学习参数。
层归一化技术可以有效地缓解优化过程中潜在的不稳定,收敛速度慢等问题。
结语
至此,transformer中所有结构的功能解释完毕,希望能够帮助你理解,同时后续的BERT和GPT也都是在此结构基础上做的部分修改,因此理解该结构十分关键。
本篇博客主要借鉴Jay Alammar’s blogs,部分加入了自己的理解,如有不足,欢迎批评指正!