目录
1 attention机制原理
- attention机制的核心思想就是对模型的每个输出只关注输入序列的最重要的部位信息。类似人的注意力机制,当我们在观察一幅图像的时候,视眼只关注图像的核心区域。在NLP任务的机器翻译模型里,每次在解码阶段,通过注意力机制只需要关联输入与当前输出最相关的信息,而不是宽泛的关注输入的整个句子。
- attention机制,通过提供输出和输入的一个直接路径连接,也有利于减轻梯度消失问题
2 attention类型
对attention按照不同的角度进行如下三种形式的分类:
2.1 按照是否可直接BP算法计算梯度进行分类
代表论文:Show, Attend and Tell: Neural Image Caption
Generation with Visual Attention
2.1.1 Soft attention
平时我们所说的大多数attention结构都属于soft attention,soft attention 结构通常通过学习输入序列的重要性权重。soft attention是参数化的,是可导的,因此模型在训练的时候,可以根据BP算法进行梯度计算,参数更新。
2.1.2 Hard attention
而hard attention的主要特点是一个随机离散过程,每次只会依据概率选择图像的部分特征或者NLP任务中encoder部分的词向量区域来计算attention,而不是全部的隐状态,所以,不能直接用BP算法训练,需要采用梯度估计的方法比如蒙特卡洛采样方法来估计模块的梯度。
2.2 按照输入是全局还是局部参与计算attention进行分类
2.2.1 Global attention
在一个seq2seq模型结构里,在decoder阶段,每个step的context vector的权重计算与encoder阶段输入的每个隐状态有关,会依次与encoder的每个隐状态计算一个权重,再通过加权平均的方式得到context vector,这就是global attention,在encode阶段的序列每个term都会参与decode阶段的每个attention的计算。结构如下图所示:
2.2.2 Local attention
而local attention的计算只与encoder阶段的部分输出隐状态向量有关,不会对encoder的全部隐状态都用来参与计算。对于输入很长的序列,可以减少计算开销,而且直观上理解,在decoder阶段当前的输出不会和encoder的所有输入都有关联,特别是输入长度很大的时候,但是缺陷就是每次需要计算局部选择的窗口范围,如果输入长度较短,局部窗口计算不一定准的条件下,会降低准确率,如下图结构如下:
2.3 按照attention实现功能进行分类
2.3.1 encoder-decoder Attention
2.3.1.1 典型代表
机器翻译:Neural Machine Translation by Jointly Learning to Align and Translate (2014)
首次将attention机制应用到机器翻译任务
2.3.1.2 原理
在翻译模型里,输入序列经过encoder编码器(通常用一个RNN模型结构),最后一个词的隐层输出作为整个输入序列的特征表示输入到decoder的RNN模型里,再进行一个词一个词的解码。但是这有两个主要问题,第一:RNN模型一般经过多步的传播,越前的信息会丢失严重;第二,在解码阶段,不同的词需要的输入序列的信息不同,但是却用整个输入序列的信息作为每个词解码信息,加重模型的学习难度。
为了解决上面问题,attention机制第一次在机器翻译中提出,如下图decoder阶段:
除了上一时刻cell的输出和隐层状态,还需要输入一个context向量 c c c,其中 c c c是输入序列在encoder阶段的所有隐层状态值的加权平均 。计算形式如下:
c i = ∑ j = 1 T x a i j h j c_i = \sum_{j=1}^{T_x}a_{ij}h_j ci=j=1∑Txaijhj
这里 a i j a_{ij} aij表示decoder阶段第 i i i个输出应该关注encoder阶段第 j j j个输入词的权重, h j h_j hj表示第 j j j个输入的隐层状态。 a i j a_{ij} aij权重的计算是与第 i i i个输出与所有encoder输入的attention 分值 e e e进行softmax归一化得到,如下所示:
a i j = s o f t m a x ( e i j ) = e x p ( e i j ) ∑ k = 1 T x e x p ( e i k ) a_{ij} = softmax(e_{ij}) = \frac{exp(e_{ij})}{\sum_{k=1}^{T_x}exp(e_{ik})} aij=softmax(eij)=∑k=1Txexp(eik)exp(eij)
而分值 e i j e_{ij} eij的计算是:
e i j = f ( s i − 1 , h j ) e_{ij} = f(s_{i-1}, h_j) eij=f(si−1,hj)
其中 f f f是一个衡量encoder中的第 j j j个输入和decoder中的第 i i i个输出匹配程度, s i − 1 s_{i-1} si−1是decoder中的上一个隐层状态。
其中 f f f函数的计算形式,一般有三种方法,详细可以参考我上一篇博文seq2seq beam search和attention机制,三种计算公式如下:
f ( s i − 1 , h j ) = { s i − 1 T h j dot s i − 1 T W h j g e n e r a l v T t a n h ( W [ s i − 1 , h j ] ) c o n c a t f(s_{i-1}, h_j) = \begin{cases} s^T_{i-1}h_{j} \text{ } \text{ dot}\\\\ s^T_{i-1}Wh_j \text{ } \text{ } general\\\\ v^Ttanh(W[s_{i-1}, h_j]) \text{ } \text{ } concat\end{cases} f(si−1,hj)=⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧si−1Thj dotsi−1TWhj generalvTtanh(W[si−1,hj]) concat
2.3.2 Multi-Head Attention
2.3.2.1 典型代表
Attention is all you need
我们知道RNN模型有强大的时序特征提取能力,但是由于是step by step形式,模型结构不能并行计算,速度相对CNN等这些可以并行计算的结构要慢。transformer结构现在越来越得到广泛应用,在NLP任务中各指标刷新历史记录的bert或者改进版本模型,基本都是基于transformer结构,transformer结构的优势主要有两点:第一,通过attention机制结构,可以学习时序特征;第二,由于attention结构可以并行计算,所以可以更好的用GPU进行加速,提高训练速度。
2.3.2.2 原理
Multi-head attention允许模型去学习在不同位置和空间上的不同表征特征。我们可以这么理解,“一词多意”的时候,希望模型在不同的空间维度可以学习不同的含义。
transformer结构中,使用的Multi-Head attention,如下图所示:
当head=1的时候,就是我们通常的attention形式计算,在transformer结构中的计算形式如下:
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dkQKT)V
Multi-Head就是分别计算多个head,然后再把结果concat到一起,计算公式如下:
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) W O MultiHead(Q,K,V)=Concat(head_1,...,head_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) head_i = Attention(QW_i^Q, KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)
其中Q,K,V都会经过一层映射变化层,对应的参数矩阵分别为 W Q , W K , W V W^Q, W^K, W^V WQ,WK,WV,多个Head则对应多个不同的这样一组参数,最后将每个head的输出结果concat到一起,再经过一层 W O W^O WO的映射层,得到输出结果。具体可以参考我上一篇博文:transformer结构Multi-Head attention
2.3.3 Hierarchical Attention
2.3.3.1 典型代表
Hierarchical Attention Networks for Document Classification
基于word-level attention机制,计算每个词的权重,然后加权和得到句子向量;基于sentence-level attention机制,计算每个句子的权重,然后加权得到文本向量
2.3.3.2 原理
hierarchical attention顾名思义包含层级关系的attention结构。比如对一个文本分类,文本是由句子构成的,每个句子的重要程度并不都一样,而句子又是由单词构成的,同样每个单词在句子中起到的作用也不一样。所以这两层都有各自的重要性关系。结构层次关系是: 单 词 ∈ 句 子 ∈ 文 本 单词 \in 句子 \in 文本 单词∈句子∈文本,而attention结构关系是:带attention权重的单词组合成句子,带attention权重的句子组成文本。HAN提出了层级结构attention,对文本进行分类,如下图结构所示:
模型从底往上,首先用一个BiGRU模型编码一个句子词的的向量,每个句子的词经过BiGRU模型,得到每个词的特征表示,再与一个单词级别的context vector计算每个单词的attenion权重,主要分两步计算:
Step 1: 计算由权重的词组成的句子向量
u i t = t a n h ( W w h i t + b w ) u_{it} = tanh(W_wh_{it}+b_w) uit=tanh(Wwhit+bw)
a i t = e x p ( u i t T u w ) ∑ t e x p ( u i t T u w ) a_{it} = \frac{exp(u_{it}^Tu_w)}{\sum_texp(u_{it}^Tu_w)} ait=∑texp(uitTuw)exp(uitTuw)
s i = ∑ t a i t h i t s_i=\sum_ta_{it}h_{it} si=t∑aithit
其中 h i t h_{it} hit表示第 i i i个句子中第 t t t个词经过BiGRU模型输出的隐层状态值, W w W_w Ww是一个映射层参数矩阵, u w u_w uw是词那层的全局context vector上下文向量(这个是在训练过程中需要学习的参数), a i t a_{it} ait代表第 i i i个句子的第 t t t个词的attention权重,最后带权词向量和得到句子向量 s i s_i si
Step 2: 计算带权重的句子向量组成的文本向量
经过word level层,得到每个句子向量后,再经过另外一个BiGRU按照word level的方式计算每个句子attention分值,最后进行加权句向量和作为整个文本向量,计算公式如下:
u i = t a n h ( W s h i + b s ) u_{i} = tanh(W_sh_{i}+b_s) ui=tanh(Wshi+bs)
a i = e x p ( u i T u s ) ∑ t e x p ( u i T u s ) a_{i} = \frac{exp(u_{i}^Tu_s)}{\sum_texp(u_{i}^Tu_s)} ai=∑texp(uiTus)exp(uiTus)
v = ∑ t a i h i v=\sum_ta_{i}h_{i} v=t∑aihi
其中 h i h_i hi表示的第 i i i个句向量经过BiGRU编码得到的输出隐层状态, W s W_s Ws是句子那层的映射层参数权重, u s u_s us是句子层的context vector上下文向量(同样是需要学习的模型参数),最后加权和句向量得到文本向量 v v v
2.3.4 Self Attention
2.3.4.1 典型代表
Attention is all you need,transformer结构是一个attention-based model,它是由全连接层和self-attention 层组成的。构建基本的attention思路大概是,给定一个sequence序列元素 V = v 1 , v 2 , . . . , v n V={v_1, v_2, ...,v_n} V=v1,v2,...,vn和一个模式向量 u u u,对于每个元素 v i v_i vi,我们可以计算attention分值 a i = a ( u , v i ) a_i=a(u, v_i) ai=a(u,vi),这也叫做外部attention(external attention),因为attention的是通过匹配一个外部模式 u u u和每个元素 v i v_i vi计算出来的。而在self attention,外部模式 u u u是来自sequence内部自己的元素代替,因此,也叫做内部attention(internal attention) 。
2.3.4.2 原理
在 Attention is all you need,假设输入sequence为 V ∈ R n × d i n V \in R^{n×d_{in}} V∈Rn×din,则attention计算公式可以梳理如下:
A = s o f t m a x [ ( V W 1 ) ( V W 2 ) T d o u t ] A = softmax[\frac{(VW_1){(VW_2)}^T}{\sqrt{d_{out}}}] A=softmax[dout(VW1)(VW2)T]
C = A T ( V W 3 ) C = A^T(VW_3) C=AT(VW3)
W 1 , W 2 , W 3 ∈ R d i n × d o u t W_1, W_2, W_3 \in R^{d_{in}×d_{out}} W1,W2,W3∈Rdin×dout是参数矩阵,将输入 V V V转换成对应的query,key和value向量表示,而 C ∈ R n × d o u t C \in R^{n×d_{out}} C∈Rn×dout表示一个序列的self-attentive的token编码,也可以理解成以每个token进行的self attention加权和得到的句向量。
2.3.5 Memory-based Attention
2.3.5.1 典型代表
End-To-End Memory Networks,将输入 x i {x_i} xi转成memory向量 m i {m_i} mi,对query q q q转成状态向量 u u u,计算每个memory m i m_i mi与 u u u的匹配程度,也就是attention权重:
a i = s o f t m a x ( u T m i ) a_i = softmax(u^Tm_i) ai=softmax(uTmi)
得到权重向量 a i a_i ai后,而每个 x i x_i xi有一个对应的输出表征向量 c i c_i ci,计算输出memory表征:
o = ∑ i p i c i o = \sum_ip_ic_i o=i∑pici
产生最终的预测向量,将输入向量 u u u和输出向量 o o o相加,经过分类层,得到预测label:
a ^ = s o f t m a x ( W ( o + u ) ) \hat{a} = softmax(W(o+u)) a^=softmax(W(o+u))
其中query更新通过对当前的query向量 u u u和输出 o o o向量相加。
2.3.5.2 原理
假设在对话系统中,存储一系列上下文按照key, value形式存储< k i , v i k_i, v_i ki,vi>和一个问题query q q q,则基于memory-based attention计算形式如下:
e i = a ( q , k i ) ( 加 强 m e m o r y ) e_i = a(q, k_i) \text{ }(加强memory) ei=a(q,ki) (加强memory)
a i = e x p ( e i ) ∑ i e x p ( e i ) ( 计 算 a t t e n t i o n ) a_i = \frac{exp(e_i)}{\sum_iexp(e_i)} \text{ } (计算attention) ai=∑iexp(ei)exp(ei) (计算attention)
c = ∑ i a i v i ( 读 取 内 容 ) c = \sum_ia_iv_i \text{ } (读取内容) c=i∑aivi (读取内容)
在这里,我们采用一种soft memory计算方式,通过query q q q来计算attention分值。注意,如果 k i , v i k_i, v_i ki,vi相同的话,这和我们基本的attention机制self attention没有很大的区别。通过增加一些功能变体,memory-based attention机制可以更加有效和灵活,在一些问答任务中,问题的答案可能不能直接得到,为了解决这个问题,可以不断的更新迭代memory将注意力转移到答案所在位置,momory-based attention计算公式如下:
1. 初 始 化 q = q u e s t i o n 1. 初始化 q = question 1.初始化q=question
2. e i = a ( q , ϕ k ( k i ) ) ( 加 强 m e m o r y ) 2. e_i = a(q, \phi_k(k_i)) \text{ } (加强memory) 2.ei=a(q,ϕk(ki)) (加强memory)
3. a i = e x p ( e i ) ∑ i e x p ( e i ) ( 计 算 a t t e n t i o n ) 3. a_i = \frac{exp(e_i)}{\sum_iexp(e_i)} \text{ } (计算attention) 3.ai=∑iexp(ei)exp(ei) (计算attention)
4. c = ∑ i a i ϕ v ( v i ) ( 读 取 内 容 ) 4. c = \sum_ia_i \phi_v(v_i) \text{ } (读取内容) 4.c=∑iaiϕv(vi) (读取内容)
5. q = u p d a _ q u e r y ( q , c ) ( 更 新 q u e r y ) 5. q = upda\_query(q, c) \text{ } (更新query) 5.q=upda_query(q,c) (更新query)
6. g o t o 2 6. goto 2 6.goto2
通过query,与memory中的 k k k计算attention,计算得到相关的上下文向量 c c c,再拼接到一起作为新的 q q q,不断迭代,直到找到最终的答案,如下图例子所示:
3 attention应用
3.1 计算输入序列的权重
上面介绍的大部分attenion机制计算方法都是为了计算输入序列的每个单元(字或者词)的一个权重,再通过加权和来表征最终的向量:
c = ∑ i a i v i c = \sum_ia_iv_i c=i∑aivi
a a a代表计算的attention权重, v v v表示输入的序列向量, c c c代表最终的加权输出向量。直观解释是输入的每个词的在不同的任务中起到的作用是不同的。
3.2 更新门机制
attention中的另外一个应用就是将这种attention机制用于RNN模型中的memory更新,传统的GRU结构,hidden state更新策略如下:
h i ^ = t a n h ( W v i + r i ◦ ( U h i − 1 ) + b ( h ) ) \hat{h_i} = tanh(Wv_i+r_i◦(Uh_{i-1})+b^{(h)}) hi^=tanh(Wvi+ri◦(Uhi−1)+b(h))
h i = u i ◦ h i ^ + ( 1 − u i ) ◦ h i − 1 h_i = u_i◦\hat{h_i}+(1-u_i)◦h_{i-1} hi=ui◦hi^+(1−ui)◦hi−1
其中 u i u_i ui和 r i r_i ri分别是update和reset门,这些参数在模型训练过程中需要更新学习。attention机制将 u i u_i ui用attention权重 a i a_i ai取代,所以hidden state的更新计算公式改动如下:
h i = a i ◦ h i ^ + ( 1 − a i ) ◦ h i − 1 h_i = a_i ◦ \hat{h_i} + (1-a_i)◦h_{i-1} hi=ai◦hi^+(1−ai)◦hi−1
3.3 pre-training初始化模型
基于self-attention结构的bert通过大量的语料进行两个任务:mask和next sentence预测的pre-train训练,在NLP各项任务指标中都取得了较大的提升。所以基于attenion结构的模型通过pre-train提升模型的表征能力
4 参考
- End-To-End Memory Networks
- An Introductory Survey on Attention Mechanisms in NLP Problems
- An Introductory Survey on Attention Mechanisms in NLP Problems
- Attention Is All You Needf
- https://towardsdatascience.com/the-definitive-guide-to-bidaf-part-3-attention-92352bbdcb07
- https://medium.com/@joealato/attention-in-nlp-734c6fa9d983
- https://towardsdatascience.com/attention-and-its-different-forms-7fc3674d14dc