NLP(二十九)一步一步,理解Self-Attention
本文大部分内容翻译自Illustrated Self-Attention, Step-by-step guide to self-attention with illustrations and code,仅用于学习,如有翻译不当之处,敬请谅解!
什么是Self-Attention(自注意力机制)?
如果你在想Self-Attention(自注意力机制)是否和Attention(注意力机制)相似,那么答案是肯定的。它们本质上属于同一个概念,拥有许多共同的数学运算。
一个Self-Attention模块拥有n个输入,返回n个输出。这么模块里面发生了什么?从非专业角度看,Self-Attention(自注意力机制)允许输入之间互相作用(“self”部分),寻找出谁更应该值得注意(“attention”部分)。输出的结果是这些互相作用和注意力分数的聚合。
一步步理解Self-Attention
理解分为以下几步:
- 准备输入;
- 初始化权重;
- 获取
key
,query
和value
; - 为第1个输入计算注意力分数;
- 计算softmax;
- 将分数乘以values;
- 对权重化后的values求和,得到输出1;
- 对其余的输入,重复第4-7步。
注意:实际上,这些数学运算都是向量化的,也就是说,所有的输入都会一起经历这些数学运算。我们将会在后面的代码部分看到。
第一步:准备输入
在这个教程中,我们从3个输入开始,每个输入的维数为4。
1 |
|
第二步:初始化权重
每个输入必须由三个表示(看下图)。这些输入被称作key
(橙色),query
(红色)value
(紫色)。在这个例子中,我们假设我们想要的表示维数为3。因为每个输入的维数为4,这就意味着每个权重的形状为4×3。
注意:我们稍后会看到
value
的维数也是output的维数。
为了获取这些表示,每个输入(绿色)会乘以一个权重的集合得到keys
,乘以一个权重的集合得到queries
,乘以一个权重的集合得到values
。在我们的例子中,我们初始化三个权重的集合如下。
key
的权重:
1 |
|
query
的权重:
1 |
|
value
的权重:
1 |
|
注意: 在神经网络设置中,这些权重通常都是一些小的数字,利用随机分布,比如Gaussian, Xavier and Kaiming分布,随机初始化。在训练开始前已经完成初始化。
第三步:获取key
,query
和value
;
现在我们有了3个权重的集合,让我们来给每个输入获取key
,query
和value
。
第1个输入的key
表示:
1 |
|
利用相同的权重集合获取第2个输入的key
表示:
1 |
|
利用相同的权重集合获取第3个输入的key
表示:
1 |
|
更快的方式是将这些运算用向量来描述:
1 |
|
让我们用相同的操作来获取每个输入的value
表示:
最后是query
的表示:
1 |
|
注意:实际上,一个偏重向量也许会加到矩阵相乘后的结果。
第四步:为第1个输入计算注意力分数
为了获取注意力分数,我们从输入1的query
(红色)和所有keys
(橙色)的点积开始。因为有3个key
表示(这是由于我们有3个输入),我们得到3个注意力分数(蓝色)。
1 |
|
注意到我们只用了输入的query
。后面我们会为其他的queries
重复这些步骤。
第五步:计算softmax
对这些注意力分数进行softmax函数运算(蓝色部分)。
1 |
|
第六步: 将分数乘以values
将每个输入(绿色)的softmax作用后的注意力分数乘以各自对应的value
(紫色)。这会产生3个向量(黄色)。在这个教程中,我们把它们称作权重化value
。
1 |
|
第七步:对权重化后的values求和,得到输出1
将权重后value
按元素相加得到输出1:
1 |
|
产生的向量[2.0, 7.0,
1.5](暗绿色)就是输出1,这是基于输入1的query
表示与其它的keys
,包括它自身的key
互相作用的结果。
第八步:对输入2、3,重复第4-7步
既然我们已经完成了输入1,我们重复步骤4-7能得到输出2和3。这个可以留给读者自己尝试,相信聪明的你可以做出来。
代码
这里有PyTorch的实现代码,PyTorch是一个主流的Python深度学习框架。为了能够很好地使用代码片段中的@
运算符,
.T
and None
操作,请确保Python≥3.6,PyTorch
≥1.3.1。
1. 准备输入
1 |
|
2. 初始化权重
1 |
|
3.
获取key
,query
和value
1 |
|
4. 为第1个输入计算注意力分数
1 |
|
5. 计算softmax
1 |
|
6. 将分数乘以values
1 |
|
7. 对权重化后的values求和,得到输出
1 |
|
注意:PyTorch已经提供了这个API,名字为
nn.MultiheadAttention
。但是,这个API需要你提供PyTorch的Tensor形式的key,value,query。还有,这个模块的输出会经历一个线性变换。
自己实现?
以下是笔者自己写的部分。
对于不熟悉PyTorch的读者来说,上述的向量操作理解起来有点困难,因此,笔者自己用简单的Python代码实现了一遍上述Self-Attention的过程。
完整的Python代码如下:
1 |
|
输出结果如下:
1 |
|
总结
本文主要讲述了如何一步一步来实现Self-Attention机制,对于想要自己实现算法的读者来说,值得一读。
本文分享到此结束,感谢大家的阅读~
欢迎关注我的公众号NLP奇幻之旅,原创技术文章第一时间推送。欢迎关注我的知识星球“自然语言处理奇幻之旅”,笔者正在努力构建自己的技术社区。