1. 什么是Attention机制
在“编码器—解码器(seq2seq)”⼀节⾥,解码器在各个时间步依赖相同的背景变量来获取输⼊序列信息。当编码器为循环神经⽹络时,背景变量来⾃它最终时间步的隐藏状态。
现在,让我们再次思考那⼀节提到的翻译例⼦:输⼊为英语序列“They”“are”“watching”“.”,输出为法语序列“Ils”“regardent”“.”。不难想到,解码器在⽣成输出序列中的每⼀个词时可能只需利⽤输⼊序列某⼀部分的信息。例如,在输出序列的时间步1,解码器可以主要依赖“They”“are”的信息来⽣成“Ils”,在时间步2则主要使⽤来⾃“watching”的编码信息⽣成“regardent”,最后在时间步3则直接映射句号“.”。这看上去就像是在解码器的每⼀时间步对输⼊序列中不同时间步的表征或编码信息分配不同的注意⼒⼀样。这也是注意⼒机制的由来。
仍然以循环神经⽹络为例,注意⼒机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每⼀时间步调整这些权重,即注意⼒权重,从而能够在不同时间步分别关注输⼊序列中的不同部分并编码进相应时间步的背景变量。
在注意⼒机制中,解码器的每⼀时间步将使⽤可变的背景变量。记 ct′ 是解码器在时间步 t′ 的背景变量,那么解码器在该时间步的隐藏状态可以改写为:
这⾥的关键是如何计算背景变量 ct′ 和如何利⽤它来更新隐藏状态 st′。下⾯将分别描述这两个关键点。
2. 计算背景变量
我们先描述第⼀个关键点,即计算背景变量。下图描绘了注意⼒机制如何为解码器在时间步 2 计算背景变量。
- 函数 a 根据解码器在时间步 1 的隐藏状态和编码器在各个时间步的隐藏状态计算softmax运算的输⼊。
- softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从而得到背景变量。
令编码器在时间步t的隐藏状态为 ht,且总时间步数为 T。那么解码器在时间步 t′ 的背景变量为所有编码器隐藏状态的加权平均:
矢量化计算背景变量
我们还可以对注意⼒机制采⽤更⾼效的⽮量化计算。我们先定义,在上⾯的例⼦中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。
⼴义上,注意⼒机制的输⼊包括查询项以及⼀⼀对应的键项和值项,其中值项是需要加权平均的⼀组项。在加权平均中,值项的权重来⾃查询项以及与该值项对应的键项的计算。
让我们考虑⼀个常⻅的简单情形,即编码器和解码器的隐藏单元个数均为 h,且函数 (a(s,h)=s^Th)。假设我们希望根据解码器单个隐藏状态 st′−1 和编码器所有隐藏状态 ht, t = 1, . . . , T来计算背景向量 ct′ 。我们可以将查询项矩阵 Q 设为 (s_{t^{′}-1}^T),并令键项矩阵 K 和值项矩阵 V 相同且第 t ⾏均为 (h_t^T)。此时,我们只需要通过⽮量化计算:
即可算出转置后的背景向量 (c_{t^{′}}^T)。当查询项矩阵 Q 的⾏数为 n 时,上式将得到 n ⾏的输出矩阵。输出矩阵与查询项矩阵在相同⾏上⼀⼀对应。
3. 更新隐藏状态
现在我们描述第⼆个关键点,即更新隐藏状态。以⻔控循环单元为例,在解码器中我们可以对⻔控循环单元(GRU)中⻔控循环单元的设计稍作修改,从而变换上⼀时间步 t′−1 的输出 yt′−1、隐藏状态 st′−1 和当前时间步t′ 的含注意⼒机制的背景变量 ct′。解码器在时间步: math:t’ 的隐藏状态为:
其中的重置⻔、更新⻔和候选隐藏状态分别为:
其中含下标的 W 和 b 分别为⻔控循环单元的权重参数和偏差参数。
4. 发展
本质上,注意⼒机制能够为表征中较有价值的部分分配较多的计算资源。这个有趣的想法⾃提出后得到了快速发展,特别是启发了依靠注意⼒机制来编码输⼊序列并解码出输出序列的变换器(Transformer)模型的设计。变换器抛弃了卷积神经⽹络和循环神经⽹络的架构。它在计算效率上⽐基于循环神经⽹络的编码器—解码器模型通常更具明显优势。含注意⼒机制的变换器的编码结构在后来的BERT预训练模型中得以应⽤并令后者⼤放异彩:微调后的模型在多达11项⾃然语⾔处理任务中取得了当时最先进的结果。不久后,同样是基于变换器设计的GPT-2模型于新收集的语料数据集预训练后,在7个未参与训练的语⾔模型数据集上均取得了当时最先进的结果。除了⾃然语⾔处理领域,注意⼒机制还被⼴泛⽤于图像分类、⾃动图像描述、唇语解读以及语⾳识别。
5. 代码实现
注意力模型实现中英文机器翻译
-
数据预处理
首先先下载本目录的数据和代码,并执行 datautil.py,生成中、英文字典。
-
执行 train.ipynb,训练时间会比较长。
-
测试模型,运行test.py文件。
6. 参考文献
作者:@mantchs