本文已参与「新人创作礼」活动,一起开启掘金创作之路。
5. Attention机制详解
前面讲到,在一般形式的encoder-decoder中,输入信息先经过encoder编码保存在C中,C再被decoder使用。这种“直接粗暴”的方式,可能会导致输入信息没有被合理的利用,尤其是当输入信息过长的时候。为了解决这个问题,Attention机制被提出,解决的思路是:在decoder阶段,每个时间点输入的C是不同的(示意图如下图所示),需要根据当前时刻要输出的y去合理地选择输入x中的上下文信息。
具体来讲,就是对encoder的隐藏状态进行加权求和,以便得到不同的C,以中文翻译英文为例,示意图如下:
记为encoder中第个隐藏状态到decoder中第个隐藏状态对应的的权重,可以通过训练确定的,具体计算方法见后文。attention机制的核心思想可以概括为"对输入信息加权求和得到编码信息c",也即如下公式:
5.1. attention机制中权重系数的计算过程
attention机制中权重系数有多种计算过程,对应于不同种类的attention机制。但是大部分的attention机制,都能表示为下文提到的三个抽象阶段。这里先引入几个概念。 我们将模型输入内容记为source,输出内容记为target。 source可以表示为一个一个的<key,value>,target则表示为一个一个的query。在机器翻译中,key和value合并为一个,就是输入句子中每个单词对应的隐藏层状态。 通过计算Query和各个Key的相似性或者相关性(需要进行softmax归一化),得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。
具体来说可以分为三个阶段,如下图所示:
其中第一阶段计算相似性时有多种方法,例如向量点积、余弦相似度,甚至可以用一个小的神经网络来通过学习的方式计算。 第二阶段softmax归一化的公式如下:
5.2. 几种典型的attention机制
5.2.1. 第一种:Bahdanau Attention
Neural Machine Translation by Jointly Learning to Align and Translate,这篇论文可以看做是attention机制的开山论文。该论文也是为了解决翻译问题而提出的模型,encoder采用了双向的RNN结构,正向RNN和反向RNN的每个时刻的隐藏state拼接成一个两倍长的新的state。如果要用一个简洁的公式来概括attention,那就是mlp + softmax+加权求和。之前的模型都是用一个固定长度的语义向量C来将encoder和decode连接起来,而这篇论文里是采用一个attention模型来连接。
Encoder:
语义向量:
其中是Encoder中时刻隐藏层状态对Decoder中时刻的处处状态的影响程度;称为一个对齐模型,本论文中采用的是一个单隐藏层的多层感知机,注意在实际推理的时候,是可以在推理之前预先算好的以减少推理计算量;是对进行softmax归一化成的概率,也即前文提到的或者叫attention权重;是时刻的语义向量。可见上述计算得到权重系数的的过程主要分为两步:MLP+SOFTMAX Decoder:
5.2.2. 第二种: Luong Attention
源自论文Effective Approaches to Attention-based Neural Machine Translation。该论文提出了两种不同的attention:global attention和local attention。前者attention将作用在源句子的每个词,计算量较大;后者是出于减小计算量的考虑,只关注一个区间内的词(并且是在一个句子内部)。
5.2.2.1. Global attention
Encoder与上一小节中的不同之处在于,采用最顶层的LSTM的隐藏状态用于计算后续的语义向量C。 语义向量与上一小节的不同之处在于,在计算权重系数的时候利用的是decoder中第个隐藏状态(上一小节是第个)和encoder中第个隐藏状态来计算:
其中的选择有多种:
Decoder:
5.2.2.2. Local Attention
Global attention的缺点在于,预测某个target word时,需要计算该target对应的hidden state与encoder汇总所有hidden state之间的关系。当输入句子比较长时,这将非常耗时。Local attention就散为了解决这个问题,它只关注源句子中一个窗口内的词对应的hidden state。它的思想来源于soft-attention和hard-attention。
具体来说,对于要预测的某个target word, 首先计算出一个对齐位置,然后一个以为中心的窗口会被用来计算。窗口大小由经验给定。计算的方法与前面类似。 因此,重点在于如何计算。论文给出了两种方法:
- 单调对齐方式(Monotonic alignment):假设源句子和目标句子是单调对齐的。取。
- 预测对齐方式(Predictive alignment):采用如下公式计算:
其中S是源句子的长度。同时,为了增大附近的hidden state权重,权重系数将再乘上一个高斯分布:
其中。是个实数,而j是个整数
5.2.3. Self-Attention
Self-Attention最著名的应用是在论文Attention Is All You Need中,作为transformer结构的一个重要组成部分。 前面提到的几种attention,都是应用于基于RNN或者LSTM的encoder-decoder架构,通过计算decoder中隐藏状态和encoder中各个隐藏状态之间的关系来得到对应的权重。在《Attention Is All You Need》中,完全抛弃RNN/LSTM/CNN等结构,仅采用attention机制来进行机器翻译任务。并且在本论文中的attention机制采用的是self-attention,在encode源句子中一个词时,会计算这个词与源句子中其他词的相关性,减少了外部信息的依赖(这里我的理解是,与前面的几种attention机制不同,self-attention不需要decoder中的信息,也即encode一个句子时只用到了自身的信息,这就是self的含义)。 下面个详细讲解self-attention原理。第一阶段是计算三个vector(Q,K,V),见下图:
为了简单起见,假设输入句子只有两个词,是"Thinking Machines"。如上图所示:首先得到这两个词的Embedding向量(跟一般的nlp任务中的Embedding向量是一个概念),然后对于每个词,都计算出三个向量:Query Vector,Key Vector和Value Vector。计算过程为分别乘以三个矩阵:。
第二阶段是计算attention分数,假设现在要计算的是"Thinking"的attention值,那么需要计算"Thinking"与该句子中所有词的分数。需要计算。常见是计算公式是内积。过程如下图所示:
第三阶段是对分数进行归一化。首先除以(Key Vector的维度),这是为了避免梯度爆炸;然后进行softmax归一化,这样是为了使得分数都在之间。
这个分数代表了encode "Thinking"需要放置多少注意力在各个单词上,不妨记为。
第四阶段就是利用上述得到分数对所有的Value Vector加权求和得到"Thinking"的representation:
值得注意的是,上述过程是可以并行化计算的,这是self-attention相对于RNN,LSTM等序列模型的优势(在处理长序列问题上)。 最后,我们给出self-attention的紧凑表达式:
这样就一步到位得到了输入句子中所有词的represent vector。
5.2.4. Multi-Headed Attention
所谓multi-headed attention,其实就是对输入Embedding做多次self-attention计算,每次都是在不同的子空间,可以学习到多份不同的权重参数(transformer里面是8份,也即8个head)对应不同的模式(类似于卷积里面的多个通道),然后将结果concat在一起。具体来讲这样做有两点好处:
- 这是为了增加模型对于其他位置的词的注意力能力。因为如果只是一个self-attention,很容易使得某个词的注意力大部分集中在它自身。
- 为attention层提供多个“表征子空间”。因为multi-headed attention有多个Q/K/V的矩阵集合(在transformer中有8个head),每个Q/K/V集合可以将输入的Embedding向量(或者上一个encoder-decoder)映射到不同的表征空间里。
如下图所示,输入Embedding得到8个head(对应8个分数z):
在进行后续计算时,一般会把这8个zconcat成一个长的矩阵,然后乘以一个矩阵,得到一个矩阵,这个捕获了前面8个z的信息。
6. 对输入序列进行位置编码
在经典的序列处理模型中,对于序列中各元素的“位置信息”的利用似乎都不太够。例如CNN只关注filter覆盖的区域中的局部位置信息;RNN能稍微关注到较长的信息,但是容易丢失更早期的信息;LSTM会挑出重点位置的信息,但由此可能造成丢失其他的位置信息;self attention/transformer中只关注全局位置信息,容易丢失相对位置信息。对于序列问题,尤其是自然语言这种有强逻辑性的序列问题,显示地引入位置信息作为特征似乎显得格外重要。
例如,对于I believe I have fallen in love with you,如果采用self-attention,两个I的encoded输出将会是一样的。但是显然他们不一样。
那么如何引入位置信息呢?最朴素的想法是直接对位置进行整数编码:给定一个长度为的文本,位置编码.这样的缺点在于,越往后面的元素,它的位置编码越大,可能会导致权重在它们身上的倾斜;它比其他的特征(例如input Embedding)大许多,会导致权重在位置编码特征倾斜太多。那对上述位置编码进行归一化呢??这样只解决了数值过大的问题,但是它只关注绝对位置信息而丢失了相对位置信息。例如I like orange, because it provides me with VC和Since orange can provide me with VC, I like orange.其中两个like,按理说位置信息应该相差不大(它们在句中的绝对位置虽然不一样,但是相对位置是一样的),用上述编码是会出问题的。
简单总结一下位置编码的需求:
- 需要体现同一个单词在不同位置的区别;
- 需要体现一定的先后次序关系,并且在一定范围内的编码差异不应该依赖于文本长度,具有一定不变性。
- 需要值域落入一定数值区间内的编码,又需要保证编码大小与文本长度无关
一种选择就是周期函数,例如三角函数,这也是transformer中选用sin和cos函数来进行位置编码的原因。
参考
www.elecfans.com/d/1482740.h… www.zhihu.com/question/34… blog.csdn.net/qq_33431368… arxiv.org/abs/1508.04… arxiv.org/abs/1409.04… jalammar.github.io/illustrated… arxiv.org/abs/1706.03… jalammar.github.io/illustrated…