10.11 注意力机制
在10.9节(编码器—解码器(seq2seq))里,解码器在各个时间步依赖相同的背景变量来获取输入序列信息。当编码器为循环神经网络时,背景变量来自它最终时间步的隐藏状态。
现在,让我们再次思考那一节提到的翻译例子:输入为英语序列“They”“are”“watching”“.”,输出为法语序列“Ils”“regardent”“.”。不难想到,解码器在生成输出序列中的每一个词时可能只需利用输入序列某一部分的信息。例如,在输出序列的时间步1,解码器可以主要依赖“They”“are”的信息来生成“Ils”,在时间步2则主要使用来自“watching”的编码信息生成“regardent”,最后在时间步3则直接映射句号“.”。这看上去就像是在解码器的每一时间步对输入序列中不同时间步的表征或编码信息分配不同的注意力一样。这也是注意力机制的由来 [1]。
仍然以循环神经网络为例,注意力机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每一时间步调整这些权重,即注意力权重,从而能够在不同时间步分别关注输入序列中的不同部分并编码进相应时间步的背景变量。本节我们将讨论注意力机制是怎么工作的。
在10.9节(编码器—解码器(seq2seq))里我们区分了输入序列或编码器的索引 t t t与输出序列或解码器的索引 t ′ t' t′。该节中,解码器在时间步 t ′ t' t′的隐藏状态 s t ′ = g ( y t ′ − 1 , c , s t ′ − 1 ) \boldsymbol{s}_{t'} = g(\boldsymbol{y}_{t'-1}, \boldsymbol{c}, \boldsymbol{s}_{t'-1}) st′=g(yt′−1,c,st′−1),其中 y t ′ − 1 \boldsymbol{y}_{t'-1} yt′−1是上一时间步 t ′ − 1 t'-1 t′−1的输出 y t ′ − 1 y_{t'-1} yt′−1的表征,且任一时间步 t ′ t' t′使用相同的背景变量 c \boldsymbol{c} c。但在注意力机制中,解码器的每一时间步将使用可变的背景变量。记 c t ′ \boldsymbol{c}_{t'} ct′是解码器在时间步 t ′ t' t′的背景变量,那么解码器在该时间步的隐藏状态可以改写为
s t ′ = g ( y t ′ − 1 , c t ′ , s t ′ − 1 ) . \boldsymbol{s}_{t'} = g(\boldsymbol{y}_{t'-1}, \boldsymbol{c}_{t'}, \boldsymbol{s}_{t'-1}). st′=g(yt′−1,ct′,st′−1).
这里的关键是如何计算背景变量 c t ′ \boldsymbol{c}_{t'} ct′和如何利用它来更新隐藏状态 s t ′ \boldsymbol{s}_{t'} st′。下面将分别描述这两个关键点。
10.11.1 计算背景变量
我们先描述第一个关键点,即计算背景变量。图10.12描绘了注意力机制如何为解码器在时间步2计算背景变量。首先,函数 a a a根据解码器在时间步1的隐藏状态和编码器在各个时间步的隐藏状态计算softmax运算的输入。softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从而得到背景变量。
具体来说,令编码器在时间步 t t t的隐藏状态为 h t \boldsymbol{h}_t ht,且总时间步数为 T T T。那么解码器在时间步 t ′ t' t′的背景变量为所有编码器隐藏状态的加权平均:
c t ′ = ∑ t = 1 T α t ′ t h t , \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 , … , T t=1,\ldots,T t=1,…,T的值是一个概率分布。为了得到概率分布,我们可以使用softmax运算:
α t ′ t = exp ( e t ′ t ) ∑ k = 1 T exp ( e t ′ 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运算的输入 e t ′ t e_{t' t} et′t。由于 e t ′ t e_{t' t} et′t同时取决于解码器的时间步 t ′ t' t′和编码器的时间步 t t t,我们不妨以解码器在时间步 t ′ − 1 t'-1 t′−1的隐藏状态 s t ′ − 1 \boldsymbol{s}_{t' - 1} st′−1与编码器在时间步 t t t的隐藏状态 h t \boldsymbol{h}_t ht为输入,并通过函数 a a a计算 e t ′ t e_{t' t} et′t:
e t ′ t = a ( s t ′ − 1 , h t ) . e_{t' t} = a(\boldsymbol{s}_{t' - 1}, \boldsymbol{h}_t). et′t=a(st′−1,ht).
这里函数 a a a有多种选择,如果两个输入向量长度相同,一个简单的选择是计算它们的内积 a ( s , h ) = s ⊤ h a(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{s}^\top \boldsymbol{h} a(s,h)=s⊤h。而最早提出注意力机制的论文则将输入连结后通过含单隐藏层的多层感知机变换 [1]:
a ( s , h ) = v ⊤ tanh ( W s s + W h h ) , 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、 W s \boldsymbol{W}_s Ws、 W h \boldsymbol{W}_h Wh都是可以学习的模型参数。
10.11.1.1 矢量化计算
我们还可以对注意力机制采用更高效的矢量化计算。广义上,注意力机制的输入包括查询项以及一一对应的键项和值项,其中值项是需要加权平均的一组项。在加权平均中,值项的权重来自查询项以及与该值项对应的键项的计算。
在上面的例子中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。
让我们考虑一个常见的简单情形,即编码器和解码器的隐藏单元个数均为
h
h
h,且函数
a
(
s
,
h
)
=
s
⊤
h
a(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{s}^\top \boldsymbol{h}
a(s,h)=s⊤h。假设我们希望根据解码器单个隐藏状态
s
t
′
−
1
∈
R
h
\boldsymbol{s}_{t' - 1} \in \mathbb{R}^{h}
st′−1∈Rh和编码器所有隐藏状态
h
t
∈
R
h
,
t
=
1
,
…
,
T
\boldsymbol{h}_t \in \mathbb{R}^{h}, t = 1,\ldots,T
ht∈Rh,t=1,…,T来计算背景向量
c
t
′
∈
R
h
\boldsymbol{c}_{t'}\in \mathbb{R}^{h}
ct′∈Rh。
我们可以将查询项矩阵
Q
∈
R
1
×
h
\boldsymbol{Q} \in \mathbb{R}^{1 \times h}
Q∈R1×h设为
s
t
′
−
1
⊤
\boldsymbol{s}_{t' - 1}^\top
st′−1⊤,并令键项矩阵
K
∈
R
T
×
h
\boldsymbol{K} \in \mathbb{R}^{T \times h}
K∈RT×h和值项矩阵
V
∈
R
T
×
h
\boldsymbol{V} \in \mathbb{R}^{T \times h}
V∈RT×h相同且第
t
t
t行均为
h
t
⊤
\boldsymbol{h}_t^\top
ht⊤。此时,我们只需要通过矢量化计算
softmax ( Q K ⊤ ) V \text{softmax}(\boldsymbol{Q}\boldsymbol{K}^\top)\boldsymbol{V} softmax(QK⊤)V
即可算出转置后的背景向量 c t ′ ⊤ \boldsymbol{c}_{t'}^\top ct′⊤。当查询项矩阵 Q \boldsymbol{Q} Q的行数为 n n n时,上式将得到 n n n行的输出矩阵。输出矩阵与查询项矩阵在相同行上一一对应。
10.11.2 更新隐藏状态
现在我们描述第二个关键点,即更新隐藏状态。以门控循环单元为例,在解码器中我们可以对6.7节(门控循环单元(GRU))中门控循环单元的设计稍作修改,从而变换上一时间步 t ′ − 1 t'-1 t′−1的输出 y t ′ − 1 \boldsymbol{y}_{t'-1} yt′−1、隐藏状态 s t ′ − 1 \boldsymbol{s}_{t' - 1} st′−1和当前时间步 t ′ t' t′的含注意力机制的背景变量 c t ′ \boldsymbol{c}_{t'} ct′ [1]。解码器在时间步 t ′ t' t′的隐藏状态为
s t ′ = z t ′ ⊙ s t ′ − 1 + ( 1 − z t ′ ) ⊙ 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′,
其中的重置门、更新门和候选隐藏状态分别为
r t ′ = σ ( W y r y t ′ − 1 + W s r s t ′ − 1 + W c r c t ′ + b r ) , z t ′ = σ ( W y z y t ′ − 1 + W s z s t ′ − 1 + W c z c t ′ + b z ) , s ~ t ′ = tanh ( W y s y t ′ − 1 + W s s ( s t ′ − 1 ⊙ r t ′ ) + W c s c t ′ + b s ) , \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分别为门控循环单元的权重参数和偏差参数。
10.11.3 发展
本质上,注意力机制能够为表征中较有价值的部分分配较多的计算资源。这个有趣的想法自提出后得到了快速发展,特别是启发了依靠注意力机制来编码输入序列并解码出输出序列的变换器(Transformer)模型的设计 [2]。变换器抛弃了卷积神经网络和循环神经网络的架构。它在计算效率上比基于循环神经网络的编码器—解码器模型通常更具明显优势。含注意力机制的变换器的编码结构在后来的BERT预训练模型中得以应用并令后者大放异彩:微调后的模型在多达11项自然语言处理任务中取得了当时最先进的结果 [3]。不久后,同样是基于变换器设计的GPT-2模型于新收集的语料数据集预训练后,在7个未参与训练的语言模型数据集上均取得了当时最先进的结果 [4]。除了自然语言处理领域,注意力机制还被广泛用于图像分类、自动图像描述、唇语解读以及语音识别。
小结
- 可以在解码器的每个时间步使用不同的背景变量,并对输入序列中不同时间步编码的信息分配不同的注意力。
- 广义上,注意力机制的输入包括查询项以及一一对应的键项和值项。
- 注意力机制可以采用更为高效的矢量化计算。
练习
- 基于本节的模型设计,为什么不可以将解码器在不同时间步的隐藏状态 s t ′ − 1 ⊤ ∈ R 1 × h , t ′ ∈ 1 , … , T ′ \boldsymbol{s}_{t' - 1}^\top \in \mathbb{R}^{1 \times h}, t' \in 1, \ldots, T' st′−1⊤∈R1×h,t′∈1,…,T′ 连结成查询项矩阵 Q ∈ R T ′ × h \boldsymbol{Q} \in \mathbb{R}^{T' \times h} Q∈RT′×h,从而同时计算不同时间步的含注意力机制的背景变量 c t ′ ⊤ , t ′ ∈ 1 , … , T ′ \boldsymbol{c}_{t'}^\top, t' \in 1, \ldots, T' ct′⊤,t′∈1,…,T′?
注意力机制的本质:注意力机制的核心思想是在解码的每一步,模型都能够关注到输入序列中的不同部分,从而生成更准确的输出。这要求模型在每一步都根据当前的解码状态(即隐藏状态)和输入序列的状态来计算一个特定的背景变量(即上下文向量)。
时间步的独立性:在seq2seq模型中,解码器的每一步都是独立的,即每一步都基于前一步的输出和当前的背景变量来生成输出。将不同时间步的隐藏状态连结成查询项矩阵意味着在所有时间步上使用相同的查询,这违反了注意力机制的基本原则,因为它没有考虑到解码过程中每个时间步的独特性。
计算复杂性和效率:即使技术上可以实现将隐藏状态连结成查询项矩阵并同时计算所有时间步的背景变量,但这种做法会显著增加计算复杂性和内存需求。在每一步中,模型都需要计算一个softmax分布,并对编码器隐藏状态进行加权平均,这是一个相对耗时的操作。如果同时计算所有时间步的背景变量,将会导致计算效率大大降低。
模型性能:更重要的是,将隐藏状态连结成查询项矩阵并同时计算背景变量可能会降低模型的性能。因为每个时间步的输出都依赖于特定的背景变量,而这个背景变量是根据当前解码状态和输入序列状态计算得出的。如果所有时间步都使用相同的背景变量,那么模型可能无法准确地捕捉到输入序列和输出序列之间的对齐关系,从而导致生成不准确的输出。
- 不修改“门控循环单元(GRU)”一节中的
gru
函数,应如何用它实现本节介绍的解码器?
1.初始化:
首先,你需要初始化解码器的隐藏状态(例如,设置为零向量或随机向量)。
2.编码过程:
首先,你需要一个编码器(可以是另一个GRU或者其他类型的RNN)来处理输入序列,并得到每个时间步的隐藏状态。
3.注意力计算:
对于解码器的每一个时间步,计算注意力权重。这通常涉及一个评分函数,它根据解码器当前时间步的隐藏状态和编码器所有时间步的隐藏状态来计算得 分。
将这些得分通过softmax函数转化为注意力权重。
使用注意力权重对编码器隐藏状态进行加权平均,得到上下文向量(背景变量)。
4.解码过程:
在解码器的每个时间步,将上一时间步的输出(或开始符号,对于第一个时间步),当前时间步的上下文向量,以及前一个时间步的隐藏状态作为输入,送入GRU函数。
GRU函数将返回新的隐藏状态,这个状态现在已经融入了上下文信息。
使用新的隐藏状态(可能还结合上下文向量)来预测当前时间步的输出。
5.迭代:重复步骤4,直到达到输出序列的末尾或满足某个停止条件。
6.输出处理:将解码器在每个时间步的输出转换为最终序列(例如,通过词汇表进行映射)。
- 除了自然语言处理,注意力机制还可以应用在哪些地方?
计算机视觉:
目标检测:通过关注图像中特定区域来提高目标检测和识别的准确性和鲁棒性。注意力机制可以帮助模型聚焦于图像中的关键部分,减少背景噪声的干扰。
图像分割:在图像分割任务中,注意力机制可以帮助模型区分图像中的不同区域或对象,提高分割的精度。
图像分类:结合注意力机制,模型可以更加关注图像中的关键特征,从而提高图像分类的准确率。
语音识别:
声学模型建模:注意力机制可以用于声学模型的建模过程中,通过动态地调整对不同时间步的关注程度,提高声学模型对语音信号的建模能力。
语言模型建模:注意力机制还可以用于语言模型的建模过程中,通过动态地调整对不同位置的关注程度,提高语言模型对语言序列的建模能力。
上下文建模:在语音识别中,注意力机制可以建模上下文信息,提高语音识别的准确率。
数据预测:
在数据预测任务中,注意力机制可以帮助模型关注历史数据中的关键信息,从而提高预测的准确性。
推荐系统:
在处理长文本(如用户评论)时,注意力机制可以有效地提取文本中的重点,帮助推荐系统理解用户的兴趣点,从而提供个性化的推荐。
图像处理:
注意力机制可以帮助模型在图像处理任务中关注图像中的关键区域,如图像修复、图像增强等。
参考文献
[1] Bahdanau, D., Cho, K., & Bengio, Y. (2014). Neural machine translation by jointly learning to align and translate. arXiv preprint arXiv:1409.0473.
[2] Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., … & Polosukhin, I. (2017). Attention is all you need. In Advances in Neural Information Processing Systems (pp. 5998-6008).
[3] Devlin, J., Chang, M. W., Lee, K., & Toutanova, K. (2018). Bert: Pre-training of deep bidirectional transformers for language understanding. arXiv preprint arXiv:1810.04805.
[4] Radford, A., Wu, J., Child, R., Luan, D., Amodei, D., Sutskever I. (2019). Language Models are Unsupervised Multitask Learners. OpenAI.