自注意力机制
该篇博客是笔者学习李宏毅老师课程后所写的学习笔记,如文中有错误,感谢大家指正
文章目录
一、解决的问题
在前面的学习中,我们是将一个向量作为输入,当我们把输入推广到Sequence,且长度是会改变的,例如文字处理(把每一个词汇表示成一个向量)、一段声音信号(一排声音向量,10ms是一个向量)、Graph(一个节点是要给向量)
输出的三种可能:
(1)每一个向量都有一个对应的label、(词性标注,每一个输入的词汇都有对应的词性)
(2)一整个Sequence只输出一个lable (情感分析,给机器一段话,机器给出情感标签)
(3)一整个Sequence输入,输出label个数机器自己决定
下面我们重点讨论输入输出数目一样多的情况,又叫做Sequence Labeling问题
如上图所示,我们为一句话词性标注。如果只把一个向量输入到对应的一个FC里面,上例中两个saw拼写相同,所以无法得出不同的词性,为了解决这个问题,要把每个目标单词前后的单词一起送入FC中,即将整个window一起送入一个FC中
但是如果一个问题需要整个sequence的输入才能满足要求,显然一味的将window放大不能满足要求,那么我们就需要用到Self-attention来解决这个问题
二、自注意力机制Self-attention
在使用Self-attention模型做对应输入输入的计算时,先让Self-attention“吃”进一整个序列,然后再做向量的输出。注意,有几个向量的输入,就有几个向量输出,且该输出向量是考虑了整个sequence资讯的向量
self-attention也可以多次叠加使用,所以self-attention的输入可以是初始的input,也可以是将上一次self-attention的输入作为本次的输入
在Self-attention模型中,每个输出
b
1
b^1
b1都和所有的输入相关,其相关性用
α
\alpha
α来表示
三、Self-attention中输出的计算方法
1.每个输出的计算过程
b1的产生: 因为输出
b
1
b^1
b1不仅与
a
1
a^1
a1有关,还有整个序列有关,在本例中我们要先计 算
a
1
a^1
a1和
a
2
a^2
a2、
a
3
a^3
a3、
a
4
a^4
a4的关联系数
α
1
,
i
\alpha_{1,i}
α1,i
(1) 先将
a
1
a^1
a1和矩阵
W
q
W^q
Wq相乘,得到向量
q
1
q^1
q1
(2)将
a
1
a^1
a1、
a
2
a^2
a2、
a
3
a^3
a3、
a
4
a^4
a4分别和矩阵
W
k
W^k
Wk相乘,得到向量
k
1
k^1
k1、
k
2
k^2
k2、
k
3
k^3
k3、
k
4
k^4
k4
(3)将
q
1
q^1
q1分别和
k
1
k^1
k1、
k
2
k^2
k2、
k
3
k^3
k3、
k
4
k^4
k4做内积,得到
α
1
,
1
\alpha_{1,1}
α1,1、
α
1
,
2
\alpha_{1,2}
α1,2、
α
1
,
3
\alpha_{1,3}
α1,3、
α
1
,
4
\alpha_{1,4}
α1,4四个常数
(4)对
α
1
,
1
\alpha_{1,1}
α1,1、
α
1
,
2
\alpha_{1,2}
α1,2、
α
1
,
3
\alpha_{1,3}
α1,3、
α
1
,
4
\alpha_{1,4}
α1,4做归一化处理,在这里我们使用Soft-max,从而得到
α
1
,
1
′
\alpha^{'}_{1,1}
α1,1′、
α
1
,
2
′
\alpha^{'}_{1,2}
α1,2′、
α
1
,
3
′
\alpha^{'}_{1,3}
α1,3′、
α
1
,
4
′
\alpha^{'}_{1,4}
α1,4′
(5)将
a
1
a^1
a1、
a
2
a^2
a2、
a
3
a^3
a3、
a
4
a^4
a4分别和矩阵
W
v
W^v
Wv相乘,得到向量
v
1
v^1
v1、
v
2
v^2
v2、
v
3
v^3
v3、
v
4
v^4
v4
(6)将
α
1
,
i
\alpha_{1,i}
α1,i和
v
i
v^{i}
vi分别做点乘,并求和,最终得到
b
1
b^1
b1
注意:
W
q
W^q
Wq、
W
k
W^k
Wk、
W
v
W^v
Wv、三个矩阵是通过训练数据集训练而来的
2.输出的矩阵化计算
通过上述方法我们可以得到所有的对应输出,但是在实际应用中,输出
b
i
b^i
bi是同时计算出来的,为了达到此目的,我们需要通过矩阵来完成计算。
(1)将向量
a
1
a^1
a1、
a
2
a^2
a2、
a
3
a^3
a3、
a
4
a^4
a4拼成一个矩阵A
(2)将矩阵A分别左乘矩阵
W
q
W^q
Wq、
W
k
W^k
Wk、
W
v
W^v
Wv,从而得到矩阵Q、K、V
(3)将矩阵K的转置
K
T
K^T
KT右乘Q,得到整个
α
i
,
j
\alpha_{i,j}
αi,j矩阵
(4)对矩阵
α
\alpha
α做Soft-max归一化处理,得到
α
′
\alpha^{'}
α′
(5)将矩阵V右乘
α
′
\alpha^{'}
α′,得到又
b
i
b^i
bi组成的矩阵b
具体计算过程演示图下图所示
四、Multi-head Self-attention多头注意力机制
Self-attentiona可以有效的将一个输入向量和整个序列关联起来,但它也存在局限性,一个两个输入之间只能存在一种关联,此时我们引入多头注意力机制来解决这个问题。
head指的是一个输入
a
i
a^i
ai的分支数量,即将
a
i
a^i
ai分成多个
q
i
q^i
qi,记为
q
i
,
j
q^{i,j}
qi,j
其计算方式为:
(1)首先和普通的Self-attention中相同,计算出
q
i
q^i
qi、
k
i
k^i
ki、
v
i
v^i
vi
(2)将
q
i
q^i
qi分别和两个不同的
W
q
W^q
Wq矩阵相乘,如在本示例中
q
i
,
1
=
W
q
,
1
q
i
q^{i,1}=W^{q,1}q^i
qi,1=Wq,1qi,
q
i
,
2
=
W
q
,
2
q
i
q^{i,2}=W^{q,2}q^i
qi,2=Wq,2qi
(3)以此类推,
k
i
k^i
ki和
k
i
k^i
ki也分别和head个矩阵相乘,得到
k
i
,
j
k^{i,j}
ki,j和
v
i
,
j
v^{i,j}
vi,j
(4)后续计算方法和Self-attention中相同,将对用的q,k,v进行计算,最终得到
b
i
,
j
b^{i,j}
bi,j
(5)将
b
i
b^i
bi的j个矩阵罗列拼接起来,与
W
o
W^o
Wo矩阵相乘,最终得到
b
i
b^i
bi
五、Positional encoding
通过上述改进,我们能将整个序列中的向量做有关联的输出,也可以将两个输入的不同意义层面的关联计算出来,但是此时输入的位置还没有被区别出来,即在上例中 a 1 a^1 a1、 a 2 a^2 a2、 a 3 a^3 a3、 a 4 a^4 a4四个输入的意义是相同的,但在有些案例中(例如词性标注),不同的位置的意义有明显的不同,为了解决这个问题,我们用Positional encoding的技术来解决这个问题
为每一个位置设定一个位置向量
e
e
e,将其先和
a
a
a相加,再进行处理
这个位置向量是人设置的,早期不是通过数据集自己学习的(现在也可以通过数据集学习而来)
六、Self-attention的应用和对比
1.语言处理
在语音处理中,由于10ms的语音就会被转化为一个向量,这使得它的输入向量矩阵是非常庞大的,从而带来参数过多,容易过拟合的问题。
而Truncated Self-attention 带来了不错的改进效果,在Truncated Self-attention不在计算将每个输入与整个序列进行计算,而是改为计算一个输入和它周围的一部分输入计算关联度,从而缓解了输入向量过多带来的问题。
2.图像处理
图像通常是一个3通道的像素矩阵,将一个像素位置对应的三个通道数据拉成一个向量,即可进行Self-attention处理
3.和CNN对比
我们知道CNN在做特征提取时是用一个滑动的窗口来提取一个窗口内像素点之间的关联信息,而CNN可以看作是简化的self-attention,或self-attention是复杂的CNN
通过上图的对比可以看出数据量越大,self-attenton的效果越好,当数据超过一定范围时self-attenton的效果超过了CNN,这也是因为self-attenton更加复杂,参数更多,需要更多的数据进行训练以达到优秀的效果
4.和RNN对比
RNN虽然是一个序列模型,但是最右边的输出很难考虑到最左边的输入,需要一个memony去记住最左边的输入,且RNN没有平行化,不能一次处理所有的output。但self-attention的输出是同时产生的,更有效率