Transformer回顾与细节

news/2024/7/19 11:12:19 标签: transformer, 自然语言处理, nlp, 深度学习

我们在《Seq2seq Attention模型详解》中,详细地回顾了以 RNN 为基础模块的Seq2seq模型。本文所讲述的Transformer也采用Seq2seq式的编码器-解码器结构,不过它摒弃了经典的 RNN,采用 self-Attention。由于并行计算、长时序建模、模型容量大等优势,它受到BERT、GPT、T5等众多预训练模型的青睐。Transformer的模型结构简单,但细节较多,本文会用尽可能深入而明了的方式进行讲述。

本文结构

    • 0.序
    • 1. 总体结构:Encoder与Decoder
    • 2. 输入
      • 2.1 Embedding
      • 2.2 位置编码
    • 3. 多头Attention
    • 4. 残差模块
    • 5. 输出
    • Reference

0.序

进入正文前,我们先对上述的3个Transformer优势进一步说明。其一,RNN 的串行结构无法支持并行计算,而Transformer的同一层的多个self-Attention完全独立,即多个head,可并行计算。其二,RNN 的串行结构会"遗忘"位于时序输入靠前位置的内容,而Transformer的self-Attention只需一步计算,就能得出时序输入中的任意两个位置的内容的联系,缓解了长距离依赖问题;其三,Transformer的参数量更多,对数据分布的建模能力更强,满足海量数据场景的要求。

在这里插入图片描述

1. 总体结构:Encoder与Decoder

Encoder由多层结构一致的layer串联而成(默认6层),每个layer包含两个sublayer:“多头self-Attention"和"前馈神经网络”。

Decoder同样由多层结构一致的layer串联而成,每个layer包含三个sublayer:“Masked多头self-Attention”、“多头self-Attention"和"前馈神经网络”。

在这里插入图片描述

2. 输入

Encoder和Decoder的输入,皆由Embedding和位置编码组成。

在这里插入图片描述

2.1 Embedding

Encoder的Embedding层是一个look-up表,用于得到输入序列经过tokenizer后的各个token的嵌入表示。Decoder的Embedding层通常与Encoder共享参数,用于得到Decoder前一时刻的预测输出的token的嵌入表示。如果采用Teacher Forcing,这里变为用于得到Decoder前一时刻的真实标签的token的嵌入表示。

2.2 位置编码

在Transformer中,self-Attention把任意两个字之间计算距离缩小为1,因此丢失了序列顺序。

位置不敏感的模型,例如Transformer、CNN,无法捕捉输入顺序,即在序列顺序打乱后,模型的输出保持不变。所以,通过额外加入位置编码,补偿输入的顺序关系。

根据不同位置是否存在相对关系,分为绝对位置编码和相对位置编码。绝对位置编码能够反映位置k的信息,通常直接加在输入x_k上;相对位置编码能够反映不同位置i和j的距离关系,通常加在Attention计算中。

Transformer采用了固定式位置编码,即三角函数cos和sin,公式如下:
P E ( p o s , 2 i ) = s i n ( p o s 1000 0 2 i d m o d e l ) P E ( p o s , 2 i + 1 ) = c o s ( p o s 1000 0 2 i d m o d e l ) PE_{(pos,2i)}=sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}}) \\ PE_{(pos,2i+1)}=cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}}) PE(pos,2i)=sin(10000dmodel2ipos)PE(pos,2i+1)=cos(10000dmodel2ipos)

其中, p o s pos pos表示token在输入序列中的位置,2i表示PE向量的第2i个分量, d m o d e l d_model dmodel表示位置编码的维度(与embedding维度相等)。
由此,绝对位置编码可表示为位置的线性函数。

此外,受益于三角函数特性,模型能学习到不同token的相对位置关系,推导如下:

利用和差公式:
sin ⁡ ( α + β ) = sin ⁡ α ⋅ cos ⁡ β + cos ⁡ α ⋅ sin ⁡ β cos ⁡ ( α + β ) = cos ⁡ α ⋅ cos ⁡ β − sin ⁡ α ⋅ sin ⁡ β \begin{aligned} &\sin (\alpha+\beta)=\sin \alpha \cdot \cos \beta+\cos \alpha \cdot \sin \beta \\ &\cos (\alpha+\beta)=\cos \alpha \cdot \cos \beta-\sin \alpha \cdot \sin \beta \end{aligned} sin(α+β)=sinαcosβ+cosαsinβcos(α+β)=cosαcosβsinαsinβ

代入pos+k的位置编码计算中,设 w i = 1 1000 0 2 i d m o d e l w_i=\frac{1}{10000^{\frac{2i}{d_{model}}}} wi=10000dmodel2i1

{ P E ( p o s + k , 2 i ) P E ( p o s + k , 2 i + 1 ) = { sin ⁡ ( w i ⋅ ( pos + k ) ) cos ⁡ ( w i ⋅ (  pos  + k ) ) = { sin ⁡ ( w i ⋅ p o s ) cos ⁡ ( w i ⋅ k ) + cos ⁡ ( w i ⋅ p o s ) sin ⁡ ( w i ⋅ k ) cos ⁡ ( w i ⋅ p o s ) cos ⁡ ( w i ⋅ k ) − sin ⁡ ( w i ⋅ p o s ) sin ⁡ ( w i ⋅ k ) = { P E ( p o s , 2 i ) cos ⁡ ( w i ⋅ k ) + P E ( p o s , 2 i + 1 ) sin ⁡ ( w i ⋅ k ) P E ( p o s , 2 i + 1 ) cos ⁡ ( w i ⋅ k ) − P E ( p o s , 2 i ) sin ⁡ ( w i ⋅ k ) \begin{aligned} \begin{cases} PE_{(pos+k, 2 i)} \\ PE_{(pos+k, 2i+1)} \end{cases} &= \begin{cases} \sin \left(w_{i} \cdot (\text{pos}+k)\right) \\ \cos \left(w_{i} \cdot(\text { pos }+k)\right) \end{cases} \\ &= \begin{cases}\sin \left(w_{i} \cdot pos\right) \cos \left(w_{i} \cdot k\right)+\cos \left(w_{i} \cdot pos\right) \sin \left(w_{i} \cdot k\right) \\ \cos \left(w_{i} \cdot pos\right) \cos \left(w_{i} \cdot k\right) - \sin \left(w_{i} \cdot pos \right) \sin \left(w_{i} \cdot k\right) \end{cases} \\ &= \begin{cases}PE_{(pos,2i)} \cos \left(w_{i} \cdot k\right) + PE_{(pos,2i+1)} \sin \left(w_{i} \cdot k\right) \\ PE_{(pos,2i+1)} \cos \left(w_{i} \cdot k\right) - PE_{(pos,2i)} \sin \left(w_{i} \cdot k\right) \end{cases} \\ \end{aligned} {PE(pos+k,2i)PE(pos+k,2i+1)={sin(wi(pos+k))cos(wi( pos +k))={sin(wipos)cos(wik)+cos(wipos)sin(wik)cos(wipos)cos(wik)sin(wipos)sin(wik)={PE(pos,2i)cos(wik)+PE(pos,2i+1)sin(wik)PE(pos,2i+1)cos(wik)PE(pos,2i)sin(wik)

由于相对距离 k k k是常数,设 u = cos ⁡ ( w i ⋅ k ) , v = sin ⁡ ( w i ⋅ k ) u=\cos \left(w_{i} \cdot k\right), v=\sin \left(w_{i} \cdot k\right) u=cos(wik),v=sin(wik),可得:
[ P E ( p o s + k , 2 i ) P E ( p o s + k , 2 i + 1 ) ] = [ u v − v u ] × [ P E ( p o s , 2 i ) P E ( p o s , 2 i + 1 ) ] \begin{bmatrix} PE_{(pos+k, 2 i)} \\ PE_{(pos+k, 2i+1)} \end{bmatrix}=\begin{bmatrix} u& v \\ -v& u\end{bmatrix} \times \begin{bmatrix} PE_{(pos, 2 i)} \\ PE_{(pos, 2i+1)} \end{bmatrix} [PE(pos+k,2i)PE(pos+k,2i+1)]=[uvvu]×[PE(pos,2i)PE(pos,2i+1)]

由此, P E ( p o s + k , 2 i ) PE_{(pos+k, 2 i)} PE(pos+k,2i)可表示为 P E ( p o s , 2 i ) PE_{(pos, 2 i)} PE(pos,2i)的线性函数。

固定式位置编码的优点是,推理时支持任意长度的输入(不受训练时输入长度的限制)。

BERT采用了可训练式位置编码,训练前,位置编码随机初始化,并和词嵌入加在一起送入模型,作为参数进行训练。推理时,以查表的方式找到特定位置的编码向量。

可训练式位置编码的优点是,在大语料上准确性比较好,缺点是推理时限制了输入的长度(超过的position无法查表得到编码),超出部分可随机初始化,但效果依赖于数据量。

3. 多头Attention

本小节由3个问题展开,问题一是“Attention的计算细节?”,问题二是“multi-head的计算细节?”,问题三是“不同类型Attention的计算细节?”。

问题1. Attention的计算细节?

Q, K, V矩阵是Attention计算的关键。不同类型的Attention的Query、Key、Value来源不同,具体差别将在下文"问题3. 不同类型Attention的计算细节"中详细说明。

此处假设已经确定Query、Key、Value,分别通过线性变换,即可得到Q、K、V矩阵,再按如下公式计算Attention:
Attention(Q,K,V) = s o f t m a x ( Q K T d k ) ⋅ V \text{Attention(Q,K,V)} = softmax(\frac{QK^T}{\sqrt{d_k}})·V Attention(Q,K,V)=softmax(dk QKT)V

其中,Q、K的维度为[batch_size, seq_len, d_k] ,V的维度为[batch_size, seq_len, d_v]。分母 1 d k \frac{1}{\sqrt{d_k}} dk 1 是一个放缩因子,防止d_k增大时,Q和K的点积值过大,方差变成原来的 d_k 倍,导致softmax梯度变得非常小。
D ( q ⋅ k d k ) = d k ( d k ) 2 = 1 D(\frac{q·k}{\sqrt{d_k}}) = \frac{d_k}{(\sqrt{d_k})^2} = 1 D(dk qk)=(dk )2dk=1

放缩因子 1 d k \frac{1}{\sqrt{d_k}} dk 1 将方差控制为1,有效缓解了梯度消失问题。

在这里插入图片描述

问题2. multi-head的计算细节?

我们将Attention视为一个头。Encoder和Decoder的每一层中,都有多个头。这样做的好处有,多个头之间相互独立,可以并行计算;并且可以关注到不同子空间的信息。

在单头Attention中,我们只计算一组Q, K, V矩阵。在多头Attention中,Query、Key、Value分别通过n次线性变换得到n组Qi、Ki、Vi矩阵,其中n是头的个数。此时,以K矩阵为例,维度由单头的[nbatches, seq_len, d_model],变为了[nbatches, seq_len, num_head, d_k],其中d_k=d_model/num_head。

每一组Qi、Ki、Vi,分别经过Attention计算,得到单头输出Zi。最后,所有的Z0 ~ Zn拼接在一起,此时维度变回了[nbatches, seq_len, d_model],并通过线性变换得到最终输出Z。

在这里插入图片描述

问题3. 不同类型Attention的计算细节?

Encoder和Decoder中,共包含"多头self-Attention"、"masked 多头self-Attention"和"多头cross-Attention"三种Attention机制。
在这里插入图片描述

其一,多头self-Attention位于Encoder中,即上图左侧橘色模块。它的输入Query、Key、Value均来源于同一文本,即Encoder的输入(从Encoder第二层开始,此处变为前一层的输出)。多头self-Attention的作用是建模输入中的各个单词的依存关系(e.g.语法特征)。

其二,masked 多头self-Attention位于Decoder中,即上图右侧下方橘色模块。它的Query、Key、Value都来源于前一时刻的Decoder的输出(若采用Teacher Forcing,此处变为前一时刻的ground truth)。

为了在推理过程中,避免模型看到要预测的信息,防止泄露,采用了Sequence Mask。

Transformer所采用的的mask分为Padding Mask和Sequence Mask。其中,Padding Mask(可用于encoder和decoder)用于将被PAD为0的位置上的值成为一个非常小的负数-1e9(可以是负无穷),经过softmax之后,这些位置的概率就变为了0。由此,相当于把[PAD]的无用信息给mask掉了。Sequence Mask(只用于decoder)则使用和原Tensor大小相同的下三角形掩码Tensor,即上三角部分全为非常小的负数(可以是负无穷),经过softmax之后,这些位置的概率就变为了0。由此,相当于把序列尾端元素给mask掉了。

其三,多头cross-Attention,又称为多头encoder-decoder Attention,位于Decoder中,即上图右侧上方橘色模块。它的query来自前一层decoder的输出,它的key和value来自encoder的输出。多头cross-Attention是Source各单词和Target各单词的对齐机制。

4. 残差模块

每个sublayer中,都包含一个 Add&Norm 模块。其中Add是残差连接;Norm是层归一化;还包含dropout。

以Encoder为例,如下图,残差模块的计算顺序是:step 1.对原始输入进行层归一化;step 2.把层归一化的输出,送入自注意或前馈神经网络;step 3.把自注意或前馈神经网络的输出,送入dropout;step 4.把dropout的输出与未经过层归一化的原始输入直接相加。

层归一化的优点是,避免数据落入激活函数的饱和区,减缓梯度消失问题。
残差连接的优点是,可以加快模型收敛,解决随着层数加深,误差传播的值越来越小的问题。

在这里插入图片描述

5. 输出

位于最后的 linear layer 将 decoder 的输出扩展到与 vocabulary size 一样的维度上。
FFN ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 \text{FFN}(x)=max(0, xW_1+b_1)W_2+b_2 FFN(x)=max(0,xW1+b1)W2+b2

经过 softmax 后,得到词表中各个 word 作为预测结果的概率。采用beam search,得到生成序列。

在这里插入图片描述
附:训练小技巧

技巧1. 标签平滑,公式如下,防止过拟合;
技巧2. 学习率先线性增长,前5000步预热,再指数衰减;
在这里插入图片描述


Reference

[1] The Illustrated Transformer
[2] The Annotated Transformer
[3] 图解Transformer(完整版)
[4] positional encoding位置编码详解
[5] 让研究人员绞尽脑汁的Transformer位置编码


http://www.niftyadmin.cn/n/1797957.html

相关文章

一道比较有趣的题

一道比较有趣的题A与B能相互转换。B在沸水中可生成C。C在空气中可变成D,D有臭鸡蛋气味,问ABCD各是什么??? 转载于:https://www.cnblogs.com/newblog/archive/2006/06/12/423622.html

如何下载谷歌地球高程为TIF格式的文件

众所周知,谷歌地球为广大用户提供了全球的高程数据,用户可以在线浏览和查看某个点的高程(图1),但是在线浏览并不是那么方便,一旦没有网,就无法得知想要点的高程值。那我们如何才能获取到这些高程…

如何利用ArcScene制作简单的三维模型

一、材料准备水经注万能地图下载器 ArcScene10.2万能地图下载地址:http://www.rivermap.cn/download/mdwn.exe获取更多免费软件、技术加群:329081749二、制作步骤1、下载卫星影像图1.1新建下载任务打开水经注万能地图下载器,点击“在线地图”…

Python的高级特性9:蹩脚的多态

学习了java再来看python的多态,总感觉怪怪的,很蹩脚。。 1.python的父类根本不能调用子类的方法,只能蹩脚的依靠重写方法,然后在运行时去调用,实现伪多态。。。 2.所谓的鸭子类型看起来很方便,其实会让代码…

中文生成模型T5-Pegasus详解与实践

我们在前一篇文章《生成式摘要的四篇经典论文》中介绍了Seq2seq在生成式研究中的早期应用,以及针对摘要任务本质的讨论。 如今,以T5为首的预训练模型在生成任务上表现出超出前人的效果,这些早期应用也就逐渐地淡出了我们的视野。本文将介绍T…

UTF-8的编码方式

UTF编码 UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下: UCS-2编码(16进制)UTF-8 字节流(二进制)0000 - 007F0xxxxxxx0080 - 07FF110xxxxx 10xxxxxx0800 - FFFF1110xxxx 10xxxxxx 10xxxxxx例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间…

水经注万能地图下载器功能大全

一、下载地图多元化支持下载谷歌地球、谷歌地图、谷歌高程、百度地图、天地图、高德地图、海图、三维图、谷歌地形等32种地图下载,内容丰富,任你选择。二、支持自定义下载地图通过下载器将你在浏览器上看到的在线地图下载到电脑上,具体操作方…

GCD的简单封装

扩展: dispatch_block_t :无参数block,使用起来很简单下载链接:http://pan.baidu.com/s/1bndN6Yb//串行队列- (void)test1 {WJGCDQueue *queue [[WJGCDQueue alloc]initSerial];[queue execute:^{NSLog("1--%",[NSThread currentT…