文章目录
- 1、Transformer基本原理介绍
- 1.Transformer 结构
- 2.嵌入表示层
- 3. 注意力层
- 3.1 输⼊矩阵
- 3.2 查询矩阵和键矩阵
- 3.3 Q和K的转置的点击除以键向量维度的平⽅根
- 3.4 应⽤softmax函数
- 3.5 注意力矩阵通过分数矩阵乘以值矩阵得出
- 3.6 注意⼒矩阵
- 4. 前馈层
- 5. 残差连接与层归一化
- 6. 编码器和解码器结构
- 二、Transformer家族
- 1.Decoder模型
- 1.GPT-2
- 2.LLaMA系列
- 2.1 RMSNorm 归一化函数
- 2. 2 SwiGLU 激活函数
- 2. 3 旋转位置嵌入(RoPE)
- 2.Bert系列(Eecoder模型)
- 2.1 标记嵌⼊层
- 2.2 分段嵌⼊层
- 2.3 位置嵌⼊层
1、Transformer基本原理介绍
Transformer 结构完全通过注意力机制完成对源语言序列和目标语言序列全局依赖的建模。
1.Transformer 结构
Transformer结构分为编码器(Encoder)和解码器(Decoder)结构。均有若干个基本的transformer块组成,这里 N× 表示进行了 N 次堆叠。主要涉及到如下几个模块:
- 注意力层:使用多头注意力(Multi-Head Attention)机制整合上下文语义,它使得序列中任 意两个单词之间的依赖关系可以直接被建模而不基于传统的循环结构,从而更好地解决文本 的长程依赖。
- 位置感知前馈层(Position-wise FFN):通过全连接层对输入文本序列中的每个单词表示进行更复杂的变换。
- 残差连接:对应图中的 Add 部分。它是一条分别作用在上述两个子层当中的直连通路,被用于连接它们的输入与输出。从而使得信息流动更加高效,有利于模型的优化。
- 层归一化:对应图中的 Norm 部分。作用于上述两个子层的输出表示序列中,对表示序列进行层归一化操作,同样起到稳定优化的作用。
2.嵌入表示层
对于输入文本序列,首先通过输入嵌入层(Input Embedding)将每个单词转换为其相对应的向量表示。通常直接对每个单词创建一个向量表示。由于 Transfomer 模型不再使用基于循环的方式建模文本输入,序列中不再有任何信息能够提示模型单词之间的相对位置关系。在送入编码器端建模其上下文语义之前,一个非常重要的操作是在词嵌入中加入位置编码(Positional Encoding)这一特征。具体来说,序列中每一个单词所在的位置都对应一个向量。这一向量会与单词表示对应相加并送入到后续模块中做进一步处理。在训练的过程当中,模型会自动地学习到如何利用这部分位置信息。
为了得到不同位置对应的编码,Transformer 模型使用不同频率的正余弦函数如下所示:
其中,pos 表示单词所在的位置,2i 和 2i+ 1 表示位置编码向量中的对应维度,d 则对应位置编码的总维度。通过上面这种方式计算位置编码有这样几个好处:首先,正余弦函数的范围是在 [-1,+1],导出的位置编码与原词嵌入相加不会使得结果偏离过远而破坏原有单词的语义信息。其次,依据三角函数的基本性质,可以得知第 pos + k 个位置的编码是第 pos 个位置的编码的线性组合,这就意味着位置编码中蕴含着单词之间的距离信息。
3. 注意力层
3.1 输⼊矩阵
通过输⼊矩阵 ,我们可以看出,矩阵的第⼀⾏表⽰单词I的词嵌⼊向量。以此类推,第⼆⾏对应单词am的词嵌⼊向量,第三⾏对应单词good的词嵌⼊向量。所以矩阵 的维度为[句⼦的⻓度×词嵌⼊向量维度]。原句的⻓度为3,假设词嵌⼊向量维度为512,那么输⼊矩阵的维度就是[3×512]。
现在通过矩阵 ,我们再创建三个新的矩阵:查询(query)矩阵 、键(key)矩阵 ,以及值(value)矩阵 。等⼀下,怎么⼜多了三个矩阵?为何需要创建它们?接下来,我们将继续了解在⾃注意⼒机制中如何使⽤这三个矩阵。如图所⽰,将输⼊矩阵分别乘以权重矩阵,我们就可以得出对应的查询矩阵、键矩阵和值矩阵。
- 三个矩阵的第⼀⾏ 、 和 分别代表单词I的查询向量、键向量和值向量。
- 三个矩阵的第⼆⾏ 、 和 分别代表单词am的查询向量、键向量和值向量。
- 三个矩阵的第三⾏ 、 和 分别代表单词good的查询向量、键向量和值向量。
因为每个向量的维度均为64,所以对应的矩阵维度为[句⼦⻓度×64]。因为我们的句⼦⻓度为3,所以代⼊后可得维度为[3×64]。
3.2 查询矩阵和键矩阵
图显⽰了查询矩阵与键矩阵的点积结果。
3.3 Q和K的转置的点击除以键向量维度的平⽅根
3.4 应⽤softmax函数
⽬前所得的相似度分数尚未被归⼀化,我们需要使⽤softmax函数对其进⾏归⼀化处理。如图1-15所⽰,应⽤softmax函数将使数值分布在0到1的范围内,且每⼀⾏的所有数之和等于1。
我们将图1-15中的矩阵称为分数矩阵。通过这些分数,我们可以了解句⼦中的每个词与所有词的相关程度。以图1-15中的分数矩阵的第⼀⾏为例,它告诉我们,I这个词与它本⾝的相关程度是90%,与am这个词的相关程度是7%,与good这个词的相关程度是3%。
3.5 注意力矩阵通过分数矩阵乘以值矩阵得出
3.6 注意⼒矩阵
由图1-16可以看出,注意⼒矩阵 就是值向量与分数加权之后求和所得到的结果。让我们逐⾏理解这个计算过程。⾸先,第⼀⾏ 对应I这个词的⾃注意⼒值,它通过图所⽰的⽅法计算所得。
4. 前馈层
前馈层接受自注意力子层的输出作为输入,并通过一个带有 Relu 激活函数的两层全连接网络对输入进行更加复杂的非线性变换。
5. 残差连接与层归一化
由 Transformer 结构组成的网络结构通常都是非常庞大。编码器和解码器均由很多层基本的Transformer 块组成,每一层当中都包含复杂的非线性映射,这就导致模型的训练比较困难。因此,研究者们在 Transformer 块中进一步引入了残差连接与层归一化技术以进一步提升训练的稳定性。具体来说,残差连接主要是指使用一条直连通道直接将对应子层的输入连接到输出上去,从而避免由于网络过深在优化过程中潜在的梯度消失问题:
此外,为了进一步使得每一层的输入输出范围稳定在一个合理的范围内,层归一化技术被进一步引入每个 Transformer 块的当中:
其中 µ 和 σ 分别表示均值和方差,用于将数据平移缩放到均值为 0,方差为 1 的标准分布,α 和 b是可学习的参数。层归一化技术可以有效地缓解优化过程中潜在的不稳定、收敛速度慢等问题。
6. 编码器和解码器结构
解码器的每个 Transformer 块的第一个自注意力子层额外增加了注意力掩码,对应图中的掩码多头注意力(Masked Multi-Head Attention)部分。这主要是因为在翻译的过程中,编码器端主要用于编码源语言序列的信息,而这个序列是完全已知的,因而编码器仅需要考虑如何融合上下文语义信息即可。而解码端则负责生成目标语言序列,这一生成过程是自回归的,即对于每一个单词的生成过程,仅有当前单词之前的目标语言序列是可以被观测的,因此这一额外增加的掩码是用来掩盖后续的文本信息,以防模型在训练阶段直接看到后续的文本序列进而无法得到有效地训练。
此外,解码器端还额外增加了一个多头注意力(Multi-Head Attention)模块,使用交叉注意力(Cross-attention)方法,同时接收来自编码器端的输出以及当前 Transformer 块的前一个掩码注意力层的输出。查询是通过解码器前一层的输出进行投影的,而键和值是使用编码器的输出进行投影的。它的作用是在翻译的过程当中,为了生成合理的目标语言序列需要观测待翻译的源语言序列是什么。基于上述的编码器和解码器结构,待翻译的源语言文本,首先经过编码器端的每个Transformer 块对其上下文语义的层层抽象,最终输出每一个源语言单词上下文相关的表示。解码器端以自回归的方式生成目标语言文本,即在每个时间步 t,根据编码器端输出的源语言文本表示,以及前 t − 1 个时刻生成的目标语言文本,生成当前时刻的目标语言单词。
二、Transformer家族
现在很多大模型都是基于Transformer,其中最出名就是GPT和BERT模型,在GPT和BERT模型被提出来之后,NLP领域也出现了基于Transformer结构的模型,按照模型结构基本可以分为三类:
- 纯Encoder模型(典型代表BERT,仅使用Transformer中的编码器),又称为自编码(auto-encoding)Transformer模型。
- 纯Decoder模型(典型代表GPT,仅使用Transformer中的解码器),又称为自回归(auto-regressive)Transformer模型。
- Encoder-Decoder模型(典型代表BART、T5),又称为Seq2Seq(sequence-to-sequence)Transformer模型。
1.Decoder模型
1.GPT-2
GPT 采用生成式预训练方法,单向意味着模型只能从左到右或从右到左对文本序列建模,所采用的 Transformer 结构和解码策略保证了输入文本每个位置只能依赖过去时刻的信息。
2.LLaMA系列
LLaMA 所采用的 Transformer 结构和细节,与本文所介绍的 Transformer 架构不同的地方包括采用了前置层归一化并使用RMSNorm 归一化函数,激活函数更换为 SwiGLU,并使用了旋转位置嵌入(RoP),整体 Transformer架构与 GPT-2 类似。
2.1 RMSNorm 归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT 就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了 RMSNorm 归一化函数。针对输入向量 aRMSNorm 函数计算公式如下:
2. 2 SwiGLU 激活函数
SwiGLU激活函数是 Shazeer 在文献 [50] 中提出,并在 PaLM[14] 等模中进行了广泛应用,并且取得了不错的效果,相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA 中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-Forward Network)的计算公式如下:
其中,σ(x) 是 Sigmoid 函数。 Swish 激活函数在参数 β 不同取值下的形状。可以看到当 β 趋近于 0 时,Swish 函数趋近于线性函数 y = x,当 β 趋近于无穷大时,Swish 函数趋近于 ReLU 函数,β 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace 的 Transformer 库中Swish1 函数使用 silu 函数代替。
2. 3 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary Positional Embeddings,RoPE)[52] 代替原有的绝对位置编码。RoPE 借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给 q,k 添加绝对位置信息:
2.Bert系列(Eecoder模型)
BERT成功的⼀个主要原因是,它是基于上下⽂的嵌⼊模型,这是它与其他流⾏的嵌⼊模型的最⼤不同,⽐如⽆上下⽂的word2vec 。
2.1 标记嵌⼊层
我们先对这两个句⼦进⾏分词标记,如下所⽰。在本例中,我们没有将字⺟⼩写化。
tokens = [Paris, is, a, beautiful, city, I, love, Paris]
接下来,我们添加⼀个新标记,即[CLS]标记,并将它放在第⼀句的开头。
tokens = [ [CLS], Paris, is, a, beautiful, city, I, love, Paris]
然后,我们在每个句⼦的末尾添加⼀个新标记,即[SEP]。
tokens = [ [CLS], Paris, is, a, beautiful, city, [SEP], I, love,Paris, [SEP]]
在将所有标记送⼊BERT之前,我们使⽤标记嵌⼊层将标记转换成嵌⼊。请注意,标记嵌⼊的值将通过训练学习。如图所⽰,我们计算所有标记的嵌⼊,如 表⽰[CLS]的嵌⼊, 表⽰Paris的嵌⼊,以此类推。
2.2 分段嵌⼊层
分段嵌⼊层⽤来区分两个给定的句⼦。让我们通过前⾯所列举的两个句⼦来理解分段嵌⼊。
句⼦A:Paris is a beautiful city(巴黎是⼀个美丽的城市)
句⼦B:I love Paris(我爱巴黎)
在对这两个句⼦进⾏分词后,我们得到以下内容
tokens = [ [CLS], Paris, is, a, beautiful, city, [SEP], I, love,Paris, [SEP]]
现在,除了[SEP],我们需要给模型提供某种标记来区分两个句⼦。因此,我们将输⼊的标记送⼊分段嵌⼊层。如图所⽰,句⼦A的所有标记都被映射到嵌⼊ ,句⼦B的所有标记则都被映射到嵌⼊ 。
2.3 位置嵌⼊层
最后,让我们了解⼀下位置嵌⼊层。由于Transformer没有任何循环机制,⽽且是以并⾏⽅式处理所有词的,因此需要⼀些与词序有关的信息。有鉴于此,我们使⽤了位置编码。BERT本质上是Transformer的编码器,因此在直接向BERT输⼊词之前,需要给出单词(标记)在句⼦中的位置信息。位置嵌⼊层正是⽤来获得句⼦中每个标记的位置嵌⼊的。