基于模型结构与模型源码两个层面理解Transformer


前言

之前看的Transformer源码,当时为了理解Transformer的框架,就从模型结构和模型源码两个层面做了思维导图。最近在复盘,从两个层面上又梳理了一遍,针对重要部分的内容,将个人的理解记录下来。

一、Transformer结构思维导图

在这里插入图片描述
由上图可知,Transformer 的整体结构主要包括编码器(Encoder)和解码器(Decoder)。其中:

  1. 编码器的任务是将输入序列进行编码,提取输入序列中的特征表示。编码器由多个相同的层堆叠而成。每个层都由两个子层组成:多头自注意力机制(Multi-Head Self-Attention)和前馈神经网络(Feed-Forward Neural Network)
    1)多头自注意力机制(Multi-Head Self-Attention):
    这是 Transformer 的核心部分之一。它通过对输入序列进行多头注意力计算来获取每个位置的上下文相关性。具体而言,对于输入序列中的每个位置,多头自注意力机制会计算该位置与其他所有位置之间的关联度,然后根据关联度对所有位置的特征进行加权求和。这个操作使得每个位置都能够利用序列中所有其他位置的信息,从而更好地理解上下文。
    2)前馈神经网络(Feed-Forward Neural Network):
    这是编码器层中的另一个子层。它由两个全连接层组成,通过应用激活函数(通常是 ReLU)对输入进行非线性变换。前馈神经网络在每个位置独立地作用,可以帮助模型学习特定位置的局部特征。

  2. 解码器的任务是根据编码器提取的特征表示来生成目标序列。与编码器类似,解码器也由多个相同的层堆叠而成,每个层也包含多头自注意力机制和前馈神经网络。
    1)多头自注意力机制(Multi-Head Self-Attention):
    在解码器中使用多头自注意力机制的作用和编码器中的相同,用于获取每个位置的上下文相关性。
    2)编码-解码注意力机制(Encoder-Decoder Attention):
    解码器还引入了另一种注意力机制,称为编码-解码注意力机制。这种注意力机制允许解码器直接访问编码器中的信息,并在生成序列时对其进行关注。具体而言,对于解码器中的每个位置,编码-解码注意力机制计算该位置与编码器中所有位置的关联度,然后根据关联度对编码器输出的特征进行加权求和。
    3)前馈神经网络(Feed-Forward Neural Network):
    解码器中的前馈神经网络与编码器中的相同,用于在解码器每个位置独立地处理信息。

Transformer的主体结构由编码器和解码器组成,在编码器和解码器中又都包含Layer Normalization 和 Dropout 这两个子层。其中:

  1. Layer Normalization(层归一化): Layer Normalization是一种在神经网络中常用的归一化技术,用于加速模型的训练并提高泛化性能。在 Transformer 中,Layer Normalization 被应用于每个子层的输出。Layer Normalization 的作用是对每个样本的特征进行归一化处理,使得每个特征的均值为 0、方差为 1。这有助于缓解网络训练过程中梯度消失或梯度爆炸问题,并提升模型的稳定性和学习效果。通过将输入在特征维度上进行归一化,Layer Normalization 保留了每个样本特征之间的相对关系。
  2. Dropout(随机失活): Dropout 是一种正则化技术,可以防止模型对训练数据过拟合。在 Transformer 中,Dropout 被添加到每个子层的输出之后。Dropout 的工作原理是在训练过程中,随机选择一些输出单元,并将它们的值设置为 0。这样做的效果是,强制模型不依赖于特定的单元,迫使模型学习更鲁棒和泛化能力更强的特征表示。在测试过程中,Dropout 被关闭,所有输出单元都保持活跃,但其权重会根据训练时的概率进行缩放,以保持期望输出一致性。

整体而言,Transformer 利用自注意力机制在不同位置上学习特征之间的关系,并通过堆叠多个编码器和解码器层来提供更复杂的建模能力。通过 Layer Normalization 和 Dropout 这两个子层,Transformer 可以提高模型的稳定性、泛化能力和抗过拟合能力。这种结构的优势是可以并行计算,减少了序列长度对计算效率的影响,并且克服了传统循环神经网络中的长依赖问题。

二、Transformer源码思维导图

在这里插入图片描述
上图中,黄色的是本人当时阅读源码时候写的备注,现在经过再次梳理之后,对其中的六个部分进行二次记录,分为为:

  1. 结果乘以sqrt(dmodel),原因是Embedding的分布往往是N(1, 1/sqrt(d_model)), 同时位置编码positional encoding是三角函数,在token编码和位置编码加和的时候,前者乘以sqrt(d_model)可以使两者处于相同的尺度。
  2. position encoding其实就是一个和embedding一样长的向量,在这个向量中偶数维度用sin函数计算,奇数维度用cos函数计算(维度从0开始,到dim-1结束),就这样以此类推计算出position encoding中每个维度的值,因为每个维度的值与字的位置和每个维度的不同,所以每个字的位置向量也不相同,这样就得到了位置向量。优点:①它应该为每个字输出唯一的编码;②不同长度的句子之间,任何两个字之间的差值应该保持一致;③它的值应该是有界的
  3. a_2、b_2这两个张量就是规范化层的参数。因为直接对上一层得到的结果做规范化公式计算,将改变结果的正常表征,因此就需要有参数作为调节因子,使其即能满足规范化要求,又能不改变针对目标的表征,所以初始化是1和0,后面就进行更新了,最后使用nn.parameter封装,代表他们是模型的参数。 对结果乘以我们的缩放参数,即a2,*号代表同型点乘,即对应位置进行乘法操作,加上位移参b2,返回即可。
  4. 注意力机制:
    1)所谓Multi-Head Attention,其实是为了从不同的维度来学习数据之间的特征。比如在NLP中经常存在歧义现象,这时每一个注意力机制模块就能学习到一个意思,在进行推理的时候就可以根据上下文语义选择正确的意思。
    2)为什么self.linears是四个线性层呢,这是因为在多头注意力中,Q,K,V各需要一个,最后拼接后的矩阵还需要进行映射,就是在return的时候进行映射,因此一共是四个。
    3)Wq Wk Wv就是一个dmoedl×dmodel的矩阵,也就是self.linears前三个的线性层参数,这个是用来学习的参数,作用是将输入映射为Q、K、V。
    4)首先利用zip将输入QKV分别放在三个线性层中进行映射,做完线性变换后,开始为每个头分割输入,这里使用view方法对线性变换的结构进行维度重塑,多加了一个维度h代表头,这样就可以把原来的词向量分割为h份,这就意味着每个头可以获得一部分词特征组成的句子,然后对第二维和第三维进行转置操作,为了让代表句子长度维度和词向量维度能够相邻,这样注意力机制才能找到词义与句子位置的关系,从attention函数中可以看到,利用的是原始输入的倒数第一和第二维,这样我们就得到了q k v
    5)然后将q k v输入attention进行计算,得到注意力表示x
    6)x是所有头的输出,这里需要把他们进行拼接,然后映射输出,这里的映射用到了第四个线性层
    7)关于mask的理解:①在编码过程中为了让模型看到当前位置前后的信息,所以不需要mask attention,但是Encoder的输入也有mask,这个mask是用来对不同长度句子的长度进行补全mask的,主要就是对q×k的计算结果与掩码张量的每个位置逐一比较,如果掩码张量的数值为True(因为在eq(0)的时候是把需要mask的字转换为True了),则对应的scores张量用-1e9这个值来替换,这是为了在后面的softmax中进行e^运算时对应的值为0。编码层中的mask是先根据batch×f矩阵得到,将batch×f中的0替换为True,然后进行复制和维度扩充,得到维度为 (b, h, f, f)的mask,q×k后的维度也是(b, h, f, f),把q×k中的最后一个维度与mask的最后一个维度进行对比,如果是True就换成无穷大的数。这里为啥不是对字的维度(倒数第二个维度)进行mask替换呢,因为后面q×k经过softmax后还要与v相乘,这样q×k的最后一个维度(最后一列)才能与v的倒数第二个维度(最后一行)相乘,这样才能mask掉一句话的最后一个字。
    ②在解码过程中为了模拟在真实的推理场景中,当前位置看不到下一位置,且同时需要上一位置的信息,所以在训练的时候加了mask attention,Decoder的两个self-attention都是mask attention。先生成一个下三角矩阵,对角线以上元素全为0,这样在scores和mask矩阵做对比的时候,将mask为0的scores对应的张量替换为无穷大的值,这样在softmax的时候就能将上三角元素全变为0,这样在看第一行(第一个字)的时候只知道第一个元素,第二行(第二个字)的时候只知道前两个元素,以此类推,这样就实现了遮盖后面信息的功能。解码层中的decselfattnmask是将dec selfattnpadmask和decselfattn subsequentmask相加得到,叠加两个mask的作用,不但能mask掉句末padding,还能mask掉decoder当前输入之后的信息,是一个上三角矩阵,主对角以上全是True,替换后就全是无穷小的数,softmax后全是0,这样第一行就只能看到第一个字了(具体实现跟padmask一样,用q×k的最后一个维度乘上v的倒数第二个维度,这样一句话的第一个字就只能看到第一个字了)。其中dec_ selfattnpadmask的生成与编码层一样;decselfattn subsequent_ mask先根据(batch,f,f)生成一个元素全是1的矩阵,然后利用triu(,dim=1)函数将主对角及以下元素全变为0,并将元素都转换为整数形式。解码层中的decencattnmask的生成方式也和编码层的mask生成方式一样,不过维度不一样,交叉attn的mask的维度为(b,h,fdecoder ,fencoder),其中fdecoder表示解码层的每句话的最大长度。decencattn的q来自decoder,k和v来自encoder,所以q×k得到的维度就是(b,h,fdecoder,fencoder),这就和decencattn_mask的维度对应上了。
    ③Encoder和Decoder的mask功能是不一样的,所以形状自然也是不一样的。Encoder的mask只有对不足的长度填充为0,其余值为token的id,然后后面将0替换为无穷大,然后softmax再转换为0,这样不足长度的维度就不会有信息了;Decoder的第一个mask是一个下三角矩阵,主对角线及以下元素为1,其余元素为0,然后后面将0替换为无穷大,然后softmax再转换为0,这样得到的还是一个下三角矩阵,这样在看第一行(第一个字)的时候只知道第一个元素,第二行(第二个字)的时候只知道前两个元素,以此类推,这样就实现了遮盖后面信息的功能,第二个mask和encoder的功能一样,只是维度不一样。
    8)q k v的维度都是(b, h, f, d),分别代表batch,头,句子长度,字向量维度。具体的向量计算简化为:①(b, h, f, d)×(b, h, d, f)得到(b, h, f, f),最后两个维度表示注意力权重矩阵,比如第一行表示第一个字与句子中所有字的注意力权重,第二行表示第二个字与句子中所有字的注意力权重…;②(b, h, f, f)×(b, h, f, d)得到(b, h, f, d),最后两个维度表示注意力矩阵,比如第一行表示第一个字与句子中所有字的注意力,第二行表示第二个字与句子中所有字的注意力。
    9)cross attention部分可以看成解码器在用编码器的输出信息来计算当前解码应该输出什么。
  5. ffd层就是两个线性层加一个Relu函数,具体运算顺序就是:512→1024的映射,Relu,dropout,1024→512的映射。
    前馈全连接层的作用:考虑注意力机制可能对复杂过程的拟合程度不够,通过增加两层网络来增强模型的表达能力,并且激活函数能拟合非线性特征。
  6. Cross Attn层的K、V是编码层的输出m,m,Q是解码层的输出x。

总结

本文从Transformer的模型结构和模型源码两个层面对Transformer进行解读。在模型结构层面上,分析了Transformer主要结构的功能;在模型源码层面,记录了本人对于源码的理解。以上就是全部内容了,本文内容都是基于个人的理解进行的记录,如果错误欢迎批评指正。

参考文章:
Transformer源码:http://nlp.seas.harvard.edu/2018/04/03/attention.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值