图解transformer

一、什么是transformer

transformer是目前最流行的特征抽取器

transformer是采用encoder-decoder架构。论文Attention Is All You Need中给出encoder层是6层encoder堆叠在一起的,deco样是6层decoder堆叠在一起。

分解成一个encoder和一个decoder的话如下:

RNN缺点:

1. RNN不能并行:RNN是依赖前一时刻输出的隐层状态,这就导致RNN必须一步一步走完,而不能并行,结果就会很慢

2. RNN词间距过长:词间距是两个词相隔的距离,当距离过长可能会导致梯度消失或梯度爆炸等问题。

而transformer很好的弥补了这两个缺点:

transformer并行速度极快,而且transformer每个词之间的词间距都是1。

因此奠定了transformer是目前最流行的特征抽取器。

 

二、远观transformer

transformer是采用encoder-decoder架构。论文Attention Is All You Need中给出encoder层是6层encoder堆叠在一起的,decoder是6层decoder堆叠在一起。

分解成一个encoder和一个decoder的话如下:

 

可以看到一个encoder是由Self-Attention(自注意力机制层)和Feed Forward(前向神经网络层)组成,而decoder比encoder多了一层Encoder-Decoder Attention,该层目的是接收encoder层的结果。值得注意的是,decoder与encoder的Self-Attention并不完全相同,decoder采用的是Masked Self-Attention(掩码自注意力),这个后面会详细说明。

三、拆解transformer

transformer整体细节图如下:

 

将其拆分成五部分:输入 + 中间部分(Multi-Head Attention + FeedForward + Add & Normalize)+ 输出

 

1. 输入层

encoder的输入层和decoder的输入层是一样的结构,都是token embedding(词向量)+ positional embedding(位置向量),得到最终的输入向量。之所以引入positional embedding主要是解决单单使用token embedding(类似于词袋子),并没有词序的概念的问题。

positional embedding的计算公式如下:

这里,pos表示单词的位置,i是指单词的维度。可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码。

2. Multi-Head Attention

2.1. Self-Attention

在说Multi-Head Attention(多头注意力机制)之前,先来了解一下Self-Attention(想象成单头注意力机制)~

Self-Attention是解决什么问题呢?比如:"The animal didn't cross the street because it was too tired." 对于这个句子来说,我如何知道"it"指代的是"animal"呢?这就是Self-Attention需要做的事——将"it"和"animal"关联起来。接下来我们详细讲一下它们如何关联起来:

首先,我们需要了解三个向量:

a. 查询向量(Query 向量,简写:q):

Score(其它词相对于当前词的注意力得分) = Query(当前单词) ✖️ Key(所有单词)。

注意:我们只关心目前正在处理的单词的查询向量。

b. 键向量(Key 向量,简写:k):

序列中每个单词的标签。

c. 值向量(Value 向量,简写:v):

值向量是单词真正的表征,当得到注意力得分Score后,使用值向量进行加权求和得到能代表当前位置上下文的向量。

然后,我们看一下如何利用这三个向量实现自注意力机制的:

  • 通过第1步【token embedding + positional embedding】,得到输入向量x
  • 通过输入向量x得到q、k、v三个向量
  • 得到当前词与所有词的注意力得分Score(112和96)
  • 为了梯度稳定,除以[公式][公式]当前为64)(112/8=14;96/8=12)
  • 进行softmax激活函数

  • 将softmax激活函数的结果点乘值向量,结果仍为向量(v1,v2)
  • 将上一步的所有结果向量相加得到最后的向量z

其中,第二小步骤是通过向量x的矩阵计算方式得到q、k、v三个向量的:

以Q(q)向量为例:向量x(1*512)乘以一个权重矩阵w(512*64),得到q向量(1*64)。而w矩阵初始化时可以随机取值,通过不断的优化会将参数w更新到一个最优值。

以上步骤可以抽象出Self-Attention的计算公式:

2.2. Masked Self-Attention

Masked Self-Attention(掩码自注意力机制)与Self-Attention(自注意力机制)就差在Masked(掩码)

Masked是什么意思呢?就是相当于盖住你当前关注的词的后面所有词,我只关心前面出现的词,而后面的词我不关注,因为我要生成后面的词。如下图所示,对于当前词,我只用它及它之前的所有词进行计算,后面不管。

那为什么要使用Masked Self-Attention呢?

因为在做解码(decoder)操作时,我们需要预测当前词的下一个词是什么,如果后面的词都能看见了,还预测什么呢?这也是为什么bert采用双向语言模型时需要盖住一些词的原因啦

所以我们不能看见后面的词,这样才能保证我是公平的预测后面的词(并没有作弊提前记住它 ),因此Masked Self-Attention是必要的。

2.3. Multi-Head Attention

多头自注意力机制,就是一个输入向量x得到多组q、k、v,从而得到多个z,将多个z拼接成一个大矩阵,乘以权重矩阵wo,得到最后的结果向量z。

问题一:为什么要分成多头处理?

回答:将一个单词映射在高维空间中,对于不同维空间都可以学到不同的特征。通过所有维空间得到一个向量,不如将其拆分成多个维度,通过多个维度得到多个向量,从而捕捉到更多的信息。论文(Attention Is All You Need)作者就将512维向量拆成8份,每64维得到一个向量,即上图我们看到的0~7的q/k/v,这样就可以让特征更丰富些。

问题二:多组q、k、v是如何计算的,如何得到多个z的?

回答:上图中是针对一个输入向量x列举了多组q、k、v,而如果再来一个输入向量R,又得到多组q、k、v,那这多组对多组是如何计算的呢?按我的理解,计算方式如下图所示,相当于每一份(共8份)单独计算得到z。以z0为例:x的Q0和x的K0相乘 ➕ x的Q0和R的K0相乘,就得到了向量x对应的词的注意力得分,然后按照上面的步骤继续除以[公式],softmax等相同操作,最后得到z0。其他份相同计算方式,就得到多个z啦~

问题三:如何将多个z整合成一个?

回答:如下图所示,将多个z拼接在一起,行程一个长矩阵,然后与权重矩阵w计算得到最后的z。

 

3. Feed Forward

Feed Forward Neural Network(前馈神经网络)包含两层,第一层是ReLU激活函数,

第二层是一个线性激活函数,表示为:

值得一提的是,是在Feed Forward这部分实现了并行操作。我们以encoder层为例,将encoder细化分解一下,得到下图所示:

大家注意到一个小细节了吗?Self-Attention画成一个大长条,而Feed Forward却画成了两个小长条,为什么不同样直接画成一个大长条呢?

这是因为我们在计算Self-Attention时用到了上下文词的信息,所以直接画成了一个大长条,而Feed Forward处理时是对每个词的输出分别单独计算的,因此也就实现了并行的方式。

4. Add & Normalize

我们在讲Feed Forward时给出了一个encoder层的细节图,从中我们可以看到在Self-Attention和Feed Forward之后都接了一个Add & Normalize(残差连接&归一化)层。

残差连接就是将 输入向量加上输出向量 后传给下一层。例如:假设一个输入向量x,经过一个网络结构,得到输出向量f(x),即:x->f(x),这时加上残差连接,相当于在输出向量中加入输入向量,输出结构变为f(x)+x这样就避免了梯度消失的问题,因为对x求偏导时,总会有一个常数项1。

因此,Add & Normalize层的实质是,输出向量经过残差连接与输入向量相加然后通过LayerNorm进行归一化,将最后结果向量传给下一层,如下图所示:

5. 输出层

从输入词得到向量,又将向量进行一系列折腾后,我如何再将向量转换成输出的词呢?其实就是通过linear层和softmax层实现的。

比如我们得到最后的向量(512维),我们需要对应到我们词库中,比如我们词库有10000个词,那就需要将512维转换成10000维,这就用到了linear,然后转换成的10000维,我取其中哪个词呢,这就用到了softmax,通过它我们知道哪个位置上的概率最大,从而得到对应位置上的词,解决了我们从向量到词的转换(上图中很好的说明了这一过程)。

四、近看transformer

了解了transformer各部分的内容及其作用后,我们再来从encoder层和decoder层的角度近看一下transformer。下图展示了两层encoder(encoder #1,encoder #2)和一层decoder(decoder #1)的细节图。

1. encoder层

  • 每个词向量(token embedding)➕ 对应的位置向量(positional embedding)=> 每个词的输入向量x
  • 输入向量通过多头自注意力机制(Multi-Head Attention)得到的向量与输入向量进行残差连接与归一化(Add & Normalize)向量向量
  • 将归一化得到的每个词的向量继续做前向神经网络(Feed Forward)
  • 最后再进行一次残差连接与归一化(Add & Normalize)

此时一层encoder层结束,将得到的结果向量当成输入向量继续传给第二层的encoder,依次传递计算,直到6层encoder计算结束,将最后结果向量保留,之后会传给decoder层计算。

2. decoder层

  • 当前词及之前词的词向量(token embedding)➕ 对应的位置向量(positional embedding)=> 当前词及之前词的输入向量x
  • 输入向量x同样经过多头自注意力机制(Multi-Head Attention)处理和残差连接与归一化
  • 这一步的Encoder-Decoder Attention,其中q、k是来自于encoder层的结果,而v是本身上一层的结果【这点很重要哦~~~
  • 接下来几步和上面encoder的步骤是一样的,最后得到结果向量,作为decoder第二层的输入向量。然后依次进行以上步骤,直到6层decoder全部计算结束。

再啰嗦一句,encoder是对于所有输入词进行的计算,而decoder是当前词及之前词进行计算的,然后将计算结果再返回到输入词中,继续进行。

下面我们来看个动图,能更好的理解decoder层是如何运行的~

首先我们先来看一下decoder层输出第一个词的动图:

需要说明的一点,其实decoder这端在输出第一个词的时候,有一个句子前缀<s>,所以是相当于通过标记标记<s>预测到了第一个输出词。

然后,我们再来看一下decoder层输出后面词的动图:

将第一输出词当成输入词继续预测,直到预测完整个句子。

五、总结

本篇文章详细记述了transformer的整个运行过程,其主要核心就是Self-Attention机制,而其在encoder层和decoder层又是不同实现的。其主要原因是encoder层是相当于学习到输入词的信息,所以需要将所有的输入词都包含进来计算,而decoder层相当于预测下一个词,因而只需要当前词及前面的词,而将后面的词都盖住。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值