文章目录
一、本文说明
看本文前,需要先彻底搞懂Self-Attention。推荐看我的另一篇博文层层剖析,让你彻底搞懂Self-Attention、MultiHead-Attention和Masked-Attention的机制和原理。本篇文章内容在上面这篇也有,可以一起看。
二. MultiHead Attention
2.1 MultiHead Attention理论讲解
在Transformer中使用的是MultiHead Attention,其实这玩意和Self Attention区别并不是很大。先明确以下几点,然后再开始讲解:
- MultiHead的head不管有几个,参数量都是一样的。并不是head多,参数就多。
- 当MultiHead的head为1时,并不等价于Self Attetnion,MultiHead Attention和Self Attention是不一样的东西
- MultiHead Attention使用的也是Self Attention的公式
- MultiHead除了三个矩阵外,还要多额外定义一个。
好了,知道上面几点,我们就可以开始讲解MultiHeadAttention了。
MultiHead Attention大部分逻辑和Self Attention是一致的,是从求出Q,K,V后开始改变的,所以我们就从这里开始讲解。
现在我们求出了Q, K, V矩阵,对于Self-Attention,我们已经可以带入公式了,用图像表示则为:
为了简单起见,该图忽略了Softmax和
而MultiHead Attention在带入公式前做了一件事情,就是拆,它按照“词向量维度”这个方向,将Q,K,V拆成了多个头,如图所示:
这里我的head数为4。既然拆成了多个head,那么之后的计算,也是各自的head进行计算,如图所示:
但这样拆开来计算的Attention使用Concat进行合并效果并不太好,所以最后需要再采用一个额外的矩阵,对Attention再进行一次线性变换,如图所示:
到这里也能看出来,head数并不是越多越好。而为什么要用MultiHead Attention,Transformer给出的解释为:Multi-head attention允许模型共同关注来自不同位置的不同表示子空间的信息。反正就是用了比不用好。
2.2. Pytorch实现MultiHead Attention
该代码参考项目annotated-transformer。
首先定义一个通用的Attention函数:
接下来尝试使用一下:
输出为:
三. Masked Attention
3.1 为什么要使用Mask掩码
在Transformer中的Decoder中有一个Masked MultiHead Attention。本节来对其进行一个详细的讲解。
首先我们来复习一下Attention的公式:
其中:
假设 对应着 。那么 就对应着 。 其中 包含着 到 的所有注意力信息。而计算 时的 这些字的权重就是 的第一行的 。
如果上面的回忆起来了,那么接下来看一下Transformer的用法,假设我们是要用Transformer翻译“Machine learning is fun”这句话。
首先,我们会将“Machine learning is fun” 送给Encoder,输出一个名叫Memory的Tensor,如图所示:
之后我们会将该Memory作为Decoder的一个输入,使用Decoder预测。Decoder并不是一下子就能把“机器学习真好玩”说出来,而是一个词一个词说(或一个字一个字,这取决于你的分词方式),如图所示:
紧接着,我们会再次调用Decoder,这次是传入“<bos> 机”:
依次类推,直到最后输出<eos>
结束:
当Transformer输出<eos>
时,预测就结束了。
到这里我们就会发现,对于Decoder来说是一个字一个字预测的,所以假设我们Decoder的输入是“机器学习”时,“习”字只能看到前面的“机器学”三个字,所以此时对于“习”字只有“机器学习”四个字的注意力信息。
但是,例如最后一步传的是“<bos>机器学习真好玩”,还是不能让“习”字看到后面“真好玩”三个字,所以要使用mask将其盖住,这又是为什么呢?原因是:如果让“习”看到了后面的字,那么“习”字的编码就会发生变化。
我们不妨来分析一下:
一开始我们只传入了“机”(忽略bos),此时使用attention机制,将“机”字编码为了
第二次,我们传入了“机器”,此时使用attention机制,如果我们不将“器”字盖住的话,那“机”字的编码就会发生变化,它就不再是是了,也许就变成了。
这就会导致第一次“机”字的编码是,第二次却变成了,这样就可能会让网络有问题。所以我们为了不让“机”字的编码产生变化,所以我们要使用mask,掩盖住“机”字后面的字,也就是即使他能attention后面的字,也不让他attention。
许多文章的解释是Mask是为了防止Transformer在训练时泄露后面的它不应该看到的信息,我认为这个解释是不对的:①Transformer的Decoder并没有区分训练和测试,所以如果是为了防止训练泄露后面信息的话,那为什么推理时也要掩码呢? ② 传给Decoder的内容都是Decoder自己推理出来的,它自己推理出来的不让它看,说是为了防止泄露信息,这不扯淡嘛。
当然,这也是我的个人看法,也许是我自己理解错看了
3.2 如何进行mask掩码
要进行掩码,只需要对scores动手就行了,也就是
第一次,我们只有
第二次,我们有
此时如果我们不对 进行掩码的话,的值就会发生变化(第一次是 ,第二次却变成了)。那这样看,我们只需要将 盖住即可,这样就能保证两次的
所以第二次实际就为:
依次类推,如果我们执行到第次时,就应该变成:
3.3 为什么是负无穷而不是0
按照上面的说法,mask掩码是0,但为什么源码中的掩码是
你仔细看,我们上面说的