注意力机制三个核心要素:
- Query:即主动注意力。
- key:突出性的环境带给人的被动注意力
- value:注意力汇聚之后得到的最终输入
注意力——本质是一种加权平均
假设有\([(x_i,y_i), ... ,(x_j,y_j)]\) 一系列配对输入,对于一个新的 \(x\) ,我们想要预测它的 \(y\) 。此时我们会想参考过往的所有配对情况,来试着加权平均出这个 \(y\),例如我们可以平等对待所有过往经验:
\[ f(x)=\frac{1}{n}\sum_{i=1}^{n} y_{i} \]
显然这样是不准确的,对于任意输入\(x\)都会得到同样的结果。因此我们还需要考虑\(x\)的影响。继续直观地想,我们可以考虑\(x\)与哪一个\(x_i\)更接近,那么\(y\)给到\(y_i\)的权重也应该更大一些:
\[ f(x)=\sum_{i=1}^{n} \frac{K\left(x-x_{i}\right)}{\sum_{j=1}^{n} K\left(x-x_{j}\right)} y_{i}=\sum_{i=1}^{n} \alpha\left(x, x_{i}\right) y_{i} \]
其中\(K\)是一种核函数,来表示\(x_i\)与\(x\)的权重关系,分母是权重和(即对于\(x\)来说的固定值)。缩写之后得到\(\alpha(x,x_i)\),即表示所谓的注意力权重,其累积和为1。回到注意力框架中,\(x\)即是query,(x_i,y_i)即是(key,value)。\(\alpha\)对\(y_i\)的加权即是注意力汇聚,注意力权重即query和key的关系度量。
对于核函数\(K\),如果\(K\)中计算函数固定,这样得到的就是非参数的注意力汇聚。如果\(K\)中带有一些可变可学习的参数\(w\),那么得到的就是 带参数的注意力汇聚。
有了核函数以及加权平均的概念,此时就可以来看更细致的注意力机制:
其中核函数的单项计算部分可以看做是注意力评分函数(attention scoring function),核函数的多项累计部分可以看做softmax,转化评分为累计和为1的权重系数。最后与value数组进行加权计算,即是注意力汇聚的过程。
评分函数
Masked Softmax
虽然是加权平均,但实际计算中存在很多value不需要进入加权计算。例如文本处理中的填充字符
Additive Attention
当query和key是同样形状的张量时,各种核函数都可以简单的应用。但是query和key是不同长度的时候呢?这时可以使用Additive Attention作为评分函数,本质上就是通过两个线性变换层将它们投影到统一长度空间:
\[ a(\mathbf{q}, \mathbf{k})=\mathbf{w}_{v}^{\top} \tanh \left(\mathbf{W}_{q} \mathbf{q}+\mathbf{W}_{k} \mathbf{k}\right) \in \mathbb{R}, \]
\(\mathbf{W}_{q} \in \mathbb{R}^{h \times q} 、 \mathbf{W}_{k} \in \mathbb{R}^{h \times k}\) 和 \(\mathbf{w}_{v} \in \mathbb{R}^{h}\) 是用于学习自适应调整的参数。
Scaled Dot-Product Attention
点积是一种很容易想到的计算query和key距离的方式,而且效率很高。因此结合缩放思想可以构造出方差为1的度量距离方式:
\[ a(\mathbf{q}, \mathbf{k})=\mathbf{q}^{\top}\mathbf{k}/\sqrt{d} \]
其中\(d\)为向量长度(显然query和key需要相同长度)。当然,为优化性能,实际计算会使用矩阵计算一个批量的点积。
编码器-解码器中的注意力机制
在编码器-解码器框架中,会将这一批所有的输入做成一个不变的上下文,再通过这个上下文去计算这一批所有的预测。显然对于某些预测计算来说,可能会与一部分输入毫无关系,这样粗暴的使用一个统一的上下文并不合理。因此可以想到对每次预测计算,定制一个属于它的上下文,即基于注意力机制定制上下文:
\[ \mathbf{c}_{t^{\prime}}=\sum_{t=1}^{T} \alpha\left(\mathbf{s}_{t^{\prime}-1}, \mathbf{h}_{t}\right) \mathbf{h}_{t} \]
对于某时刻\(t\)的预测计算,\(s\)为解码器上一时刻隐状态,\(h\)为编码器该时刻隐状态。将\(s\)视为query,\(h\)视为key,同时也视为value,最终加权得到基于注意力的上下文\(c_{t^`}\),再与解码器的输入进行连接,送入RNN进行计算:
MultiHead Attention
和多个卷积核学习多种特征一样,我们也可以想到使用多个Attention来学习到多种联系。其中每一个Attention被称作一个Head。而为了实现多个Head学习到不同的联系,需要给它们不完全相同的数据,如使用全连接层进行线性投影,取一部分原数据的子空间给一个Head。当然汇聚不同Head的输出也需要一种连接方式,即也采用一个线性变换将Multi Head组合起来:
因此可以容易给出MultiHead Attention的数学模型:给定query \(\mathbf{q} \in \mathbb{R}^{d_{q}}\) 、key \(\mathbf{k} \in \mathbb{R}^{d_{k}}\) 和value \(\mathbf{v} \in \mathbb{R}^{d_{v}}\), \(\quad f\) 为注意力汇聚操作,每个Head \(\mathbf{h}_{i}(i=1, \ldots, h)\) 的计算方法为:
\[ \mathbf{h}_{i}=f\left(\mathbf{W}_{i}^{(q)} \mathbf{q}, \mathbf{W}_{i}^{(k)} \mathbf{k}, \mathbf{W}_{i}^{(v)} \mathbf{v}\right) \in \mathbb{R}^{p_{v}} \]
Self-Attention
顾名思义,就是query,key,value都是同一个序列\([x_1,...,x_n]\)。其输出结果\([y_1,...,y_n]\)为:
\[ \mathbf{y}_i = f(\mathbf{x}_i, (\mathbf{x}_1, \mathbf{x}_1), \ldots, (\mathbf{x}_n, \mathbf{x}_n)) \in \mathbb{R}^d \]
注意力和卷积
从某种直观上来看,卷积的局部加权平均 和 注意力的加权平均(特别是自注意力) 有点相似?