起源与发展

Transformer 源自于AI自然语言处理任务NLP;在计算机视觉领域CV,近年来Transformer逐渐替代CNN成为一个热门的研究方向。此外,Transformer在文本、语音、视频等多模态领域也在崭露头角,可见Transformer模型的重要之处。

2017 年 Google 在《Attention Is All You Need》中提出了 Transformer 结构用于序列标注,在翻译任务上超过了之前最优秀的循环神经网络模型;与此同时,Fast AI 在《Universal Language Model Fine-tuning for Text Classification》中提出了一种名为 ULMFiT 的迁移学习方法,将在大规模数据上预训练好的 LSTM 模型迁移用于文本分类,只用很少的标注数据就达到了最佳性能。

这些具有开创性的工作促成了两个著名 Transformer 模型的出现:

  • GPT (the Generative Pretrained Transformer);
  • BERT (Bidirectional Encoder Representations from Transformers)。

通过将 Transformer 结构与无监督学习相结合,我们不再需要对每一个任务都从头开始训练模型,并且几乎在所有 NLP 任务上都远远超过先前的最强基准。

  Transformer和LSTM的最大区别,就是LSTM的训练是迭代的、串行的,必须要等当前字处理完,才可以处理下一个字。而Transformer的训练是并行的,即所有字是同时训练的,这样就大大增加了计算效率。Transformer使用了位置嵌入(Positional Encoding)来理解语言的顺序,使用自注意力机制(Self Attention Mechanism)和前馈全连接层进行计算,这是Transformer的创新点。

基本结构

模型的左半边Encoder部分可以看作是一个编码器,右半边Decoder部分可以看作是一个解码器,其中编码器是双向的,解码器是单向的需要循环迭代输出。

虽然新的 Transformer 模型层出不穷,它们采用不同的预训练目标在不同的数据集上进行训练,但是依然可以按模型结构将它们大致分为三类:

  • 纯 Encoder 模型(例如 BERT),又称自编码 (auto-encoding) Transformer 模型;
  • 纯 Decoder 模型(例如 GPT),又称自回归 (auto-regressive) Transformer 模型;
  • Encoder-Decoder 模型(例如 BART、T5),又称 Seq2Seq (sequence-to-sequence) Transformer 模型。

特点

  • 自注意力机制(Self-Attention):这是Transformer的核心概念之一,它使模型能够同时考虑输入序列中的所有位置,而不是像循环神经网络(RNN)或卷积神经网络(CNN)一样逐步处理。自注意力机制允许模型根据输入序列中的不同部分来赋予不同的注意权重,从而更好地捕捉语义关系。
  • 多头注意力(Multi-Head Attention):Transformer中的自注意力机制被扩展为多个注意力头,每个头可以学习不同的注意权重,以更好地捕捉不同类型的关系。多头注意力允许模型并行处理不同的信息子空间。
  • 堆叠层(Stacked Layers):Transformer通常由多个相同的编码器和解码器层堆叠而成。这些堆叠的层有助于模型学习复杂的特征表示和语义。
  • 位置编码(Positional Encoding):由于Transformer没有内置的序列位置信息,它需要额外的位置编码来表达输入序列中单词的位置顺序。
  • 残差连接和层归一化(Residual Connections and Layer Normalization):这些技术有助于减轻训练过程中的梯度消失和爆炸问题,使模型更容易训练。
  • 编码器和解码器:Transformer通常包括一个编码器用于处理输入序列和一个解码器用于生成输出序列,这使其适用于序列到序列的任务,如机器翻译。

注意力

当人类的视觉机制察觉到一个物体时,通常不会从头到尾地扫视整个场景;一般会根据个人的需求集中关注特定的部分。

比如下面这张图,我们第一眼应该是看到一只动物,然后,眼睛会先注意到动物的脸,然后得出初步结论,这应该是一只狼;就像右边注意力图所示,颜色更深的部分表示一般是我们人类最先看见(注意)的。

注意力最早应用在机器视觉领域(CV,Computer Vision),后来才应用到NLP和LLM领域。

在Transformer架构中,有3种不同的注意力层:

  • 编码器中的全局自注意力层(Global self attention layer)
  • 解码器中的交叉注意力层(Cross attention layer)
  • 解码器中的因果自注意力层(Causal attention layer)

注意力机制基础

注意力机制的数学表示如下:
$$
Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V
$$
其中,Q,K和V分别指的是查询(Query),键(Key)以及值(Value)矩阵。

简单来说,查询矩阵Q里的数据代表了我们关注的词,键矩阵K里的数据用来帮我们计算这些词之间的相似度(即注意力分数:attention score,向量点乘可以计算相似度),而值矩阵V里的数据则用来根据这些相似度计算出最终的输出结果

为了确保计算过程中的数据不会因为维度(即键的大小)太大而爆炸,或者太小而消失,注意力分数会通过键的维度的平方根来进行调整;接着,通过softmax函数把这些分数转化成权重,最后这些权重会和值矩阵相乘,得到最后的输出(注意力向量)。

理解Q、K、V

注意力机制中有两个输入:

  • 查询序列(Q):正在处理的序列(在底部)。
  • 上下文序列(K,V):被关注的序列(在左侧)。

输出序列的维度与查询序列相同。

这个操作常常被比作字典查找,但是,是一个模糊的,可微分的,向量化的字典查找。

举个例子,假设有一个普通的Python字典,有 3 个键和 3 个值,被传递了一个单独的查询:

d = {'color': 'blue', 'age': 22, 'type': 'pickup'}
result = d['color']

这里,查询(Q)是你要找的内容,键(K)表示字典里有什么样的信息,而值(V)则是对应的信息;在普通的字典查找中,字典会找到匹配的键,并返回其对应的值;如果查询找不到完全匹配的键,也许你会期望返回最接近的值,比如在上面的例子中,如果你查找 d["species"],你可能会期望返回 “pickup”,因为它是最接近查询的匹配

一个注意力层就像是这样的一个模糊查找,但它不仅仅是寻找最佳键;它结合了查询(Q)和键(K)向量,来确定它们匹配的程度,也就是“注意力分数”。然后,根据“注意力分数”对所有值进行加权平均;在注意力层中,每个位置的查询(Q)序列都提供一个查询向量,而上下文序列则充当了一个字典,每个位置提供一个键和值向量;在使用这些向量之前,注意力层会用一个全连接层对输入向量进行投影。

编码器 Encoder

输入部分 Embedding

为了能够把文本数据或音频数据输入进Transformer处理,我们必须先通过Embedding将其转换成编码标识,使其成为计算机能够处理的数字。

在理解Embedding层之前,我们需要关注于文本数据的特点,举例:“我爱北京天安门”,我们在做文本数据处理的时候,传统的汉字是不能给计算机做运算的,为了解决汉字运算的问题,提出了将汉字进行编码(或叫文本张量表示)的思想。目前主流的编码方式one-hot编码及word Embedding。下面就两种编码进行介绍,其中穿插关于word2vec的理解。

one-hot 编码

该编码格式较为傻瓜式,就是将词库中所有的单词,从[0,max_len-1]的进行编号,使用哪个词对应的编号位置部分置1,其余部分置0。举例说明:如果整个词库为“我爱北京天安门”这七个字,依次对其进行编号,便会得到如下的表示:

我:1000 000 爱:0100 000 北:0010 000 京:0001 000 天:0000 100 安:0000 010 门:0000 001

word2vec 编码

word2vecword to vec文本推导张量,它存在两个模式,一个是 CBOW,一个是 skip-gram,其中 CBOW(continuous bag of words,连续词袋模型) 类似于我们在英文考试中的完形填空,即根据上下文推导中间的单词。而 skip-gram(跳字模型) 与之相反,通过某个单词,推导上下文,其中 Skip-gram 的计算复杂度是比 CBOW 的复杂度要大的,如下左图是 CBOW 的工作模式,右图是 Skip-gram 的工作方式。(具体区别请看:word2vec原理(一): 词向量、CBOW与Skip-Gram模型基础-CSDN博客

自注意力 Self-Attention

随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。在处理过程中,自注意力机制会将对所有相关单词的理解融入到我们正在处理的单词中。更具体的功能如下:

  • 序列建模:自注意力可以用于序列数据(例如文本、时间序列、音频等)的建模。它可以捕捉序列中不同位置的依赖关系,从而更好地理解上下文。这对于机器翻译、文本生成、情感分析等任务非常有用。
  • 并行计算:自注意力可以并行计算,这意味着可以有效地在现代硬件上进行加速。相比于RNN和CNN等序列模型,它更容易在GPU和TPU等硬件上进行高效的训练和推理。(因为在自注意力中可以并行的计算得分)
  • 长距离依赖捕捉:传统的循环神经网络(RNN)在处理长序列时可能面临梯度消失或梯度爆炸的问题。自注意力可以更好地处理长距离依赖关系,因为它不需要按顺序处理输入序列。

自注意力结构如下:

自注意力的计算

第一步,从每个编码器的输入向量中生成三个向量,即查询向量、键向量和一个值向量。这三个向量是通过词嵌入与三个权重矩阵相乘后创建出来的,即:
$$
W^Q, W^K, W^V
$$
新向量在维度上往往比词嵌入向量更低。

第二步,计算得分,假设我们在为这个例子中的第一个词 “Thinking” 计算自注意力向量,我们需要拿输入句子中的每个单词对 “Thinking” 打分。这些分数是通过所有输入句子的单词的键向量与 “Thinking” 的查询向量相点积来计算的。

第三步和第四步是将分数除以 8(8 是论文中使用的键向量的维数 64 的平方根,这会让梯度更稳定。这里也可以使用其它值,8 只是默认值,这样做是为了防止内积过大),然后通过softmax传递结果。随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。softmax 的作用是使所有单词的分数归一化,得到的分数都是正值且和为1。

这个 softmax 分数决定了每个单词对编码当下位置(“Thinking”)的贡献。显然,已经在这个位置上的单词将获得最高的softmax 分数。

第五步是将每个值向量乘以 softmax 分数(这是为了准备之后将它们求和)。这里的直觉是希望关注语义上相关的单词,并弱化不相关的单词(例如,让它们乘以0.001这样的小数)。

第六步是对加权值向量求和,然后即得到自注意力层在该位置的输出。

最终得到了自注意力,并将得到的向量传递给前馈神经网络。以上二到六步合为一个公式:
$$
Attention(Q,K,V)=softmax(\frac{Q \cdot K^T}{\sqrt{d_k}})\cdot V
$$

多头注意力 Multi-head Attention

多头即有多个查询/键/值权重矩阵集合,(Transformer使用八个注意力头)并且每一个都是随机初始化的。把同一个句子利用多组不同的Q、K、V权重矩阵相乘,最后把得到的 8 个 Z0~Z7 对位相加(或者拼接起来再乘一个权重矩阵 W0 可以恢复到原来 embedding_size 的大小维度)得到最终的Z,这样可以捕捉到更多的特征信息。

Multi-head Attention 的本质是,在参数总量保持不变的情况下,将同样的 Query,Key,Value 映射到原来的高维空间的不同子空间中进行 Attention 的计算,在最后一步再合并不同子空间中的 Attention 信息。这样降低了计算每个 head 的 Attention 时每个向量的维度,在某种意义上防止了过拟合;由于 Attention 在不同子空间中有不同的分布,Multi-head Attention 实际上是寻找了序列之间不同角度的关联关系,并在最后拼接这一步骤中,将不同子空间中捕获到的关联关系再综合起来。也可以类比CNN中同时使用多个卷积核的作用,直观上讲,多头的注意力有助于网络捕捉到更丰富的特征/信息

Add & Normalize

在经过多头注意力机制得到矩阵 Z 之后,并没有直接传入全连接神经网络,而是经过了一步 Add & Normalize,计算公式如下:
$$
LayerNorm(X+MultiHeadAttention(X))
$$
其中 X 表示 Multi-Head Attention 或者 Feed Forward 的输入,MultiHeadAttention(X) 和 FeedForward(X) 表示输出(输出与输入 X 维度是一样的,所以可以相加)。

Add

Add,就是在 Z 的基础上加了一个残差块 X,加入残差块的目的是为了防止在深度神经网络的训练过程中发生退化的问题,退化的意思就是深度神经网络通过增加网络的层数,Loss逐渐减小,然后趋于稳定达到饱和,然后再继续增加网络层数,Loss反而增大。

Normalize

使用到的归一化方法是 Layer Normalization(层归一化),Layer Normalization 的作用是把神经网络中隐藏层归一为标准正态分布,以起到加快训练速度,加速收敛的作用,也有利于模型更好的训练。

优势:

  • Layer Normalization 是每个样本内部做标准化,跟 size 没关系,不受其影响。
  • RNN 中 LN 也不受影响,内部自己做标准化,所以 LN 的应用面更广。

和 BN(Batch Normalization,批归一化)的区别是:

LN 是在同一个样本中不同神经元之间进行归一化,而 BN 是在同一个 batch 中不同样本之间的同一位置的神经元之间进行归一化。BN求标准化的均值和方差与该批次所有的向量有关(比如计算第一个位置的均值和标准差,那么要用到该批次所有向量第一位置的值),LN求标准化的均值和方差只与自己的向量有关(用一个向量所有位置的值来求均值方差)。从下图也可知,BN 是横向的,LN 是纵向的。二者都是有利于模型的收敛,但是不同场景用的方法也不同。

那为什么Transformer用的是Layer Normalization?

NLP 的文本本质上可以看成一个时间序列,而时间序列是不定长的,长度不同的序列原则上属于不同的统计对象,所以很难得到稳定的统计量,而得不到稳定的统计量,BN就无法成立了(因为BN依靠滑动平均来获得一组预测用的统计量),也就是横向求解均值和方差的时候,有些向量上可能因为句长较短而导致后面的部分没有值可计算,因而效果不好。

前馈神经网络 FFN (Feed Forward Network)

位置前馈网络就是一个全连接前馈网络,每个位置的词都单独经过这个完全相同的前馈神经网络,具体是先线性变换,然后ReLU非线性,再线性变换,目的是将输入的 Z 映射到更加高维的空间中然后通过非线性函数 ReLU 进行筛选,筛选完后再变回原来的维度。

解码器 Decoder

解码器与编码器不同之处在于,多了一层 Masked Multi-Head Self-Attention;Multi-Head Attention的 K、V 从编码器传入。Q K V的来源有所不同。因此也叫Cross attetion 交叉注意力

Masked Multi-Head Attention

与编码器的 Multi-Head Attention 计算原理一样,只是多加了一个 mask。mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。其中,Padding Mask 在所有的 scaled dot-product attention 里面都需要用到,而 Sequence Mask 只有在解码器的 Self-Attention 里面用到。为什么需要添加这两种 mask 码呢?

  • Padding Mask
      什么是 Padding mask 呢?因为每个批次输入序列的长度是不一样的,所以我们要对输入序列进行对齐。具体来说,就是在较短的序列后面填充 0(但是如果输入的序列太长,则是截断,把多余的直接舍弃)。因为这些填充的位置,其实是没有什么意义的,所以我们的 Attention 机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。
      具体的做法:把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 Softmax 后,这些位置的概率就会接近 0
  • Sequence Mask
     Sequence Mask 是为了使得 Decoder 不能看见未来的信息。也就是对于一个序列,在 t 时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因为我们需要想一个办法,把 t 之后的信息给隐藏起来。
      具体的做法:产生一个上三角矩阵,上三角的值全为 -∞。把这个矩阵作用在每个序列上,就可以达到我们的目的。

举个例子,当我们输入”I”时,模型目前仅知道包括”I”在内之前所有字的信息,即””和”I”的信息,不应该让其知道”I”之后词的信息。道理很简单,我们做预测的时候是按照顺序一个字一个字的预测,怎么能这个字都没预测完,就已经知道后面字的信息了呢?Mask 非常简单,首先生成一个下三角全0,上三角全为负无穷的矩阵,然后将其与Scaled Scores相加即可。

参考链接

Hello! · Transformers快速入门

史上最详细Transformer讲解以及transformer实现中文版完形填空(掩蔽字训练MASK) 内容详细易懂且附有全部代码_transformer mask-CSDN博客

【超详细】【原理篇&实战篇】一文读懂Transformer-CSDN博客

第四篇:一文搞懂Transformer架构的三种注意力机制 - 知乎 (zhihu.com)