Transformer模型详解

Transformer模型详解

前言

Transformer作为目前最火的模型之一。可以说横扫了整个NLP领域。众所周知无论是chatcpt还是各种大模型,多模态,其底层架构都是transformer。所以,学好transformer对于了解并学习大模型是不可或缺的一步。transformer于2017年的一篇论文《Attention is All You Need》提出。作者为谷歌团队成员。原文地址:https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf

在学习transformer时也查看了很多资料,听了不少教程,刚开始也是非常懵懂。网上已经有非常多的博主写了transformer的讲解,也解释的非常清楚,但是或多或少也有让人不太能理解的地方。我们都知道学习知识最好的办法就是能够将其表述给听众,让听众能够理解,才能说明我们真正掌握。所以也当作是学习笔记。以下是参考的一些博客,讲的非常清晰,本文也会融合他们的精华与自己的理解,尽量通俗地解释transformer的架构细节和完整流程。

00 预训练语言模型的前世今生(全文 24854 个词) - B站-水论文的程序猿 - 博客园 (cnblogs.com)

史上最小白之Transformer详解_transformer最小白-CSDN博客

自然语言处理Transformer模型最详细讲解(图解版)-CSDN博客

一、Transformer整体架构

先看图

img

乍一看会觉得这个结构好复杂啊,没事刚开始是这样,多看几眼就熟悉了。

我们可以把该框架拆解为以下几个部分

可以看到我们把transformer拆解为以上四个部分。主要为输入——Ecoder——Decoder——输出。其中Encoder-Decoder是最核心的部分,包含了Transformer的核心思想——Attention(注意力机制)

接下来我将根据transformer的算法流程来一步一步分析其细节。并且尽可能利用通俗的例子来解释它的原理。

二、Transformer的输入Inputs

我们都知道transformer设计的初衷是用于NLP领域。可以使用最常用的机器翻译来进行解释。就比如我们在Inputs输入"我爱中国",最终输出为"I love China"。那么它是怎么一步一步进行翻译的呢?

2.1词向量(Input Embedding)

首先,"我爱中国"这段文字我们人肯定能看懂,但是计算机不认识,计算机只认识数字,所以第一步肯定是将文字转化为计算机认识的数字,也就是向量。而词向量的发展也经历了很久。主要有以下几种:

2.1.1独热(one-hot)编码

独热编码是最原始的方法,一个向量代表一个词,一张图就能看懂

img

但是这种方式一个向量只能代表该词,其它什么也表示不了。并且词越多其维度就越高,缺少语义联系信息等等有很多缺点。。。

2.1.2Word Embedding(词嵌入)

通过网络进行训练或者通过一些训练好的模型将其转化成连续性的向量

意思就是通过一些训练得到的模型,最经典的就是Word2Vec 模型,然后通过Word2Vec 模型将每一个词都转换为固定长度的向量,也就是词向量。我们简单看一下怎么通过模型来计算一个词向量。
[ 0 0 0 1 0 ] [ 17 24 1 23 5 7 4 6 13 10 12 19 11 18 25 ] = [ 10 12 19 ] \left[\begin{array}{lllll}0 & 0 & 0 & 1 & 0\end{array}\right]\left[\begin{array}{ccc}17 & 24 & 1 \\ 23 & 5 & 7 \\ 4 & 6 & 13 \\ 10 & 12 & 19 \\ 11 & 18 & 25\end{array}\right]=\left[\begin{array}{lll}10 & 12 & 19\end{array}\right] [00010] 1723410112456121817131925 =[101219]
可以看到上面公式中第四个词通过权重矩阵得到该词的词向量(上述公式假设词向量为3维)

所以我们知道了当输入一段文字(序列)时,我们首先需要将其转化为固定维度的词向量(大部分情况下是512维),也就是一个1x512的向量表示一个词。

2.2Positional Encoding(位置编码)

通过上面的知识我们了解到了输入一段序列时我们首要任务就是将其转换为词向量才能输入到我们的模型中去。但是我们还需要添加每个词的位置信息,也就是位置编码。

那么问题来了,为什么要加位置编码呢?

首先需要知道的是Transformer是完全基于self-attention的,self-attention只是计算词与词之间的相关性,即使句子中词语的顺序打乱也不会影响self-attention的计算结果。换句话说计算在计算注意力机制的时候无法获取词的位置关系的。由于RNN与LSTM独特的网络结构(必须将特征逐个输入到网络)就隐含了位置关系。但是我们都知道句子中词的位置关系信息也是非常重要的。而attention计算却丢掉了这个信息。

所以,为了解决这个问题,作者提出了 Position Embedding,也就是在进行注意力计算之前,在词向量中添加了位置信息。

img

如上图所示,我们假设输入三个词,然后在Embedding层将三个词转化为词向量,在加上位置编码(Positional Encoding),然后得到新的带有位置信息的词向量。注意,二者相加就是单纯的向量加,所以位置编码和词向量维度是相等的。也就是说新的词向量计算公式为
X f i n a l = X E m b e d d i n g + T P o s i t i o n E n c o d i n g X_{final} = X_{Embedding} + T_{Position Encoding} Xfinal=XEmbedding+TPositionEncoding
既然已经知道了如何添加位置编码,那么位置编码怎么计算呢?

如下图所示:

简单解释一下这个公式:pos代表的就是该词的在句子中绝对位置,比如序列"我爱你",其中"我"的pos就是0,"爱"的pos就是1,以此类推。而 d m o d e l d_{model} dmodel就是词向量的维度,比如词向量维度为512,所以 d m o d e l = 512 d_{model} = 512 dmodel=512。而 i 就是递增的维度数。比如词向量维度为512, i = 0 , 1 , 2 , … , 255 i = 0,1,2,\dots,255 i=0,1,2,,255。2i和2i+1则代表维度的奇偶性。

在这里插入图片描述

如上图,比如一个512维的位置编码向量,其中每一维就是交叉使用上述公式进行计算,交叉计算sin和cos。最终得到该词的位置编码然后加上词向量得到新的词向量。至于为什么Position Encodding能代表位置信息。可以参考上述的参考博客,这里就不细究了。不过这并不是最好的,后面还有很多优化的位置编码,比如旋转位置编码等,更能体现相对位置信息。

三、Encoder

在讲解Encoder之前呢,首先需要了解的,也是Transformer最核心的思想——Self-Attention(自注意力机制)。

3.1Attention

首先了解一下什么是Attention,从人类的角度来看,介绍一下人类的视觉注意力

img

当人查看一张图片时,人类视觉会快速扫描全局图像,然后经过大脑的处理定位到需要重点关注的区域,也就是常说的焦点。因为我们不可能能够同时处理图片的所有信息。所以肯定会首先关注对自己重要的信息。而对这一区域投入更多的注意力。

以上面的图片来看,经过科学家的研究,上幅图片能够很好的展示人们在看到图像时是如何高效分配有限的注意力资源。红色区域就是大量关注的目标。比如婴儿的脸、文章的标题、首段文字等信息。而通过这种注意力就能够从众多杂乱的信息中挑选出对自己更加有用的信息。

3.2Self-Attention

好了,通过上面的介绍相信对注意力机制有了一定的认识,而transformer使用的是自注意力机制。那么"自"又是什么意思?

首先,注意力机制肯定是分为谁对谁的注意。也就是要有观察者和被观察者。就拿上面的图像来说。人就是观察者(Query),图像是被观察者。而注意力计算就是相对于人来说提取图片中对人关键的信息。反过来图片也可以作为观察者(Query),人作为被观察者。

那么自注意力机制,顾名思义就是自己对自己。还是上面的图像。自注意力就是观察者和被观察者都是这张图。怎么解释呢?因为这张图也包含了很多不同的信息。比如观察者可以是婴儿,而被观察者可以是文章标题,然后进行注意力计算出对于婴儿来说文章标题的重要程度。或者观察者可以是文章标题,被观察者是纸尿片,又可以计算注意力。

最后,了解了自注意力的本质思想,回到NLP领域。举个例子:“我吃了一个苹果”和“我正在用苹果手机”。如果单看“苹果”这个词,谁也不知道是被咬过的苹果还是没被咬过的。但是从整句话来看,第一句里有个“吃”,而第二句有“手机”。这样就能知道苹果是哪种苹果。也就是说通过计算“苹果”对“吃”和“手机”的注意力分数。就能得到他们的相关程度,从而正确理解这句话。

3.3 Self-Attention模型

现在基本已经了解了Self-Attention的基本思想,那么在Transformer中是怎么计算呢?

先来张Self-Attention模型的架构图,感性认识一下。

img

首先可以看到Self-Atetntion有三个输入Q、K、V。那么这三个Q、K、V是怎么来的呢?首先Query就是观察者,Keys就是被观察者,而Values就是包含词向量的信息。之前已经讲过Transformer的输入是词向量。也就是一个单词一个词向量。**而Q、K、V就是词向量X通过分别和三个矩阵 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV相乘得来的。**也就是说Q、K、V是同源的。

如下图,假如输入序列是"Thinking Machines",X1,X2就是对应地"Thinking"和"Machines"通过Embedding和添加位置编码之后的词向量,然后通过三个权重矩阵 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV,就得到了Query,Keys,Values向量。

注意:这里的权重矩阵 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV就是可训练参数,在训练过程中通过不断的参数更新得到最佳的权重。

上面的图假设了词向量的维度是4,也就是说两个单词组成的词向量为(2,4)。但在实际应用中词向量的维度一般为512。那么就假设X矩阵维度为(2,512),则 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV矩阵维度为(512,64)。得到Q、K、V都是2x64的矩阵。

那么,既然得到了Q、K、V者三个向量,就开始进行注意力计算了

img

上图就展示了注意力计算的核心所在。可以分为以下几步:

  1. Q对K转置做点积运算得到相关性矩阵score。比如Q和K都是2x3的矩阵,则 s c o r e = Q ⋅ K T score = Q\cdot K^T score=QKT。得到一个2x2的方阵。而这个方阵的值就是注意力得分。
  2. 然后对得分进行规范,除以 d k \sqrt{d_k} dk 。这里的 d k d_k dk就是K矩阵的维度,如果K是2x64的矩阵,则 d k = 64 d_k = 64 dk=64
  3. 通过softmax函数将的得分转化为[0,1]之间的概率值不过方阵的维度不变。
  4. 最后再点乘上Value值得到最后的Z矩阵。

因为Q、K、V都是(2,64)。然后 Z = s o f t m a x ( Q ⋅ k T d k ) ⋅ V Z = softmax(\frac{Q\cdot k^T}{\sqrt{d_k}}) \cdot V Z=softmax(dk QkT)V。就相对于(2,64)x(64,2)x(2,64) = (2,64)。你会发现最后维度不变。所以Z矩阵维度也是2x64。但是Z矩阵和普通的词向量不同的就是包含了词与词之间的相关信息。

3.4Multi-Head Attention

既然已经清楚了self-Attention的本质思想,那么Multi-Head Attention就非常简单了。

前面已经说过输入词向量矩阵为(2,512)。self-Attention使用了一组 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV矩阵得到了Q、K、V。而Multi-Head Attention使用多组 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV得到多组Q、K、V同时进行注意力计算。然后得到多组Z矩阵进行拼接。而再Transformer中使用了8组不同的 W Q 、 W K 、 W V W^Q、W^K、W^V WQWKWV矩阵,最终得到8组维度为(2,64)的Z矩阵进行拼接得到(2,512)的矩阵。为什么这样做呢?就好比你把一件事交给一个人干不放心,同时交给8个人做就更有保障,并且也能获取更多的信息。

你会发现最终Z矩阵维度和刚开始输入的词向量维度相等了?

没错,这就不得不继续往后说

3.5Add&Normalize

3.5.1Add

Add就是残差块,对深度学习比较熟悉的同学肯定知道经典的残差神经网络,加入残差块X的目的是为了防止在深度神经网络训练中发生退化问题。而残差就必须保证两个矩阵维度要完全相等。这里就不细讲了。

在这里插入图片描述

3.5.2Normalize

LayerNorm是指Layer Normalization,他与Batch Normalization是不同的,对于Batch Normalization我们会对同一批次的所有样本的同一特征计算均值和方差,但是对于文本问题,一般来将我们的序列长度是不一致的,所以无法对于同一特征进行计算,所以这里采用了Layer Normalization,它的意思就是对于同一样本的所有特征计算均值和方差。
而为什么要进行归一化,很简单,能够加快训练速度,提高训练稳定性,加速收敛等。

至于具体怎么计算LayerNorm,这里借用一篇博客里的一张图,非常清晰,一看就懂。

在这里插入图片描述

3.6Feed Forward

Feed Forward就是很普通的全连接神经网络,使用了两层网络,激活函数为relu,公式如下:
F F N ( x ) = r e l u ( 0 , x W 1 ​ + b 1 ​ ) W 2 ​ + b 2 ​ FFN(x)=relu(0,xW 1 ​ +b 1 ​ )W 2 ​ +b 2 ​ FFN(x)=relu(0,xW1​+b1​)W2​+b2​
这里经过全连接神经网络后维度还是和之前的一样,没有发生变化,但是信息经过了筛选然后经过Add&Normalize,输入下一个encoder中,经过6个encoder后最终输入到decoder中。

最后再来看一下完整的Encoder图片

img

是不是非常清晰,里面的细节都已经讲到了。需要注意的是,上述的 x、z、r都具有相同的维数,论文中为 512 维。

四、Decoder

上面Encoder的流程想必已经了解得比较清楚了,既然在Encoder层将词进行编码,那么肯定就要解码,最终才能输出我们所看到的内容。首先看一下Decoder的模型图:

有聪明的同学看到下图肯定会问:为什么Decoder层也会有输入呢,那么输入的是什么?

这个问题很简单,用动态图就能够非常清晰展示:

img

拿翻译为例,熟悉gpt的都知道对于这种生成式的语言模型,都是一个单词一个单词生成的。那么在生成时就可以把上一个生成的单词输入到模型来预测下一个单词。这样就可以极大提高模型的准确性。继续看后续动态图

img

看到这里肯定已经清楚Decoder在预测时输入是什么了。不过需要注意的一点是,在最开始进行翻译时,也就是上图预测"I"这个单词时,Decoder并不是没有任何输入,它会输入一个代表开始的也是512维的词向量。图中没有展示出来。

4.1Masked Multi-Head Attention

前面已经讲解了Multi-Head Attention,但是Masked是什么呢?,为什么要加Masked?

首先需要清楚的一点就是,Transformer是分为训练模式和预测模式,而上面的动态图就是典型的预测模式。应该已经了解了。那么接下来将详细描述一下是如何训练的:

还是拿je suis etudiant的翻译举例。首先Transformer的训练过程是采用了Teacher Forcing的训练模型,也就是说在训练时会把问题和答案都喂给模型。比如训练时,

  1. Encoder输入"je suis etudiant",Decoder输入"I am a student"。然后预测出第一个单词"I"
  2. Encoder输入"je suis etudiant",Decoder输入"I am a student"。然后预测出第二个单词"am"
  3. Encoder输入"je suis etudiant",Decoder输入"I am a student"。然后预测出第三个单词"a"

我们都知道Transformer在预测时单词是一个一个生成的。也就是说在预测下一个单词时上一个单词可以起到作用。比如预测"am"的时候"I"已经存在了,"I"就可以输入到模型进行注意力计算,对进行"am"的预测起到了贡献。但是"am"后面的"a student"都还没出现,不知道是什么,肯定就不能对"am"的预测起到贡献。

那么问题来了,Transformer在进行训练时每次Decoder都输入了完整的答案"I am a student"。这样的话,在预测"am"的时候,"a"和"student"也会对"am"做注意力计算,对"am"的预测有贡献。这就和预测模式行为不一致,训练就很容易产生过拟合。

总结来说,就是前面已经生成的词可以对后面需要预测的词有一定的贡献,但是训练时后面的词不能对前面词的生成有影响。

那么怎么达到这个效果呢?这就是**Masked Multi-Head Attention(带掩码的多头注意力机制)**的由来。masked就是让模型在训练时预测当前单词时看不到后面所有单词的信息,但是可以看到前面单词的信息。

那么如何实现masked呢,很简单,前面讲过在进行注意力计算时有一步不是 Q ⋅ K T Q\cdot K^T QKT吗,它得到的结果是一个方阵就是词与词之间的注意力分数,如下图所示:

img

这个方阵第一行就是"I"对所有单词的注意力分数,第二行就是"have"对所有单词的注意力分数,以此类推。既然我们需要让前面的单词无法知道后面单词信息,如上图就添加一个上三角的灰色区域用0覆盖掉,不给模型看到未来的信息。详细来说就是:

  1. “I” 作为第一个单词,只能有和 “I” 自己的 attention;
  2. “have” 作为第二个单词,有和 “I、have” 前面两个单词的 attention;
  3. “a” 作为第三个单词,有和 “I、have、a” 前面三个单词的 attention;
  4. “dream” 作为最后一个单词,才有对整个句子 4 个单词的 attention。

然后进行softmax,横轴结果合为 1。如下图所示:

img

到这里就已经基本了解了为什么要加Maske和Masked具体怎么计算的。接下来再看一下Transformer的整体架构:

你会发现Decoder在细节上只比Encoder多了一个Masked掩码,其它都是一样的。不过细心的同学发现Decoder做了两层注意力计算,并且第二层注意力计算和Encoder几乎是一模一样。下面说一下两个注意力机制的区别:

  1. 第一个是 Masked multi-head self-attention,也是计算输入的 self-attention;而前面也讲过,这一层是为了计算当前词与前面词的注意力分数,换句话说就是为了得到已经生成的词的信息,用于下一层注意力计算。
  2. 好了重点来了,那就是第二层 Encoder-Decoder 注意力计算,首先看到Encoder会向Decoder输入东西来进行注意力计算,那输入的是什么呢?首先注意力计算需要的是Q、K、V。所以很明显, Encoder提供的是K、V矩阵,而Decoder提供的就是Q矩阵。

至于为什么 Encoder-Decoder 注意力是Encoder提高K、V而Decoder提供Q呢?还是通过“我有一个梦想”翻译维"I have a dream"举例,

当翻译"I"时,Decoder输入的是向量,然后让<开始>向量转化为Q矩阵对"我有一个梦想"转化的K、V矩阵进行注意力计算,找出其中对预测第一个单词最有用的词,很明显就是里面的"我",然后依次类推,预测出"have"、"a"等等,最终以标志结束。这就很好的体现了注意力机制想要达到的目的,把焦点放在对自己而言更为重要的信息上。

五、输出output

在这里插入图片描述

那么最后这个Transformer的输出就很简单了,入门深度学习的都很清楚这就是经过一次线性变换,然后Softmax得到输出的概率,输出的维度就是词典的维度,然后在词典中找出概率最大对应的单词就是预测出来的输出。

六、总结

来最后看一眼Transformer的模型图:

img

是不是现在看起来变得更清晰了呢,不过还有一个之前没提到就是Decoder和Encoder不止一层,都是N层进行叠加的。论文中N为6。下图就能很通俗表示:

img

结语

Transformer的诞生可以说是NLP领域一个翻天覆地的变化,目前几乎所有大模型底层架构都是Transformer,并且现在Transformer也在向CV领域发展,有极大的潜力统一NLP与CV。也就是现在常说的多模态。不过在工业界中Transformer还是有很多值得改进的地方,比如位置编码,完全基于self-Attention,在后面也有很多提出了各种优化。最后希望本文能够对同学的学习有所帮助。
叠加的。论文中N为6。下图就能很通俗表示:

img

结语

Transformer的诞生可以说是NLP领域一个翻天覆地的变化,目前几乎所有大模型底层架构都是Transformer,并且现在Transformer也在向CV领域发展,有极大的潜力统一NLP与CV。也就是现在常说的多模态。不过在工业界中Transformer还是有很多值得改进的地方,比如位置编码,完全基于self-Attention,在后面也有很多提出了各种优化。最后希望本文能够对同学的学习有所帮助。

  • 34
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜀黍鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值