轉自:
https://easyai.tech/ai-definition/attention/
https://www.zhihu.com/question/68482809
https://zhuanlan.zhihu.com/p/46313756
paper 《NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE》
1、為什么要引入Attention機制?
根據通用近似定理,前饋網絡和循環網絡都有很強的能力。但為什么還要引入注意力機制呢?
- 計算能力的限制:當要記住很多“信息“,模型就要變得更復雜,然而目前計算能力依然是限制神經網絡發展的瓶頸。
- 優化算法的限制:雖然局部連接、權重共享以及pooling等優化操作可以讓神經網絡變得簡單一些,有效緩解模型復雜度和表達能力之間的矛盾;但是,如循環神經網絡中的長距離以來問題,信息“記憶”能力並不高。
- 可以借助人腦處理信息過載的方式,例如Attention機制可以提高神經網絡處理信息的能力。*
2、Attention機制有哪些(怎么分類)?
當用神經網絡來處理大量的輸入信息時,也可以借鑒人腦的注意力機制,只選擇一些關鍵的信息輸入進行處理,來提高神經網絡的效率。按照認知神經學中的注意力,可以總體上分為兩類:
- 聚焦式(focus)注意力:自上而下的有意識的注意力,主動注意——是指有預定目的、依賴任務的、主動有意識地聚焦於某一對象的注意力;
- 顯著性(saliency-based)注意力:自下而上的有意識的注意力,被動注意——基於顯著性的注意力是由外界刺激驅動的注意,不需要主動干預,也和任務無關;可以將max-pooling和門控(gating)機制來近似地看作是自下而上的基於顯著性的注意力機制。
在人工神經網絡中,注意力機制一般就特指聚焦式注意力。
另外也有其它分類類型,如分Soft、Hard兩種 見第四部分。
3、Attention機制的計算流程是怎樣的?

Attention機制的實質:尋址(addressing)Attention機制的實質其實就是一個尋址(addressing)的過程,如上圖所示:給定一個和任務相關的查詢Query向量 q,通過計算與Key的注意力分布並附加在Value上,從而計算Attention Value。這個過程實際上是Attention機制緩解神經網絡模型復雜度的體現:不需要將所有的N個輸入信息都輸入到神經網絡進行計算,只需要從X中選擇一些和任務相關的信息輸入給神經網絡。
上面的圖看起來比較抽象,下面用一個例子來解釋 attention 的原理:
圖書管(source)里有很多書(value),為了方便查找,我們給書做了編號(key)。當我們想要了解漫威(query)的時候,我們就可以看看那些動漫、電影、甚至二戰(美國隊長)相關的書籍。
為了提高效率,並不是所有的書都會仔細看,針對漫威來說,動漫,電影相關的會看的仔細一些(權重高),但是二戰的就只需要簡單掃一下即可(權重低)。當我們全部看完后就對漫威有一個全面的了解了。
基本步驟如下:
step1-從輸入信息中確定Key和value,並計算相似度:用$X = [x_1, · · · , x_N]$表示N個輸入信息,令Key=Value=X,query和key進行相似度計算,得到權值;
step2-權值歸一化(softmax)計算注意力分布:利用softmax進行權值歸一化,則可以給出注意力分布:
$ \alpha_i=softmax(s(key_i, q))=softmax(s(x_i, q)) $
我們將$ \alpha_i $稱之為注意力分布(概率分布),$ s(x_i, q) $為注意力打分機制,有幾種打分機制:

step3-信息加權平均,即權重和Value進行加權求和:注意力分布$ \alpha_i $可以解釋為在上下文查詢q時,第i個信息受關注的程度,采用一種“軟性”的信息選擇機制對輸入信息X進行編碼為:
$ att(q,X)=\sum_{i=1}^{N}{\alpha_iX_i} $
這種編碼方式為軟性注意力機制(soft Attention),軟性注意力機制有兩種:普通模式(Key=Value=X)和鍵值對模式(Key!=Value)。

結合paper《NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE》再來看下attention過程:
這里h是encoder的hidden state,是輸入信息的編碼,s是decoder的hidden state。在論文中value和key取h,query取s。
4、Attention機制的變種有哪些?
與普通的Attention機制(上圖左)相比,Attention機制有哪些變種呢?
- 變種1-硬性注意力:之前提到的注意力是軟性注意力,其選擇的信息是所有輸入信息在注意力 分布下的期望。還有一種注意力是只關注到某一個位置上的信息,叫做硬性注意力(hard attention)。硬性注意力有兩種實現方式:(1)一種是選取最高概率的輸入信息;(2)另一種硬性注意力可以通過在注意力分布式上隨機采樣的方式實現。硬性注意力模型的缺點:
硬性注意力的一個缺點是基於最大采樣或隨機采樣的方式來選擇信息。因此最終的損失函數與注意力分布之間的函數關系不可導,因此無法使用在反向
傳播算法進行訓練。為了使用反向傳播算法,一般使用軟性注意力來代替硬性注意力。硬性注意力需要通過強化學習來進行訓練。
- 變種2-鍵值對注意力:即上圖右邊的鍵值對模式,此時Key!=Value,注意力函數變為:

- 變種3-多頭注意力:多頭注意力(multi-head attention)是利用多個查詢Q = [q1, · · · , qM],來平行地計算從輸入信息中選取多個信息。每個注意力關注輸入信息的不同部分,然后再進行拼接:

5、一種強大的Attention機制:為什么自注意力模型(self-Attention model)在長距離序列中如此強大?
- 卷積或循環神經網絡難道不能處理長距離序列嗎?
當使用神經網絡來處理一個變長的向量序列時,我們通常可以使用卷積網絡或循環網絡進行編碼來得到一個相同長度的輸出向量序列,如圖所示:

- 要解決這種短距離依賴的“局部編碼”問題,從而對輸入序列建立長距離依賴關系,有哪些辦法呢?
如果要建立輸入序列之間的長距離依賴關系,可以使用以下兩種方法:一 種方法是增加網絡的層數,通過一個深層網絡來獲取遠距離的信息交互,
另一種方法是使用全連接網絡。 ——《神經網絡與深度學習》

由上圖可以看出,全連接網絡雖然是一種非常直接的建模遠距離依賴的模型, 但是無法處理變長的輸入序列。不同的輸入長度,其連接權重的大小也是不同的。
這時我們就可以利用注意力機制來“動態”地生成不同連接的權重,這就是自注意力模型(self-attention model)。由於自注意力模型的權重是動態生成的,因此可以處理變長的信息序列。
總體來說,為什么自注意力模型(self-Attention model)如此強大:利用注意力機制來“動態”地生成不同連接的權重,從而處理變長的信息序列。
- 自注意力模型(self-Attention model)具體的計算流程是怎樣的呢?
見 Transformer 部分。
6、Transformer(Attention Is All You Need)詳解
* 1) Transformer的整體架構是怎樣的?由哪些部分組成?
* 2) Transformer Encoder 與 Transformer Decoder 有哪些不同?
* 3) Encoder-Decoder attention 與self-attention mechanism有哪些不同?
* 4) multi-head self-attention mechanism具體的計算過程是怎樣的?
* 5) Transformer在GPT和Bert等詞向量預訓練模型中具體是怎么應用的?有什么變化?
擴展,attention機制實現具體步驟case
attention機制實現的基本思路三部曲,參見論文《neural machine translation by jointly learning to align and translate》,首先根據場景定義出attention變量 \(c_i\)
1 梳理出與attention變量的相關參數\(s_{i-1}\)、\(h_j\)
2 使用一層前饋網絡\(\alpha\)處理,該層網絡的輸入即上步梳理的\(s_{i-1}\)、\(h_j\),輸出維度根據需要設置,然后進行歸一化softmax處理,最終the weight \(\alpha_{ij}\) of each annotation \(h_j\) is computed by
3 得到的權重因子 \(\alpha_{ij}\)與第一步梳理得到的關鍵變量\(h_j\)做加權求和得到最終的attention變量 \(c_i\):
tensorflow 典型實現示例:
def _attention(self, query, key, units, name ,reuse):
# we are doing this to perform addition to calculate the score
query = tf.expand_dims(query, 1) # (batch_size, 1, hidden_size)
Q = tf.layers.dense(query, units, activation=tf.nn.relu, name='mul_att_q_' + name, reuse=reuse) # (batch_size, 1, units)
K = tf.layers.dense(key, units, activation=tf.nn.relu, name='mul_att_k_' + name,reuse=reuse) # ((batch_size, seq_length, units)
V = tf.layers.dense(key, units, activation=tf.nn.relu, name='mul_att_v_' + name,reuse=reuse) # (batch_size, seq_length, units)
#l2 正則歸一
Q = tf.nn.l2_normalize(Q, dim=2) # (batch_size, 1, units)
K = tf.nn.l2_normalize(K, dim=2) # ((batch_size, seq_length, units)
V = tf.nn.l2_normalize(V, dim=2) # (batch_size, seq_length, units)
# score shape == (batch_size, seq_length, 1)
# we get 1 at the last axis because we are applying score to self.V
G = Q + K # ((batch_size, seq_length, units)
score = tf.layers.dense(G, 1, activation=tf.nn.tanh, name='mul_att_score_' + name, reuse=reuse) # (batch_size, seq_length, 1)
# attention_weights shape == (batch_size, seq_length, 1)
attention_weights = tf.nn.softmax(score, axis=1)
context_vector = attention_weights * V # (batch_size, seq_length, units)
context_vector = tf.reduce_sum(context_vector, axis=1) # (batch_size, units)
return context_vector, attention_weights