# 注意力机制概括

总结来自[这篇论文的第7章](http://arxiv.org/abs/1808.09772)

## 注意力机制

注意力机制是一种在**编码器-解码器**结构中使用到的机制, 现在已经在多种任务中使用:

* 机器翻译(Neural Machine Translation, NMT)
* 图像描述(Image Captioning (translating an image to a sentence))
* 文本摘要(Summarization(translating to a more compact language))

而且也不再局限于**编码器-解码器**结构, 多种变体的注意力结构, 应用在各种任务中.

总的来说, 注意力机制应用在:

* 允许**解码器**在序列中的多个向量中, 关注它所需要的信息, 是传统的注意力机制的用法. 由于使用了编码器多步输出, 而不是使用对应步的单一定长向量, 因此保留了更多的信息.
* 作用于**编码器**, 解决表征问题(例如Encoding Vector再作为其他模型的输入), 一般使用**自注意力**(self-attention)

### 1. 编码器-解码器注意力机制

#### 1.1 编码器-解码器结构

![](https://mmbiz.qpic.cn/mmbiz_png/KmXPKA19gWicMiaqpI5cdFEvj2sOZVykZicf02bU7VDhpNWAsu5ZoFYpum7RyEjJRhJiapmn7C0GV7IwzIIicWNDgbA/640?wx_fmt=png\&tp=webp\&wxfrom=5\&wx_lazy=1\&wx_co=1)

如上图, **编码器**将输入**嵌入**为一个向量, **解码器**根据这个向量得到输出. 由于这种结构一般的应用场景(机器翻译等), 其输入输出都是**序列**, 因此也被称为序列到序列的模型**Seq2Seq**.

对于编码器-解码器结构的训练, 由于这种结构**处处可微**, 因此模型的参数$$\theta$$可以通过训练数据和**最大似然估计**得到最优解, 最大化对数似然函数以获得最优模型的参数, 即:

$$\arg\max\limits\_{\theta}{\sum\limits\_{(x,y)\in{corpus}}\log{p(y|x;\theta)}}$$

这是一种**端到端**的训练方法.

#### 1.2 编码器

原输入通过一个网络模型(CNN, RNN, DNN), 编码为一个向量. 由于这里研究的是注意力, 就以**双向RNN**作为示例模型.

对于每个时间步$$t$$, 双向RNN编码得到的向量$$h\_t$$可以如下表示:

![](http://garnet.oss-cn-shenzhen.aliyuncs.com/18-10-10/2726445.jpg)

#### 1.3 解码器

这里的解码器是**单向RNN**结构, 以便在每个时间点上产生输出, 行程序列. 由于解码器**仅**使用**最后时间步**$$T$$对应的编码器的隐藏向量$$h\_{T\_x}$$, $$T\_x$$指的是当前样本的时间步长度(对于NLP问题, 经常将所有样本处理成等长的). 这就迫使编码器将更多的信息整合到最后的隐藏向量$$h\_{T\_x}$$中.

但由于$$h\_{T\_x}$$是单个长度一定的向量, 这个单一向量的**表征能力**有限, 包含的信息量有限, 很多信息都会损失掉.

**注意力机制**允许**解码器**在每一个时间步$$t$$处考虑整个编码器输出的**隐藏状态序列**$$(h\_1, h\_2, \cdots, h\_{T\_x})$$, 从而**编码器**将更多的信息分散地保存在所有隐藏状态向量中, 而**解码器**在使用这些隐藏向量时, 就能决定对哪些向量更关心.

具体来说, 解码器生产的目标序列$$(y\_1, \cdots, y\_{T\_x})$$中的每一个输出(如单词)$$y\_t$$, 都是基于如下的条件分布:

$$P\[y\_t|{y\_1,\cdots,y\_{t-1}},c\_t]=softmax(W\_s \tilde{h}\_t)$$

其中$$\tilde{h}\_t$$是**引入注意力的隐藏状态向量**(attentional hidden state), 如下得到:

$$\tilde{h}\_t=\tanh(W\_c\[c\_t;h\_t])$$

$$h\_t$$为编码器顶层的隐藏状态, $$c\_t$$是上下文向量, 是通过当前时间步上下文的隐藏向量计算得到的, 主要有**全局**和**局部**两种计算方法, 下午中提到. $$W\_c$$和$$W\_s$$参数矩阵训练得到. 为了式子的简化没有展示偏置项.

#### 1.4 全局注意力

通过全局注意力计算**上下文向量**$$c\_t$$时, 使用整个序列的隐藏向量$$h\_t$$, 通过**加权和**的方式获得. 假设对于样本$$x$$的序列长度为$$T\_x$$, $$c\_t$$如下计算得到:

$$c\_t=\sum\limits\_{i=1}^{T\_x}\alpha\_{t,i}h\_i$$

其中长度为$$T\_x$$的校准向量**alignment vector** $$\alpha\_t$$的作用是在$$t$$时间步, 隐藏状态序列中的所有向量的重要程度. 其中每个元素$$\alpha\_{t,i}$$的使用**softmax**方法计算:

$$\alpha\_{t,i}=\frac{\exp(score(h\_t, h\_i))}{\sum\limits\_{j=1}^{T\_x}\exp(score(h\_t, h\_j))}$$

值的大小指明了序列中哪个时间步对预测当前时间步$$t$$的作用大小.

**score函数**可以是任意的比对向量的函数, 一般常用:

* 点积: $$score(h\_t, h\_i)=h\_t^Th\_i$$

  这在使用全局注意力时有更好的效果
* 使用参数矩阵:

  $$score(h\_t, h\_i)=h\_t^TW\_{\alpha}h\_i$$

  这就相当于使用了一个**全连接层**, 这种方法在使用局部注意力时有更好的效果.

全局注意力的总结如下图:

![](https://mmbiz.qpic.cn/mmbiz_png/KmXPKA19gWicMiaqpI5cdFEvj2sOZVykZic5SwVXksjias1lA5ukFcJ4ficRgmwIyBLK8PcibmvT8Tq4iaIqMl0IaQfVw/640?wx_fmt=png\&tp=webp\&wxfrom=5\&wx_lazy=1\&wx_co=1)

#### 1.5 局部注意力

全局注意力需要在序列中所有的时间步上进行计算, 计算的代价是比较高的, 可以使用**固定窗口大小**的局部注意力机制, 窗口的大小为$$2D+1$$. $$D$$为超参数, 为窗口边缘距离中心的单方向距离. 上下文向量$$c\_t$$的计算方法如下:

$$c\_t=\sum\limits\_{i=p\_t-D}^{p\_t+D}\alpha\_{t,i}h\_i$$

可以看到, 只是考虑的时间步范围的区别, 其他完全相同. $$p\_t$$作为窗口的中心, 可以直接使其等于当前时间步$$t$$, 也可以设置为一个变量, 通过训练获得, 即:

$$p\_t=T\_x\sigma(v\_p^T\tanh(W\_ph\_t))$$

其中$$\sigma$$为**sigmoid**函数, $$v\_p$$和$$W\_p$$均为可训练参数. 因此这样计算得到的$$p\_t$$是一个**浮点数**, 但这并没有影响, 因为计算校准权重向量$$\alpha\_t$$时, 增加了一个均值为$$p\_t$$, 标准差为$$\frac{D}{2}$$的**正态分布**项:

$$\alpha\_{t,i}=\frac{\exp(score(h\_t, h\_i))}{\sum\limits\_{j=1}^{T\_x}\exp(score(h\_t, h\_j))}\exp(-\frac{(i-p\_t)^2}{2(D/2)^2})$$

当然, 这里有$$p\_t\in\mathbb{R}\cap\[0, T\_x]$$, $$i\in\mathbb{N}\cap\[p\_t-D, p\_t+D]$$. 由于正态项的存在, 此时的注意力机制认为窗口中心附近的时间步对应的向量更重要, 且与全局注意力相比, 除了正态项还增加了一个截断, 即一个截断的正态分布.

局部注意力机制总结如下图:

![](https://mmbiz.qpic.cn/mmbiz_png/KmXPKA19gWicMiaqpI5cdFEvj2sOZVykZicY0S8hIU5KTVdgIyhkibh0t8jUaPnR0oKSD2QVF3sE3v50agib3ZySuqQ/640?wx_fmt=png\&tp=webp\&wxfrom=5\&wx_lazy=1\&wx_co=1)

### 2. 自注意力

#### 2.1 与编码器-解码器注意力机制的不同

最大的区别是自注意力模型**没有解码器**. 因此有两个最直接的区别:

* **上下文向量**$$c\_t$$在**seq2seq**模型中, $$c\_t=\sum\limits\_{i=1}^{T\_x}\alpha\_{t,i}h\_i$$, 用来组成**解码器**的输入$$\tilde{h}\_t=\tanh(W\_c\[c\_t;h\_t])$$, 但由于自注意力机制没有解码器, 所以这里就直接是模型的输出, 即为$$s\_t$$
* 在计算校准向量$$\alpha\_t$$时, **seq2seq**模型使用的是各个位置的隐藏向量与当前隐藏向量的比较值. 在**自注意力**机制中, 校准向量中的每个元素由每个位置的隐藏向量与当前时间步$$t$$的**平均最优向量**计算得到的, 而这个平均最优向量是通过训练得到的

#### 2.2 自注意力机制实现

首先将隐藏向量$$h\_i$$输入至全连接层(权重矩阵为$$W$$), 得到$$u\_i$$:

$$u\_i=\tanh(Wh\_i)$$

使用这个向量计算校正向量$$\alpha\_t$$, 通过**softmax**归一化得到:

$$\alpha\_{t,i}=\frac{\exp(score(u\_i, u\_t))}{\sum\limits\_{j=1}^{T\_x}\exp(score(u\_j, u\_t))}$$

这里的$$u\_t$$是当前时间步$$t$$对应的**平均最优向量**, 每个时间步不同, 这个向量是通过**训练**得到的.

最后计算最后的输出:

$$s\_t=\sum\limits\_{i=1}^{T}a\_{t, i}h\_i$$

一般来说, 在序列问题中, 只关心最后时间步的输出, 前面时间步不进行输出, 即最后的输出为$$s=s\_T$$

#### 2.3 层级注意力

如下图, 对于一个NLP问题, 在整个架构中, 使用了两个**自注意力**机制: **词层面**和**句子层面**. 符合文档的自然层级结构:

**词->句子->文档**. 在每个句子中, 确定每个单词的重要性, 在整片文档中, 确定不同句子的重要性.

![](https://mmbiz.qpic.cn/mmbiz_png/KmXPKA19gWicMiaqpI5cdFEvj2sOZVykZic11SAVzYTkwjmr0v3r0Gk2zfgiakvPfqkdQDCW768A3JTFFzc4B0PT6A/640?wx_fmt=png\&tp=webp\&wxfrom=5\&wx_lazy=1\&wx_co=1)
