zl程序教程

您现在的位置是:首页 >  工具

当前栏目

【NLP相关】深入理解attention机制(产生、发展、原理、应用和代码实现)

应用原理代码 实现 深入 理解 机制 相关
2023-09-27 14:29:07 时间

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️

👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈

1. 前言

attention机制在深度学习各个领域都被广泛使用,尤其是CV和NLP任务中经常会出现attention机制的身影。本文将从原理角度深入分析attention机制。

Attention是一种用于提升基于RNN(LSTM或GRU)的Encoder + Decoder模型的效果的的机制(Mechanism),一般称为Attention Mechanism。Attention Mechanism目前非常流行,广泛应用于机器翻译、语音识别、图像标注(Image Caption)等很多领域,之所以它这么受欢迎,是因为Attention给模型赋予了区分辨别的能力,例如,在机器翻译、语音识别应用中,为句子中的每个词赋予不同的权重,使神经网络模型的学习变得更加灵活(soft),同时Attention本身可以做为一种对齐关系,解释翻译输入/输出句子之间的对齐关系,解释模型到底学到了什么知识,为我们打开深度学习的黑箱,提供了一个窗口,如下图所示 [ 1 ] ^{[1]} [1]
图1NLP中的attention可视化

2. attention机制的产生

attention机制并不是一个新概念,在很久之前(90年代)就有学者提出,其最早产生并且应用在计算机视觉(CV)领域,之后在自然语言处理(NLP)领域快速发展,最近又在CV领域火了起来。

attention机制来源于人类的视觉注意力机制,可以算是仿生学的一个应用,视觉注意力机制是人类视觉所特有的大脑信号处理机制。人类视觉通过快速扫描全局图像,获得需要重点关注的目标区域,也就是一般所说的注意力焦点,而后对这一区域投入更多注意力资源,以获取更多所需要关注目标的细节信息,而抑制其他无用信息。

这是人类利用有限的注意力资源从大量信息中快速筛选出高价值信息的手段,是人类在长期进化中形成的一种生存机制,人类视觉注意力机制极大地提高了视觉信息处理的效率与准确性。

图2人类的视觉注意力机制
图2形象化展示了人类在看到一副图像时是如何高效分配有限的注意力资源的,其中红色区域表明视觉系统更关注的目标,很明显对于图1所示的场景,人们会把注意力更多投入到人的脸部,文本的标题以及文章首句等位置。

深度学习中的注意力机制从本质上讲和人类的选择性视觉注意力机制类似,核心目标也是从众多信息中选择出对当前任务目标更关键的信息 [ 2 ] ^{[2]} [2]

3. attention机制的发展

attention第一次火起来是2014年Google Mind团队发表的论文《Recurrent Models of Visual Attention》。

随后Bahdanau等人在论文《Neural Machine Translation by Jointly Learning to Align and Translate》中,使用类似attention的机制在机器翻译任务上将翻译和对齐同时进行,他们的工作算是第一个将attention机制应用到NLP领域中。

2017年,Google机器翻译团队发表的《Attention is all you need》中完全使用自注意力(Self-attention)机制来学习文本表示。这篇论文算是开起了Self-attention机制(这个结构也被叫做Transformer结构)的研究浪潮,之后的Bert预训练模型也是在这个基础(Transformer)上构建。

2018年底,Google发布了论文《Pre-training of Deep Bidirectional Transformers for Language Understanding》,Bert的出现,刷新了NLP领域的11个方向的记录,当时属于霸榜的存在,之后的预训练模型基本上离不开基于Self-attention的Transformer结构了 [ 3 ] ^{[3]} [3]

4. attention机制的原理

讲到attention的原理,就不得不提RNN的缺陷了,下图是一个基于RNN的神经翻译系统,红色部分是encoding部分,蓝色的是decoding部分,encoding部分输入的是被翻译语言单词的嵌入式表示,进过RNN网络,得到包含有整个句子的信息的向量hidden vector,然后在经过decoding解码得到目标语言向量。这个结构主要存在以下几个问题:
1.RNN本身所具有的梯度消失问题,对于较长的句子,我们很难寄希望于将输入的序列转化为定长的向量而保存所有的有效信息,所以随着所需翻译句子的长度的增加,这种结构的效果会显著下降。
2.这个结构得到的hidden vector虽然包含了整句话的全部信息,但是这个全部信息具有局部依赖的特性,也就是说越近的句子对hidden vector的贡献越大,很多时候hidden vector其实只学到了每句话最后几个词的信息
3.不能够支持并行计算,训练起来会很慢,每个词向量对应的导数依赖后续的词的导数,这样递归求导也是梯度消失问题的主要原因 [ 4 ] ^{[4]} [4]
基于RNN的神经翻译模型
这些问题并不是一下子解决的,每个问题的解决都间隔了一段时间。引入attention机制能够解决前两个问题,下面我们来看看attention的原理。Attention机制跟人类翻译文章时候的思路有些类似,即将注意力关注于我们翻译部分对应的上下文。同样的,Attention模型中,当我们翻译当前词语时,我们会寻找源语句中相对应的几个词语,并结合之前的已经翻译的部分作出相应的翻译,如下图所示,当我们翻译“knowledge”时,只需将注意力放在源句中“知识”的部分,当翻译“power”时,只需将注意力集中在"力量“。这样,当我们decoder预测目标翻译的时候就可以看到encoder的所有信息,而不仅局限于原来模型中定长的hidden vector,并且不会丧失长距离的信息,尤其是在翻译一些倒装句等特殊句式的时候,attention机制就能比传统的RNN起到一个更好的效果。

attention机制的原理图解
为了便于解释attention的详细原理,我们采用下图作为神经机器翻译的原理图。

神经机器翻译NMT原理图

首先我们利用RNN结构得到encoder中的hidden state ( h 1 h_1 h1- h t h_t ht),这个 h 1 h_1 h1- h t h_t ht代表着上文提到的hidden vector,只不过上文提到的hidden vector是最后一个状态的hidden vector,即 h t h_t ht的hidden vector。

假设当前decoder的hidden state 是 s t − 1 s_{t-1} st1,我们可以计算每一个输入位置j的hidden vector与当前输出位置的关联性similarity( s t − 1 s_{t-1} st1, h j h_j hj),这个有很多种计算方式,其实就是相似度的计算方式。

对于所有的similarity( s t − 1 s_{t-1} st1, h j h_j hj)进行softmax操作后将其normalize得到attention的分布,这一步得到的就是下图中的 a t , 1 a_{t,1} at,1- a t , t a_{t,t} at,t,也就是decoder的下一层输出与所有输入之间的权重关系。 α t , j = e s i m i l a r i t y ( s t − 1 , h j ) ∑ k = 1 T e s i m i l a r i t y ( s t − 1 , h k ) \alpha_{t,j}={e^{similarity(s_{t-1},h_j)}\over{\sum_{k=1}^{T}e^{similarity(s_{t-1},h_k)}}} αt,j=k=1Tesimilarity(st1,hk)esimilarity(st1,hj)

利用 α t , j \alpha_{t,j} αt,j我们可以进行加权求和得到相应的context vector c t = ∑ j = 1 T α t , j h j c_t=\sum_{j=1}^{T}\alpha_{t,j}h_j ct=j=1Tαt,jhj

由此,我们可以计算decoder的下一个hidden state s t = f ( s t − 1 , y t − 1 , c t ) s_t=f(s_{t-1},y_{t-1},c_t) st=f(st1,yt1,ct)以及该位置的输出 p ( y t ∣ y 1 , . . . , y t − 1 , x ) = g ( y i − 1 , s t , c t ) p(y_t|y_1,...,y_{t-1},x)=g(y_{i-1},s_t,c_t) p(yty1,...,yt1,x)=g(yi1,st,ct)
attention机制的数学原理
这里关键的操作是计算encoder与decoder state之间的关联性的权重,得到Attention分布,从而对于当前输出位置得到比较重要的输入位置的权重,在预测输出时相应的会占较大的比重。

注意力分配概率的计算

attention的形成过程

通过Attention机制的引入,我们打破了只能利用encoder最终单一向量结果的限制,从而使模型可以集中在所有对于下一个目标单词重要的输入信息上,使模型效果得到极大的改善。还有一个优点是,我们通过观察attention 权重矩阵的变化,可以更好地知道哪部分翻译对应哪部分源文字,有助于更好的理解模型工作机制,如下图所示。

attention的工作机制图解
如果把Attention机制从上文讲述例子中的Encoder-Decoder框架中剥离,并进一步做抽象,可以更容易看懂Attention机制的本质思想。

attention本质
我们可以这样来看待Attention机制:将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定Target中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。即可以将其本质思想改写为如下公式:
A t t e n t i o n ( Q u e r y , S o u r c e ) = ∑ i = 1 L x S i m i l a r i t y ( Q u r e y , K e y i ) ∗ V a l u e i Attention(Query,Source)=\sum_{i=1}^{L_x}Similarity(Qurey,Key_i)*Value_i Attention(Query,Source)=i=1LxSimilarity(Qurey,Keyi)Valuei
其中, L x L_x Lx=||Source||代表Source的长度,公式含义即如上所述。上文所举的机器翻译的例子里,因为在计算Attention的过程中,Source中的Key和Value合二为一,指向的是同一个东西,也即输入句子中每个单词对应的语义编码,所以可能不容易看出这种能够体现本质思想的结构。

当然,从概念上理解,把Attention仍然理解为从大量信息中有选择地筛选出少量重要信息并聚焦到这些重要信息上,忽略大多不重要的信息,这种思路仍然成立。聚焦的过程体现在权重系数的计算上,权重越大越聚焦于其对应的Value值上,即权重代表了信息的重要性,而Value是其对应的信息。

从上图可以引出另外一种理解,也可以将Attention机制看作一种软寻址(Soft-Addressing):Source可以看作存储器内存储的内容,元素由地址Key和值Value组成,当前有个Key=Query的查询,目的是取出存储器中对应的Value值,即Attention数值。通过Query和存储器内元素Key的地址进行相似性比较来寻址,之所以说是软寻址,指的不像一般寻址只从存储内容里面找出一条内容,而是可能从每个Key地址都会取出内容,取出内容的重要性根据Query和Key的相似性来决定,之后对Value进行加权求和,这样就可以取出最终的Value值,也即Attention值。所以不少研究人员将Attention机制看作软寻址的一种特例,这也是非常有道理的。

至于Attention机制的具体计算过程,如果对目前大多数方法进行抽象的话,可以将其归纳为两个过程:第一个过程是根据Query和Key计算权重系数,第二个过程根据权重系数对Value进行加权求和。而第一个过程又可以细分为两个阶段:第一个阶段根据Query和Key计算两者的相似性或者相关性;第二个阶段对第一阶段的原始分值进行归一化处理;这样,可以将Attention的计算过程抽象为如下图展示的三个阶段。

attention的三个阶段
在第一个阶段,可以引入不同的函数和计算机制,根据Query和某个 K e y i Key_i Keyi,计算两者的相似性或者相关性,最常见的方法包括:求两者的向量点积、求两者的向量Cosine相似性或者通过再引入额外的神经网络来求值,即如下方式:
点积: S i m i l a r i t y ( Q u e r y , K e y i ) = Q u e r y ⋅ K e y i 点积:Similarity(Query,Key_i)=Query·Key_i 点积:Similarity(Query,Keyi)=QueryKeyi
c o s 相似度: S i m i l a r i t y ( Q u e r y , K e y i ) = Q u e r y ⋅ K e y i ∣ ∣ Q u e r y ∣ ∣ ⋅ ∣ ∣ K e y i ∣ ∣ cos相似度:Similarity(Query,Key_i)={Query·Key_i\over{||Query||·||Key_i||}} cos相似度:Similarity(Query,Keyi)=∣∣Query∣∣∣∣Keyi∣∣QueryKeyi
M L P 网络: S i m i l a r i t y ( Q u e r y , K e y i ) = M L P ( Q u e r y , K e y i ) MLP网络:Similarity(Query,Key_i)=MLP(Query,Key_i) MLP网络:Similarity(Query,Keyi)=MLP(Query,Keyi)
第一阶段产生的分值根据具体产生的方法不同其数值取值范围也不一样,第二阶段引入类似softMax的计算方式对第一阶段的得分进行数值转换,一方面可以进行归一化,将原始计算分值整理成所有元素权重之和为1的概率分布;另一方面也可以通过softMax的内在机制更加突出重要元素的权重。即一般采用如下公式计算:
a i = s o f t m a x ( S i m i ) = e s i m i ∑ j = 1 L x e s i m i a_i = softmax(Sim_i)={e^{sim_i}\over{\sum_{j=1}^{L_x}e^{sim_i}}} ai=softmax(Simi)=j=1Lxesimiesimi
第二阶段的计算结果 a i a_i ai即为 v a l u e i value_i valuei对应的权重系数,然后进行加权求和即可得到Attention数值:
A t t e n t i o n ( Q u e r y , S o u r c e ) = ∑ i = 1 L x a i ⋅ V a l u e i Attention(Query,Source)=\sum_{i=1}^{L_x}a_i·Value_i Attention(Query,Source)=i=1LxaiValuei
通过如上三个阶段的计算,即可求出针对Query的Attention数值,目前绝大多数具体的注意力机制计算方法都符合上述的三阶段抽象计算过程。

说完了attention的机制,现在还有一个最重要的问题没有解决,那就是并行计算的问题,解决这个问题就要提到self-attention了。

Self Attention也经常被称为intra-Attention(内部Attention),最近几年也获得了比较广泛的使用,比如Google最新的机器翻译模型内部大量采用了Self-Attention模型。

在一般任务的Encoder-Decoder框架中,输入Source和输出Target内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attention机制发生在Target的元素Query和Source中的所有元素之间。而Self-Attention顾名思义,指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。其具体计算过程是一样的,只是计算对象发生了变化而已,所以此处不再赘述其计算过程细节。

如果是常规的Target不等于Source情形下的注意力计算,其物理含义正如上文所讲,比如对于机器翻译来说,本质上是目标语单词和源语单词之间的一种单词对齐机制。那么如果是Self-Attention机制,一个很自然的问题是:通过Self Attention到底学到了哪些规律或者抽取出了哪些特征呢?或者说引入Self-Attention有什么增益或者好处呢?我们仍然以机器翻译中的Self Attention来说明,下图是可视化地表示Self-Attention在同一个英语句子内单词间产生的联系。
self-attention可视化例子

self-attention可视化例子
从两张图可以看出,Self-Attention可以捕获同一个句子中单词之间的一些句法特征(比如第一张图展示的有一定距离的短语结构)或者语义特征(比如第二张图展示的its的指代对象Law)。

很明显,引入Self-Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。

但是Self-Attention在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征。除此外,Self-Attention对于增加计算的并行性也有直接帮助作用。这是为何Self-Attention逐渐被广泛使用的主要原因。到此为止,关于RNN的三个问题就都被解决了。

5. attention的应用

在NLP领域几乎到处都能见到attention的身影,尤其是近几年self-attention的兴起,基于self-attention的机器翻译、机器阅读理解、文本情感分析、文本生成、语音识别等方法相继出现,使得NLP领域近些年来火了一把。

attention机制除了在NLP各类任务中应用广泛之外,在图像领域也有很多应用,例如图片描述(Image-Caption)领域,输入一张图片,人工智能系统输出一句描述句子,语义等价地描述图片所示内容。通过attention机制就能够动态捕捉到整张图像中的重要信息,通过这些信息对图像内容进行描述。

6. attention的代码实现

import torch
import torch.nn as nn

class Attention(nn.Module):
    def __init__(self, hidden_size):
        super(Attention, self).__init__()
        self.hidden_size = hidden_size
        self.attn = nn.Linear(self.hidden_size * 2, hidden_size)
        self.v = nn.Parameter(torch.rand(hidden_size))
        self.v.requires_grad = True

    def forward(self, hidden, encoder_outputs):
        seq_len = encoder_outputs.size(0)
        hidden = hidden.repeat(seq_len, 1, 1)
        encoder_outputs = encoder_outputs.permute(1, 0, 2)
        energy = torch.tanh(self.attn(torch.cat([hidden, encoder_outputs], dim=2)))
        energy = energy.permute(0, 2, 1)
        v = self.v.repeat(encoder_outputs.size(0), 1).unsqueeze(1)
        attention_scores = torch.bmm(v, energy).squeeze(1)
        return nn.functional.softmax(attention_scores, dim=1)

这是一个简单的Attention模块,该代码基于torch框架,包含一个线性层用于计算attention分数,以及一个可训练的参数v。在forward方法中,通过输入隐藏状态和编码器输出,计算得到attention分数,并使用softmax将其转换为注意力权重。最终输出的是编码器输出的加权平均值,其中权重即为注意力权重。此处的代码仅为示例,实际的Attention模型可能需要根据具体情况进行更复杂的设计。

参考文献

[1] 模型汇总24 - 深度学习中Attention Mechanism详细介绍:原理、分类及应用,深度学习于NLP,https://zhuanlan.zhihu.com/p/31547842
[2] 深度学习中的注意力模型,张俊林,https://zhuanlan.zhihu.com/p/37601161
[3] 浅谈Attention机制的理解,TheLongGoodbye,https://zhuanlan.zhihu.com/p/35571412
[4] Attention机制详解,川陀学者,https://zhuanlan.zhihu.com/p/47063917
[5] attention机制原理及简单实现,不分享的知识毫无意义,https://www.jianshu.com/p/1d67638139da


❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️

👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈