文章目录
前言
Self - Attention是Transformer中最核心的思想。我们在阅读Transformer论文的过程中,最难理解的可能就是自注意力机制实现的过程和繁杂的公式。本文在Illustrated: Self-Attention这篇文章的基础上,加上了自己对Self-Attention的理解,力求通俗易懂。希望大家批评指正。
一、Self-Attention是什么?
在理解Self-Attention之前,我们先通俗的解释一下什么是Attention。我们首先看一张图:
我们大部分人第一眼注意到的一定是东方明珠,但是这图其实还有旁边的楼,下面的汽车等等。这其实就是一种Attention,我们关注的是最主要的东西,而刻意“忽视”那些次要的东西。
我们再来讲解一个重要的概念,即query、key和value。这三个词翻译成中文就是查询、键、值,看到这中文的意思,还是迷迷糊糊的。我们来举个例子:小明想在b站搜索深度学习,他把深度学习四个字输入到搜索栏,按下搜索键。搜索引擎就会将他的查询query映射到数据库中相关的标签key,如吴恩达、神经网络等等,然后向小明展示最匹配的结果value。
最后我们来说说Self-Attention。和Attention类似,他们都是一种注意力机制。不同的是Attention是source对target,输入的source和输出的target内容不同。例如英译中,输入英文,输出中文。而Self-Attention是source对source,是source内部元素之间或者target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力机制。
下面我们通过一个简单的例子,来了解Self-Attention的计算步骤。
二、计算步骤
1.定义input
在进行Self - Attention之前,我们首先定义3个1×4的input。
pytorch代码如下:
import torch
x = [
[1, 0, 1, 0], # input 1
[0, 2, 0, 2], # input 2
[1, 1, 1, 1] # input 3
]
x = torch.tensor(x, dtype=torch.float32)
2.初始化权重
每个input和三个权重矩阵分别相乘会得到三个新的矩阵,分别是key(橙色),query(红色),value(紫色)。我们已经令input的shape为1×4,key、query、value的shape为1×3,因此可以推出与input相乘的权重矩阵的shape为4×3。
代码如下:
w_key = [
[0, 0, 1],
[1, 1, 0],
[0, 1, 0],
[1, 1, 0]
]
w_query = [
[1, 0, 1],
[1, 0, 0],
[0, 0, 1],
[0, 1, 1]
]
w_value = [
[0, 2, 0],
[0, 3, 0],
[1, 0, 3],
[1, 1, 0]
]
w_key = torch.tensor(w_key, dtype=torch.float32)
w_query = torch.tensor(w_query, dtype=torch.float32)
w_value = torch.tensor(w_value, dtype=torch.float32)
print("Weights for key: \n", w_key)
print("Weights for query: \n", w_query)
print("Weights for value: \n", w_value)
3.计算key,query和value
现在我们计算key,query和value矩阵的值,计算的过程也很简单,运用矩阵乘法即可:
key = input * w_key; query = input * w_query; value = input * w_value;
keys = x @ w_key
querys = x @ w_query
values = x @ w_value
print("Keys: \n", keys)
# tensor([[0., 1., 1.],
# [4., 4., 0.],
# [2., 3., 1.]])
print("Querys: \n", querys)
# tensor([[1., 0., 2.],
# [2., 2., 2.],
# [2., 1., 3.]])
print("Values: \n", values)
# tensor([[1., 2., 3.],
# [2., 8., 0.],
# [2., 6., 3.]])
4.计算attention scores
例如:为了获得input1的注意力分数(attention scores),我们将input1的query(红色)与input1、2、3的key(橙色)的转置分别作点积,得到3个attention scores(蓝色)。 同理,我们也可以得到input2和input3的attention scores。
attn_scores = querys @ keys.T
print(attn_scores)
# tensor([[ 2., 4., 4.], # attention scores from Query 1
# [ 4., 16., 12.], # attention scores from Query 2
# [ 4., 12., 10.]]) # attention scores from Query 3
5.对attention scores作softmax
上一步得到了attention scores矩阵后,我们对attention scores矩阵作softmax计算。softmax的作用为归一化,使得其中各项相加后为1。这样做的好处是凸显矩阵中最大的值并抑制远低于最大值的其他分量。
from torch.nn.functional import softmax
attn_scores_softmax = softmax(attn_scores, dim=-1)
print(attn_scores_softmax)
# tensor([[6.3379e-02, 4.6831e-01, 4.6831e-01],
# [6.0337e-06, 9.8201e-01, 1.7986e-02],
# [2.9539e-04, 8.8054e-01, 1.1917e-01]])
attn_scores_softmax = [
[0.0, 0.5, 0.5],
[0.0, 1.0, 0.0],
[0.0, 0.9, 0.1]
]
attn_scores_softmax = torch.tensor(attn_scores_softmax)
print(attn_scores_softmax)
6.将attention scores与values相乘
每个score(蓝色)乘以其对应的value(紫色)得到3个alignment vectors(黄色)。在本教程中,我们将它们称为weighted values(加权值)。
weighted_values = values[:,None] * attn_scores_softmax.T[:,:,None]
print(weighted_values)
7.对weighted values求和得到output
从图中可以看出,每个input生成3个weighed values(黄色),我们将这3个weighted values相加,得到output(深绿)。图中一共有3个input,所以最终生成3个output。
outputs = weighted_values.sum(dim=0)
print(outputs)
# tensor([[2.0000, 7.0000, 1.5000], # Output 1
# [2.0000, 8.0000, 0.0000], # Output 2
# [2.0000, 7.8000, 0.3000]]) # Output 3
三、回到论文
我们在Attention is all you need这篇论文中,可以看到这样一个公式:
A
t
t
e
n
t
i
o
n
(
Q
,
K
,
V
)
=
s
o
f
t
m
a
x
(
Q
K
T
d
k
)
V
Attention(Q,K,V)\, =\, softmax(\frac {Q{K}^{T}} {\sqrt {{d}_{k}}})V
Attention(Q,K,V)=softmax(dkQKT)V
其实,这个公式就是描述了我们上面计算的过程。我们首先将Query与Key的转置作点积,然后将结果除以
d
k
\sqrt {{d}_{k}}{}_{}
dk,再作softmax计算,最后将计算的结果与Value作矩阵乘法得到output。
这里有一个点,就是为什么要除以 d k \sqrt {{d}_{k}}{}_{} dk? d k {d}_{k} dk表示的是词向量的维度。我们除以 d k \sqrt {{d}_{k}}{}_{} dk是为了防止 Q K T Q{K}^{T} QKT值过大,导致softmax计算时上溢出(overflow)。其次,使用 d k {d}_{k} dk可以使 Q K T Q{K}^{T} QKT的结果满足期望为0,方差为1的分布。
四、为什么这样操作?
最后的问题是,为什么要像公式那样计算呢?
我们先从 Q K T Q{K}^{T} QKT看起,从几何角度看,点积是两个向量的长度与它们夹角余弦的积。如果两向量夹角为90°,那么结果为0,代表两个向量线性无关。如果两个向量夹角越小,两向量在方向上相关性也越强,结果也越大。点积反映了两个向量在方向上的相似度,结果越大越相似。
对 Q K T Q{K}^{T} QKT进行相似度的计算后,再使用softmax归一化。最后将归一化的结果与 V V V作乘法,计算的结果就是输入经过注意力机制加权求和之后的表示。
参考文献
- 详解Transformer:https://zhuanlan.zhihu.com/p/48508221
- 超详细图解Self-Attention:https://zhuanlan.zhihu.com/p/410776234
- Attention机制与Self-Attention机制的区别:http://t.csdn.cn/GFTC2
- Illustrated: Self-Attention:https://towardsdatascience.com/illustrated-self-attention-2d627e33b20a
- self-attention为什么要除以根号d_k:http://t.csdn.cn/oaOIq