之前组会师兄师姐分享的内容经常提到 vit (Vision Transformer),由于自己没有学习过这个模型,所以打算最近学习以下这个模型,但是 Transformer 我也没有详细的学习过,只是有所耳闻,所以在开始 vit 学习前,先来补一下 Transformer 的知识。
1.背景
在 NLP 领域,由于我们所面对都是序列数据,所以我们通常使用 RNN 来解决研究 NLP 领域内的问题,但由于 RNN 自身的步长序列问题,存在步长依赖的缺陷。同时 RNN 采取线性序列结构不断从前往后收集输入信息,这种情况在反向传播的时候存在优化困难问题,因为反向传播路径太长,容易导致严重的梯度消失或梯度爆炸问题。所以研究者们为了解决 RNN 存在的问题来实现 NLP 领域的前进,Transformer 模型应运而生。
Transformer 由 Google 于2017年6月发布的文章《Attention is all you need》提出。Transformer在当年完成 NLP 领域11项任务的 SOTA,这对 NLP 领域来说,无疑是改写历史的时刻。那既然它如此强大,所以我们肯定要学习一下。
2.模型结构
我从论文中截取了最原生的结构图,如下图。
可以清楚的看到 Transformer 是一种标准的 Encoder - Decoder 结构模型,左边是encoder结构,右边是decoder结构。
2.1Encoder
左边编码器由6个layer堆叠而成(也就是6个灰色块),每个层由两个sublayer组成,一个是多头注意力机制 Multi-Head-Attention,一个是position wise fully connected feed-forward network(MLP),很明显,在这里我们要着重注意这个多头注意力机制 Multi-Head-Attention ,这个是Transformer比较重要的创新点:
想要搞清楚多头注意力机制,我们就得讲一下自注意力机制 (self - Attention)。自注意力机制的基本思想是,在处理序列数据时,每个元素都可以与序列中的其他元素建立关联,而不仅仅是依赖于相邻位置的元素。它通过计算元素之间的相对重要性来自适应地捕捉元素之间的长程依赖关系。
2.1.1自注意力
自注意力模型采用(Query—— Key ——Value)模式,计算过程如图。
这张图我第一次看也是感觉有点懵的状态,我查了一些资料,感觉有一篇分析写得好,接下来我搭配着博文分享自己的理解。
上面的图是出自博文的自注意力机制中的图。接下来我们按步骤讲解。
2.1.1.1embedding
我们将要输入的序列先进行分词,会获得 x1,x2 这样的词,我们第一步要做的工作就是将词进行 embedding 操作,也就是将词变为词向量。你可以理解为将词变为词的特征向量。
2.1.1.2.Q K操作
自注意力机制中我认为最有亮点也是和注意力最直接有关的操作就是QK操作,我们将上一步获得的特征向量分别与Q矩阵,K矩阵,V矩阵相乘。
也就是图中第2步我们做的计算,我们先获得 qi,ki,vi ,然后来进行QK操作,其实就是K的转置乘以Q就完成了QK。QK相乘其实是为了计算当前字和其他字的关系,可以理解为上下文的关系。当然,为了a1 和 a2 的关系,我们当然要让 q1 乘以 k2。在这我们用下式来计算:
这样可以获得a1 和其他字的关系。根号d是为了控制两个相乘的大小。这里有很多计算方法,在transformer用这个计算方法。
这样我们就可以获得字和字之间的权重系数,也就是获得上下文的关系,接下来我们还有一个v操作。
2.1.1.3.V操作
我们将QK操作获得的a11,a12经过一个softmax层直接与 v 进行相乘然后再相加。
这样我们就完成 “自” 注意力这个操作。QKV计算后的最终输出代表的是输入序列中每个元素与其他元素之间的注意力分数。这个输出将用于计算该元素与其他元素之间的注意力权重和自注意力表示。
其实我自己之前也在这发懵,我们自注意力机制算来算去到底在算什么,其实就是通过计算注意力分数,不断的训练迭代去调整注意力权重,让需要被注意的地方的分数变得越来越大,也就有利于我们下游任务的实现。
自注意力机制基本上就是以上的内容。多头注意力其实就是多个自注意力的结合。从名字就可以看出来多头注意力代表代表着QKV的次数要变多的意思。所以我们来看下多头注意力机制的图。
2.1.2多头注意力
从上图可以看出,多头注意力在注意力的基础上,QKV上又有一层QKV,这也形象的代表着多头的意思。
其实可以发现基本和自注意力是一样样的,只是我们需要再多一步计算 q(i,1)和 q(i,2)的计算,当然在后面的每一步计算中,我们都需要算两次。最终我们需要将不同头获得注意力分数进行拼接通过线性映射层获得最终的注意力分数。
感觉说的有点苍白,我发现了一张比较清楚的图,放在下面。
可以看到我们得到每个头的 b(注意力分数)值,然后进行 concat,再来一个线性层,就可以输出最终的 b 了。
其实可以发现,多头注意力和注意力其实没有太大的区别,就是多了一层而已,类似自注意力的堆叠。多头注意力可以更好的考虑到字之间的依赖关系,注意力的本质就是在寻找字与字间的关系分布,这样多头注意力其实也就处理了 RNN 存在的步长依赖关系的缺陷,所以比 RNN 强确实是有理可依的。
那讲完多头注意力,其实我们就 get 了 transformer 中最有亮点的操作,接下来还有一些点我们也来逐一讲解。
2.1.3.Add-Norm
Add-Norm 层也是 encoder 的又一个子层。Add-Norm在原文中的计算公式如下:
这个x其实其实就是原始输入,而 sublayer(x)就是经过多头注意力的输出或者是 FNN 的输出,这个Add-Norm的数学公式是一个典型的skip connection的模式,也就是 Resnet 中残差连接,这有利于模型解决梯度消失或梯度爆炸的问题,还可以加快模型收敛速度。这里没有什么要特别的说明的,所以我们的 encoder 中的要点就讲完了。
我们来将以上点串起来画个图:
这再回头看原始图的 encoder 图是不是觉得还是比较好理解的。
下一个篇章我们会继续讲解 decoder 结构,写了不少了,今天就写到这,明天继续更。
有错误请指正。如果你也感兴趣,点赞留言,咱们一块讨论。
参考:
https://arxiv.org/abs/1706.03762
Attention注意力机制与self-attention自注意力机制 - 知乎
一步一步理解大模型:缩放点积注意力机制_注意力机制 缩放点积_chattyfish的博客-CSDN博客