1. 编码器—解码器(seq2seq)
在自然语言处理的很多应用中,输入和输出都可以是不定长序列。以机器翻译为例,输入可以是一段不定长的英语文本序列,输出可以是一段不定长的法语文本序列,例如
英语输入:“They”、“are”、“watching”、“.”
法语输出:“Ils”、“regardent”、“.”
当输入和输出都是不定长序列时,我们可以使用编码器—解码器(encoder-decoder)[1] 或者seq2seq模型 [2]。这两个模型本质上都用到了两个循环神经网络,分别叫做编码器和解码器。编码器用来分析输入序列,解码器用来生成输出序列。
下图描述了使用编码器—解码器将上述英语句子翻译成法语句子的一种方法。在训练数据集中,我们可以在每个句子后附上特殊符号“<eos>”(end of sequence)以表示序列的终止。编码器每个时间步的输入依次为英语句子中的单词、标点和特殊符号“<eos>”。图中使用了编码器在最终时间步的隐藏状态作为输入句子的表征或编码信息。解码器在各个时间步中使用输入句子的编码信息和上个时间步的输出以及隐藏状态作为输入。我们希望解码器在各个时间步能正确依次输出翻译后的法语单词、标点和特殊符号"<eos>"。需要注意的是,解码器在最初时间步的输入用到了一个表示序列开始的特殊符号"<bos>"(beginning of sequence)。

接下来,我们分别介绍编码器和解码器的定义。
编码器
编码器的作用是把一个不定长的输入序列变换成一个定长的背景变量c\boldsymbol{c}c,并在该背景变量中编码输入序列信息。常用的编码器是循环神经网络。
让我们考虑批量大小为1的时序数据样本。假设输入序列是x1,…,xTx_1,\ldots,x_Tx1,…,xT,例如xix_ixi是输入句子中的第iii个词。在时间步ttt,循环神经网络将输入xtx_txt的特征向量xt\boldsymbol{x}_txt和上个时间步的隐藏状态ht−1\boldsymbol{h}_{t-1}ht−1变换为当前时间步的隐藏状态ht\boldsymbol{h}_tht。我们可以用函数fff表达循环神经网络隐藏层的变换:
ht=f(xt,ht−1). \boldsymbol{h}_t = f(\boldsymbol{x}_t, \boldsymbol{h}_{t-1}). ht=f(xt,ht−1).
接下来,编码器通过自定义函数qqq将各个时间步的隐藏状态变换为背景变量
c=q(h1,…,hT). \boldsymbol{c} = q(\boldsymbol{h}_1, \ldots, \boldsymbol{h}_T). c=q(h1,…,hT).
例如,当选择q(h1,…,hT)=hTq(\boldsymbol{h}_1, \ldots, \boldsymbol{h}_T) = \boldsymbol{h}_Tq(h1,…,hT)=hT时,背景变量是输入序列最终时间步的隐藏状态hT\boldsymbol{h}_ThT。
以上描述的编码器是一个单向的循环神经网络,每个时间步的隐藏状态只取决于该时间步及之前的输入子序列。我们也可以使用双向循环神经网络构造编码器。在这种情况下,编码器每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入),并编码了整个序列的信息。
解码器
刚刚已经介绍,编码器输出的背景变量c\boldsymbol{c}c编码了整个输入序列x1,…,xTx_1, \ldots, x_Tx1,…,xT的信息。给定训练样本中的输出序列y1,y2,…,yT′y_1, y_2, \ldots, y_{T'}y1,y2,…,yT′,对每个时间步t′t't′(符号与输入序列或编码器的时间步ttt有区别),解码器输出yt′y_{t'}yt′的条件概率将基于之前的输出序列y1,…,yt′−1y_1,\ldots,y_{t'-1}y1,…,yt′−1和背景变量c\boldsymbol{c}c,即P(yt′∣y1,…,yt′−1,c)P(y_{t'} \mid y_1, \ldots, y_{t'-1}, \boldsymbol{c})P(yt′∣y1,…,yt′−1,c)。
为此,我们可以使用另一个循环神经网络作为解码器。在输出序列的时间步t′t^\primet′,解码器将上一时间步的输出yt′−1y_{t^\prime-1}yt′−1以及背景变量c\boldsymbol{c}c作为输入,并将它们与上一时间步的隐藏状态st′−1\boldsymbol{s}_{t^\prime-1}st′−1变换为当前时间步的隐藏状态st′\boldsymbol{s}_{t^\prime}st′。因此,我们可以用函数ggg表达解码器隐藏层的变换:
st′=g(yt′−1,c,st′−1). \boldsymbol{s}_{t^\prime} = g(y_{t^\prime-1}, \boldsymbol{c}, \boldsymbol{s}_{t^\prime-1}). st′=g(yt′−1,c,st′−1).
有了解码器的隐藏状态后,我们可以使用自定义的输出层和softmax运算来计算P(yt′∣y1,…,yt′−1,c)P(y_{t^\prime} \mid y_1, \ldots, y_{t^\prime-1}, \boldsymbol{c})P(yt′∣y1,…,yt′−1,c),例如,基于当前时间步的解码器隐藏状态 st′\boldsymbol{s}_{t^\prime}st′、上一时间步的输出yt′−1y_{t^\prime-1}yt′−1以及背景变量c\boldsymbol{c}c来计算当前时间步输出yt′y_{t^\prime}yt′的概率分布。
训练模型
根据最大似然估计,我们可以最大化输出序列基于输入序列的条件概率
P(y1,…,yT′∣x1,…,xT)=∏t′=1T′P(yt′∣y1,…,yt′−1,x1,…,xT)=∏t′=1T′P(yt′∣y1,…,yt′−1,c), \begin{aligned} P(y_1, \ldots, y_{T'} \mid x_1, \ldots, x_T) &= \prod_{t'=1}^{T'} P(y_{t'} \mid y_1, \ldots, y_{t'-1}, x_1, \ldots, x_T)\\ &= \prod_{t'=1}^{T'} P(y_{t'} \mid y_1, \ldots, y_{t'-1}, \boldsymbol{c}), \end{aligned} P(y1,…,yT′∣x1,…,xT)=t′=1∏T′P(yt′∣y1,…,yt′−1,x1,…,xT)=t′=1∏T′P(yt′∣y1,…,yt′−1,c),
并得到该输出序列的损失
−logP(y1,…,yT′∣x1,…,xT)=−∑t′=1T′logP(yt′∣y1,…,yt′−1,c), -\log P(y_1, \ldots, y_{T'} \mid x_1, \ldots, x_T) = -\sum_{t'=1}^{T'} \log P(y_{t'} \mid y_1, \ldots, y_{t'-1}, \boldsymbol{c}), −logP(y1,…,yT′∣x1,…,xT)=−t′=1∑T′logP(yt′∣y1,…,yt′−1,c),
在模型训练中,所有输出序列损失的均值通常作为需要最小化的损失函数。在上图所描述的模型预测中,我们需要将解码器在上一个时间步的输出作为当前时间步的输入。与此不同,在训练中我们也可以将标签序列(训练集的真实输出序列)在上一个时间步的标签作为解码器在当前时间步的输入。这叫作强制教学(teacher forcing)。
2. 注意力机制
在上一节(编码器—解码器(seq2seq))里,解码器在各个时间步依赖相同的背景变量来获取输入序列信息。当编码器为循环神经网络时,背景变量来自它最终时间步的隐藏状态。
现在,让我们再次思考那一节提到的翻译例子:输入为英语序列“They”“are”“watching”“.”,输出为法语序列“Ils”“regardent”“.”。不难想到,解码器在生成输出序列中的每一个词时可能只需利用输入序列某一部分的信息。例如,在输出序列的时间步1,解码器可以主要依赖“They”“are”的信息来生成“Ils”,在时间步2则主要使用来自“watching”的编码信息生成“regardent”,最后在时间步3则直接映射句号“.”。这看上去就像是在解码器的每一时间步对输入序列中不同时间步的表征或编码信息分配不同的注意力一样。这也是注意力机制的由来。
仍然以循环神经网络为例,注意力机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每一时间步调整这些权重,即注意力权重,从而能够在不同时间步分别关注输入序列中的不同部分并编码进相应时间步的背景变量。本节我们将讨论注意力机制是怎么工作的。
在上一节(编码器—解码器(seq2seq))里我们区分了输入序列或编码器的索引ttt与输出序列或解码器的索引t′t't′。该节中,解码器在时间步t′t't′的隐藏状态st′=g(yt′−1,c,st′−1)\boldsymbol{s}_{t'} = g(\boldsymbol{y}_{t'-1}, \boldsymbol{c}, \boldsymbol{s}_{t'-1})st′=g(yt′−1,c,st′−1),其中yt′−1\boldsymbol{y}_{t'-1}yt′−1是上一时间步t′−1t'-1t′−1的输出yt′−1y_{t'-1}yt′−1的表征,且任一时间步t′t't′使用相同的背景变量c\boldsymbol{c}c。但在注意力机制中,解码器的每一时间步将使用可变的背景变量。记ct′\boldsymbol{c}_{t'}ct′是解码器在时间步t′t't′的背景变量,那么解码器在该时间步的隐藏状态可以改写为
st′=g(yt′−1,ct′,st′−1).\boldsymbol{s}_{t'} = g(\boldsymbol{y}_{t'-1}, \boldsymbol{c}_{t'}, \boldsymbol{s}_{t'-1}).st′=g(yt′−1,ct′,st′−1).
这里的关键是如何计算背景变量ct′\boldsymbol{c}_{t'}ct′和如何利用它来更新隐藏状态st′\boldsymbol{s}_{t'}st′。下面将分别描述这两个关键点。
计算背景变量
我们先描述第一个关键点,即计算背景变量。下图描绘了注意力机制如何为解码器在时间步2计算背景变量。首先,函数aaa根据解码器在时间步1的隐藏状态和编码器在各个时间步的隐藏状态计算softmax运算的输入。softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从而得到背景变量。

具体来说,令编码器在时间步ttt的隐藏状态为ht\boldsymbol{h}_tht,且总时间步数为TTT。那么解码器在时间步t′t't′的背景变量为所有编码器隐藏状态的加权平均:
ct′=∑t=1Tαt′tht, \boldsymbol{c}_{t'} = \sum_{t=1}^T \alpha_{t' t} \boldsymbol{h}_t, ct′=t=1∑Tαt′tht,
其中给定t′t't′时,权重αt′t\alpha_{t' t}αt′t在t=1,…,Tt=1,\ldots,Tt=1,…,T的值是一个概率分布。为了得到概率分布,我们可以使用softmax运算:
αt′t=exp(et′t)∑k=1Texp(et′k),t=1,…,T. \alpha_{t' t} = \frac{\exp(e_{t' t})}{ \sum_{k=1}^T \exp(e_{t' k}) },\quad t=1,\ldots,T. αt′t=∑k=1Texp(et′k)exp(et′t),t=1,…,T.
现在,我们需要定义如何计算上式中softmax运算的输入et′te_{t' t}et′t。由于et′te_{t' t}et′t同时取决于解码器的时间步t′t't′和编码器的时间步ttt,我们不妨以解码器在时间步t′−1t'-1t′−1的隐藏状态st′−1\boldsymbol{s}_{t' - 1}st′−1与编码器在时间步ttt的隐藏状态ht\boldsymbol{h}_tht为输入,并通过函数aaa计算et′te_{t' t}et′t:
et′t=a(st′−1,ht). e_{t' t} = a(\boldsymbol{s}_{t' - 1}, \boldsymbol{h}_t). et′t=a(st′−1,ht).
这里函数aaa有多种选择,如果两个输入向量长度相同,一个简单的选择是计算它们的内积a(s,h)=s⊤ha(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{s}^\top \boldsymbol{h}a(s,h)=s⊤h。而最早提出注意力机制的论文则将输入连结后通过含单隐藏层的多层感知机变换 [1]:
a(s,h)=v⊤tanh(Wss+Whh), a(\boldsymbol{s}, \boldsymbol{h}) = \boldsymbol{v}^\top \tanh(\boldsymbol{W}_s \boldsymbol{s} + \boldsymbol{W}_h \boldsymbol{h}), a(s,h)=v⊤tanh(Wss+Whh),
其中v\boldsymbol{v}v、Ws\boldsymbol{W}_sWs、Wh\boldsymbol{W}_hWh都是可以学习的模型参数。
矢量化计算
我们还可以对注意力机制采用更高效的矢量化计算。广义上,注意力机制的输入包括查询项以及一一对应的键项和值项,其中值项是需要加权平均的一组项。在加权平均中,值项的权重来自查询项以及与该值项对应的键项的计算。
在上面的例子中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。
让我们考虑一个常见的简单情形,即编码器和解码器的隐藏单元个数均为hhh,且函数a(s,h)=s⊤ha(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{s}^\top \boldsymbol{h}a(s,h)=s⊤h。假设我们希望根据解码器单个隐藏状态st′−1∈Rh\boldsymbol{s}_{t' - 1} \in \mathbb{R}^{h}st′−1∈Rh和编码器所有隐藏状态ht∈Rh,t=1,…,T\boldsymbol{h}_t \in \mathbb{R}^{h}, t = 1,\ldots,Tht∈Rh,t=1,…,T来计算背景向量ct′∈Rh\boldsymbol{c}_{t'}\in \mathbb{R}^{h}ct′∈Rh。
我们可以将查询项矩阵Q∈R1×h\boldsymbol{Q} \in \mathbb{R}^{1 \times h}Q∈R1×h设为st′−1⊤\boldsymbol{s}_{t' - 1}^\topst′−1⊤,并令键项矩阵K∈RT×h\boldsymbol{K} \in \mathbb{R}^{T \times h}K∈RT×h和值项矩阵V∈RT×h\boldsymbol{V} \in \mathbb{R}^{T \times h}V∈RT×h相同且第ttt行均为ht⊤\boldsymbol{h}_t^\topht⊤。此时,我们只需要通过矢量化计算
softmax(QK⊤)V\text{softmax}(\boldsymbol{Q}\boldsymbol{K}^\top)\boldsymbol{V}softmax(QK⊤)V
即可算出转置后的背景向量ct′⊤\boldsymbol{c}_{t'}^\topct′⊤。当查询项矩阵Q\boldsymbol{Q}Q的行数为nnn时,上式将得到nnn行的输出矩阵。输出矩阵与查询项矩阵在相同行上一一对应。
更新隐藏状态
现在我们描述第二个关键点,即更新隐藏状态。以门控循环单元为例,在解码器中我们可以对6.7节(门控循环单元(GRU))中门控循环单元的设计稍作修改,从而变换上一时间步t′−1t'-1t′−1的输出yt′−1\boldsymbol{y}_{t'-1}yt′−1、隐藏状态st′−1\boldsymbol{s}_{t' - 1}st′−1和当前时间步t′t't′的含注意力机制的背景变量ct′\boldsymbol{c}_{t'}ct′ [1]。解码器在时间步t′t't′的隐藏状态为
st′=zt′⊙st′−1+(1−zt′)⊙s~t′,\boldsymbol{s}_{t'} = \boldsymbol{z}_{t'} \odot \boldsymbol{s}_{t'-1} + (1 - \boldsymbol{z}_{t'}) \odot \tilde{\boldsymbol{s}}_{t'},st′=zt′⊙st′−1+(1−zt′)⊙s~t′,
其中的重置门、更新门和候选隐藏状态分别为
rt′=σ(Wyryt′−1+Wsrst′−1+Wcrct′+br),zt′=σ(Wyzyt′−1+Wszst′−1+Wczct′+bz),s~t′=tanh(Wysyt′−1+Wss(st′−1⊙rt′)+Wcsct′+bs), \begin{aligned} \boldsymbol{r}_{t'} &= \sigma(\boldsymbol{W}_{yr} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{sr} \boldsymbol{s}_{t' - 1} + \boldsymbol{W}_{cr} \boldsymbol{c}_{t'} + \boldsymbol{b}_r),\\ \boldsymbol{z}_{t'} &= \sigma(\boldsymbol{W}_{yz} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{sz} \boldsymbol{s}_{t' - 1} + \boldsymbol{W}_{cz} \boldsymbol{c}_{t'} + \boldsymbol{b}_z),\\ \tilde{\boldsymbol{s}}_{t'} &= \text{tanh}(\boldsymbol{W}_{ys} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{ss} (\boldsymbol{s}_{t' - 1} \odot \boldsymbol{r}_{t'}) + \boldsymbol{W}_{cs} \boldsymbol{c}_{t'} + \boldsymbol{b}_s), \end{aligned} rt′zt′s~t′=σ(Wyryt′−1+Wsrst′−1+Wcrct′+br),=σ(Wyzyt′−1+Wszst′−1+Wczct′+bz),=tanh(Wysyt′−1+Wss(st′−1⊙rt′)+Wcsct′+bs),
其中含下标的W\boldsymbol{W}W和b\boldsymbol{b}b分别为门控循环单元的权重参数和偏差参数。
本文探讨了在自然语言处理中,如何使用编码器-解码器(seq2seq)模型处理不定长序列输入和输出的问题,特别是在机器翻译场景中。介绍了模型的工作原理,包括编码器和解码器的定义,以及注意力机制如何提升模型性能。
638

被折叠的 条评论
为什么被折叠?



