Attention

  2020-5-29 


以前的,整理到网站上

Attention机制

img

如上图,将Source中的构成元素(输入序列)想象成是由一系列的$$数据对构成,此时给定Target中的某个元素$Query$,①通过计算$Query$和每个$Key$的相似性(相关性),得到每个$Key$对应$Value$的权重系数,②然后将得到的各个权重系数与对应的各个$Value$相乘进行加权求和,即得到了最终的$Attention$数值。所以本质上Attention机制是对Source中元素的$Value$值进行加权求和,即可以将其本质思想改写为如下公式:

$Similaity(Query,Key_i)$也叫Attention Score。在词嵌入空间,两个向量的相似度可以由内积求得,也就是说$query·key$再经过softmax归一化后即为attention权重

理解思想:以上步骤可以理解为从大量信息中有选择地筛选出少量重要信息并聚焦到这些重要信息上,忽略大多不重要的信息。聚焦的过程体现在权重系数的计算上($softmax(query·key)$),权重越大越聚焦于其对应的$value$值上,即权重代表了信息的重要性,而$value$是其对应的信息。

也可以理解为是一种软寻址过程(这种寻址会从各个地址根据一定权重取出数据):$key$是数据地址,$value$是对应地址储存的数据内容,$query$是待查地址,任务目标是查询$key=query$地址所储存的数据。于是先用$query$与每个$key$求相似度,得到每个地址的重要性,然后再对每个地址的$value$进行加权求和,得到最终的$value$值

P.S.1在基于Attention的Seq2Seq任务中,$Key=Value$,即输入的都是句子中每个单词对应的语义编码,具体实践反应在$Key$和$Value$是共享同一个线性层(参数矩阵)

P.S.2 Attention Score即$query与key$的相似度,其计算方式有多种,最常用的点积:即$q·k$,还有其它方式,略

P.S.3 求得各输入的$key$与$value$的相似度(Attention Score)之后还要经过一层softmax,做归一化,转化为概率才是注意力权重

应用Attention于Seq2Seq结构

无attention的Seq2Seq模型:

img

→→→有attention的Seq2Seq模型($Source≠Target$,non-intra attention)←←←:

img

在有attention的seq2seq模型中,$C$变成了不同的$C_1,C_2,C_3$就是说:不同输出时刻(输出序列的不同单词)的注意力(对Encoder所编码的语义分配的概率信息)不同。换句话说在生成每个单词$\mathbb y_i$的时候,原先都是相同固定的中间语义表示$C$会被替换成根据当前生成单词而不断变化的$C_i$。理解Attention模型的关键就是这里。

如何理解Attention?一般在NLP里会把Attention模型看作是[输出Target句子中某个单词]和[输入Source句子每个单词]的对齐(对应概率关系)模型

对于采用RNN的Decoder来说,$query$是Decoder RNN目前时刻的hidden state $h_t$,$Key$和$ Value$是Encoder RNN各个时刻的hidden state $H_1,H_2,H_3,H_4$。 (这个例子使用soft-attention+2RNN seq2seq结构)

(接上段话)于是就有:在时刻$i$,如果要生成$y_i$单词,我们是可以知道Target在生成$Y_i$之前的时刻$i-1$时,隐层节点$i-1$时刻的输出值$H_{i-1}$的,而我们的目的是要计算生成$Y_i$时输入句子中的单词$x_1,x_2,x_3$对$Y_i$来说的注意力分配概率分布,那么可以用Target输出句子$i-1$时刻的隐层节点状态$H_{i-1}$去一一和输入句子Source中每个单词对应的RNN隐层节点状态$h_j$进行对比,即通过函数$F(h_j,H_i-1)$来获得目标单词$y_i$和每个输入单词对应的对齐可能性,这个$F$函数在不同论文里可能会采取不同的方法。

Non-Intra Attention

源与目标不同,$Source≠Target$

$query$来源于输出Decoder部分,$key$来源于输入Encoder部分。如上面例子里用的soft-attention+2RNN seq2seq结构,非self-attention都是decoder里输出的每个Target:$y$作为$query$,encoder的语义编码(隐藏层输出)作为$key$,然后这两做内积求attention

下面三种attention都以Encoder为RNN举例

Soft attention

这里写图片描述

该图中橘黄色方块就是Decoder部分的当前输出$s_t$,$\alpha_i$就是注意力权重,$query=s_t$,$Key=h_1,h_2,\cdots,h_N$,最基本的attention机制,原理很容易理解

上面举的soft-attention+2RNN seq2seq结构例子用的就是用的soft attention

这个“软”指的是每个输入的向量(单词)都会分配一个注意力权重

实践例子:官网DEMO 这个例子用GRU Decoder + soft-attention做seq2seq机器翻译

Hard attention

这里写图片描述

权重很硬,只在输入句子中找到特定单词,其注意力权重才为1,其它单词的注意力权重都是0

这个“硬”指的就是只有某特定向量权重为1,其它权重全为0,只注意那一个向量;用在图像领域

local attention (半软半硬attention)

这里写图片描述

只考虑部分窗口内的encoder隐藏输出,其余部分为0,在窗口内和soft attention(global attention)一样

半软:窗口内的是soft attention

半硬:对于指定窗口外的所有输入全部设置注意力权重为0

相比soft(global) attention可以减少计算量

Intra Attention:Self-Attention

intra attention与上面几种attention都不同,是一种特殊的attention

①【源与目标相同,$Source=Target$】,也就是说一个Self-Attention结构本身就是一个Source输入与Target输出相同的Seq2Seq,如下图

也就是说【self-attention的$query$和$key$都来源于输入句子】,是一种原文自己内部的注意力机制

②其$Q,K,V$不通过RNN等神经网络产生,而是训练三个嵌入层参数矩阵

这里写图片描述

这种结构可以完全替代Seq2Seq中Encoder和Decoder中的RNN,变成后面的Seq2Seq with self-attention结构

也是Transformer结构的基础

与RNN和CNN相比

  1. Seq2Seq模型中运用RNN或CNN的问题:

    RNN难以平行化;CNN虽可以平行化,但是dependent范围比较短,必须通过叠多层来扩大视野域

    RNN有长距离依赖问题,当前时间必然受最相邻时间步输入的影响,而以前时间步需要经过若干时间步步骤的信息累积,距离越远,有效捕捉得到的历史信息越少,甚至可能出现梯度消失;

  2. 于是提出Self-Attention来完全代替RNN:

    一切RNN能做的,都可以用self-attention替代

    也同理,使用预训练word2vec之后,Transformer模型之前也可以nn.embedding嵌入层生成词向量,一起训练嵌入层参数以特化词向量)

  3. self-attention的好处:

    并行、可以很好捕捉长距离依赖问题(用注意力解决),它也 摒弃了 CNN 的局部假设,想要寻找长距离的关联依赖。

  4. 为什么Self-Attention可以替代RNN

    无论是RNN还是CNN还是DNN,还是self-attention,本质都是特征提取器

    RNN在每个时刻存在一个隐藏状态,其中包含了当前和以前时刻输入的信息==>其实就是特征提取,同CNN;

    Self-Attention是直接同时输出所有”隐藏状态”,其中包含通过每一个输出从整句话中获取到的注意力信息=>也是特征提取

    于是它们就都可以对隐藏层的输出输入进一个前馈神经网络,执行任务,或用提取得到的特征干其它事情

结构

$q,k,v$的含义以及为什么要这么运算:见上面的“Attention的本质

  1. 由每个输入获取$q、k、v$三个向量

    输入$x_i$是已经embedding的词向量

    $a_i=Wx_i$每一个输入$x_i$乘以三个不同的权值矩阵$W^q,W^k,W^v$(即线性变换),得到每个输入对应的$q_i、k_i、v_i$。query,key,value(information)。

    此操作即对输入进行三个不同的embedding:$x_i$经过三个不同的线性层变成$q,k,v$,其实就相当于再经过了三个不同的词嵌入(embedding,权值矩阵$W^q,W^k,W^v$即不同的词嵌入矩阵)。结合上面的attention本质可以理解为什么要这样。

    这个权值矩阵的形状即为: 词表长度 x 目标向量q/k/v维度,得到一维向量$q,k,v$

    image-20200228205121484

  2. 然后拿每一个$q$去与每一个输入对应的$k$做点积,得到每一个输入对应一个的$\alpha$

    这个$\alpha$就是attention权重,其实质上就是q和k的相似度(点积求相似度)

    这里先用第一个$q_1$

    image-20200228205627470

    $q·k$之后除以$\sqrt d$,为了防止太大

  3. 然后将self attention得到的$\alpha$经过softmax得到$\hat \alpha$

    image-20200228210057957

  4. 然后再将softmax输出的$\hat \alpha$乘各自的$v$向量,并全部求和,得到第一个$q_1$的self-attention输出$b_1$,也就是第一个输入的self-attention输出结果

    下图softmax层没画出来

    image-20200228210221791

  5. 同理,以上1234都是求第一个输入对应的$q_1$的self-attention输出结果$b_1$,求第二个输入对应的输出就用$q_2$重复上述流程

    如下列举第二个$q_2$,softmax层没画出来

    image-20200228211904865

可以看到,产生的每个输出,都用到了整个句子所有输入的信息。每个位置所乘的$W^q、W^k、W^v$就是模型要学习的东西。不同单词乘以这个权值参数生成不同的$q,k,v$,体现了”输入序列中不同单词的关注度不一样,具有注意力

$q,k,v$的意义:$q$代表着这一整句话的embedding,$k=v$代表着每个单词的embedding

此时输出的每一个位置的$b$就已经包含了从整句话(输入)中提取得到的注意力信息(特征信息)了

如果再多经过几层,那么提取得到的语义信息将会更抽象

矩阵表达:

注意矩阵乘法的左行右列

  1. 将上面图中每个位置对应的$q,k,v$组合起来成为矩阵以并行计算:

    image-20200228212453547

    于是根据上面的流程继续推:

    只看$q_1$的1,2步过程(softmax之前,生成$q_1$与每一个位置上的$k_i$的每一个位置上的内积向量$\alpha_i$),可以如此组合

    image-20200228212629935

    若看所有输入位置的$q$:

    image-20200228213211597

    如此便生成了$\alpha$构成的Attention矩阵$A$,再经过softmax生成$\hat A$。

  2. 再看第4步乘$b$求和,矩阵表达

    image-20200228214136216

    $O$即最终输出的序列

    $Q、K、V$的维度都是$h_{hidden}×l_{src}$

总结

  1. 实际的矩阵乘法表示

    image-20200228214322939

    全是矩阵乘法,可以方便用GPU加速

  2. $q,k,v$这个过程的意义的补充

    主要部分都在Attention机制一节里,这里更具体化一下

    通过$q$和$k$进行点积,并通过softmax得到每个词的一个attention权重(归一化,转化为概率),在句子内部做了一个attention,所以称作Self AttentionSelf Attention可以刻画句子内部各成分之间的联系,比如说“看”跟“书”之间就建立了联系。这样,每个词的向量表示($\hat \alpha$)就包含了句子里其他词的关联信息。

Multi-head Self-attention

多个self-attention,对于一句话(一个输入序列)生成多个$Q、K、V$

得到多个$O$

这时候将多个$O$整合(可以求平均(多个head的期望),etc)

image-20200228214704364

Multi-head Self-attention的意义:每个head(即一个完整的attention)的关注点不一样(即每个attention生成的$Q、K、V$不一样),于是多个attention组合起来就可以从“多个角度”去匹配输入句子中不同的模式

注意区别,单个attention与multi-head attention:

一个attention能够学习到输入序列的一种模式:即每个时刻的输出对输入(整句话)的“注意点”都不同,输入序列到每个输出时刻识别出一种模式,最终多个输出构成一个序列

多个attention就能够学习到输入序列的多种模式每个输出时刻识别出多种模式,最终多个时刻的多个输出构成多个序列

Positional Encoding

在self-attention中没有编码输入单词的相对位置信息如句子$i_1,i_2,i_3,i_4$中,$i_1$与$i_2$相邻,$i_1$与$i_4$相隔很远,这种信息就没有编码进去。

具体实现有两种方式,一种是Facebook版本:《Convolutional Sequence to Sequence Learning》,另一种Google版本:Postional Encoding,两种效果没有差别。


输入[经过一个嵌入层]再[加上]一个位置向量$e^i$再乘以权值矩阵

这个位置向量是每个位置独有一个的,不是从数据中学习到的

位置向量$e^i$生成:由编码位置信息的one-hot向量$p_i$乘上词嵌入矩阵$W^P$得到的。这个$W^P$是人为设定的,就是原论文中sin,cos公式所表达的矩阵:

NLP-Transformer

当然这个$W^p$也可以直接随机初始化让模型来学习

为什么要用这个公式的一种理解是:如何理解Transformer论文中的positional encoding,和三角函数有什么关系? - 徐啸的回答 - 知乎 (mark)

【O】Seq2seq with Self-Attention

将Seq2Seq模型中Encoder和Decoder全用self-attention代替

注意力允许解码器网络针对解码器自身输出的每一步“聚焦”编码器输出的不同部分。

image-20200301182413221

实践

Pytorch.nn中已经实现Multi-head Attention

torch.nn.MultiheadAttention(embed_dim, num_heads, dropout=0.0, bias=True, add_bias_kv=False, add_zero_attn=False, kdim=None, vdim=None)

attention的实现实际上就是从原理上来实现,本质就是在线性层(参数就是个矩阵)基础上多了一些(一堆)变换,训练attention就是训练该线性变换层的参数矩阵

而self-attention由于有三个参数矩阵,输入经过了三个不同的线性层,要训练的就是这三个线性层的参数矩阵

具体实现见源代码


Attention机制+Encoder Decoder结构不仅在NLP(在NLP已成标配),在很多领域都有大量应用,如图像描述等


且听风吟