本文需要的前序知识储备是: 循环神经网络 RNN , 词向量 WordEmbedding , 门控单元 VanillaRNN/GRU/LSTM .
1 seq2seq
seq2seq 是 sequence to sequence 的缩写. 前一个 sequence 称为编码器 encoder , 用于接收源序列 source sequence . 后一个 sequence 称为解码器 decoder , 用于输出预测的目标序列 target sequence .
seq2seq 主要用于序列生成任务, 例如: 机器翻译, 文本摘要, 对话系统, 等等. 当然也可以用于文本分类等任务.
图 1.1 seq2seq
最传统的 seq2seq 流程如图 1.1 所示:
( 1 )将源序列输入 encoder 网络.
( 2 ) encoder 将源序列的信息编码成一个定长的向量 encoder vector .
( 3 ) encoder vector 被送入 decoder 网络.
( 4 ) decoder 根据输入的向量信息, 输出预测的目标序列.
seq2seq 在被提出后, 马上受到了广泛的关注和应用, 也暴露出一些问题. 首先被关注到的, 就是人们发现把一整个文本序列通过 encoder 压缩到区区一个向量里, 很难通过 decoder 进行完美地没有信息缺失的解码.
此外, 由于循环神经网络 RNN 的特性, 源序列中越迟输入的文本, 对 encoder vector 的影响也越大. 换句话说, encoder vector 里会包含更多的序列尾的文本信息, 而忽略序列头的文本信息. 所以在很多早期的论文中, 会将文本序列进行倒序后再输入 encoder , 模型测评分数也会有一个显着地提高.
为了让 decoder 能够更好地提取源序列的信息, Bahdanau 在 2014 年提出了注意力机制 Attention Mechanism , Luong 在 2015 年对 Bahdanau Attention 进行了改进. 这是两个最经典的注意力机制模型. 两个 Attention 模型的本质思路是一样的, 下文均以 Luong Attention 模型作为范例.
2 Attention Mechanism
注意力机制的理解, 可以参考 CV 领域的思想: 我们在看到一幅画的时候, 每个时刻总会有一个关注重点, 比如说某个人, 某个物品, 某个动作.
所以, 在 NLP 领域, 我们在通过 decoder 预测输出目标序列的时候, 也希望能够有一种机制, 将目标序列当前 step , 和源序列某几个 step 的文本关联起来.
以翻译任务为例, 将 "我爱机器学习" 翻译成 "I love machine learning." 在 decoder 输出序列第一个 step , 我们希望关注输入序列中的 "我", 并将 "我" 翻译成 "I"; 在第三个 step , 我们希望关注 "机器", 并翻译成 "machine".
这个例子比较简单, 我们就会产生一个初步的想法: 是不是把源序列中的每个词语单独翻译成英文, 再依次输出, 就构成目标序列了呢?
但是, 如果进一步思考下, 我们就会发现两个问题:
( 1 ) 一词多义 : 源序列里的同一个词, 在输出序列里, 可能根据场景的不同, 会有不同的输出. 例如 "我" 可能被翻译成 "I", 也有可能被翻译成 "me". 这有点类似于中文的 "一词多义", 在英文里估计是叫做 "一词多态" 吧, 我们姑且将这类由一个词可以映射成多个词的现象, 广义地统称为 "一词多义". 解决 "一词多义" 问题的一个有效途径, 就是参考源序列的语境信息, 也就是上下文信息, 来生成词向量.
( 2 ) 序列顺序 : 源序列和目标序列并不是顺序依次映射的, 例如 "你是谁?" 翻译成 "who are you?", 不同语言有不同的语法规则和顺序. 这就需要在 decoder 输出的每一个 step , 确定当前 step 应该翻译源序列中的哪一个词.
这两个问题也就是 Attention 机制的关注重点.
图 2.1 LuongAttention
图 2.1 是一个 Luong Attention 的示意图, 是作者其后续的论文里呈现的一张修订后的示意图.
还有个理解 Attention 的方式, 就是参考残差网络 ResNet . 因为源序列太长了, 导致早期的信息无法有效地被传递, 所以需要一个额外的通道, 把早期的信息送到解码器上. 送的时候还不能只送一个词的信息, 最好把上下文信息一起给送了.
下一节会用一个最简单的模型, 介绍 Attention 机制的实现步骤, 在此之前, 先约定下参数符号:
h(output) : RNN 的隐藏状态, 主要用于将信息输出到 RNN 模型外.
s(state) : RNN 的状态, 主要用于 RNN 模型内部, 模型将信息传递给下一个 step .
a : 对齐向量
c : 上下文信息向量.
x : 源序列.
y : 目标序列.
下标 s 表示源序列, 下标 t 表示目标序列. s1 表示源序列第 1 个 step , 以此类推.
括号里的 output 和 state , 是为了方便读者将论文里的算法理论, 和工业实践里 tensorflow 的 tf.nn.dynamic_rnn 函数联系起来, 稍微有个印象就好. dynamic_rnn 函数返回两个向量, 第一个是 output , 也就是 encoder 所有 step , 网络最后一层输出的 h ; 第二个是 state , 也就是 encoder 最后一个 step , 网络层所有层输出的 s .
3 Attention 五部曲
3.1 执行 encoder
图 3.1 步骤一: 执行 encoder
步骤一的行为是将源数据依次输入 Encoder , 执行 Encoder . 目的在于将源序列的信息, 编译成语义向量, 供后续 decoder 使用.
在每个 step , endocer 会输出一个表征当前 step 语义的 output ( h )向量和一个 state ( s )向量:
( 1 ) 我们收集 每个 step 的 output ( h ), 构成 output 矩阵, 矩阵的维度是 [step_len,dim_rnn] , 即源数据 step 长度, 乘以 rnn 单元数量.
( 2 ) 我们收集 最后一个 step 的 state ( s ), 作为传入 decoder 的向量.
encoder 对于模型的贡献, 在于提供了 outputs 矩阵和 state 向量.
注一: 为了便于理解, 我这里的 encoder 使用了单层网络, 多层网络的 outputs 和 state 见上一节末尾的描述.
注二: 很多论文的 h 和 s 的描述并没有一个统一的标准, 经常混淆. 因为早期论文的 RNN 单元, 是用 VanillaRNN 或 GRU 实现的, 这两个门控单元在同一个 step , 输出的 h 和 s 是一样的. 但是, 若通过 LSTM 实现, h 和 s 是不同的, 这个需要引起注意.
注三: 早期的论文中, encoder 的 state 是直接传递给 decoder , 作为 initial state 的. 但是在工程应用中, 也存在直接将 0 序列作为 initial state 传递给 decoder 的情况. 另外, 部分论文也有将 state 进行一些处理, 添加一些额外的信息, 再传递给 decoder 的算法. 总之, encoder 和 decoder 之间传递 state 的方式比较灵活, 可以根据实际情况自行选择和改进.
注四: RNN 的单元数量, 即为 encoder 输出向量的维度. 也就是用 dim_rnn 维度的向量, 来表征源序列当前 step 文本的语义信息. 对照同样表征语义信息的词向量的维度 dim_word_embd , 我建议两者的维度不宜相差过大, 否则会造成浪费.
3.2 计算对齐系数 a
图 3.2 步骤二: 计算对齐系数 a
步骤二解决的是第 2 节提出的 "序列顺序" 的问题. 在 decoder 的每个 step , 我们需要关注源序列的所有 step 和目标序列当前 step 的相关性大小, 并输出相关 (对齐) 系数 a .
所以, 在 decoder 输出一个预测值前, 都会针对 encoder 的所有 step , 计算一个 score . 这个 score 表示当前的 decoder 工作, 需要从 encoder 的哪些 step 里抽取信息, 以及抽取的权重大小. 然后将 score 汇总向量化后, 每个 decoder step 能获得一个维度为 [step_len,1] 的 score 向量.
这个 score 的计算方式有很多种, 图 3.2 中列举了 Luong Attention 提及的 3 种的传统计算方式. 我画的流程图中采用的是第 1 种, 就是将源序列所有 step 的 output ( h )和目标序列当前 step 的 output ( h )逐个相乘, 得到的值即为 score . 有些论文就是在 score 的计算方式上进行创新的.
计算出 score 后, 很自然地按惯例使用 softmax 进行归一化, 得到对齐向量 a , 维度也是 [step_len,1] .
注一: 很多论文的各种参数的缩写符号都不一样, 有一个理清模型流程顺序的小技巧: 就是去找 softmax 函数, 以 softmax 为锚点. Attention 常见的使用 softmax 的地方有两个, 一个是步骤二的对齐系数 a , 另一个在步骤五将会提到, 在输出预测词之前, 要对概率分数进行 softmax 归一化处理.
注二: 对齐系数 a 虽然只是一个过程数据, 但是却蕴含很重要的信息, 可用于 PointerNet 和 CopyNet .
3.3 计算上下文语义向量 c
图 3.3 步骤三: 计算上下文语义向量 c
在描述这个步骤前, 我们先回顾下词向量的 CBOW 模型. 在 CBOW 模型收敛后, 每个词的词向量, 等于它周围若干个词的词向量的均值. 这其中蕴含的意思是: 表征一个词的, 不是这个词本身, 而是这个词的上下文(语境).
CBOW 模型是比较简单粗暴地将上下文的词向量求平均. 实际上, 如果能够以一个加权平均的方式获取词向量, 那幺这个词向量一定能够更准确地表达这个词在当前语境里的语义.
举个例子:"孔夫子经历了好几个春秋寒暑, 终于修订完成了春秋麟史." 在这里, 第一个 "春秋" 表示 "一年","经历","寒暑" 显然和它关系更密切, 利用加权上下文构成词向量时, 应该赋予更高的权重. 第二个 "春秋" 表示儒家六经之一,"修订","麟史" 关系和它更密切, 同样应该赋予高权重.
在步骤三里, 我们将对齐系数 a 作为权重, 对 encoder 每个 step 的 output 向量进行加权求和(对齐向量 a 点乘 outputs 矩阵), 得到 decoder 当前 step 的上下文语义向量 c .
注一: BERT 也有用到对齐系数的思想, 而且更为直观漂亮.
3.4 更新 decoder 状态
图 3.4 步骤四: 更新 decoder 状态
在步骤四里, 需要 更新 decoder 状态, 这个状态可以是 h , 也可以是 s . 能够用于更新 h 和 s 的信息数据, 可以是: 前 step 的 s , 现 step 的 h , 现 step 的上下文向量 c , 以及其它一些包含有效信息的数据.
BahdanauAttention 和 Luong Attention 最大的区别就在于这个步骤, 前者更新的是 s , 后者更新的是 h . 不过由于 Bahdanau 用的是前 step 的 s , Luong 用的是先 step 的 h , 所以后者在工程化实现上会简单点.
具体的更新公式的细节, 在这里不作详细描述, 因为不同模型可能会采用不同的更新公式, 很多论文也是围绕更新公式进行创新点研究的.
需要注意的是, 在这个环节, 训练模式和预测模式略有差别: decoder 每个 step 都要输入一个数据, 在训练模式, 输入的数据是目标序列当前 step 的真实值, 而不使用前 step 的 h ; 在预测模式, 输入的数据是前 step 的 h , 而不使用输出序列的真实值. 虽然在图 3.4 中, 我画了两条输入, 但是要根据模型当前处于训练模式还是预测模式, 选择其中的一条进行输入.
3.5 计算输出预测词
图 3.5 步骤五: 计算输出预测词
这个步骤我在图里没有画全, 其实很简单, 同 CBOW 模型 /Skip-Gram 模型的隐藏层到输出层的那部分一样, 做一个语义向量到目标词表的映射(如果 attention 用于分类模型, 那就是做一个到各个分类的映射), 然后再进行 softmax 就可以了.
4 其它
4.1 Local Attention 和 Global Attention
前文所提及的 Attention 都是 Global Attention , 还有一个 Local Attention , 将在这个小节作一个简单的说明.
Global Attention 就是针对源序列的所有 step , 求对齐系数 a . 而 LocalAttention 只针对源序列的部分 step , 求对齐系数 a , 这个部分 step 的长度是超参数, 需要凭经验人为配置.
Local Attention 所截取的部分 step 的中心点的选取 (对齐) 方式, 是另一个需要关注的点. 论文中提及了两个对齐方式:
( 1 ) Monotonicalignment (local-m) : 简单粗暴的, 直接按源序列和目标序列的 step 绝对值对齐.
( 2 ) Predictivealignment (local-p) : 通过模型, 学习计算出截断 step 的对齐中心.
Luong 的论文里有提及, LocalAttention 的效果优于 Global Attention .
注: CV 领域有个 Soft-Attention 和 Hard-Attention , 和这里 NLP 领域的两个 Attention 优点类似.
4.2 常见的可以替换改进的模块
1. 用于生成对齐向量 a 的分值 score 的计算方式.
2.h 和 s 的更新公式.
3. 基本 RNN 的结构, 包括替换门控单元, 更改 RNN 层数, 单向改双向等.
参考资料
- [1] Bahdanau D ,Cho K , Bengio Y . Neural Machine Translation by Jointly Learning to Align andTranslate[J]. Computer Science, 2014.
- [2] Luong M T ,Pham H , Manning C D . Effective Approaches to Attention-based Neural MachineTranslation[J]. Computer Science, 2015.
[3] Andrew Ng RecurrentNeural Networks
由于微信文章 有 修改字数的限制, 故附上知乎文章的链接: https://zhuanlan.zhihu.com/p/73589030
后续有更新或纠错, 会在知乎文章上呈现.
本文转载自公众号: 数论遗珠, 作者阮智昊
来源: http://www.tuicool.com/articles/Ebu2ea6