李沐精读论文:transformer 《Attention Is All You Need》 by Google

news2024/9/29 1:16:26

论文:Attention Is All You Need

视频:Transformer论文逐段精读【论文精读】_哔哩哔哩_bilibili

课程(推荐先看这个):李宏毅机器学习:self-attention(自注意力机制)和transformer及其变形

代码:https://github.com/tensorflow/tensor2tensor

《The Annotated Transformer》翻译——注释和代码实现《Attention Is All You Need》_神洛华的博客-CSDN博客

The Annotated Transformer

本文主要参考博文并摘取文字和图片:李沐论文精读系列一: ResNet、Transformer、GAN、BERT_神洛华的博客

Transformer模型详解_爱编程真是太好了的博客

目录

1 简介

2 结论

3 导论

4 背景

5 模型架构

模型特点

李宏毅关于自回归的解释

模型架构图     

6 编码器和解码器

6.1 编码器

6.2 解码器

结构

模型训练阶段的输入

6.3 编码器和解码器结构图

6.4 为什么使用LN而不是BN?

三维表示

二维表示

7 注意力机制

7.1 Self-Attention

7.2 缩放的点积注意力(Scaled Dot-Product Attention)

步骤

矩阵实现  

为什么进行缩放

如何做mask

7.3 多头注意力

李宏毅的解释

论文的解释

使用多头自注意力的好处

7.4 Decoder 的 Encode-Decode Attention 层

7.5 注意力在Transformer中的应用(总结)

7.6 基于位置的前馈神经网络(Position-wise Feed-Forward Networks)

7.7 词嵌入和输出层Softmax

7.8 位置编码(Positional Encoding)

8 为什么使用自注意力机制

9 实验

训练数据和批处理

硬件和时间

优化器

正则化

模型配置

10 评价


1 简介

  主流的序列转换模型(由一个序列生成另一个序列)都是基于复杂的循环或卷积神经网络,这个模型包含一个编码器和一个解码器。论文提出了一个新的简单网络结构——Transformer,其仅仅是基于注意力机制,而完全不需要循环或卷积 。在两个机器翻译任务上的实验表明,该模型具有更好的性能,同时并行度更好,并且训练时间更少。泛化到其它任务效果也不错。     

     这篇文章最开始只是针对机器翻译来写的,transformer在机器翻译上效果也很好。但是随着bert、GPT等把这种架构用在更多的NLP任务上,甚至后面CV和video等也可以使用注意力机制,整个工作就火出圈了。

2 结论

  本文介绍了Transformer,这是第一个完全基于注意力的序列转换模型,用多头自注意力(multi-headed self-attention)代替了 encoder-decoder 架构中最常用的循环层。对于翻译任务,Transformer可以比基于循环或卷积层的体系结构训练更快。

  未来方向:将Transformer应用于文本之外的涉及输入和输出模式的问题中任务,以有效处理大型输入&输出任务,如图像、音频和视频等。让生成不那么时序化。 

3 导论

  序列建模和转换问题(如机器翻译)最新方法是LSTM和GRN等,后面许多研究都围绕循环语言模型和编码器-解码器体系结构进行。

  循环网络模型通常是考虑了输入和输出序列的中字符位置的计算,计算限制为是顺序的。这种机制带来了两个问题

1.时刻t的隐藏状态ht,是由上一时刻隐藏状态 ht−1和 t时刻输入共同决定的。这样可以把之前学到的历史信息都放在隐藏状态里,一个个传递下去。这种固有的时序模型难以并行化处理,无法利用GPU/TPU的并行计算功能,计算性能就很差。这些年做了一些并行化改进,但是问题依然存在。

2.存在长距离衰减问题,解码阶段越靠后的内容,翻译效果越差。如果不想丢掉,就要把ht维度设置的很高,并且在每一个时间步的信息都把它存下来,这样会造成内存开销很大。尽管 LSTM 等门控机制的结构一定程度上缓解了长期依赖的问题,但是对于特别长期的依赖现象,LSTM 依旧无能为力。

This inherently sequential nature precludes parallelization within training examples, which becomes critical at longer sequence lengths, as memory constraints limit batching across examples

  自注意力模型的权重是动态生成的,因此可以处理变长的信息序列,优势不仅仅在于对词语进行编码时能充分考虑到词语上下文中的所有信息还在于序列是一次性送入模型,通过矩阵运算做到并行化处理。attention在此之前,已经成功的应用在encoder-decoder 架构中,但主要是用在如何把编码器的信息有效的传递给解码器,所以是和RNN一起使用的。

  本文提出的Transformer,不再使用循环神经层,而是纯基于注意力机制,来构造输入和输出之间的全局依赖关系(draw global dependencies between input and output)。Transformer可以进行更多的并行化,训练时间更短,翻译效果更好。

4 背景

  使用卷积神经网络替换循环神经网络,并行计算所有输入和输出位置的隐藏表示,是扩展神经GPU,ByteNet和ConvS2S的基础,因为这样可以减少时序计算。但是CNN对长序列难以建模,因为卷积计算时,卷积核/感受野比较小,如果序列很长,需要使用多层卷积才可以将两个比较远的位置关联起来。但是使用Transformer的注意力机制的话,每次(一层)就能看到序列中所有的位置,就不存在这个问题。关联来自两个任意输入或输出位置的数据所需的操作数量,随着距离增长,对于ConvS2S呈线性,对于ByteNet呈对数,而对于Transformer是常数,因为一次就看到了。

  但是卷积的好处是,一个输出可以有多个通道,每个通道可以认为是识别不同的模式,作者也想得到这种多通道输出的效果,所以提出了Multi-Head Attention多头注意力机制,去模拟卷积多通道输出效果。

        Attention可以理解为一种序列聚焦方法,基本思想是对序列分配注意力权重,把注意力集中在最相关的序列上,在此之前已成功用于多种任务。但Transformer是第一个完全依靠self-attention,而不使用卷积或循环的的encoder-decoder 转换模型。

5 模型架构

使用encoder-decoder 结构。

模型特点

  • Encoder 和 Decoder 的输入都是单词的 Embedding 向量 和 位置编码(Positional Encoding)。
  • Encoder 的初始输入是训练集——输入序列 X(x1​,...xn​),对于句子而言xt表示第t个词,将X映射到一个连续的表示 z=(z1​,...zn​)中,其中zt是对应于xt的一个向量表示。
  • Decoder 的初始输入是训练集的标签Y,并且需要整体右移(Shifted Right)一位。此外在 Decoder 中,第二子层的输入为 Encoder 的输出(key 向量和 value 向量)以及前一子层的输出(query 向量)。解码器生成输出序列 (y1​,...ym​),每一步生成一个元素。
  • 编码器和解码器序列可以不一样长。
  • 编码器可以一次看到整个序列,但是解码器的输出序列的元素是一个个生成的。
  • 解码器是自回归(auto-regressive)模型,它在生成下一个结果时,会将先前生成的结果加入输入序列。自回归模型的特点:过去时刻的输出可以作为当前时刻的输入。

At each step the model is auto-regressive , consuming the previously generated symbols as additional input when generating the next.

  • 最后的输出要通过Linear层(全连接层),再通过 softmax 做预测。

李宏毅关于自回归的解释

Decoder先输出BEGIN 这个Token产生“机”这个输出,现在Decoder的输入有 BEGIN 和“机”,根据这两个输入,输出一个蓝色的向量,根据这个蓝色的向量确定第二个输出,再作为输入,继续输出后续的文字,以此类推

模型架构图     

        Transformer采用这种架构设计,对编码器和解码器使用堆叠的自注意力和全连接层,分别如下图的左半部分和右半部分所示。

整体上Transformer由四部分组成:

Inputs : Inputs = Word Embedding(Inputs)+Positional Embedding

Outputs : Ouputs = Word Embedding(Outputs)+Positional Embedding

Encoders stack : 由六个相同的Encoder层组成,除了第一个Encoder层的输入为Inputs,其他Encoder层的输入为上一个Encoder层的输出

Decoders stack : 由六个相同的Decoder层组成,除了第一个Decoder层的输入为Outputs和最后一个Encoder层的输出,其他Decoder层的输入为上一个Decoder层的输出和最后一个Encoder层的输出

        Outputs(shifted right):解码器在t0​时刻其实是没有输入的,其输入是编码器的输出,所以这里写的是output,shifted right就是逐个右移的意思。

        Nx:模块堆叠N次

每一个 encoder 和 decoder 的内部简版结构如下图,Encoder层和Decoder层之间的差别在于Decoder中多了一个Encoder-Decoder Attention子层,而其他两个子层的结构在两者中是相同的:

6 编码器和解码器

6.1 编码器

假设句子长度为n,那么编码器的输入是n个长为d的 embedding 向量与位置编码进行结合后的向量。

编码器由N=6个相同encoder层堆栈组成。每层有两个子层:

    1.multi-head self-attention

    2.FFNN层(前馈神经网络层,Feed Forward Neural Network),其实就是MLP,为了fancy一点,就把名字起的很长。

特点:

  • 两个子层都使用残差连接(residual connection),即每个子层的输出是LayerNorm(x + Sublayer(x)),其中Sublayer(x)是当前子层的函数。
  • 然后进行层归一化(layer normalization)
  • 为了简单起见,模型中的所有子层以及嵌入层的向量维度都是dmodel= 512(如果输入输出维度不一样,残差连接就需要做投影,将其映射到统一维度)。这和之前的CNN或MLP做法是不一样的,比如CNN会改变空间维度和通道维度
  • 各层统一维度使得模型比较简单,只有N和 dmodel​两个参数需要调。这个也影响到后面一系列网络,比如bert和GPT等等。

  • 6.2 解码器

  • 结构

  • 解码器同样由 N=6个相同的decoder层堆栈组成,每个层有三个子层。

  •     1.masked multi-head self-attention:做预测的时候,接受encoder 的输入,和自己之前的输出,决定接下来输出的一个向量

  •     2.Encoder-Decoder Attention :编码器输出最终向量,将会输入到每个解码器的Encoder-Decoder Attention层,用来帮解码器把注意力集中输入序列的合适位置。

  •    3. FFNN

  • 与编码器类似,每个子层都使用残差连接,然后进行层归一化。

  • 模型训练阶段的输入

  • Decoder的初始输入:训练集的标签Y,并且需要整体右移(Shifted Right)一位。
  • Shifted Right 的原因:t-1时刻需要预测 t 时刻的输出,所以 Decoder 的输入需要整体后移一位。

举例说明:我爱中国I Love China

位置关系:

  • 0-“I”
  • 1-“Love”
  • 2-“China”

操作:整体右移一位(Shifted Right)

  • 0-</s>【起始符】目的是为了预测下一个Token
  • 1-“I”
  • 2-“Love”
  • 3-“China”

具体步骤:

Time Step 1

  • 初始输入: 起始符</s> + Positional Encoding
  • 中间输入:(我爱中国)Encoder Embedding
  • Decoder:产生预测 I

Time Step 2

  • 初始输入:起始符</s> + I + Positonal Encoding
  • 中间输入:(我爱中国)Encoder Embedding
  • Decoder:产生预测 Love

Time Step 3

  • 初始输入:起始符</s> + I + Love + Positonal Encoding
  • 中间输入:(我爱中国)Encoder Embedding
  • Decoder:产生预测 China
  • 6.3 编码器和解码器结构图

  •  假设一个 Transformer 是由 2 层编码器和两层解码器组成的,那么结构如下图所示:

decoder 有很多层 self-attention,Transformer 论文中,每一层 self-attention 的输出都是与 encoder 最后的输出 sequence 做 cross attention。但是也可以用不同的设计,比如Decoder可以连接Encoder中的许多层而不一定只是最后一层。

6.4 为什么使用LN而不是BN?

Normalization有很多种,但是它们都有一个共同的目的,那就是把输入转化成均值为0,方差为1的数据。我们在把数据送入激活函数之前进行 Normalization,因为我们不希望输入数据落在激活函数的饱和区。

三维表示

输入可以看成3维向量:

  • 对于CV任务,N是样本数,C是通道数,高是图片的H×W
  • 对于NLP任务,N是样本数,C是序列长度,高是每个词的向量长度(512)

Batch Normalization和Layer Normalization可以用下图表示。图中要在蓝色的区域内做Normalization

二维表示

Batch Normalization:在特征/通道维度做归一化,即归一化不同样本的同一特征。

  • 计算不定长序列时,不够长的序列后面会pad 0,这样做特征维度归一化缺少实际意义。
  • 输入序列长度变化大时,不同 batch 计算出来的均值和方差抖动很大。
  • 预测时使用训练时记录下来的全局均值和方差。如果预测时新样本特别长,超过训练时的长度,那么超过部分是没有记录的均值和方差的,预测会出现问题。

Layer Normalization:在每一个样本上计算均值和方差,进行归一化,即归一化一个样本所有特征。

  • NLP任务中一个序列的所有token都是同一语义空间,进行LN归一化有实际意义
  • 因为是在每个样本内做的,序列变长时,相比BN计算的数值更稳定。
  • 不需要存一个全局的均值和方差,预测样本长度不影响最终结果。

Batch Normalization和Layer Normalization的实现细节,可以参考Batch Normalization和Dropout_iwill323的博客

CS231n笔记-CNN网络结构_iwill323的博客

7 注意力机制

7.1 Self-Attention

Attention 和 Self-Attention 的区别:

  • 1.以 Encoder-Decoder 框架为例,输入 Source 和输出 Target 内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attention 发生在 Target 的元素 Query 和 Source 中的所有元素之间。
  • 2.Self Attention是 Source 内部元素之间发生的Attention 机制,也可以理解为 Target=Source 这种特殊情况下的 Attention。

所谓self-attention自注意力机制,就是探索当前序列(self)中每一个元素对当前元素(self)的影响程度(相关程度),而传统attention的注意力概率分布来自外部。两者具体计算过程是一样的,只是计算对象发生了变化而已。

比如我们当前要翻译的句子为The animal didn’t cross the street because it was too tired。在翻译it时,它究竟指代的是什么呢,street还是animal?要确定it指代的内容,毫无疑问我们需要同时关注到这个词的上下文语境中的所有词。下图是模型的最上一层(下标0是第一层,5是第六层)Encoder的Attention可视化图。可以看到,在编码it的时候有一个Attention Head注意到了Animal,因此编码后的it有Animal的语义。

self-attention 会使用每个输入向量计算出三个新的向量,分别称为Query、Key、Value,这三个向量是用 embedding 向量(包含位置编码)与不同的矩阵相乘得到的结果,矩阵是随机初始化的。输出被计算为value的加权求和,其中每个value的权重由query与对应key计算所得,其实就是query与对应key相似度,该分数值决定了在某个位置 encode 一个词时,对输入句子的其他部分的关注程度(也即其他部分对该位置元素的贡献程度)。输出也是向量,由于是加权平均,所以输出和value的维度一致。

 

不同的相似函数导致不一样的注意力版本,有两个最常用的attention函数:

  • 加法attentionhttps://arxiv.org/abs/1409.0473

使用具有单个隐层的前馈网络计算,q和k维度不一致也可以进行;

  • 点积(乘法)attention

实现细节见下文。虽然理论上点积attention和加法attention复杂度相似,但在实践中,点积attention可以使用高度优化的矩阵乘法来实现,因此点积attention计算更快、更节省空间。

比较:当向量维度(下文的dk)的值比较小的时候,这两个机制的性能相差相近,当dk比较大时,加法attention比点积attention性能好。

transformer用的是缩放的点积注意力Scaled Dot-Product Attention

7.2 缩放的点积注意力(Scaled Dot-Product Attention)

步骤

  • 输入为query、key(维度都是dk,一般512​)以及values(维度是dv​)。
  • 计算query和所有key的点积,得到两个向量的相似度(结果越大相似度越高);然后对每个点积结果除以sqrt(dk​)​
  • 点积结果输入softmax函数,对每一行做softmax,行与行之间独立,结果就是value的权重。
  • 对value进行加权求和

下图中α带有'上标,代表经过了softmax处理

也可以参考下图,thinking machines是输入序列

矩阵实现  

在实际的应用场景,需要把上面的向量计算变为矩阵的运算。​下图所示为矩阵运算的形式。其中X为输入对应的词向量矩阵,WQ、WK、WV为相应的线性变换矩阵,Q、K、V为X经过线性变换得到的Query向量矩阵、Key向量矩阵和Value向量矩阵

 计算的输出矩阵为:

上图中Q的形状是(n,dk),K的形状是(m,dk),结果形状是(n,m),n是query的个数,m是key的个数,一行就是一个query对所有key的内积值。V矩阵形状是(m,dv),A和V相乘结果是(n, dv),每一行就是我们要的输出。

上图中的z1和 z2,再通过全连接层,就能输出该 Encoder 层的输出r1 和r2 ,作为下一层 encoder 的输入。

Self-Attention 是所有的输入向量共同参与了这个过程。 x1和 x2互相不知道对方的信息,但因为在第一个步骤 Self-Attention 中发生了信息交换,所以r1 和r2各自都有从x1和 x2得来的信息了。

下图来自李宏毅课程,也比较清晰,不过矩阵形状和该论文中的规定相比差了一个转置

        注:K、V 矩阵的序列长度是一样的(加权求和),而 Q 矩阵的序列长度可以和前两者不一样;这种情况发生在:解码器部分的Encoder-Decoder Attention层中,Q 矩阵是来自解码器输出tgt,而 K、V 矩阵则是来自编码器最后的输出memory。即tgt2 = self.multihead_attn(tgt, memory, memory, attn_mask=memory_mask,key_padding_mask=memory_key_padding_mask)[0]

        value 的维度和向量 query 或 key 的维度不一定相同,但是Q和K的维度必须一样,因为要计算点积。

为什么进行缩放

维度dk很大时,点积(Q*K的结果矩阵中的值)结果可能很大,最大的值softmax结果接近1,剩下的值接近0,softmax结果向两端靠拢,反向传播时发生梯度消失,相当于训练快要收敛了,跑不动。为了抵消这种影响,我们将点积缩小1/sqrt(dk​)​​ ​倍。

We suspect that for large values of dk, the dot products grow large in agnitude, pushing the softmax function into regions where it has extremely small gradients. To counteract this effect, we scale the dot products by 1/sqrt(dk​)​​.

To illustrate why the dot products get large, assume that the components of q and k are independent random variables with mean 0 and variance 1. Then their dot product has mean 0 and variance dk.

从softmax求梯度的角度理解,参见反向传播之一:softmax函数 - 知乎:

求梯度结果:

softmax结果向两端靠拢,yi和yj要么接近0,要么接近1,带入上式,梯度接近为0

如何做mask

mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。其中,padding mask 在所有的 scaled dot-product attention 里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到。

  • Padding Mask

       很多时候,每个批次输入序列长度是不一样的,但机器学习模型一般要求输入的大小是一致的,所以要对输入序列根据最大长度进行对齐,具体来说就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,attention机制不应该把注意力放在这些位置上,所以我们需要进行Padding Mask,具体的做法是,将这些没有意义的位置上的值置为一个很小的数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0。

        padding mask 实际上是一个张量,每个值都是一个Boolean,值为 false 的地方就是要进行处理的地方。

  • Sequence mask

        decoder做预测的时候,t 的时刻的解码输出应该只能依赖于 t 时刻之前的输出,不能看见未来的信息,而计算的时候,Q会和所有的K做计算。在Q和K的计算结果经过 Softmax 层之前,对应masked位置使用一个很大的负数-inf,使得softmax之后其对应值为0,从而屏蔽当前位置之后的那些位置。

        具体做法,是产生一个下三角矩阵,这个矩阵的上三角的值全为0,下三角的值全为输入矩阵对应位置的值,这样就实现了在每个时刻对未来信息的掩盖。

  •  对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。
  •  其他情况,attn_mask 一律等于 padding mask。


mask部分参考:爱编程真是太好了的博客

7.3 多头注意力

有时候需要考虑多种相关性,于是计算多组 q,k,v,不同的 q,k,v 负责查找不同种类的相关性。可以类比CNN中同时使用多个卷积核的作用,直观上讲,多头的注意力有助于网络捕捉到更丰富的特征/信息。

李宏毅的解释

下图为 2 heads 的情况, (q,k,v) 由一组变成多组,第一类的放在一起算,第二类的放在一起算。相关性变多了,所以参数也增加了,原来只需要三个 W矩阵,现在需要六个 W矩阵。下图是算第一种相关性的过程

下图是计算第二种相关性的过程

与单个的 self attention 相比,Multi-head Self-attention 最后多了一步:由多个输出组合得到一个输出。将刚刚得到的所有 b组成一个向量,再乘以矩阵,输出一个 bi,目的就是将不同种类的相关性整合在一起,成为一个整体,作为 a1 的输出 b1。下面是一个 2 heads 的例子

论文的解释

Instead of performing a single attention function with dmodel-dimensional keys, values and queries, we found it beneficial to linearly project the queries, keys and values h times with different, learned linear projections to dk, dk and dv dimensions, respectively. On each of these projected versions of queries, keys and values we then perform the attention function in parallel, yielding dv-dimensional output values. These are concatenated and once again projected, resulting in the final values

        在Multi-head Attention中,每个head的输入都只是模型的输入词向量矩阵的一部分,从词向量矩阵的最后一维进行切分。论文采用 h=8个head,模型输入的词向量矩阵大小为n∗dmodel,则对每个head使用dk​=dv​=dmodel​/h=64,每个head的输入矩阵大小为n∗(dmodel/8),最后得到8个矩阵Z。由于每个头都降了维,所以总计算成本与具有全部维度的单个head attention相似。 输出要做concat,然后使用WO矩阵进行投影,其中映射由权重矩阵完成:

  •  输入 X 和8组权重矩阵 WQ,WK,WV相乘,得到 8 组 Q, K, V 矩阵。进行attention计算,得到 8 组 Z 矩阵。

  • 把8组Z矩阵在矩阵的最后一个维度上进行拼接,得到一个大的矩阵,乘以权重矩阵 WO,将其映射回 d 维向量(相当于将多维特征进行汇聚),得到最终的矩阵 Z。这个矩阵包含了所有 attention heads(注意力头) 的信息。

  •  矩阵Z会输入到 FFNN层。(前馈神经网络层接收的也是 1 个矩阵,而不是8个。其中每行的向量表示一个词)

完整的过程:

使用多头自注意力的好处

  • 多语义匹配:本身缩放点积注意力是没什么参数可以学习的,就是计算点积、softmax、加权和而已。但是使用Multi-head attention之后,投影到低维的权重矩阵  WQ, WK ,  WV是可以学习的,而且有h=8次学习机会。使得模型可以在不同语义空间下学到不同的的语义表示,也扩展了模型关注不同位置的能力。类似卷积中多通道的感觉。

      例如,“小明养了一只猫,它特别调皮可爱,他非常喜欢它”。“猫”从指代的角度看,与“它”的匹配度最高,但从属性的角度看,与“调皮”“可爱”的匹配度最高。标准的 Attention 模型无法处理这种多语义的情况。

  •  注意力结果互斥:自注意力结果需要经过softmax归一化,导致自注意力结果之间是互斥的,无法同时关注多个输入。使用多组自注意力模型产生多组不同的注意力结果,则不同组注意力模型可能关注到不同的输入,从而增强模型的表达能力。

那么我们如何来理解多个head分别注意到的内容呢?下面给出两个图来举例说明。第一个图给出了在翻译it时两个head分别注意到的内容,从中可以很明显的看到,第一个head注意到了animal,而第二个head注意到了tired,这就保证了翻译的正确性。

第二个图中给出了所有head分别注意到的内容,这时候attention究竟能否抓取到最需要被获取的信息变得不再那么直观。

7.4 Decoder 的 Encode-Decode Attention 层

在Decoder中的第二个注意力层,输入不仅有前一层的输出,还有来自 Encoder 的输出。把 Encoder 产生的向量作为Decoder 的 key 和 value,Decoder 的向量作为query,然后进行Attention。

在做预测时,步骤如下:

  1. 给 Decoder 输入 Encoder 对整个句子 embedding 的结果和一个特殊的开始符号</s>。Decoder 将产生预测,在我们的例子中应该是 I
  2. 给 Decoder 输入 Encoder 的 embedding 结果和</s> I,在这一步 Decoder 应该产生预测 am
  3. 给 Decode r输入 Encoder 的 embedding 结果和</s> I am,在这一步 Decoder 应该产生预测a
  4. 给 Decoder 输入 Encoder 的 embedding 结果和</s> I am a,在这一步 Decoder 应该产生预测student
  5. 给 Decoder 输入 Encoder 的 embedding 结果和</s> I am a student, Decoder 应该生成句子结尾的标记,Decoder 应该输出</eos>
  6. 然后 Decoder 生成了</eos>,翻译完成。

7.5 注意力在Transformer中的应用(总结)

Transformer中用3种不同的方式使用multi-head attention:

  • encoder包含self-attention层。在self-attention层中,所有key,value和query来自同一个地方,即原始输入或encoder中前一层的输出。每一层的输出其实就是输入的加权和(权重来自输入本身,即各个元素的相似度),于是encoder中的每个位置都可以关注到encoder上一层的所有位置。对于多头,会学习出h个不同的距离空间。假设句子长度为n,那么编码器的输入是n个长为d的向量,最后一层向外输出就是n个长为d的向量。
  • decoder中的masked-self-attention层。它让decoder中的每个位置都关注decoder层中当前位置之前的所有位置(包括当前位置)。为了保持解码器的自回归特性,需要防止解码器中的信息向左流动,后面位置的权重要设为0。在缩放点积attention的内部,通过屏蔽softmax输入中所有的非法连接值(设置为 −∞)实现了这一点。输入是m个长为d的向量,最后一层向外输出是m个长为d的向量。
  • encoder-decoder的attention层中,不再是自注意力。query来自前面的decoder层(n个长为d的向量),而keys和values来自encoder的输出(m个长为d的向量)。这使得decoder中的每个位置都能关注到输入序列中的所有位置。
 

7.6 基于位置的前馈神经网络(Position-wise Feed-Forward Networks)

  编码器和解码器中的每个层都包含一个全连接的前馈网络,该前馈网络应对每个向量单独计算,可以并行。该前馈网络包括两个线性变换,并在两个线性变换中间有一个ReLU激活函数。

In addition to attention sub-layers, each of the layers in our encoder and decoder contains a fully connected feed-forward network, which is applied to each position separately and identically

  Position-wise 就是把MLP对每个token作用一次,且作用的是同一个MLP。说白了就是MLP只作用于最后一个维度d=512。两层线性变换第一层输入512维,输出2048维;第二层输入2048维,输出512维,好做残差。

  对比transformer和RNN,发现两者都是使用MLP来进行语义空间的转换,但区别是二者传递信息的方式不一样:(图来自神洛华的博客)

        因为前面的attention层已经抓取了输入序列的相关信息,并做了一次汇聚(拼接后映射回d维),所以attention层结果已经包含了感兴趣的输入序列中信息,所以后面在做MLP投影映射到想要的语义空间时,只需要对每个position(token)单独做MLP就行。从attention抽取序列信息,通过MLP映射到需要的语义空间(非线性变换),就整个是transformer处理信息的基础过程。     

比较:

  • RNN是把上一时刻输出和t时刻输入一起,传递给当前时刻,并用MLP做语义转换。
  • Transformer是通过attention层为每个token直接关联全局的序列信息,然后用MLP做语义转换。

为什么MLP Block先升维再降维?

    神经网络中线性连接可以写成  d=W⋅x。其中三者维度分别是m×1、m×n、n×1。

  •         m>n:升维,将特征进行各种类型的特征组合,提高模型分辨能力
  •         m<n:降维,去除区分度低的组合特征。所以一般神经网络都是先做宽再做窄。

7.7 词嵌入和输出层Softmax

  • 1.将输入token转换为dmodel维的向量,这是embedding。
  • 2.当 decoder 层全部执行完毕后,需要在结尾再添加普通的线性变换和 softmax 层,将解码器输出转换为概率,预测下一个token,在最后的softmax函数前这个操作也是embedding。

在我们的模型中,输入输出两个嵌入层和pre-softmax线性变换共享相同的权重矩阵,这样训练起来简单一些。

     这些权重要乘以 sqrt(dmodel​)​,因为学embedding时多多少少会把一个向量的L2 Norm(L2范数)学到相对比较小,比如接近1,于是向量维度一大,学到的权重值就会很小。但是位置编码不会把权重的L2 Norm学成接近1,所以把权重乘上sqrt(dmodel​)​​之后,token embedding和位置编码Positional Encoding相加的时候,在一个量级上。(都在-1到1之间)

7.8 位置编码(Positional Encoding)

  在同一个句子中,即使所有的词都相同但词序的变化也可能导致句子的语义完全不同。然而Attention计算时本身是不考虑词的顺序的,假如改变了序列顺序,那么计算出来的结果还是一样的,这是不合理的。所以我们必须在序列中加入关于词符相对或者绝对位置的一些信息,这样的话如果两个词在不同的位置出现了,虽然它们的Embedding是相同的,但是由于位置编码不同,最终得到的向量也是不同的。

        为了处理这个问题,transformer给encoder层和decoder层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,都是dmodel​。这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。有多种位置编码可以选择

  在这项工作中,使用不同频率的正弦和余弦函数:

  其中pos是指当前词在句子中的位置,i是指词向量中每个元素的index,可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码。这些波长形成一个从 2π 到 10000⋅2π的集合级数。

        为什么这样编码就能引入词语的位置信息呢?如果只按照第一个公式那样根据输入矩阵的下标值进行编码的话,显然编码的是词汇的绝对位置信息,即绝对位置编码。但词语的相对位置也是非常重要的,这也是Transformer中引入正弦函数的原因进行相对位置编码的原因。正弦函数能够表示词语的相对位置信息,主要是基于以下两个公式,这表明位置k+p的位置向量可以表示为位置k的特征向量的线性变化,这为模型捕捉单词之间的相对位置关系提供了非常大的便利。

最终编码向量每个元素值都是在-1到1之间,讲到这里,为什么embedding的权重要乘上sqrt(dmodel​)​​,就可以理解了。

position_encoding = np.array(
    [[pos / np.power(10000, 2.0 * (j // 2) / d_model) for j in range(d_model)] for pos in range(max_seq_len)])

position_encoding[:, 0::2] = np.sin(position_encoding[:, 0::2])
position_encoding[:, 1::2] = np.cos(position_encoding[:, 1::2])

  此外,我们会将编码器和解码器堆栈中的embedding和位置编码的和再加一个dropout。对于基本模型,我们使用的dropout比例是Pdrop​=0.1。

8 为什么使用自注意力机制

使用self-attention是基于三个问题,也就是下图中后三列

    上图n是序列长度,d是token维度。

    Attention:

  • 计算复杂度:矩阵Q*K,两个矩阵都是n行d列,所以相乘时复杂度是O(n2⋅d),其它还有一些计算量但影响不大;
  • 顺序计算量:整个计算主要就是矩阵乘法,矩阵里面并行度是很高的,所以可以认为顺序计算量就是O(1);
  • 最大路径长度:也就是从一个点关联到任何一个点的路径长度。attention是一次看到整个序列,所以只需要一次操作,复杂度为 O(1)

  k就是卷积核大小,一般是3、5之类的;而n和d现在的模型都是做到几百几千,所以可以认为前三种操作,计算复杂度差不多,但是并行度是attention和卷积更好;且attention在信息的融合上更好(最大路径长度=1)。

     实际上attention对模型的假设更少,导致模型需要更多的数据和更大的模型才能训练到和RNN或CNN差不多的效果。所以现在基于transformer的模型都是很大,训练起来很贵。

9 实验

训练数据和批处理

  在标准的WMT 2014 English-German dataset上进行了训练,其中包含约450万个句子对。这些句子使用byte-pair编码进行编码,源语句和目标语句共享大约37000个词符的词汇表。对于英语-法语翻译,我们使用大得多的WMT 2014 English-French dataset,它包含3600万个句子,并将词符分成32000个word-piece词汇表。序列长度相近的句子一起进行批处理。每个训练批处理的句子对包含大约25000个源词符和25000个目标词符。

  bpe编码,是因为英语/德语中有很多ing之类的词根,又或者一个动词有几种形式。如果直接使用token进行表示,词表就太大了。bpe就可以把词根提取出来,这样词表会小很多,而且还能表示不同时态等等这些相关信息。

  共用词表可以使编码器和解码器共用一个embedding,权重共享,模型更简单。

硬件和时间

        在一台具有8个NVIDIA P100 GPU的机器上训练模型。每个batch训练步骤耗时约0.4秒。基础模型共训练了10万步或12小时。对于我们的大型模型(在表3的底部描述),步长为1.0秒。大型模型接受了30万步(3.5天)的训练。

     因为TPU非常适合做很大的矩阵乘法,所以后面Google都推荐自己的员工多使用TPU

优化器

我们使用Adam优化器,其中 β1​=0.9, β2​=0.98并且ϵ=10−9。根据以下公式在训练过程中改变学习率:

这对应于在第一次 warmup_steps步中线性地增加学习速率,并且随后将其与步数的平方根成比例地减小。我们使用 warmup_steps=4000。

正则化

采用两种正则化:

  • Residual Dropout

     将dropout应用到每个子层(多头注意力和MLP)的输出上,在子层输出进入残差连接之前,和进入LayerNorm之前,都使用dropout。此外,在编码器和解码器中,token embedding+Positional Encoding时也使用了dropout。对于base模型,我们使用drop概率为 0.1。

  • Label Smoothing

       在训练过程中,我们使用的label smoothing的值为ϵls= 0.1。softmax要逼近于1,其输入几乎要无穷大,这是很不合理的,会使模型训练困难。ϵls= 0.1意味着,对于正确的词,只需要softmax到0.1就行了。这让模型不易理解,因为模型不确信度下降,但提高了准确性和BLEU得分。

模型配置

  可以看到模型虽然比较复杂,但是没有多少超参数可以调,使得后面的人工作简单很多。

10 评价

  Transformer(attention机制)能用在几乎所有NLP任务上并且提升性能,类似于CNN对整个CV领域的革新,CNN提供了一个框架,不需要那么多的特征提取或者模型建模,学会CNN就行了。Transformer也是一样,不需要那么多的文本预处理,不需要为每个任务设计不同的架构,Transformer这个架构就能够在各个任务上取得好的成绩,并且预设的模型也让大家的训练变得更加简单

  现在transformer在CV、语音、video等领域也广泛使用,等于一个架构可以适用于所有领域,任何个领域的突破,能在别的领域都能被使用,减少新技术的应用时间。 而且Transformer可以融合多模态的数据(文字、图片、语音等),大家都用同一个架构提取特征,可以都抽取到同一个语义空间,使得我们可以用文字、图片、语音等训练更大更好的模型。

  虽然Transformer效果这么好,但是对它的理解还在初级阶段。

  • 不是只需要attention就足够了。最新的一些结果表明,attention在里面只是起到一个聚合序列信息的作用 ,但是后面的MLP/残差连接是缺一不可的,如果去掉的话,模型是基本训练不出什么的。
  • Attention不会对序列的顺序建模。为何Attention能打败RNN?RNN可以显式地建模序列信息,应该比attention更好。现在大家觉得attention使用了更广泛的归纳偏置,使得他能处理更一般化的信息;这也是为什么attention没有做空间上的假设,但是比CNN/RNN能做到更好的效果。代价就是假设更一般,所以抓取数据信息能力变差,必须使用更大的模型和更多的数据才能训练到一个比较好的效果,因此transform模型一个比一个大,一个比一个贵。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot整合Shiro环境搭建

SpringBoot整合Shiro环境搭建导入 SpringBoot 和 Shiro 整合包的依赖&#xff1a; <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --> <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring<…

XXL-Job分布式任务调度框架-- 定时任务注册案例2

一 案例操作 1.1 新建工程 简单建一个springboot的工程&#xff0c;如下图结构 1.2 工程的配置 1.pom中依赖配置 2&#xff09;代码 <!-- xxl-job --><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactI…

ANTLR4入门(一):Windows安装antlr4命令行环境

最近开始学习ANTLR4&#xff0c;《ANTLR 4权威指南》这本书是看完了&#xff0c;现在开始实践&#xff0c;本系列文记录实践过程中的遇到的问题解决过程及心得体会 下载 从antlr官方网站下载最新的antr4版本(jar)&#xff1a;https://www.antlr.org/download.html 目前最新的…

牛客java刷题知识点总结(七)

instanceof运算符作用 instance是java的二元运算符&#xff0c;用来判断他左边的对象是否为右面类&#xff08;接口&#xff0c;抽象类&#xff0c;父类&#xff09;的实例。 我们考虑的时候&#xff0c;左边的对象如果是父类的引用指向子类的对象&#xff0c;我们用子类对象的…

C++【并查集】

文章目录一、并查集是什么并查集的简单表示并查集的合并并查集的代码实现并查集小练习1并查集小练习2并查集的压缩问题一、并查集是什么 并查集是一个森林 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元素…

CS61A Lab 4

更好的阅读体验 Lab 4: Recursion, Tree Recursion lab04.zip What Would Python Do? Q1: Squared Virahanka Fibonacci Use Ok to test your knowledge with the following “What Would Python Display?” questions: python3 ok -q squared-virfib-wwpd -u✂️Hint: If…

CountDownLatch类的使用

&#x1f388;专栏链接:多线程相关知识详解 目录 一.CountDownLatch的介绍 二.CountDownLatch类里面的方法 三.CountDownLatch的两种应用场景 ①一等多情况 ②多等一情况 一.CountDownLatch的介绍 CountDownLatch是一种用来控制多线程的工具类,它被称为门阀、计数器或者…

LeetCode HOT 100 —— 301.删除无效的括号

题目 给你一个由若干括号和字母组成的字符串 s &#xff0c;删除最小数量的无效括号&#xff0c;使得输入的字符串有效。 返回所有可能的结果。答案可以按 任意顺序 返回。 思路 DFS 回溯算法&#xff1a; 首先最终合法的方案&#xff0c;必然有左括号的数量 右括号的数量 …

钉钉获取免登用户信息

大家好&#xff0c;这里是一口八宝周&#x1f44f; 欢迎来到我的博客❤️一起交流学习 文章中有需要改进的地方请大佬们多多指点 谢谢&#x1f64f; 最近好像搞了个什么钉钉小程序&#xff0c;具体做什么咱也不知道&#xff0c;就让我搞一个钉钉获取免登录用户信息的接口出来&…

计网理论模拟

一. 单选题&#xff08;共10 题&#xff0c;20.0分&#xff09; 1. (单选题,2.0分)网络协议主要由 3 个基本要素组成&#xff0c;即&#xff08; &#xff09; A. 层次、语义和同步B. 语法、原语和同步C. 语法、语义和同步D. 语法、语义和功能 正确答案: C 2. (单选题,2.0分…

计算机毕业设计ssm+vue基本微信小程序的智能图书管理系统

项目介绍 本设计旨在研究一种社区图书管理系统设计与实现系统,以各种浏览器web页面加上云服务器后端服务系统,通过这一设计过程,进一步熟悉web前端开发技术和云服务器后端开发技术和方法,培养理论联系实际及知识的综合运用能力。 图书管理系统可以有效实现图书管理的规范化、系…

SAP Gateway 后台模型的缓存设置

/iwbep/cl_mgw_med_provider 类里的成员 mv_cache_active: 这个 cache 默认是开启状态。 调用 OData 服务的 MPC_EXT 类的 get_last_modified 方法获取最后一次修改的时间戳。这个时间戳(timestamp)也会影响到 cache 的行为&#xff0c;我们后续也会详细讨论。 第12 行 super 方…

PySpark--spark local 的环境部署

Spark环境搭建-Local 环境搭建 基本原理 本质&#xff1a;启动一个JVM Process进程(一个进程里面有多个线程)&#xff0c;执行任务Task Local模式可以限制模拟Spark集群环境的线程数量, 即Local[N] 或 Local[*]其中N代表可以使用N个线程&#xff0c;每个线程拥有一个cpu core。…

【使用Netty实现群发消息】

使用Netty实现群发消息netty简单介绍实现群发流程图代码实现NettyServer 类MyChannelInitializer 类MyServerHandler 类ChannelHandler 类Netty 依赖效果展示netAssist 工具启动Netty server打开netAssist 工具netty简单介绍 Netty是由JBOSS提供的一个java开源框架&#xff0c…

第三十一章 linux-模块的加载过程

第三十一章 linux-模块的加载过程 文章目录第三十一章 linux-模块的加载过程sys_init_modulestruct moduleload_module在用户空间&#xff0c;用insmod这样的命令来向内核空间安装一个内核模块&#xff0c;本节将详细讨论模块加载时的内核行为。当调用“insmod demodev.ko”来安…

通讯录的思路与实现(C语言)

目录 前言 程序的分装 程序的结构 函数实现 通讯录的初始化 通讯录的扩容 将数据保存到本地 增加联系人 显示通讯录所有联系人 目标联系人的检索(根据名称) 目标联系人的检索(根据号码) 检索发展来的函数 删除联系人 查询目标联系人 联系人信息的更改 按名称对通…

Python写个“点球大战”小游戏

大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 看过我Python入门教程的朋友应该会看到其中有提到一个点球小游戏的作业。 在世界杯决赛即将到来之际&#xff0c;我们再来回顾一下这个小游戏。对于刚刚学习编程不久的同学&#xff0c;这是个不错的练手习题&…

(二)RT-Thread入门——线程管理

目录 线程管理 线程管理特点 线程工作机制 线程控制块 线程属性 线程栈 线程状态 线程优先级 时间片 线程入口函数 无限循环模式 顺序执行或有限次循环模式 线程错误码 线程状态切换 线程操作 创建动态线程 删除 初始化静态线程 脱离 获得当前线程 让出…

数据结构基础篇》》用c语言实现复数的八个基本运算

数据结构开讲啦&#xff01;&#xff01;&#xff01;&#x1f388;&#x1f388;&#x1f388; 本专栏包括&#xff1a; 抽象数据类型线性表及其应用栈和队列及其应用串及其应用数组和广义表树、图及其应用存储管理、查找和排序将从简单的抽象数据类型出发&#xff0c;深入浅出…

B-013 缓启动电路设计

缓启动电路设计1 简介2 案例分析2.1 电路说明2.2 原理分析3 电路参数设定说明1 简介 缓启电路的供电是由一个PMOS控制通断的&#xff0c;软启动的设计是让PMOS的导通时间变缓&#xff0c;电路上的做法是在PMOS的栅极和源极之间接一个合适的电容&#xff0c;PMOS的导通时间就会…