目前,AIGC(AI-Generated Content,人工智能生产内容)发展迅猛,选代速度呈现指数级增长,全球范围内经济价值预计将达到数万亿美元。在中国市场,AIGC的应用规模有望在2025年突破2000亿元,这一巨大的潜力吸引着业内领军企业竞相推出千亿、万亿级参数量的大模型,底层GPU算力部署规模也达到万卡级别。以GPT3.5为例,参数规模达1750亿,作为训练数据集的互联网文本量也超过45TB,其训练过程依赖于微软专门建设的AI超算系统,以及由1万颗V100GPU组成的高性能网络集群,总计算力消耗约为3640PF-days(即每秒一千万亿次计算,运行3640天)。
分布式并行计算是实现AI大模型训练的关键手段,通常包含数据并行、流水线并行及张量并行等多种并行计算模式。所有并行模式均需要多个计算设备间进行多次集合通信操作。另外,训练过程中通常采用同步模式,多机多卡间完成集合通信操作后才可进行训练的下一轮迭代或计算。
Transformer 是 Google 的团队在 2017 年提出的一种 NLP 经典模型,现在比较火热的 Bert 也是基于 Transformer。Transformer 模型使用了 Self-Attention 机制,不采用 RNN 的顺序结构,使得模型可以并行化训练,而且能够拥有全局信息。
Transformer模型实在论文《Attention Is All You Need》里面提出来的,用来生成文本的上下文编码,传统的上下问编码大多数是由RNN来完成的,不过,RNN存在两个缺点:
a、计算是顺序进行的,无法并行化,例如:对于一个有10个单词的文本序列,如果我们要得到最后一个单词的处理结果,就必须要先计算前面9个单词的处理结果。
b、RNN是顺序计算,存在信息的衰减,所以很难处理相隔比较远的两个单词之间的信息,因此,RNN通常和attention相结合使用。
针对RNN的缺陷,《Attention Is All You Need》提出了Transformer模型解决这个问题。Transformer由多头注意力、位置编码、层归一化和位置前向神经网络等部分构成。
Transormer和seq2seq模型一样,由Encoder和Decoder两大部分组成,其中左侧的是Encoder,右侧的是Decoder。模型主要由多头注意力和前馈神经网络组成。
这里有个关键的点--位置编码。使用RNN的进行处理的时候,每个输入天然存在位置属性,但这也是RNN的弊端之一。文本单词的排列与文本的语义有很大的关联,所以文本的位置是一个很重要的特征,因此,在Transformer模型里面,加入了位置编码来保留单词的位置信息。
编码部分:Encoder
a、多头注意力
多头注意力是Transformer模型的重要组成部分,通过下面的图,我们来看看多头注意力的结构。
多头注意力是self-attention(自注意力)的拓展,对与self-attention不熟悉,可以参考self-attention详解 ,相对于self-attention,多头注意力再两个方面有所提高:
扩展了模型在文本序列不同位置的注意力能力。相对于self-attention,self-attention的最终输出中,包含了其他词的很少信息,其注意力权重主要由词语本身即query占主导位置。
赋予attention多种子表达方式。使用多头注意力机制,我们会有多组的Q、K、V参数矩阵(Transformer使用了8个heads,所以会有8组参数矩阵)。
1. Transformer 结构
首先介绍 Transformer 的整体结构,下图是 Transformer 用于中英文翻译的整体结构。
Transformer 整体结构
可以看到 Transformer 由 Encoder 和 Decoder 两个部分组成,Encoder 和 Decoder 都包含 6 个 block。Transformer 的工作流程大体如下:
第一步:获取输入句子的每一个单词的表示向量 X,X由单词的 Embedding 和单词位置的 Embedding 相加得到。
Transformer 的输入表示
第二步:将得到的单词表示向量矩阵 (如上图所示,每一行是一个单词的表示 x) 传入 Encoder 中,经过 6 个 Encoder block 后可以得到句子所有单词的编码信息矩阵 C,如下图。单词向量矩阵用 X(n×d)表示, n 是句子中单词个数,d 是表示向量的维度 (论文中 d=512)。每一个 Encoder block 输出的矩阵维度与输入完全一致。
Transformer Encoder 编码句子信息
第三步:将 Encoder 输出的编码信息矩阵 C传递到 Decoder 中,Decoder 依次会根据当前翻译过的单词 1~ i 翻译下一个单词 i+1,如下图所示。在使用的过程中,翻译到单词 i+1 的时候需要通过 Mask (掩盖) 操作遮盖住 i+1 之后的单词。
Transofrmer Decoder 预测
上图 Decoder 接收了 Encoder 的编码矩阵 C,然后首先输入一个翻译开始符 "",预测第一个单词 "I";然后输入翻译开始符 "" 和单词 "I",预测单词 "have",以此类推。这是 Transformer 使用时候的大致流程,接下来是里面各个部分的细节。
2. Transformer 的输入
Transformer 中单词的输入表示 x由单词 Embedding 和位置 Embedding 相加得到。
Transformer 的输入表示
2.1 单词 Embedding
单词的 Embedding 有很多种方式可以获取,例如可以采用 Word2Vec、Glove 等算法预训练得到,也可以在 Transformer 中训练得到。
2.2 位置 Embedding
Transformer 中除了单词的 Embedding,还需要使用位置 Embedding 表示单词出现在句子中的位置。因为 Transformer 不采用 RNN 的结构,而是使用全局信息,不能利用单词的顺序信息,而这部分信息对于 NLP 来说非常重要。所以 Transformer 中使用位置 Embedding 保存单词在序列中的相对或绝对位置。
位置 Embedding 用 PE表示,PE 的维度与单词 Embedding 是一样的。PE 可以通过训练得到,也可以使用某种公式计算得到。在 Transformer 中采用了后者,计算公式如下:
其中,pos 表示单词在句子中的位置,d 表示 PE的维度 (与词 Embedding 一样),2i 表示偶数的维度,2i+1 表示奇数维度 (即 2i≤d, 2i+1≤d)。使用这种公式计算 PE 有以下的好处:
使 PE 能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20 个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以计算出第 21 位的 Embedding。可以让模型容易地计算出相对位置,对于固定长度的间距 k,PE(pos+k) 可以用 PE(pos) 计算得到。因为 Sin(A+B) = Sin(A)Cos(B) + Cos(A)Sin(B), Cos(A+B) = Cos(A)Cos(B) - Sin(A)Sin(B)。将单词的词 Embedding 和位置 Embedding 相加,就可以得到单词的表示向量 x,x 就是 Transformer 的输入。
3. Self-Attention
Transformer Encoder 和 Decoder
上图是论文中 Transformer 的内部结构图,左侧为 Encoder block,右侧为 Decoder block。红色圈中的部分为 Multi-Head Attention,是由多个 Self-Attention组成的,可以看到 Encoder block 包含一个 Multi-Head Attention,而 Decoder block 包含两个 Multi-Head Attention (其中有一个用到 Masked)。Multi-Head Attention 上方还包括一个 Add & Norm 层,Add 表示残差连接 (Residual Connection) 用于防止网络退化,Norm 表示 Layer Normalization,用于对每一层的激活值进行归一化。
因为 Self-Attention是 Transformer 的重点,所以我们重点关注 Multi-Head Attention 以及 Self-Attention,首先详细了解一下 Self-Attention 的内部逻辑。
3.1 Self-Attention 结构
Self-Attention 结构
上图是 Self-Attention 的结构,在计算的时候需要用到矩阵 Q(查询), K(键值), V(值)。在实际中,Self-Attention 接收的是输入(单词的表示向量 x组成的矩阵 X) 或者上一个 Encoder block 的输出。而 Q, K, V 正是通过 Self-Attention 的输入进行线性变换得到的。
3.2 Q, K, V 的计算
Self-Attention 的输入用矩阵 X进行表示,则可以使用线性变阵矩阵 WQ, WK, WV 计算得到 Q, K, V。计算如下图所示,注意 X, Q, K, V 的每一行都表示一个单词。
Q, K, V 的计算
3.3 Self-Attention 的输出
得到矩阵 Q, K, V之后就可以计算出 Self-Attention 的输出了,计算的公式如下。
Self-Attention 的输出
公式中计算矩阵 Q和 K 每一行向量的内积,为了防止内积过大,因此除以 dk 的平方根。Q 乘以 K 的转置后,得到的矩阵行列数都为 n,n 为句子单词数,这个矩阵可以表示单词之间的 attention 强度。下图为 Q 乘以 K 的转置,1234 表示的是句子中的单词。
QKT 的计算
得到 QKT 之后,使用 Softmax 计算每一个单词对于其他单词的 attention 系数,公式中的 Softmax 是对矩阵的每一行进行 Softmax,即每一行的和都变为 1。
对矩阵的每一行进行 Softmax
得到 Softmax 矩阵之后可以和 V相乘,得到最终的输出 Z。
Self-Attention 输出
上图中 Softmax 矩阵的第 1 行表示单词 1 与其他所有单词的 attention 系数,最终单词 1 的输出 Z1 等于所有单词 i 的值 Vi 根据 attention 系数的比例加在一起得到,如下图所示:
Zi 的计算方法
3.4 Multi-Head Attention
在上一步,我们已经知道怎么通过 Self-Attention 计算得到输出矩阵 Z,而 Multi-Head Attention 是由多个 Self-Attention 组合形成的,下图是论文中 Multi-Head Attention 的结构图。
Multi-Head Attention
从上图可以看到 Multi-Head Attention 包含多个 Self-Attention 层,首先将输入 X分别传递到 h 个不同的 Self-Attention 中,计算得到 h 个输出矩阵 Z。下图是 h=8 时候的情况,此时会得到 8 个输出矩阵 Z。
多个 Self-Attention
得到 8 个输出矩阵 Z1 到 Z8 之后,Multi-Head Attention 将它们拼接在一起 (Concat),然后传入一个 Linear层,得到 Multi-Head Attention 最终的输出 Z。
Multi-Head Attention 的输出
可以看到 Multi-Head Attention 输出的矩阵 Z与其输入的矩阵 X 的维度是一样的。
4. Encoder 结构
Transformer Encoder block
上图红色部分是 Transformer 的 Encoder block 结构,可以看到是由 Multi-Head Attention, Add & Norm, Feed Forward, Add & Norm 组成的。刚刚已经了解了 Multi-Head Attention 的计算过程,现在了解一下 Add & Norm 和 Feed Forward 部分。
4.1 Add & Norm
Add & Norm 层由 Add 和 Norm 两部分组成,其计算公式如下:
Add & Norm 公式
其中 X表示 Multi-Head Attention 或者 Feed Forward 的输入,MultiHeadAttention(X) 和 FeedForward(X) 表示输出 (输出与输入 X 维度是一样的,所以可以相加)。
Add指 X+MultiHeadAttention(X),是一种残差连接,通常用于解决多层网络训练的问题,可以让网络只关注当前差异的部分,在 ResNet 中经常用到。
残差连接
Norm指 Layer Normalization,通常用于 RNN 结构,Layer Normalization 会将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛。
4.2 Feed Forward
Feed Forward 层比较简单,是一个两层的全连接层,第一层的激活函数为 Relu,第二层不使用激活函数,对应的公式如下。
Feed Forward
X是输入,Feed Forward 最终得到的输出矩阵的维度与 X 一致。
4.3 组成 Encoder
通过上面描述的 Multi-Head Attention, Feed Forward, Add & Norm 就可以构造出一个 Encoder block,Encoder block 接收输入矩阵 X(n×d),并输出一个矩阵 O(n×d)。通过多个 Encoder block 叠加就可以组成 Encoder。
第一个 Encoder block 的输入为句子单词的表示向量矩阵,后续 Encoder block 的输入是前一个 Encoder block 的输出,最后一个 Encoder block 输出的矩阵就是 编码信息矩阵 C,这一矩阵后续会用到 Decoder 中。
Encoder 编码句子信息
5. Decoder 结构
Transformer Decoder block
上图红色部分为 Transformer 的 Decoder block 结构,与 Encoder block 相似,但是存在一些区别:
包含两个 Multi-Head Attention 层。第一个 Multi-Head Attention 层采用了 Masked 操作。第二个 Multi-Head Attention 层的 K, V 矩阵使用 Encoder 的编码信息矩阵 C 进行计算,而 Q 使用上一个 Decoder block 的输出计算。最后有一个 Softmax 层计算下一个翻译单词的概率。5.1 第一个 Multi-Head Attention
Decoder block 的第一个 Multi-Head Attention 采用了 Masked 操作,因为在翻译的过程中是顺序翻译的,即翻译完第 i 个单词,才可以翻译第 i+1 个单词。通过 Masked 操作可以防止第 i 个单词知道 i+1 个单词之后的信息。下面以 "我有一只猫" 翻译成 "I have a cat" 为例,了解一下 Masked 操作。
下面的描述中使用了类似 Teacher Forcing 的概念,不熟悉 Teacher Forcing 的童鞋可以参考以下上一篇文章Seq2Seq 模型详解。在 Decoder 的时候,是需要根据之前的翻译,求解当前最有可能的翻译,如下图所示。首先根据输入 "" 预测出第一个单词为 "I",然后根据输入 "I" 预测下一个单词 "have"。
Decoder 预测
Decoder 可以在训练的过程中使用 Teacher Forcing 并且并行化训练,即将正确的单词序列 (I have a cat) 和对应输出 (I have a cat) 传递到 Decoder。那么在预测第 i 个输出时,就要将第 i+1 之后的单词掩盖住,注意 Mask 操作是在 Self-Attention 的 Softmax 之前使用的,下面用 0 1 2 3 4 5 分别表示 "I have a cat"。
第一步:是 Decoder 的输入矩阵和 Mask 矩阵,输入矩阵包含 "I have a cat" (0, 1, 2, 3, 4) 五个单词的表示向量,Mask 是一个 5×5 的矩阵。在 Mask 可以发现单词 0 只能使用单词 0 的信息,而单词 1 可以使用单词 0, 1 的信息,即只能使用之前的信息。
输入矩阵与 Mask 矩阵
第二步:接下来的操作和之前的 Self-Attention 一样,通过输入矩阵 X计算得到 Q, K, V 矩阵。然后计算 Q 和 KT 的乘积 QKT。
QKT
第三步:在得到 QKT 之后需要进行 Softmax,计算 attention score,我们在 Softmax 之前需要使用 Mask矩阵遮挡住每一个单词之后的信息,遮挡操作如下:
Softmax 之前 Mask
得到 Mask QKT 之后在 Mask QKT 上进行 Softmax,每一行的和都为 1。但是单词 0 在单词 1, 2, 3, 4 上的 attention score 都为 0。
第四步:使用 Mask QKT 与矩阵 V相乘,得到输出 Z,则单词 1 的输出向量 Z1 是只包含单词 1 信息的。
Mask 之后的输出
第五步:通过上述步骤就可以得到一个 Mask Self-Attention 的输出矩阵 Zi,然后和 Encoder 类似,通过 Multi-Head Attention 拼接多个输出 Zi 然后计算得到第一个 Multi-Head Attention 的输出 Z,Z与输入 X 维度一样。
5.2 第二个 Multi-Head Attention
Decoder block 第二个 Multi-Head Attention 变化不大, 主要的区别在于其中 Self-Attention 的 K, V矩阵不是使用 上一个 Decoder block 的输出计算的,而是使用 Encoder 的编码信息矩阵 C 计算的。
根据 Encoder 的输出 C计算得到 K, V,根据上一个 Decoder block 的输出 Z 计算 Q (如果是第一个 Decoder block 则使用输入矩阵 X 进行计算),后续的计算方法与之前描述的一致。
这样做的好处是在 Decoder 的时候,每一位单词都可以利用到 Encoder 所有单词的信息 (这些信息无需 Mask)。
5.3 Softmax 预测输出单词
Decoder block 最后的部分是利用 Softmax 预测下一个单词,在之前的网络层我们可以得到一个最终的输出 Z,因为 Mask 的存在,使得单词 0 的输出 Z0 只包含单词 0 的信息,如下。
Decoder Softmax 之前的 Z
Softmax 根据输出矩阵的每一行预测下一个单词
Decoder Softmax 预测
这就是 Decoder block 的定义,与 Encoder 一样,Decoder 是由多个 Decoder block 组合而成。
6. Transformer 总结
Transformer 与 RNN 不同,可以比较好地并行训练。
Transformer 本身是不能利用单词的顺序信息的,因此需要在输入中添加位置 Embedding,否则 Transformer 就是一个词袋模型了。
Transformer 的重点是 Self-Attention 结构,其中用到的 Q, K, V矩阵通过输出进行线性变换得到。
Transformer 中 Multi-Head Attention 中有多个 Self-Attention,可以捕获单词之间多种维度上的相关系数 attention score。
参考文献
论文:Attention Is All You NeedJay Alammar 博客:The Illustrated Transformerpytorch transformer 代码:The Annotated Transformer
Attention是如何发挥作用的,其中的参数的含义和作用是什么,反向传播算法如何更新其中参数,又是如何影响其他参数的更新的?
为什么要用scaled attention?
Multi-head attention相比single head attention为什么更加work,其本质上做了一件什么事?从反向传播算法的角度分析?
Positional encoding是如何发挥作用的,应用反向传播算法时是如何影响到其他参数的更新的?同样的理论可以延伸到其他additional embedding,比如多语言模型中的language embedding
每个encoder/decoder layer中feed-forward部分的作用,并且从反向传播算法角度分析?
decoder中mask后反向传播算法过程细节,如何保证training和inference的一致性?
如果不一致(decoder不用mask)会怎么样?
1. Attention的背景溯源
想要深度理解Attention机制,就需要了解一下它产生的背景、在哪类问题下产生,以及最初是为了解决什么问题而产生。
首先回顾一下机器翻译领域的模型演进历史:
机器翻译是从RNN开始跨入神经网络机器翻译时代的,几个比较重要的阶段分别是: Simple RNN, Contextualize RNN,Contextualized RNN with attention, Transformer(2017),下面来一一介绍。
「Simple RNN」 :这个encoder-decoder模型结构中,encoder将整个源端序列(不论长度)压缩成一个向量(encoder output),源端信息和decoder之间唯一的联系只是: encoder output会作为decoder的initial states的输入。这样带来一个显而易见的问题就是,随着decoder长度的增加,encoder output的信息会衰减。
Simple RNN(without context)
这种模型有2个主要的问题:
源端序列不论长短,都被统一压缩成一个固定维度的向量,并且显而易见的是这个向量中包含的信息中,关于源端序列末尾的token的信息更多,而如果序列很长,最终可能基本上“遗忘”了序列开头的token的信息。
第二个问题同样由RNN的特性造成: 随着decoder timestep的信息的增加,initial hidden states中包含的encoder output相关信息也会衰减,decoder会逐渐“遗忘”源端序列的信息,而更多地关注目标序列中在该timestep之前的token的信息。
「Contextualized RNN」 :为了解决上述第二个问题,即encoder output随着decoder timestep增加而信息衰减的问题,有人提出了一种加了context的RNN sequence to sequence模型:decoder在每个timestep的input上都会加上一个context。为了方便理解,我们可以把这看作是encoded source sentence。这样就可以在decoder的每一步,都把源端的整个句子的信息和target端当前的token一起输入到RNN中,防止源端的context信息随着timestep的增长而衰减。
Contextualized RNN
但是这样依然有一个问题: context对于每个timestep都是静态的(encoder端的final hiddenstates,或者是所有timestep的output的平均值)。但是每个decoder端的token在解码时用到的context真的应该是一样的吗?在这样的背景下,Attention就应运而生了:
「Contextualized RNN with soft align (Attention)」 : Attention在机器翻译领域的应用最早的提出来自于2014年的一篇论文 Neural Machine Translation by Jointly Learning to Align and Translate
Contextualized RNN with Attention
在每个timestep输入到decoder RNN结构中之前,会用当前的输入token的vector与encoderoutput中的每一个position的vector作一个"attention"操作,这个"attention"操作的目的就是计算当前token与每个position之间的"相关度",从而决定每个position的vector在最终该timestep的context中占的比重有多少。最终的context即encoderoutput每个位置vector表达的 「加权平均」 。
context的计算公式
2. Attention的细节
2.1. 点积attention
我们来介绍一下attention的具体计算方式。attention可以有很多种计算方式:加性attention、点积attention,还有带参数的计算方式。着重介绍一下点积attention的公式:
Attention中(Q^T)*K矩阵计算,query和key的维度要保持一致
如上图所示, , 分别是query和key,其中,query可以看作M个维度为d的向量(长度为M的sequence的向量表达)拼接而成,key可以看作N个维度为d的向量(长度为N的sequence的向量表达)拼接而成。
【一个小问题】为什么有缩放因子 ?
先一句话回答这个问题: 缩放因子的作用是 「归一化」 。
假设 , 里的元素的均值为0,方差为1,那么 中元素的均值为0,方差为d. 当d变得很大时, 中的元素的方差也会变得很大,如果 中的元素方差很大,那么 的分布会趋于陡峭(分布的方差大,分布集中在绝对值大的区域)。总结一下就是 的分布会和d有关。因此 中每一个元素乘上 后,方差又变为1。这使得 的分布“陡峭”程度与d解耦,从而使得训练过程中梯度值保持稳定。
2.2. Attention机制涉及到的参数
一个完整的attention层涉及到的参数有:
把 , , 分别映射到 , , 的线性变换矩阵 ( ), ( ), ( )
把输出的表达 映射为最终输出 的线性变换矩阵 ( )
2.3. Query, Key, Value
Query和Key作用得到的attention权值作用到Value上。因此它们之间的关系是:
Query 和Key 的维度必须一致,Value 和Query/Key的维度可以不一致。
Key 和Value 的长度必须一致。Key和Value本质上对应了同一个Sequence在不同空间的表达。
Attention得到的Output 的维度和Value的维度一致,长度和Query一致。
Output每个位置 i 是由value的所有位置的vector加权平均之后的向量;而其权值是由位置为i 的query和key的所有位置经过attention计算得到的 ,权值的个数等于key/value的长度。
Attention示意图
在经典的Transformer结构中,我们记线性映射之前的Query, Key, Value为q, k, v,映射之后为Q, K, V。那么:
self-attention的q, k, v都是同一个输入, 即当前序列由上一层输出的高维表达。
cross-attention的q代表当前序列,k,v是同一个输入,对应的是encoder最后一层的输出结果(对decoder端的每一层来说,保持不变)
而每一层线性映射参数矩阵都是独立的,所以经过映射后的Q, K, V各不相同,模型参数优化的目标在于将q, k, v被映射到新的高维空间,使得每层的Q, K,V在不同抽象层面上捕获到q, k, v之间的关系。一般来说,底层layer捕获到的更多是lexical-level的关系,而高层layer捕获到的更多是semantic-level的关系。
2.4. Attention的作用
下面这段我会以机器翻译为例,用通俗的语言阐释一下attention的作用,以及query, key, value的含义。
Transformer模型Encoder, Decoder的细节图(省去了FFN部分)
query对应的是需要 「被表达」 的序列(称为序列A),key和value对应的是 「用来表达」A的序列(称为序列B)。其中key和query是在同一高维空间中的(否则无法用来计算相似程度),value不必在同一高维空间中,最终生成的output和value在同一高维空间中。上面这段巨绕的话用一句更绕的话来描述一下就是:
❝
序列A和序列B在高维空间 中的高维表达 的每个位置 _「分别」 _ 和 计算相似度,产生的权重作用于序列B在高维空间 中的高维表达 ,获得序列A在高维空间 中的高维表达
❞
Encoder部分中只存在self-attention,而Decoder部分中存在self-attention和cross-attention
【self-attention】encoder中的self-attention的query, key,value都对应了源端序列(即A和B是同一序列),decoder中的self-attention的query, key, value都对应了目标端序列。
【cross-attention】decoder中的cross-attention的query对应了目标端序列,key,value对应了源端序列(每一层中的cross-attention用的都是encoder的最终输出)
2.5. Decoder端的Mask
Transformer模型属于自回归模型(p.s.非自回归的翻译模型我会专门写一篇文章来介绍),也就是说后面的token的推断是基于前面的token的。Decoder端的Mask的功能是为了保证训练阶段和推理阶段的一致性。
论文原文中关于这一点的段落如下:
❝
We also modify the self-attention sub-layer in the decoder stack to preventfrom attending to subsequent positions. This masking, combined with the factthat the output embeddings are offset by one position, ensures that thepredictions for position i can depend only on the known outputs at positionsless than i.
❞
在推理阶段,token是按照从左往右的顺序推理的。也就是说,在推理timestep=T的token时,decoder只能“看到”timestep < T的T-1 个Token,不能和timestep大于它自身的token做attention(因为根本还不知道后面的token是什么)。为了保证训练时和推理时的一致性,所以,训练时要同样防止token与它之后的token去做attention。
2.6. 多头Attention (Multi-head Attention)
Attention是将query和key映射到同一高维空间中去计算相似度,而对应的multi-head attention把query和key映射到高维空间 的不同子空间
中去计算相似度。
为什么要做multi-head attention?论文原文里是这么说的:
❝
Multi-head attention allows the model to jointly attend to information fromdifferent representation subspaces at different positions. With a singleattention head, averaging inhibits this.
❞
也就是说,这样可以在不改变参数量的情况下增强每一层attention的表现力。
Multi-headAttention示意图
Multi-head Attention的本质是,在 「参数总量保持不变」 的情况下,将同样的query, key, value映射到原来的高维空间的「不同子空间」中进行attention的计算,在最后一步再合并不同子空间中的attention信息。这样降低了计算每个head的attention时每个向量的维度,在某种意义上防止了过拟合;由于Attention在不同子空间中有不同的分布,Multi-head Attention实际上是寻找了序列之间不同角度的关联关系,并在最后concat这一步骤中,将不同子空间中捕获到的关联关系再综合起来。
从上图可以看出, 和 之间的attentionscore从1个变成了h个,这就对应了h个子空间中它们的关联度。
3. Transformer模型架构中的其他部分
3.1. Feed Forward Network
每一层经过attention之后,还会有一个FFN,这个FFN的作用就是空间变换。FFN包含了2层lineartransformation层,中间的激活函数是ReLu。
曾经我在这里有一个百思不得其解的问题:attention层的output最后会和 相乘,为什么这里又要增加一个2层的FFN网络?
其实,FFN的加入引入了非线性(ReLu激活函数),变换了attention output的空间,从而增加了模型的表现能力。把FFN去掉模型也是可以用的,但是效果差了很多。
3.2. Positional Encoding
位置编码层只在encoder端和decoder端的embedding之后,第一个block之前出现,它非常重要,没有这部分,Transformer模型就无法用。位置编码是Transformer框架中特有的组成部分,补充了Attention机制本身不能捕捉位置信息的缺陷。
positionencoding
PositionalEmbedding的成分直接叠加于Embedding之上,使得每个token的位置信息和它的语义信息(embedding)充分融合,并被传递到后续所有经过复杂变换的序列表达中去。
论文中使用的PositionalEncoding(PE)是正余弦函数,位置(pos)越小,波长越长,每一个位置对应的PE都是唯一的。同时作者也提到,之所以选用正余弦函数作为PE,是因为这可以使得模型学习到token之间的相对位置关系:因为对于任意的偏移量k, 可以由 的线性表示:
上面两个公式可以由 和
的线性组合得到。也就是 乘上某个线性变换矩阵就得到了
p.s. 后续有一个工作在attention中使用了“相对位置表示” ( Self-Attention with Relative PositionRepresentations) ,有兴趣可以看看。
3.3. Layer Normalization
在每个block中,最后出现的是Layer Normalization。LayerNormalization是一个通用的技术,其本质是规范优化空间,加速收敛。
当我们使用梯度下降法做优化时,随着网络深度的增加,数据的分布会不断发生变化,假设feature只有二维,那么用示意图来表示一下就是:
数据的分布发生变化,左图比较规范,右图变得不规范
为了保证数据特征分布的稳定性(如左图),我们加入Layer Normalization,这样可以加速模型的优化速度。
机器学习——图解Transformer(完整版)
Transformer是一种基于注意力机制的序列模型,最初由Google的研究团队提出并应用于机器翻译任务。与传统的循环神经网络(RNN)和卷积神经网络(CNN)不同,Transformer仅使用自注意力机制(self-attention)来处理输入序列和输出序列,因此可以并行计算,极大地提高了计算效率。下面是Transformer的详细解释。
1. 自注意力机制
自注意力机制是Transformer的核心部分,它允许模型在处理序列时,将输入序列中的每个元素与其他元素进行比较,以便在不同上下文中正确地处理每个元素。
自注意力机制中有三个重要的输入矩阵:查询矩阵Q(query)、键矩阵K(key)和值矩阵V(value)。这三个矩阵都是由输入序列经过不同的线性变换得到的。然后,查询矩阵Q与键矩阵K的乘积经过一个softmax函数,得到一个与输入序列长度相同的概率分布,该分布表示每个元素对于查询矩阵Q的重要性。最后,将这个概率分布乘以值矩阵V得到自注意力向量,表示将每个元素的值加权平均后的结果。
2. 多头注意力机制
为了进一步提高模型的性能,Transformer引入了多头注意力机制(multi-head attention)。多头注意力机制通过将自注意力机制应用于多组不同的查询矩阵Q、键矩阵K和值矩阵V,从而学习到不同的上下文表示。具体来说,将输入序列分别通过不同的线性变换得到多组不同的查询矩阵Q、键矩阵K和值矩阵V,然后将它们输入到多个并行的自注意力机制中进行处理。
Transformer在自然语言处理中广泛应用,例如机器翻译、文本摘要、语言生成等领域。相比于传统的递归神经网络(RNN)和卷积神经网络(CNN),Transformer的并行计算能力更强,处理长序列的能力更强,且可以直接对整个序列进行处理。
Transformer模型由编码器(Encoder)和解码器(Decoder)两部分组成,下面将详细介绍每个部分的构成和作用。
1. 编码器(Encoder)
编码器将输入序列(例如一句话)转化为一系列上下文表示向量(Contextualized Embedding),它由多个相同的层组成。每一层都由两个子层组成,分别是自注意力层(Self-Attention Layer)和前馈全连接层(Feedforward Layer)。具体地,自注意力层将输入序列中的每个位置与所有其他位置进行交互,以计算出每个位置的上下文表示向量。前馈全连接层则将每个位置的上下文表示向量映射到另一个向量空间,以捕捉更高级别的特征。
2. 解码器(Decoder)
解码器将编码器的输出和目标序列(例如翻译后的句子)作为输入,生成目标序列中每个位置的概率分布。解码器由多个相同的层组成,每个层由三个子层组成,分别是自注意力层、编码器-解码器注意力层(Encoder-Decoder Attention Layer)和前馈全连接层。其中自注意力层和前馈全连接层的作用与编码器相同,而编码器-解码器注意力层则将解码器当前位置的输入与编码器的所有位置进行交互,以获得与目标序列有关的信息。
在Transformer中,自注意力机制是关键的组成部分。它可以将输入序列中的任何两个位置之间的关系建模,并且可以根据序列的内容自动学习不同位置之间的相互依赖关系。自注意力机制的计算包括三个步骤:计算查询向量(Query Vector)、键向量(Key Vector)和值向量(Value Vector),并将它们组合起来计算注意力分数,最后将注意力分数与值向量相乘得到自注意力向量。
总体来说,Transformer通过引入自注意力机制和多头注意力机制,使得神经网络能够更好地捕捉序列中的长程依赖关系,从而在自然语言处理等领域获得了巨大的成功。
Mask
mask表示掩码。即对某些值进行掩盖,不参与计算,不会对参数更新产生效果。Decoder计算注意力的时候,为了让decoder不能看到未来的信息,需要把未来的信息隐藏。例如在 time_step 为 t 的时刻,解码计算attention的时候应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此需要想一个办法,把 t 之后的信息给隐藏起来。这就是mask的作用。
具体的办法是在计算attention步骤中,在计算softmax之前,在这些位置加上一个非常打的负数(-INF),这样,经过softmax这些位置的概率会接近0。
Linear和softmax
Decoder最终输出的结果是一个浮点型数据的向量,我们要如何把这个向量转为一个单词呢?这个就是Linear和softmax要做的事情了。
Linear层是一个全连接的神经网络,输出神经元个数一般等于我们的词汇表大小。Decoder输出的结果会输入到Linear层,然后再用softmax进行转换,得到的是词汇表大小的向量,向量的每个值对应的是当前Decoder是对应的这个词的概率,我们只要取概率最大的词,就是当前词语Decoder的结果了。
transformer模型详解
一、transformer模型原理
Transformer模型是由谷歌公司提出的一种基于自注意力机制的神经网络模型,用于处理序列数据。相比于传统的循环神经网络模型,Transformer模型具有更好的并行性能和更短的训练时间,因此在自然语言处理领域中得到了广泛应用。
在自然语言处理中,序列数据的输入包括一系列文本、语音信号、图像或视频等。传统的循环神经网络(RNN)模型已经在这些任务中取得了很好的效果,但是该模型存在着两个主要问题:一是难以并行计算,二是难以捕捉长距离依赖关系。为了解决这些问题,Transformer模型应运而生。
作为一种基于自注意力机制的神经网络模型,Transformer模型能够对序列中的每个元素进行全局建模,并在各个元素之间建立联系。与循环神经网络模型相比,Transformer模型具有更好的并行性能和更短的训练时间。
Transformer模型中包含了多层encoder和decoder,每一层都由多个注意力机制模块和前馈神经网络模块组成。encoder用于将输入序列编码成一个高维特征向量表示,decoder则用于将该向量表示解码成目标序列。在Transformer模型中,还使用了残差连接和层归一化等技术来加速模型收敛和提高模型性能。
Transformer模型的核心是自注意力机制(Self-Attention Mechanism),其作用是为每个输入序列中的每个位置分配一个权重,然后将这些加权的位置向量作为输出。
自注意力机制的计算过程包括三个步骤:
计算注意力权重:计算每个位置与其他位置之间的注意力权重,即每个位置对其他位置的重要性。
计算加权和:将每个位置向量与注意力权重相乘,然后将它们相加,得到加权和向量。
线性变换:对加权和向量进行线性变换,得到最终的输出向量。
通过不断堆叠多个自注意力层和前馈神经网络层,可以构建出Transformer模型。
对于Transformer模型的训练,通常采用无监督的方式进行预训练,然后再进行有监督的微调。在预训练过程中,通常采用自编码器或者掩码语言模型等方式进行训练,目标是学习输入序列的表示。在微调过程中,通常采用有监督的方式进行训练,例如在机器翻译任务中,使用平行语料进行训练,目标是学习将输入序列映射到目标序列的映射关系。
二、Transformer模型的优缺点
Transformer模型的优缺点
更好的并行性能:Transformer模型能够在所有位置同时计算,从而充分利用GPU并行计算的优势,加速了模型的训练和推理过程。
能够处理长序列:传统的循环神经网络模型在处理长序列时容易出现梯度消失和梯度爆炸的问题,而Transformer模型使用了自注意力机制,能够同时考虑所有位置的信息,从而更好地处理长序列。
更好的性能表现:Transformer模型在自然语言处理领域中已经取得了很多重要的研究成果,比如在机器翻译、文本生成、语言模型等任务中都取得了很好的效果。
Transformer模型的缺点
对于小数据集,Transformer模型的表现可能会不如传统的循环神经网络模型,因为它需要更大的数据集来训练。
Transformer模型的计算复杂度较高,需要更多的计算资源,比如GPU等。
Transformer模型的可解释性不如传统的循环神经网络模型,因为它使用了自注意力机制,难以解释每个位置的重要性。
三、Transformer模型的代码示例
以下是使用PyTorch实现Transformer模型的代码示例:
import torch
import torch.nn as nn
import torch.nn.functional as F
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, n_heads):
super(MultiHeadAttention, self).__init__()
self.d_model = d_model
self.n_heads = n_heads
self.d_k = d_model // n_heads
self.d_v = d_model // n_heads
self.W_Q = nn.Linear(d_model, d_model)
self.W_K = nn.Linear(d_model, d_model)
self.W_V = nn.Linear(d_model, d_model)
self.W_O = nn.Linear(d_model, d_model)
def forward(self, Q, K, V, mask=None):
Q = self.W_Q(Q)
K = self.W_K(K)
V = self.W_V(V)
Q = self.split_heads(Q)
K = self.split_heads(K)
V = self.split_heads(V)
scores = torch.matmul(Q, K.transpose(-1, -2)) / torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn_weights = F.softmax(scores, dim=-1)
attn_output = torch.matmul(attn_weights, V)
attn_output = self.combine_heads(attn_output)
attn_output = self.W_O(attn_output)
return attn_output
def split_heads(self, x):
batch_size, seq_len, d_model = x.size()
x = x.view(batch_size, seq_len, self.n_heads, self.d_k)
return x.transpose(1, 2)
def combine_heads(self, x):
batch_size, n_heads, seq_len, d_v = x.size()
x = x.transpose(1, 2).contiguous()
x = x.view(batch_size, seq_len, n_heads * d_v)
return x
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super(PositionalEncoding, self).__init__()
self.d_model = d_model
self.dropout = nn.Dropout(p=0.1)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float32).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0)
self.register_buffer('pe', pe)
def forward(self, x):
x = x * math.sqrt(self.d_model)
x = x + self.pe[:, :x.size(1)]
x = self.dropout(x)
return x
class FeedForward(nn.Module):
def __init__(self, d_model, d_ff):
super(FeedForward, self).__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.linear2 = nn.Linear(d_ff, d_model)
def forward(self, x):
x = self.linear1(x)
x = F.relu(x)
x = self.linear2(x)
return x
class EncoderLayer(nn.Module):
def __init__(self, d_model, n_heads, d_ff):
super(EncoderLayer, self).__init__()
self.multi_head_attn = MultiHeadAttention(d_model, n_heads)
self.feed_forward = FeedForward(d_model, d_ff)
self.layer_norm1 = nn.LayerNorm(d_model)
self.layer_norm2 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(p=0.1)
self.dropout2 = nn.Dropout(p=0.1)
def forward(self, x, mask=None):
attn_output = self.multi_head_attn(x, x, x, mask=mask)
x = x + self.dropout1(attn_output)
x = self.layer_norm1(x)
ff_output = self.feed_forward(x)
x = x + self.dropout2(ff_output)
x = self.layer_norm2(x)
return x
class Encoder(nn.Module):
def __init__(self, input_size, d_model, n_heads, d_ff, n_layers):
super(Encoder, self).__init__()
self.embedding = nn.Embedding(input_size, d_model)
self.pos_encoding = PositionalEncoding(d_model)
self.layers = nn.ModuleList([EncoderLayer(d_model, n_heads, d_ff) for _ in range(n_layers)])
self.layer_norm = nn.LayerNorm(d_model)
def forward(self, x, mask=None):
x = self.embedding(x)
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, mask=mask)
x = self.layer_norm(x)
return x
class Transformer(nn.Module):
def __init__(self, input_size, output_size, d_model, n_heads, d_ff, n_layers):
super(Transformer, self).__init__()
self.encoder = Encoder(input_size, d_model, n_heads, d_ff, n_layers)
self.output_layer = nn.Linear(d_model, output_size)
def forward(self, x, mask=None):
x = self.encoder(x, mask)
x = x[:, 0, :]
x = self.output_layer(x)
return x
这段代码实现了一个基于Transformer模型的文本分类器。
四、Transformer模型应用领域
Transformer模型是一种基于注意力机制的神经网络架构,最初被提出用于自然语言处理任务中的序列到序列学习。随着时间的推移,Transformer模型被应用于各种不同的领域,如下所示:
(一) 自然语言处理
自然语言处理是指将人类语言转换为计算机可以理解的形式,以便计算机能够处理和理解语言。Transformer模型在自然语言处理领域有许多应用案例。以下是一些例子:
文本分类:Transformer模型可以对文本进行分类,例如将电子邮件分类为垃圾邮件或非垃圾邮件。在这种情况下,Transformer模型可以将文本作为输入,然后输出类别标签。
机器翻译:Transformer模型可以将一种语言的文本翻译成另一种语言的文本。在这种情况下,Transformer模型可以将源语言的文本作为输入,然后输出目标语言的文本。
命名实体识别:Transformer模型可以识别文本中的命名实体,例如人名、地名、组织名称等。在这种情况下,Transformer模型可以将文本作为输入,然后输出命名实体的类型和位置。
情感分析:Transformer模型可以对文本进行情感分析,例如判断一篇文章是积极的还是消极的。在这种情况下,Transformer模型可以将文本作为输入,然后输出情感极性。
(二) 语音识别
语音识别是指将人类语音转换为计算机可以理解的形式,以便计算机能够处理和理解语音。一些最新的研究表明,基于Transformer的语音识别系统已经取得了与传统的循环神经网络(RNN)和卷积神经网络(CNN)相媲美的性能。下面是一些Transformer模型在语音识别领域的应用案例:
语音识别:Transformer模型可以对语音信号进行识别,例如将语音转换为文本。在这种情况下,Transformer模型可以将语音信号作为输入,然后输出文本结果。
语音合成:Transformer模型可以将文本转换为语音信号。在这种情况下,Transformer模型可以将文本作为输入,然后输出语音信号。
说话人识别:Transformer模型可以识别不同说话者的语音信号。在这种情况下,Transformer模型可以将语音信号作为输入,然后输出说话者的身份。
声纹识别:Transformer模型可以对声音信号进行识别,例如将声音转换为特征向量。在这种情况下,Transformer模型可以将声音信号作为输入,然后输出特征向量。
这些应用案例只是Transformer模型在语音识别领域中的一部分应用。由于Transformer模型具有处理变长序列数据的能力和更好的性能,因此在语音识别领域中得到了广泛的应用。
(三) 计算机视觉
计算机视觉是指让计算机理解和分析图像和视频。Transformer模型在计算机视觉领域也有广泛应用。以下是一些例子:
图像分类:Transformer模型可以对图像进行分类,例如将图像分类为不同的物体或场景。在这种情况下,Transformer模型可以将图像作为输入,然后输出类别标签。
目标检测:Transformer模型可以检测图像中的物体,并将它们分割出来。在这种情况下,Transformer模型可以将图像作为输入,然后输出物体的位置和大小。
图像生成:Transformer模型可以生成新的图像,例如生成一张艺术作品或者修改一张图像。在这种情况下,Transformer模型可以将图像作为输入,然后输出新的图像。
这些应用案例只是Transformer模型在计算机视觉领域中的一部分应用。由于Transformer模型具有处理变长序列数据的能力和更好的性能,因此在计算机视觉领域中得到了广泛的应用。
(四) 强化学习
Transformer模型在强化学习领域的应用主要是应用于策略学习和值函数近似。强化学习是指让机器在与环境互动的过程中,通过试错来学习最优的行为策略。在强化学习中,模型需要通过学习状态转移概率,来预测下一个状态和奖励,从而实现增强学习。
1、Transformer模型可以通过多头注意力机制来处理多个输入序列,并将它们融合成一个输出序列。在强化学习中,Transformer模型可以将当前状态作为输入,然后输出一个行动策略。具体而言,Transformer模型可以学习到状态转移概率函数,使得在当前状态下,选择行动后可以获得最大的奖励。
2、Transformer模型还可以用于值函数近似。值函数是指在给定状态下,执行一个特定行动所能获得的期望奖励。在强化学习中,值函数通常是通过蒙特卡罗方法来估计的。而Transformer模型可以通过学习值函数来近似这些值,从而提高强化学习的效率和精度。
3、Transformer模型已经被广泛应用于自然语言处理、语音识别、计算机视觉和强化学习等领域,并且在这些领域中都取得了显著的成果。它的广泛应用前景表明,Transformer模型在未来的人工智能领域中将扮演着越来越重要的角色。
总体来说,Transformer模型是一种高效、灵活、易于实现的神经网络模型,其在自然语言处理领域中发挥着越来越重要的作用。随着深度学习技术的不断发展,Transformer模型必将在未来的自然语言处理领域中发挥越来越重要的作用。
系统版本:macos 12.2.1
软件版本:PaddlePaddle2.3.0
硬件型号:MacBook Pro
审核编辑:黄飞
评论
查看更多