起这个标题的原因是,春招时期写了一篇关于word2vec的文章,按照文章的思路跟面试官讲word2vec或者里面的细节,基本上没有扑街的,有些面试官也表示讲的很好。

益达:Embedding之word2vec?

zhuanlan.zhihu.com
图标

但是有面试官这么问我:「可以看出这基础很好,但Attention、Bert等前沿模型近期很热门啊,有机会你再了解一下吧」。我当场鼠躯一震,觉得自己需要继续了解一下NLP的前沿模型了!

虽然自己开的专栏叫益达的Embedding空间,本著实用和全面的原则,近期我会写一点自己对Attention的理解。这篇文章只讲传统Attention,self-Attention留到下一篇吧。

Attention起源于图像领域的注意力机制(此处略去好多字...),发展史我这里就不多说了。直接开始切入正题吧!

1、seq2seq的翻译模型

在介绍Attention之前,有必要说一下seq2seq的翻译模型,这个模型很有利于理解Attention。可以将seq2seq看成一种通用的框架,它的输入是一个序列,输出是一个序列,好比翻译任务,输入「今天是晴天」,输出「Today is sunny」。我们使用RNN来seq2seq,RNN的结构如下:

RNN的时间步展开形式

对于每一个时间步(序列中的一个元素)将涉及2个输入, X_th_{t-1} (类比LSTM,我们可以将 h_{t-1} 看做网路的记忆,只不过RNN没有「长短期记忆」,只有「长时记忆」),同时具有2个输出(两个输出都是 h_t )。于是一个最朴素的seq2seq可以画作下图:

朴素的seq2seq模型

对于上图,我们可作如下解释。Encoder部分具有初始记忆H0,和句子的第一个单词一同输入第一个神经元,然后得到输出 h_1 ,直至句子的最后一个单词输入完毕。输入Decoder的只有 中间记忆h_3 ,它承载了前面所有输入的记忆特征,并将被用于翻译。

开始翻译时,先输入句子的开始符号<BOS>,此时Decoder里第一个RNN单元接受输入<BOS>和长时记忆 h_3 ,得到输出Y1,我们希望这个Y1越接近Today这个单词越好(这里可以近似这么理解)。第二个RNN单元接受长时记忆 h_4 和Today,我们希望它能够输出is这个单词,后面同理。这里使用了Teacher Forcing技术,即使用真实的翻译结果来强制模型学到正确的信息,防止错误积累,参见链接。

在这种设计下,Decoder模型将具备2个部分(训练、预测),因为预测的时候没有正确的标签告诉RNN单元,只能使用上一轮的翻译结果作为下一个位置的输入。

  • Encoder端 encoder_layer
  • Decoder端
    • Decoder训练 decoder_layer_train
    • Decoder预测/推断 decoder_layer_inference

2、多次利用Encoder记忆

这里我们发现,长时记忆 C=h_3 承载了大量信息,但是在翻译过程中仅被直接利用在Decoder里第一个RNN Cell上。很自然的一个想法是让Decoder中所有单元都得到长时记忆的「福泽」,如下图。

将长时记忆C用于Decoder中所有RNN单元

3、Attention的思想

将这个思想进一步扩展:我们既然已经能在翻译过程中每一个单元都使用「长时记忆」,那么我们为什么不把所有的「记忆」都拿过来(而不是丢弃掉中间记忆),供我们挑选呢?OK我认为这个可以看做Attention的另一种出发点,如何利用这些信息呢?

Attention充分利用多「记忆」辅助翻译

如上图,我们可以充分使用每一个序列的「记忆」,并对不同的「记忆」使用不同的权重。比如翻译「Today」的时候,我们希望「今天」这个词在最终翻译的「贡献」更大(图中以粗线表示更高的权重)。令 a_{t,1} 表示Encoder中第1个输出对Decoder翻译第t个单词时所产生的贡献,图中 a_{3,3} 表示在翻译第3个单词「Sunny」时,「晴天」对翻译的贡献程度。

OK先不管 a_{t,1} 是怎么计算的,考虑一下我们有这个权重了,要怎么计算Decoder的输入呢?在那之前我们先将这些权重归一化吧,使用softmax将权重归一化。这个结果就叫做AttentionScore,注意力评分。

Attention-score = softmax(a_{t,1}) = frac {e^{a_{t,1}}}{sum_j e^{a_{t,j}}}

然后再将归一化过后的结果与每个隐层状态相乘。s_{t}=sum_{k}^{T_x} {frac {e^{a_{t,k}}}{  sum_{j}e^{a_{t,j}} } * h_k}

其中 T_x 表示输入序列的长度,相应地有 T_x 个Cell输出。根据上式,就能获得一个和原始「长期记忆」C大小相同的向量 s_t (图中粉色虚线双箭头表示Attention和C结合得到 s_t )。将 s_t 与Teacher Forcing相结合(就是将Y标签后移一个时间步,用于「监督」Decoder的训练),即完成Decoder的训练部分。推断部分,没有现成的标签,就使用 t-1 时刻已经预测得到的单词 v_{t-1} 作为下一个时间步的输入,并计算 t 时刻的Attention结果 s_t ,输入 t 时刻的Cell用于翻译。

现在我们可以讨论一下 a_{t,1}=sim(c_{t-1}, h_1) 要怎么计算了,常见的计算方式有3种,点乘、映射、加性:

sim(c_{t-1}, h_1)= left{egin{matrix} v*tanh(Wc_{t-1}+Uh_1) & add \  c_{t-1}*h_1 & dot \  c_{t-1}*W*h_1 & projection  end{matrix}
ight.   \

注意有时候加性计算方式也被写成两个向量concat的形式: v*tanh(W*[c_{t-1} ; h_1]) ,形式不同但是没有本质区别。

注意力评分是个 T_y*T_x 大小的矩阵,如果将矩阵绘制出来,就是常说的Attention评分矩阵,可以看到模型学习到的Attention信息。

Attention矩阵可视化示例

4、后记和参考文献

发现自己之前使用的分类模型用了Attention实现多分类(当时直接从github拉取的Keras代码),分别实现了在LSTM之前和之后施加Attention。当时还有点纳闷,现在一想,其实Attention就是一种对前一层网路节点评分后输出经softmax加权表示的一个结果。那份代码的网路结构应该如下图(画的有可能有点问题,欢迎大佬指正):

在LSTM之前施加Attention

至此程度应该足够应付面试里让简单讲讲Attention的需求了,如果有遗漏欢迎评论区讨论。下一篇准备讲讲self-attention和Transformer。

下面是本文的参考文献。

Understanding LSTM Networks?

colah.github.io
图标
What is Teacher Forcing for Recurrent Neural Networks??

machinelearningmastery.com
图标
何之源:完全图解RNN、RNN变体、Seq2Seq、Attention机制?

zhuanlan.zhihu.com
图标
Attention and Memory in Deep Learning and NLP - Open Data Science - Your News Source for AI, Machine Learning & more?

opendatascience.com
图标

推荐阅读:
相关文章