「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战」。
导语
本文为我之前在CSDN平台上的一篇博客记录。原链接为:NLP学习笔记(八)注意力机制(Attention)
注意力机制(Attention)
这节课我们学习注意力机制(Attention),它可以大幅度提升机器翻译的效果。
Revisiting Seq2Seq Model(复习Seq2seq模型)
我们首先来复习一下上节课的内容。
seq2seq模型由一个编码器Encoder和一个解码器Decoder组成。 Encoder输出最后一个状态向量作为对之前全部输入的总结。Decoder RNN的初始状态,通过,Decoder就知道了这句话的信息。然后Decoder就像一个文本生成器一样,逐字进行翻译。
可惜Seq2seq模型有一个明显的缺陷就是当输入句子很长时,Encoder会记不住完整的句子,Encoder最后一个状态可能会漏掉一些信息。
如果拿Seq2seq模型做机器翻译,会得到这样的结果。
横轴是句子长度,纵轴是BLUE score是评价机器翻译好坏的标准,值越高说明越准确。 从上图可以看到,如果不用Attention,大概20个词后,BLUE score就会往下降。用Attention后,即使句子很长也不会明显下降。
Attention for Seq2Seq Model(在Seq2seq模型上应用Attention)
Attention是2015的ICLR上的这篇论文提出的,使用Attention后,Decoder每次在更新状态时都会再看一眼Encoder的所有状态,这样就不会遗忘。Attention还可以告诉Decoder应该关注Encoder的哪个状态,这也是Attention名字的由来。Attention可以大幅度提高准确率,但缺点是计算量很大。
下面简要介绍Attention的原理。
在Encoder结束工作之后,Attention和Decoder同时开始工作。
Decoder的初始状态是Encoder的最后一个状态,我们同时保留Encoder的所有状态,然后计算和每一个状态的相关性。我们用
来表示Encoder第i个状态和Decoder第0个状态的相关性。将结果记为,被称为权重Weight。
Encoder有m个状态,所以一共算出m个,它们都是介于0到1之间的实数并且加和为1。下面我么来看一下具体怎么计算。
有很多方法可以用来计算和的相关性。第一种方法如下:
我们首先把和做concatenation得到一个更大的向量。然后求矩阵W和这个向量的乘积,得到一个向量。再把双曲正切函数应用到向量的每一个元素上,把每一个元素值都压缩到-1到+1之间。双曲正切函数的输出还是一个向量。最后计算向量v和刚算出来的向量的内积。两个向量的内积是个实数,记为。
这里的矩阵W和向量v都是参数,需要从训练数据里学习。
算出这些之后,对他们进行Softmax变换。把输出结果记为。这种计算方法是Attention第一篇论文中所提出的。在这之后,有其他很多论文提出了很多计算Attention的方法。
下面介绍一个更流行的方法。
输入还是与向量,第一步是分别用两个参数矩阵和对两个输入做线性变换。得到与两个向量。这两个参数矩阵要从训练数据中学习。
第二步是计算这两个向量的内积,把结果记为。得到m个结果。
第三步是对得到的结果做Softmax变换,把输出结果记为。
这种方法被Transformer模型采用。
以上讲了两种计算与的相关性的方法,随便使用哪种方法都会得到m个值,这些被称为权重,每个对应一个。利用这些权重,我们可以对这些状态向量求加权平均,结果称为context vector记为。每一个Context vector 都会对应一个状态。这里对应。
Decoder读入向量,然后需要把状态更新为。那么具体该如何计算呢?我们先来回顾一下,假如不用Attention,那么Simple RNN是这样更新状态的。
新的状态是旧的状态和输入的函数。公式如图所示,把和做concatenation,然后乘到参数矩阵上,加上偏置Intercept,然后做双曲正切变换后得到状态。Simple RNN在更新状态时只需要知道旧的状态和输入,而并不会去看Encoder的状态。
而使用Attention后,则会用到Context vector 。
在计算过程中需要把、和做concatenation。之后计算得到状态。而是知道Encoder的所有状态的,这样一来就解决了长句子遗忘的问题。
下一步我们跟之前一样的计算方式来计算,
注意:这里的是需要重新计算得到的。而不能用上一轮的值。
有了之后就可以计算,也是用同样的加权平均。
之后计算。
以此类推,全部计算。
在计算过程中,我们需要计算很多的,思考一下,为了完成计算所有的c,一共计算了多少呢?
想要计算一个Context vector ,需要把Decoder的当前状态输出和Encoder所有m个状态做对比来计算出m个权重。而Decoder每一步都会计算m个,所以假设Decoder一共运行了t步后,共计算出了个权重。所以Attention的时间复杂度是,也就是Encoder与Decoder状态数量的乘积。这个时间复杂度是很高的。
Attention避免遗忘,大幅度提高了准确率。但是代价是巨大的计算。下面举个例子来说明权重的实际意义。
上图下面是Encoder,输入为英语。上面是Decoder,输出为法语。Attention会把Encoder每个状态和Decoder每个状态作对比。得到两者相关性,也就是权重。在图中,用线连接Encoder和Decoder的每个状态,每条线给与一个权重,粗线表示很大,细的表示很小。
例如,图中法语“zone”和英语“area”有很粗的线相连,这条线有很直观的解释。法语里的“zone”就是英语的“area”,在翻译时,Decoder都会看一遍所有的Encoder的状态,而Attention则告诉Decoder重点关注哪些部分。这也是Attention名字的由来。
Summary(总结)
标准的Seq2seq在面对长句子时会忘记之前的状态。而使用Attention之后,每次Decoder都会再看一遍Encoder的所有信息,并不会遗忘。
除了解决遗忘问题,Attention还可以告诉Encoder重点关注哪个单词。
Attention可以大幅度提高 翻译准确度。但缺点是时间复杂度太高了。