计划写一个系列,讲讲、漫谈Attention,本篇为第一篇,先讲讲人类的注意力和注意力机制基础,包括入门内容。

过去文章漫谈序列编码:MLP、CNN、RNN梳理了Attention前的序列编码方式及其优缺点,包括MLP、CNN、RNN。本文正式进入注意力机制Attention的大门,一种有别于过去模型的全新模型架构。

人类的注意力

在《超负荷的大脑》一书中提到人脑的工作记忆为 7±2,就是一次能处理的资讯的数量。人类每时每刻接受来着视觉、听觉等大量的信息,由于工作记忆的限制,并不能处理所有的信息,但是我们在具体的任务中,依然表现很好。这需要的就是注意力,在大量的信息中,寻找与任务相关的信息。

注意力一般分为两种:

  • 显著性(saliency-based)注意力

  • 聚焦式(focus)注意力

为了更好地理解人类的注意力与深度学习中的注意力机制,我们把这两种注意力展开了谈一谈。

显著性注意力

显著性注意力,自下而上的无意识的注意力,对信息的处理是被动的。这个被动体现在注意力获取信息上是无意识的、受外界刺激而驱动的、没有目的性的。例如我们走在路边,马路上传来汽车喇叭的声音,吸引我们注意汽车经过。

像 CNN 中的最大汇聚(Max Pooling)和门控机制(Gating),本质上是降采样过操作。它们的目的都是筛选最显著的信息(某个度量值最大),因此这类模型可以看做是显著性注意力的运用。

聚焦式注意力

聚焦式注意力,自上而下的有意识的注意力,对信息的处理是主动的、有选择的,因此也可以称为选择性注意力。这个主动性体现在注意力获取信息上是有目的性的、有意识的、被任务驱动的。例如我们要寻找视野中的苹果,聚焦式注意力能够帮助我们快速聚焦在苹果和苹果有关的特征上,进而快速找到苹果。再比如人类在做阅读理解时,一般都是带着问题去阅读去寻找答案,这个“带着问题阅读”的过程就体现了聚焦式注意力的主动性。

聚焦式注意力和显著性注意力的最大差别是获取信息的主动性上,前者获取信息是被动的,后者则是主动的。

根据上述的讨论,我们知道人类中的显著性注意力早就在深度学习中有所体现了。而聚焦式注意力正是本文需要展开的。

Attention机制的基本思路

假设有一向量序列 X=[x1,,xn]Rn×d​,如一句子通过 Embedding 后的输出,其维度为(timesteps, features)。我们有一个和任务相关的向量,称为查询向量 q​,可以根据任务生成,也可以是可学习的参数(下一章我们谈可学习的情况),其具体的意义我们可以先不用关心。那么注意力机制要做的事情分三步:

  • 查询向量 q​ 与每个 xi​ 计算相关性 αi​,相关性通过评分函数(也称为相关性函数)获得
  • 使用softmax归一化相关性 αi,称为注意力分布
  • 根据注意力分布计算向量序列的均值

假设我们有评分函数 s 用于计算查询向量 q 与每个 xi 的相关性,那么有

αi=s(q,xi)

使用 softmax 函数进行归一化相关性,获得注意力分布,

p(z=i|X,q)=softmax(α1,,αn)=exp(αi)i=1nexp(αi)=exp(s(q,xi))i=1nexp(s(q,xi))

我们可能会问,为什么归一化使用softmax方法,而不是其他方法呢?这个疑问我们等会解答。

加权平均,即注意力分布下的均值,

Attention(X,q)=i=1np(z=i|X,q)xi

为更直观理解注意力机制,以阅读理解为例,向量序列为阅读材料,查询向量为问题,评分函数通过问题和阅读材料的相关性找出答案。

注意力机制 阅读理解任务
向量序列 阅读材料
查询向量 问题
注意力分布 阅读材料中答案有关的材料的分布
加权平均 根据阅读材料整合与答案相关的内容

阅读理解任务是典型的Seq2Seq问题或序列标注问题,借这个问题来类比思考Attention中相关的概念,以上的一一对应的。尽管不太严格,但是相当直观。

那么聚焦式注意力是如何设计到Attention机制中呢?所谓的聚焦式就是在庞大的信息集中,主动去关注需要的目标信息。这里的信息集指向量序列X=[x1,,xn]Rn×d。如何体现主动去关注需要的目标信息,就取决于查询向量q。查询向量q​决定了哪些信息是模型需要主动去关注的。这个过程可以通过一个评分函数(也称为相关性函数)来量化,评估模型应该分配多大的权重去关注某个信息。

常见评分函数

查询向量 q 与每个 xi 计算相关性 αi,相关性通过评分函数获得,目前常见的评分函数有若干个:加性模型、点积模型等等。

以下评分函数中的 WUv 都是网络中可以学习的参数。

加性模型

s(x,q)=vtanh(Wx+Uq)

加性模型无法直接计算 qx 的相关性。点积模型通过矩阵的乘法可以解决该问题,且提升计算效率。这个设计其实在LSTM里也有类似的体现,如LSTM的候选状态,

c^t=tanh(Wcxt+Ucht1+bc)

只不过里面添加了一个偏置项。这里ht1可以理解成是查询向量query。

减法模型

s(x,q)=wtanh(w[qk])

点积模型

s(x,q)=xq

点积模型有一个问题,当查询向量维度较高时,s(x,q) 取值的方差较大(正比于维度),进而导致 softmax 函数的梯度较少(落入饱和区间),加大学习难度。点积缩放模型通过添加一个缩放因子可以解决这个问题。

点积缩放模型

s(x,q)=xqd

为进一步提高泛化性能,可以引入双线性模型。

双线性模型

s(x,q)=xWq

展开看,

s(x,q)=(Ux)(Vq)=x(UV)q=xWq

双线性模型对 qx 都进行线性变换。双线性模型引入更多的参数增加泛化性能,同时,由于在矩阵的形状变换下,不要求 qx​ 有相同的维度。

总之,评分函数是可以根据自己对任务的理解自行设计,考虑如何与查询向量交互;考虑是否需要可学习的参数;考虑评分函数的值域,因为下一步要softmax归一化,要考虑后者的活性区间;考虑计算性能,梯度优良性等等。

一个具体的例子

以上我们列举了很多评分函数,这里以此为基础举一个例子。点积缩放模型s(x,q)=xqd的计算比较简单,我们以此为例子。

第一步,计算查询向量 q​ 与每个 xi​ 的相关性,那么有

s(xi,q)=xiqd

第二步,计算注意力分布,即归一化评分函数,

p(z=i|X,q)=softmax(α1,,αn)=exp(αi)i=1nexp(αi)=exp(xiqd)i=1nexp(xiqd)

第三部,加权平均,

Attention(X,q)=i=1nαixi

这就是基于点积缩放模型的Attention机制的三个步骤。获得的输出用作下游网络模型的输入以更进一步处理信息,例如输入到Dense网络中,然后做分类。

那么现在还有一个问题,如何构建查询向量?这个问题留作思考。

再谈查询向量

在注意力中,所谓的主动与被动的关键是,我们是否提前知道自己需要什么信息。知道自己需要什么信息体现在查询向量q上。

经过不断的折腾,我们找到一个”标的”向量,如果一个向量和它越”相似”,那么这个向量对任务的贡献就更大。即,如果 xi​ 和某个标的向量 q​ 越相似,它的重要性越高。至于为什么?经验罢了。现在于是,又要重新回去折腾 s 这个函数。即用 s(q,xi) 来表示 xi 的重要性。于是,每个 xi 的权重 λi​ 计算如下,

λi=es(q,xi)i=1nes(q,xi)

那么,获得的注意力输出为,

C=i=1nλixi

这个过程就是查询向量参与下的Attention机制,直观看如下,

additive-attention-query.pngadditive-attention-query.png

有了这个标的向量 q​​​ 对目标任务描述得越准确,模型性能进一步提升。

如果目标任务并不只有查询向量呢?而是一系列查询向量qi,i=1,2,,m​​,那么Attention机制应该如何表示?其实就是多少个查询向量就重复以上多少次的Attention计算过程。

我们还是以点积缩放模型s(x,q)=xqd作为评分函数,假设有一向量序列 X=[x1,,xn]Rn×d,以及一系列查询向量qiR1×d,i=1,2,,m,令Q=[q1,,qm]Rm×d​​。

使用αij​​表示第i​​个查询向量qi​​对向量序列中第j​​个元素xj​​的评分值,那么可以构成矩阵A=[aij]​,其每个元素为,

αij=s(qi,xj)=xjqid,i=1,,m;j=1,,n

于是有,

A=QXd

可以知道,矩阵A​​的每一行表示一个固定的查询向量对向量序列中所有元素的评分值,因此对矩阵按行进行softmax(x)​归一化可以得到注意力分布矩阵,

S=softmax(QXd)

因此,多查询向量下,Attention机制表示为,

Attention(X,Q)=softmax(QXd)X

由于查询向量的存在,对于X的使用可以不再使用Pooling,而是根据下游需求构造查询向量q,在再Attention下获得需要的信息,这在一定程度上缓解Pooling来说的信息容量有限的问题。例如在seq2seq中,第i步的解码时,构造查询向量qi(如decoder中RNN模型第i步的输出),解码输出需要关于X​的信息可以从Attention中获得,

yi=Attention(qi,X,X)

然后这个yi再通过一定的处理后就可以送入softmax(yi),获得当前时间步解码的分布。Attention机制其实和时间序列建模很相似,在时间序列中,我们常常想知道某个时间步和其他时间步的相关性。

引入键值对结构

有时候向量序列X=[x1,x2,,xk]不一定是这种形式,而是长键值对(key-value pair)结构,即

X=[(k1,v1),(k2,v2),,(kn,vn)]

这种数据结构,在Attention中是期望使用ki​与查询向量q​计算相关性并进行归一化,而加权平均则是使用vi​​,同时也起到记忆检索的作用。这个要求对注意力机制的计算影响不大,依旧可以分为三个步骤来完成:

  • 查询向量 q​​ 与每个 ki​​ 计算相关性 αi​​
  • 使用softmax归一化相关性 αi,称为注意力分布
  • 根据注意力分布计算向量序列[v1,,vn]的均值

假设我们有评分函数 s​ 用于计算查询向量 q​ 与每个 ki​ 的相关性,那么有

αi=s(q,ki)

使用 softmax 函数进行归一化相关性,获得注意力分布,

p(z=i|X,q)=softmax(α1,,αn)=exp(αi)i=1nexp(αi)=exp(s(q,ki))i=1nexp(s(q,ki))

加权平均,即注意力分布下的均值,

Attention(X,q)=i=1np(z=i|X,q)vi

直观的示意图如下,

attention-kvattention-kv

为什么要引入键值对结构呢?其实是为了相关性计算与注意力加权平均的分离。这样的注意力模型更具普遍性。

类似上一节的推导,当查询向量为多个,评分函数为点积缩放模型的情况下,注意力机制可以紧凑第表示为,

Attention(K,V,Q)=softmax(QKd)V

其中softmax是对矩阵按行计算。

Attention解决seq2seq问题

在没有Attention之前,seq2seq问题通常是这样的,假设输入是x=[x1,,xn]

h=encoder(x1,,xn)yi=decoder(yi1,si,h)

encoder负责对输入序列x=[x1,,xn]编码成一个向量h,理论上该向量包括了输入序列的主要信息。encoder通常是双向的RNN,如Bi-LSTM或者CNN+某种Pooling。decoder中,第i步的解码需要第i1步的解码以及当前时刻的隐状态si和encoder获得的向量h。decoder通常是单向的RNN。

这种encoder-decoder解码架构有一种问题:随着序列的变长,encoder无法把更多有效的信息融入到h​​中,即encoder存在遗忘性,即便是双向的LSTM也无法解决这个问题。

而Attention的引入,可以解决这个问题,首先encoder不需要把输入序列编码成单个向量,毕竟单个向量存储信息的能力是有限的,

H=[h1,h2,,hn]=encoder(x1,,xn)yi=decoder(yi1,si,ci)ci=Attention(si,H,H)

对于decoder来说,第i步的解码不再固定一个来自encoder的向量h,而是根据Attention机制动态地构建。构建方式是以decoder第i步的隐状态si(或者si1)作为查询向量在Attention下获取H中对当前时刻解码有用的信息。

总结

本文从人类的显著性注意力、聚焦式注意力为开头,然后讲述以聚焦式注意力为原理的Attention机制的三个步骤~

什么情况下需要注意力机制?处理大量信息、需要聚焦大量信息中的特定信息、信息记忆有限。更多注意力机制的研究,比如稀疏注意力、位置问题、注意力的可解释性、结构化注意力。注意力机制的应用,如指针网络。比如,设想一个排序过程,输入 5, 168, 13,输出排序后的序列的索引,也就是 1, 3, 2。这就网络指针做的事情。此外,还有神经图灵机。

作为一个系列,下一篇会写软硬性注意力及其导出关系。

参考文献

[1] nndl.github.io

[2] Neural Machine Translation by Jointly Learning to Align and Translate

[3] A structured Self-Attentive Sentence Embedding

[4] Sparse Attentive Backtracking: Temporal Credit Assignment Through Reminding

[5] Attention is all you need

转载请包括本文地址:https://allenwind.github.io/blog/9477
更多文章请参考:https://allenwind.github.io/blog/archives/