解决的问题:输入 \(n\) 个向量,输出相同个数的向量。(如,输入一个句子,输出句子中每个词的词性。每个单词转化成向量可以用 one-hot vector、word embedding 方法等)
一个比较初级的想法:将每个向量都连上去一个 FC(fully connected network),但是这样有个问题是,如果遇到一个句子中有两个相同的单词,在两个 FC 中得出的结果都应该相同,但是实际上可能是不同的。
这启示我们,可以在 FC 之前加一层网络,这个网络考虑到了整个句子,这就是 self-attention
内部结构
可以考虑当前向量和其余向量的相似程度,如果相似程度高,那么这个向量对应的输出中对应的向量的权重就大
如何衡量相似程度?用余弦相似度,即 dot-product
具体公式如下:
先由某个向量通过运算(\(W^q, W^k, W^v\) 为矩阵,需通过学习得出)求出对应的 query、key 和 v,将当前向量的 query 和其余向量的 key 做点乘(特殊的,自己的 query 和自己的 key 也要做),得到的 \(\alpha\) 就是原始的相似度,再通过 softmax 归一化就得到了权重 \(\alpha'\)
最后,将对应的权重和系数 \(v\) 相乘再相加,就得到了当前向量对应的输出
总的流程就是,考虑当前输入的向量 \(a^i\),由 3 个矩阵求出所有向量对应的 q、k、v,再用当前向量的 q 去点乘其它向量的 k,得到原始的 \(\alpha^{i,x}\),softmax 之后得到 \(\alpha'\),再用 \(\alpha^{i,x}\) 和 \(v^x\) 相乘相加得到输出
用矩阵的形式写出:
还有一种扩展:multi-head self-attention,就是每个向量产生出两个 q、k、v,第一个 q 做运算的时候都与第一个的 k 做运算,其余同理,得到第一个输出。同理得到第二个输出,在将这两个输出线性组合得到最终的输出。
一些相关的成果
- 可以在加上一个和位置有关的参数:Positional Encoding
- 发现 dot-product 做的事情和 CNN 中 filter 对每一个 receptive field 做的事相似,这两者有什么关系?事实上,CNN 是 self-attention 的特殊版,因为 CNN 是对每一个感受野做运算,而 self-attention 实际上是拿每一个序列中的向量和序列中的所有向量做运算,相当于把感受野设置为整个序列。在数据量相对较小的时候,CNN 效果好,数据量极大的时候,self-attention 较好
- self-attention 和 RNN 的关系?比 RNN 更强。首先,RNN 是串行的,无法并行;其次,RNN(双向 RNN 也是)对于头和尾两个元素的相关性没有那么高,但是 self-attention 没有这个问题
- 由于需要更新的是整个矩阵,运算量较大,因此产生了许多其它的变形(如 transformer)。