在基于词语的语言模型中,我们使用了循环神经网络。它的输入时一段不定长的序列,输入却是定长的,例如输入:They are,输出可能是watching或者sleeping。然而,很多问题的输出是不定长的序列。以机器翻译为例,输入是一段英文,输出是一段法语,输入和输出皆不定长,例如
英语:The are watching 法语:lls regardent
当输入输出序列都是不定长时,我们可以使用编码器-解码器(encoder-decoder)或者seq2seq。它们分别是基于2014年的两个工作:
以上两个工作本质上都用到了两个循环神经网络结构,分别叫做编码器和解码器。编码器对应输入序列,解码器对应输出序列
编码器和解码器分别对应输入序列和输出序列的两个循环神经网络。我们通常会在输入序列和输出序列后面分别附上一个特殊字符'<eos>'(end of sequence)表示序列的终止。在测试模型时,一旦输出'<eos>'就终止当前的输出序列
编码器的作用是把一个不定长的输入序列转化成一个定长的背景词向量\boldsymbol{c}。该背景词向量包含了输入序列的信息。常用的编码器是循环神经网络
首先回顾以下循环神经网络的知识。假设循环神经网络单元为f,在t时刻的输入为x_t,t=1,...,T。假设\boldsymbol{x}_t是单个输出在嵌入层的结果,例如\boldsymbol{x}_t对应的ont-hot向量\boldsymbol{o}\in \mathbb{R}^x与嵌入层参数矩阵\boldsymbol{E}\in \mathbb{R}^{x\times h}的乘积\boldsymbol{o}^\top\boldsymbol{E}。隐藏层变量
编码器的背景向量
一个简单的背景向量可以认为是该网络最终时刻的隐藏层变量\boldsymbol{h}_T。我们将这里的循环神经网络叫做编码器
编码器的输入既可以是正向传递,也可以是反向传递的。如果输入序列是\boldsymbol{x}_1,\boldsymbol{x}_2,...,\boldsymbol{x}_T,在正向传递中,隐藏层变量
而反向传递过程中,隐藏层变量的计算变为
当我们希望编码器的输入既包含正向传递信息又包含反向传递信息时,我们可以使用双向循环神经网络。例如,给定输入序列\boldsymbol{x}_1,\boldsymbol{x}_2,...,\boldsymbol{x}_T,按正向传递,它们在循环神经网络中的隐藏层变量分别是\vec {\boldsymbol{h}}_1,\vec {\boldsymbol{h}}_2,...,\vec {\boldsymbol{h}}_T;按反向传播,它们在循环神经网络中的隐藏层变量分别是\overleftarrow{\boldsymbol{h}}_1,\overleftarrow{\boldsymbol{h}}_2,...,\overleftarrow{\boldsymbol{h}}_T。在双向循环神经网络中,时刻i的隐藏层变量是将\vec{\boldsymbol{h}}_i和\overleftarrow{\boldsymbol{h}}_i拼接起来,例如
import numpy as np
h_forward = np.array([1, 2])
h_backward = np.array([3, 4])
h_bi = np.concat(h_forward, h_backward, dim=0)
# [1, 2, 3, 4]
编码器最终输出了一个背景向量\boldsymbol{c},该背景向量整合了输入序列\boldsymbol{x}_1,\boldsymbol{x}_2,...,\boldsymbol{x}_T
假设训练数据中的输出序列是\boldsymbol{y}_1,\boldsymbol{y}_2,...,\boldsymbol{y}_{T'},我们希望表示每个t'时刻输出的向量,既取决于之前的输出又取决于背景向量。因为,我们可以最大化输出序列的联合概率
并得到该输出序列的损失函数
为此,我们使用另一个循环神经网络作为解码器。解码器使用函数p来表示单个输出\boldsymbol{y}_{t'}的概率
其中的\boldsymbol{s}_{t'}为t'时刻的解码器的隐藏层变量。该隐藏层变量
其中函数g是循环神经网络单元
需要注意的是,编码器和解码器通常会使用多层循环神经网络
在以上的解码器设计中,各个时刻使用了相同的背景向量\boldsymbol{c}。如果编码器的不同时刻可以使用不同的背景向量呢?
以英语-法语翻译为例,给定一对输入序列"They are watching"和输出序列"lls regardent",解码器在时刻1可以使用更多的编码了"They are"信息的背景向量来生成"lls",而在时刻2可以使用更多编码了"watching"信息的背景向量来生成"regardent"。这看上去就像是在解码器的每一时刻对输入序列中不同时刻分配不同的注意力。这也是注意力机制的由来
现在,对上面的解码器稍作修改。我们假设时刻t'的背景向量为\boldsymbol{c}_{t'}。那么解码器在时刻t'的隐藏层变量
令编码器在t时刻的隐藏层变量为\boldsymbol{h}_t,解码器在t'时刻的背景向量为
也就是说,给定解码器的当前时刻t',我们需要对解码器中不同时刻的隐藏层变量求加权平均。而权值也称注意力权值。它的计算公式是
而e_{t' t}\in \mathbb{R}的计算公式为
其中函数a有多种设计方法。在Bahdanau的论文中
其中\boldsymbol{v}、\boldsymbol{W}_s、\boldsymbol{W}_h和编码器于解码器两个循环神经网络中的各个权重与偏移项以及嵌入层参数等都是需要同时学习的模型参数
在Bahdanau的论文的论文中,编码器和解码器均使用了GRU
在解码器中,我们需要对GRU的设计稍作修改,假设\boldsymbol{y}_t是单个输出在嵌入层的结果,例如\boldsymbol{y}_t对应的ont-hot向量\boldsymbol{o}\in \mathbb{R}^y与嵌入层参数矩阵\boldsymbol{B}\in \mathbb{R}^{y\times s}的乘积\boldsymbol{o}^\top\boldsymbol{B}。假设时刻t'的背景向量为\boldsymbol{c}_{t'}。那么解码器在时刻t'的单个隐藏层变量
其中,重置门、更新门和候选隐藏状态分别为