1. Encoder的组成
1.1 整体结构
Encoder的整体结构,由如下图左侧所示的多个Encoder子模块堆叠而成,其中,第一个 Encoder 子模块接收来自嵌入(Input Embedding)和位置编码(Position Embedding)组合后的输入(inputs)。除了第一个 Encoder 之外的其他 Encoder 子模块,它们从前一个 Encoder 接收相应的输入(inputs),这样就形成了一个顺序传递信息的链路。
1.2 Encoder layer的构成
模块主要由以下几部分构成:
- Multi-Head Attention
- Residual connection
- Normalization
- Position-wise Feed-Forward Networks
在 Transformer 模型中,Encoder 部分由多个相同的 Encoder Layer 堆叠而成,每个 Encoder Layer 包含两个主要子层,分别是 Multi-Head Self-Attention 和 Position-wise Feed-Forward Network。Multi-Head Self-Attention由 Scaled Dot-product Attention 和 Multi-Head Attention 以及 Self Attention 和 Add & Norm 组成。
2. 多头自注意力(Multi-Head Self-Attention)
2.1 自注意力
首先我们来定义一下什么是“self-Attention” 。Cheng 等人在论文《Long Short-Term Memory-Networks for Machine Reading》中将self-Attention 定义为将单个序列或句子的不同位置关联起来以获得更有效表示的机制。
在自注意力中,Query、Key和Value都来自于同一个输入序列。具体来说是它对同一个输入序列 X,分别进行三种独立的线性变换得到 Q_x、K_x、V_x 后,将其输入 Attention。它允许模型在处理序列数据时,同时考虑序列中所有元素之间的关系。
2.1.1 工作原理
(1)嵌入
首先,模型将输入序列中的每个单词嵌入到一个高维向量表示中。这个嵌入过程允许模型捕捉单词之间的语义相似性。
(2)查询、键和值向量
接下来,模型为序列中的每个单词计算三个向量:查询向量、键向量和值向量。在训练过程中,模型学习这些向量,每个向量都有不同的作用。
查询向量表示单词的查询,即模型在序列中寻找的内容。
键向量表示单词的键,即序列中其他单词应该注意的内容。
值向量表示单词的值,即单词对输出所贡献的信息。
(3)注意力分数
一旦模型计算了每个单词的查询、键和值向量,它就会为序列中的每一对单词计算注意力分数。这通常通过取查询向量和键向量的点积来实现,以评估单词之间的相似性。
(4)SoftMax 归一化
然后,使用 softmax 函数对注意力分数进行归一化,以获得注意力权重。这些权重表示每个单词应该关注序列中其他单词的程度。注意力权重较高的单词被认为对正在执行的任务更为关键。
(5)加权求和
最后,使用注意力权重计算值向量的加权和。这产生了每个序列中单词的自注意力机制输出,捕获了来自其他单词的上下文信息。
2.1.2 Self-Attention优缺点
优点:
- 参数少: self-attention的参数量为 O(n2d)O(n^2d)O(n2d),而循环网络的参数量为 O(nd2)O(nd^2)O(nd2) ,卷积的参数量为 O(knd2)O(knd^2)O(knd2),当 n 远小于 d 时,self-attention更快。
- 可并行化: RNN 需要一步步递推才能捕捉到,而 CNN 则需要通过层叠来扩大感受野。Attention机制每一步计算不依赖于上一步的计算结果,因此可以和 CNN 一样并行处理。
- 捕捉全局信息: 更好的解决了长时依赖问题,同时只需一步计算即可获取全局信息,在 Attention 机制引入之前,有一个问题大家一直很苦恼:长距离的信息会被弱化,就好像记忆能力弱的人,记不住过去的事情是一样的。Attention 是挑重点,就算文本比较长,也能从中间抓住重点,不丢失重要的信息。
缺点:
- **计算量:**单看自注意力来说参数量少,但是实际上其计算量并不低,比如 Self Attention 中,首先要对 X 做三次线性映射,这计算量已经相当于卷积核大小为 3 的一维卷积了,不过这部分计算量还只是 O(n)O(n)O(n)的;然后还包含了两次序列自身的矩阵乘法,这两次矩阵乘法的计算量都是O(n2d)O(n^2d)O(n2d)的,要是序列足够长,这个计算量其实是很难接受的。
- 没法捕捉位置信息:即没法学习序列中的顺序关系。这点可以通过加入位置信息,如通过位置向量来改善,具体可以参考BERT模型。
其他的一些缺点,在Google原文中没有提到,后来在论文Universal Transformers中指出,主要是两点:
(1)实践上:存在一些任务,RNN能够轻松应对,而Transformer则未能有效解决。例如,在复制字符串的任务中,或者当推理过程中遇到的序列长度超出训练时的最大长度时(由于遇到了未曾见过的位置嵌入),Transformer的表现不如RNN。
(2)理论上: 与RNN不同,Transformer模型并不具备计算上的通用性(即非图灵完备)。这类非RNN架构的模型,包括基于Transformer的BERT等,在处理NLP领域中的推理和决策等计算密集型问题时,存在固有的局限性。即无法独立完成某些复杂的计算任务。
2.1.3 缩放点积注意力(Scaled Dot-Product Attention)
缩放点积注意力和自注意力在Transformer模型中紧密相关。具体来说,缩放点积注意力是自注意力的一种实现方式。在Transformer模型中,自注意力机制通过缩放点积注意力的公式来实现,即通过计算查询和键的点积并除以键向量的维度平方根,然后应用softmax函数进行归一化处理,最终得到加权后的输出。
上图是transformer中缩放点积注意力的示意图,其中缩放点积注意力入下图所示来获得
最终整个从输入到输出的过程如下图:
这个公式相比于正常的点积注意力多了一个缩放因子dk\sqrt{d_k}dk ,这个缩放因子降低对key的长度的敏感度,使得无论向量的长度如何,点积的方差在不考虑向量长度的情况下仍然是1,方便模型优化,提升网络训练时的稳定性。同时可以防止内积过大,防止它经过 softmax 后落入饱和区间,因为饱和区的梯度几乎为0,容易发生梯度消失。
2.2 多头自注意力
Transformer模型中,多头注意力机制允许模型在不同的子空间中学习到不同的关系。每个头都有自己的Q、K和V,最后将所有头的输出通过一个线性层拼接起来。多头(Multi-Head) 的方式是将多个 head 的输出 z,进行拼接(concat)后,通过线性变换得到最后的输出 z。如下所示
简单理解所谓Multi-Head(多头),就是只多做几次同样的事情(参数不共享),然后把结果拼接。
原理解释:
一般来说一个多头 attention 的效果要优于单个 attention。按照Google官方的说法,这么做形成多个子空间,可以让模型关注不同方面的信息,体现出差异性。
但有实验表明,头之间的差距随着所在层数变大而减小,因此这种差异性是否是模型追求的还不一定。 至于头数 h 的设置,并不是越大越好,到了某一个数就没效果了。
优点
- 并行化:通过同时关注输入序列的不同部分,多头注意力显著加快了计算速度,使其比传统的注意力机制更加高效。
- 增强表示:每个注意力头都关注输入序列的不同方面,使模型能够捕捉各种模式和关系。这导致输入的表示更丰富、更强大,增强了模型理解和生成文本的能力。
- 改进泛化性:多头注意力使模型能够关注序列内的局部和全局依赖关系,从而提高了跨不同任务和领域的泛化性。
计算过程 - 线性变换:输入序列经历可学习的线性变换,将其投影到多个较低维度的表示,称为“头”。每个头关注输入的不同方面,使模型能够捕捉各种模式。
- 缩放点积注意力:每个头独立地计算输入序列的查询、键和值表示之间的注意力分数。这一步涉及计算令牌及其上下文之间的相似度,除以模型深度的平方根进行缩放。得到的注意力权重突出了每个令牌相对于其他令牌的重要性。
- 连接和线性投影:来自所有头的注意力输出被连接并线性投影回原始维度。这个过程将来自多个头的见解结合起来,增强了模型理解序列内复杂关系的能力。
2.2 自注意力和交叉注意力
2.2.1 交叉注意力
概念
交叉注意力是一种注意力机制,它允许一个序列(称为“查询”序列)中的元素关注另一个序列(称为“键-值”序列)中的元素,从而在两个序列之间建立联系。
序列维度要求
为了进行交叉注意力计算,两个序列必须具有相同的维度。这是因为注意力机制的计算涉及到查询(Q)、键(K)和值(V)向量的点积操作,这些操作要求参与计算的向量具有相同的维度。
序列的多样性
两个序列可以是不同模态的数据,例如:
- 文本序列:一系列单词或子词的嵌入表示。
- 声音序列:音频信号的时序特征表示。
- 图像序列:图像的像素或特征图的嵌入表示。
作用: - 跨模态学习:Cross Attention在多模态学习中尤为重要,因为它能够将不同模态(如文本、图像、声音)的信息进行有效融合。
- 交互式解码:在序列到序列的任务中,Cross Attention使得解码器能够利用编码器提供的上下文信息,从而更准确地生成目标序列。
- 灵活性:Cross Attention提供了灵活性,因为它允许模型动态地关注另一个序列中与当前任务最相关的部分。
具体操作:
- 查询(Q)序列:这个序列定义了输出的序列长度,即查询序列中的每个元素都会生成一个对应的输出元素。
- 键(K)和值(V)序列:这两个序列提供输入信息,其中键序列用于计算与查询序列中元素的相似度,值序列则用于生成最终的输出表示。
2.2.2 自注意力和交叉注意力的主要区别
Cross Attention(交叉注意力)和 Self Attention(自注意力)是注意力机制中的两种不同类型,它们在信息交互的方式上有显著的区别。具体来说,主要区别体现在输入的来源和信息交互的对象上。
2.3 多头注意力VS多头自注意力
(1)基础架构相同
Multi - Head Self - Attention 和 Multi - Head Attention 都基于多头注意力(Multi - Head Attention)机制的基本架构。它们都包含多个并行的注意力头(Attention Head),每个头都有自己的线性变换矩阵用于计算查询(Query)、键(Key)和值(Value)。计算过程都涉及到缩放点积注意力(Scaled Dot - Product Attention)
(2)计算流程相似
在整体的计算流程上,两者都需要先对输入进行线性变换以得到 Q、K、V,然后通过注意力机制计算每个头的输出,最后将各个头的输出进行拼接和线性变换得到最终的输出。
(3)查询、键、值的来源不同
Multi - Head Attention查询(Query)、键(Key)和值(Value)可以来自不同的输入源。例如 Decoder部分,查询(Query)来自解码器当前的输入,而键(Key)和值(Value)通常来自编码器的输出。这种机制使得模型能够将解码器当前的信息与编码器已经处理好的信息进行关联,从而更好地生成输出序列。
Multi - Head Self - Attention查询(Query)、键(Key)和值(Value)都来自同一个输入序列。这意味着模型关注的是输入序列自身不同位置之间的关系。它可以让模型自己发现句子中不同单词之间的相互关联,比如在句子 “The dog chased the cat” 中,单词 “dog” 与 “chased”、“chased” 与 “cat” 之间的关系可以通过 Multi - Head Self - Attention 来挖掘。
(4)功能重点有所差异
Multi - Head Attention主要用于融合不同来源的信息。比如在机器翻译的任务中,它用于将元文本经过 Encoder编码后的信息(作为 K 和 V )与解码器当前生成的部分目标语言句子(作为 Q )相结合,帮助解码器在生成目标语言句子时更好地参考源语言句子的语义和结构,从而生成更准确的翻译。
Multi - Head Self - Attention更侧重于挖掘输入序列自身的内在结构和关系。在文本生成任务中,它可以帮助模型理解当前正在生成的文本自身的语义连贯和语法结构。例如,在续写一个故事时,通过 Multi - Head Self - Attention 可以让模型把握已经生成的部分文本的主题、情节发展等内部关系,以便更好地续写。
(5)输出信息性质不同
Multi - Head Attention由于其融合了不同来源的信息,输出的结果往往包含了两个或多个不同输入序列之间相互作用后的特征。例如,在跨模态任务(如将文本和图像信息相结合)中,输出会包含文本和图像相互关联后的综合特征,用于后续的分类或生成等任务。
Multi - Head Self - Attention输出的是输入序列自身内部关系的一种特征表示。例如,在对一个文本序列进行词性标注任务时,输出的特征能够反映出句子内部单词之间的语法和语义关联,用于确定每个单词的词性。
3.前馈全连接网络
前馈全连接网络(FFN )层实际上就是一个线性变换层,用来完成输入数据到输出数据的维度变换。FFN层是一个顺序结构:包括一个全连接层(FC) + ReLU 激活层 + 第二个全连接层(FC),通过在两个 FC 中间添加非线性变换,增加模型的表达能力,使模型能够捕捉到复杂的特征和模式。 全连接层线性变换的主要作用为数据的升维和降维,第一层变换的维度是(2048,512),,第一层变换是 (512,2048)。 即先升维,后降维,这是为了扩充中间层的表示能力,从而抵抗 ReLU 带来的模型表达能力的下降。
4.残差连接和层归一化
(1)残差连接(Residual Connection)
自注意力层和前馈子层(Feedforward sublayer)均配备了残差快捷链路。从网络拓扑结构来看,这种连接方式构建了一种并行通路,使得输入信号能够以残差的形式参与到每一层的输出计算中。
自注意力层,其输入会与自注意力层的输出进行相加操作( 假设自注意力层输入为 x,输出为 y,经过残差连接后变为 x + y )
前馈层的输入也会和前馈层的输出进行相加。
残差连接(Residual Connection)有助于缓解深度网络训练过程中的梯度消失或梯度爆炸问题,使得网络能够更容易地训练深层模型,并且能够让信息更顺畅地在网络中传递。
(2)层归一化(Layer Norm)
层归一化是对每一层的神经元的输入进行归一化处理,它可以加速网络的收敛速度、提高模型的泛化能力等,使得模型训练更加稳定、高效。经过层归一化后的结果就是当前 Encoder 子模块最终的输出,然后传递给下一个 Encoder 子模块或者后续的其他模块(比如在 Encoder-Decoder 架构中传递给 Decoder 部分等情况)。
层归一化包括以下几个特点:
- 独立归一化
与批量归一化(Batch Normalization)不同,层归一化不依赖于批次中的其他样本。这意味着即使在处理小批量数据或者在线学习场景时,层归一化也能保持稳定和有效。 - 稳定训练过程
层归一化通过将每个特征的均值变为 0,标准差变为 1,有助于减少内部协变量偏移(Internal Covariate Shift)。这种偏移是指神经网络在训练过程中,由于参数更新导致的每层输入分布的变化。通过归一化,可以使得每一层的输入分布更加稳定,从而加速训练过程。 - 提高模型稳定性
由于层归一化减少了特征之间的尺度差异,这有助于避免某些特征在学习过程中占据主导地位,从而提高了模型的泛化能力和稳定性。 - 适应不同类型的网络
层归一化特别适用于循环神经网络(RNN)和Transformer模型,因为这些网络结构在处理序列数据时,每个时间步或位置的状态是相互依赖的,而批量归一化在这些情况下可能不太适用。 - 减少梯度消失和爆炸
通过归一化处理,可以减少梯度在传播过程中的消失或爆炸问题,尤其是在深层网络中。这有助于更有效地进行反向传播,从而提高训练效率。 - 不受批量大小限制
层归一化不依赖于批次大小,因此在处理不同大小的批次时,不需要调整超参数,这使得层归一化更加灵活。