参考文章: https://blog.csdn.net/Tink1995/article/details/105012972
Encoder-Decoder:
在NLP中Encoder-Decoder框架主要被用来处理序列-序列问题,也就是输入一个序列,生成一个序列的问题,可以做文本摘要、翻译和QA系统,这个框架所使用的模型主要有seq2seq模型和Transformer。
![](https://i-blog.csdnimg.cn/blog_migrate/778239b2cd54b198262ada77d561e457.png)
Encoder编码器将输入<x1,x2,x3,x4>转换为中间状态语义编码C;Decoder解码器根据输入的语义编码C,然后将其解码成序列数据,这两者可以用RNN/LSTM/BiRNN等。
缺点:每个输入对于输出的效果是一样的,不合理。仅有一个中间编码C也不足以表述完整的输入信息(过长时)。因此提出了注意力机制。
Attention Model:
attention就是模仿人的注意力机制,可以根据当前时刻的不同输出关注对应的不同输入(对应到多个中间状态C)。
![](https://i-blog.csdnimg.cn/blog_migrate/eb44dd01a5da6e6cdf509e10bd403d5b.png)
比如:当我们在预测Y1时,可能Y1的注意力是放在C1上,那就用C1作为语义编码,当预测Y2时,Y2的注意力集中在C2上,那就用C2作为语义编码,以此类推,就模拟了人类的注意力机制。因此,计算的关键就是如何算出C1,C2,C3…Cn值,从而判断每次在做解码的时候注意力应该放在哪个位置。
AM模型的关键就是:在生成每个单词Yi的时候,由原来固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的Ci。
以翻译任务"Tom chase Jerry" —— "汤姆追逐杰瑞"为例,我们希望输出杰瑞时注意力在Jerry上分配的最多,下为注意力模型分配给不同英文单词的注意力大小:
(Tom,0.3)(Chase,0.2)(Jerry,0.5)
每个Ci对应不同输入单词的注意力分配概率分布:
![](https://i-blog.csdnimg.cn/blog_migrate/0464cb86cc080f698fa894fed15f7812.png)
f2("Tom"),f2("Chase"),f2("Jerry")就是对应的隐藏层的值h("Tom"),h("Chase"),h("Jerry")。g函数就是加权求和,αi表示权值分布。因此Ci的公式就可以写成:
![](https://i-blog.csdnimg.cn/blog_migrate/15cd4a79c2ea51ababd8ac143a01e90a.png)
因此,现在的问题就只剩下,怎么知道attention模型所需要的输入单词注意力分配概率分布值呢?也就是αij ?
![](https://i-blog.csdnimg.cn/blog_migrate/6647e0b33db26fedfe8fde62854aa2ce.png)
decoder上一时刻的输出值Yi-1与上一时刻传入的隐藏层的值Si-1通过RNN生成Hi,然后计算Hi与h1,h2,h3…hm的相关性,得到相关性评分[f1,f2,f3…fm],然后对Fi进行softmax就得到注意力分配αij。然后将encoder的输出值h与对应的概率分布αij进行点乘求和,就能得到注意力attention值了。
Attention 机制的本质思想:
Attention机制并不是一定要像上文一样,基于Encoder-Decoder框架。
![](https://i-blog.csdnimg.cn/blog_migrate/735cf70a9276f0a03cd12ab045c4e352.png)
参照上图理解Attention,将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成(对应到咱们上里面的例子,key和value是相等地,都是encoder的输出值h),此时给定Target中的某个元素Query(对应到上面的例子也就是decoder中的hi),通过计算Query和各个Key的相似性或者相关性(两者越相关数值越高),得到每个Key对应于Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。即可以将其本质思想改写为如下公式:
![](https://i-blog.csdnimg.cn/blog_migrate/f23fdad2b25ddfccd5fa8bbd965515f2.png)
Lx表示source的长度,Similarity(Q,Ki)计算如下:
![](https://i-blog.csdnimg.cn/blog_migrate/196a4b697c854791d8873805399d1372.png)
点积:就是将Query和Keyi进行点积,Transformer中就是用的这种方法。
Cosine相似性-余弦相似度:分子就是两个向量Query与Key的点积;分母就是两个向量的L2范数,(L2范数:向量各元素的平方和然后求平方根)。
计算出Query和Key_i的相似性后,引入类似SoftMax的计算方式对其相似性得分进行数值转换,一方面可以进行归一化(将原始计算分值整理成所有元素权重之和为1的概率分布)另一方面也可以通过SoftMax的内在机制更加突出重要元素的权重。即一般采用如下公式计算:
![](https://i-blog.csdnimg.cn/blog_migrate/c92c83e25a6255eca585fe8cb4ad2ebe.png)
其计算结果 ai 即为 Value_i 对应的权重系数,然后进行加权求和即可得到Attention数值:
![](https://i-blog.csdnimg.cn/blog_migrate/0feac06f86ba2c5d8798fdcf3c4afdd3.png)
以上的三个阶段的计算similarity、softmax和加权求和,即可求出针对Query的Attention数值,是目前绝大多数的注意力机制计算方法。总结如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b1d19888e060c90bfea510690612a883.png)
阶段1:Query与每一个Key计算相似性得到相似性评分s;
阶段2:将s评分进行softmax转换成[0,1]之间的概率分布;
阶段3:将[a1,a2,a3…an]作为权值矩阵对Value进行加权求和得到最后的Attention值。
总的来说,Attention机制不再依赖于RNN,解决了RNN不能并行计算的问题,速度快。但只能在Decoder阶段实现并行运算,Encoder部分依旧采用的是RNN/LSTM这些按照顺序编码的模型,这部分还是无法实现并行,不够完美。而且,正是因为Encoder部分目前仍旧依赖于RNN,所以对于中长距离之间,两个词相互之间的关系没有办法很好的获取。
为了改进这两个缺点,就提出了Self-Attention。
Self-Attention:
在一般任务的Encoder-Decoder框架中,输入Source和输出Target内容是不一样的,例如中译英,Attention机制发生在Target的元素和Source中的所有元素之间。而Self Attention可以理解为Target=Source这种特殊情况下的注意力计算机制,其他过程则是一样的,只是计算对象发生了变化而已,相当于是Query=Key=Value(之前K和V是来自source,Q来自target)。
![](https://i-blog.csdnimg.cn/blog_migrate/2f5a2a62b4d9e016d54eb96d2ea3171b.png)
上述为例,想知道这句话中的its指代的是什么,与哪一些单词相关,那么就可以将its作为Query,然后将这一句话作为Key和Value来计算attention值,找到与这句话中its最相关的单词。通过self-attention发现its在这句话中与之最相关的是Law和application,也确实如此。
引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM对于远距离的相互依赖的特征,要经过若干时间步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。但是Self Attention在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征。除此外,Self Attention对于增加计算的并行性也有直接帮助作用。正好弥补了attention机制的两个缺点。
cross attention:
Transformer架构中混合两种不同嵌入序列的注意机制,这两个序列必须具有相同的维度,但是两个序列可以是不同的模式形态(文本、声音和图片)。其中,一个序列作为输入的Q,定义了输出的序列长度;另一个序列提供输入的K&V。
Cross-attention的输入来自不同的序列,Self-attention的输入来自同序列,也就是所谓的输入不同,但是除此之外,基本一致。
具体而言,Self-attention输入则是一个单一的嵌入序列。Cross-attention将两个相同维度的嵌入序列不对称地组合在一起,而其中一个序列用作查询Q输入,而另一个序列用作键K和值V输入。当然也存在个别情况,在SelfDoc的cross-attention,使用一个序列的查询和值,另一个序列的键。总而言之,QKV是由两序列拼凑的,不单一。
cross-attention的计算复杂度和显存消耗与输入特征大小呈线性关系?