14.8 注意力
编码器—解码器模型的简洁之处,在于编码器与解码器之间清晰的分工:编码器构建源文本的表示,解码器利用该上下文生成目标文本。在目前描述的模型中,上下文向量是 h n h_n h n ,即源文本最后一个时间步的隐藏状态。因此,这个最终隐藏状态形成了一个瓶颈:它必须表示源文本意义的全部信息,因为解码器对源文本的唯一了解就是上下文向量中的内容(图 14.20)。句首的信息,尤其是在长句中,可能无法同样充分地表示在上下文向量中。
图 14.20 要求上下文 c c c 只能是编码器的最终隐藏状态,会迫使整个源句的全部信息通过这一表示瓶颈。
注意力机制解决了这一瓶颈问题:它允许解码器从编码器的所有隐藏状态中获取信息,而不仅仅是最后一个隐藏状态。
在注意力机制中,与基本编码器—解码器模型一样,上下文向量 c c c 是编码器隐藏状态的函数。但它不再取自最后一个隐藏状态,而是编码器所有隐藏状态的加权平均。这个加权平均还受到解码器状态的一部分影响,即当前词元 i i i 之前的解码器状态。也就是说,c i = f ( h 1 e , … , h n e , h i − 1 d ) \mathbf{c}_i = f(\mathbf{h}_1^e,\ldots,\mathbf{h}_n^e,\mathbf{h}_{i-1}^d) c i = f ( h 1 e , … , h n e , h i − 1 d ) 。权重会聚焦于(“关注”)源文本中与解码器当前正在生成的词元 i i i 相关的部分。因此,注意力把静态上下文向量替换成一个动态向量:它由编码器隐藏状态动态产生,同时受到解码器状态影响,所以在解码的每个词元之间都不同。
这个上下文向量 c i c_i c i 会在每个解码步骤 i i i 重新生成,并在计算时考虑所有编码器隐藏状态。然后,在计算当前解码器隐藏状态时以它为条件(同时还以先前隐藏状态和解码器上一步生成的输出为条件),从而让该上下文参与解码:
h i d = g ( y ^ i − 1 , h i − 1 d , c i ) (14.34) \mathbf {h} _ {i} ^ {d} = g (\hat {y} _ {i - 1}, \mathbf {h} _ {i - 1} ^ {d}, \mathbf {c} _ {i})\tag{14.34} h i d = g ( y ^ i − 1 , h i − 1 d , c i ) ( 14.34 ) 图 14.21 注意力机制使解码器的每个隐藏状态都能看到不同的动态上下文,该上下文是所有编码器隐藏状态的函数。
计算 c i \mathbf{c}_i c i 的第一步,是计算应该在每个编码器状态上关注多少,即每个编码器状态与 h i − 1 d \mathbf{h}_{i-1}^d h i − 1 d 所表示的解码器状态有多相关。在解码的每个状态 i i i ,我们针对每个编码器状态 j j j 计算一个分数 ( h i − 1 d , h j e ) (\mathbf{h}_{i-1}^d,\mathbf{h}_j^e) ( h i − 1 d , h j e ) ,以表示相关性。
最简单的分数函数称为点积注意力,它通过衡量相似度来实现相关性:计算解码器隐藏状态与编码器隐藏状态的点积,以衡量两者有多相似:
score ( h i − 1 d , h j e ) = h i − 1 d ⋅ h j e (14.35) \operatorname{score} \left(\mathbf {h} _ {i - 1} ^ {d}, \mathbf {h} _ {j} ^ {e}\right) = \mathbf {h} _ {i - 1} ^ {d} \cdot \mathbf {h} _ {j} ^ {e}\tag{14.35} score ( h i − 1 d , h j e ) = h i − 1 d ⋅ h j e ( 14.35 ) 点积产生的分数是一个标量,反映两个向量之间的相似程度。跨越所有编码器隐藏状态的分数组成一个向量,给出每个编码器状态与当前解码器步骤的相关性。
为了利用这些分数,我们用 softmax 对其归一化,创建权重向量 α i j \alpha_{ij} α ij 。该向量告诉我们,编码器隐藏状态 j j j 相对于先前解码器隐藏状态 h i − 1 d \mathbf{h}_{i-1}^d h i − 1 d 的比例相关性。1
α i j = softmax ( score ( h i − 1 d , h j e ) ) = exp ( score ( h i − 1 d , h j e ) ∑ k exp ( score ( h i − 1 d , h k e ) ) (14.36) \begin{array}{r c l} \alpha_ {i j} & = & \text {softmax} (\text {score} (\mathbf {h} _ {i - 1} ^ {d}, \mathbf {h} _ {j} ^ {e})) \\ & = & \frac {\exp (\text {score} (\mathbf {h} _ {i - 1} ^ {d} , \mathbf {h} _ {j} ^ {e})}{\sum_ {k} \exp (\text {score} (\mathbf {h} _ {i - 1} ^ {d} , \mathbf {h} _ {k} ^ {e}))} \end{array}\tag{14.36} α ij = = softmax ( score ( h i − 1 d , h j e )) ∑ k e x p ( score ( h i − 1 d , h k e )) e x p ( score ( h i − 1 d , h j e ) ( 14.36 ) 最后,给定 α \alpha α 中的分布,我们可以对所有编码器隐藏状态进行加权平均,为当前解码器状态计算一个定长上下文向量。
c i = ∑ j α i j h j e (14.37) \mathbf {c} _ {i} = \sum_ {j} \alpha_ {i j} \mathbf {h} _ {j} ^ {e}\tag{14.37} c i = j ∑ α ij h j e ( 14.37 ) 这样,我们最终得到一个定长上下文向量:它考虑了整个编码器状态的信息,并且会根据解码器在每个解码步骤的需要动态更新。图 14.22 展示了一个带注意力的编码器—解码器网络,重点说明一个上下文向量 c i \mathbf{c}_i c i 的计算。
图 14.22 带注意力的编码器—解码器网络示意图,重点展示 c i \mathbf{c}_i c i 的计算。上下文值 c i \mathbf{c}_i c i 是计算 h i d \mathbf{h}_i^d h i d 的输入之一。它通过对所有编码器隐藏状态求加权和得到,每个权重是该状态与先前解码器隐藏状态 h i − 1 d \mathbf{h}_{i-1}^d h i − 1 d 的点积。
还可以为注意力模型设计更复杂的打分函数。与简单的点积注意力不同,我们可以用独立的一组权重 W s \boldsymbol{\mathsf{W}}_s W s 对打分函数进行参数化,从而得到更强大的函数,计算每个编码器隐藏状态与解码器隐藏状态之间的相关性:
score ( h i − 1 d , h j e ) = h i − 1 d W s h j e (14.38) \operatorname{score} \left(\mathbf {h} _ {i - 1} ^ {d}, \mathbf {h} _ {j} ^ {e}\right) = \mathbf {h} _ {i - 1} ^ {d} \mathbf {W} _ {s} \mathbf {h} _ {j} ^ {e}\tag{14.38} score ( h i − 1 d , h j e ) = h i − 1 d W s h j e ( 14.38 ) 权重 W s W_s W s 会在普通端到端训练中学习,使网络能够学会在当前应用中,解码器状态与编码器状态之间的相似性哪些方面更重要。这个双线性模型还允许编码器和解码器使用维度不同的向量;简单点积注意力则要求编码器和解码器隐藏状态具有相同维度。