1 概述
在介紹Transformer模型之前,先來回顧Encoder-Decoder中的Attention。其實質上就是Encoder中隐層輸出的權重和,公式如下:

以機器翻譯為例,我們可以将圖中的Key,Value看作是source中的資料,這裡的Key和Value是對應的。将圖中的Query看作是target中的資料。計算Attention的整個流程大緻如下:
1)計算Query和source中各個Key的相似性,得到每個Key對應的Value的權重系數。在這裡我認為Key的值是source的的隐層輸出,Key是等于Value的,Query是target的word embedding(這種想法保留)。
2)利用計算出來的權重系數對各個Value的值權重求和,就得到了我們的Attention的結果。
具體的公式如下:
$ Attention(Query, source) = \sum_{i=1}^{L_x} Similarity(Query, Key_i) * Value_i $
其中 $L_x$ 代表source中句子的長度。
再詳細化将Attention的計算分為三個階段,如下圖(圖檔來源:張俊林部落格)
1)計算相似性,在這裡計算相似性的方法有多種:點積,Cosine相似性,MLP網絡等。較常用的是點積和MLP網絡。
2)将計算出的相似性用softmax歸一化處理。
3)計算Value值的權重和。
在這裡的Attention本質上是一種對齊的方法,也可以将Attention看作是一種軟尋址的方法,以權重值将target中的詞和source中的詞對齊。相對應軟尋址(soft-Attention),還有一種hard-Attention,顧名思義就是直接用權值最大的Value值作為Attention。
2 Transformer模型
Transformer模型來源于谷歌2017年的一篇文章(Attention is all you need)。在現有的Encoder-Decoder架構中,都是基于CNN或者RNN來實作的。而Transformer模型彙中抛棄了CNN和RNN,隻使用了Attention來實作。是以Transformer是一個完全基于注意力機制的Encoder-Decoder模型。在Transformer模型中引入了self-Attention這一概念,Transformer的整個架構就是疊層的self-Attention和全連接配接層。具體的結構如下:
上面結構中的左半部分是Encoder,右半部分是Decoder。在詳細介紹結構之前,先來看幾個概念詞:
self-Attention
在一般的Attention中,source和target中的内容是不一樣的,也就是Query是不屬于Key的。而self-Attention是發生在單個句子内的,它的Query是屬于Key的,可以認為下面公式中
上面公式中Query = Key = Value。也就是說在序列内部做Attention,尋找序列内部的聯系。
那麼為什麼要用self-Attention呢?它有什麼優點:
1) 可以并行化處理,在計算self-Attention是不依賴于其他結果的。
2)計算複雜度低,self-Attention的計算複雜度是$n^2 d$,而RNN是$n d^2$,在這裡$n$是指序列的長度,$d$是指詞向量的次元,一般來說$d$的值是大于$n$的。
3)self-Attention可以很好的捕獲全局資訊,無論詞的位置在哪,詞之間的距離都是1,因為計算詞之間的關系時是不依賴于其他詞的。在大量的文獻中表明,self-Attention的長距離資訊捕捉能力和RNN相當,遠遠超過CNN(CNN主要是捕捉局部資訊,當然可以通過增加深度來增大感受野,但實驗表明即使感受野能涵蓋整個句子,也無法較好的捕捉長距離的資訊)。
Scaled dot-product attention
Scaled dot-product attention 的公式如下:
在上面公式中Q和K中的向量次元都是 $d_k$ ,V的向量次元是 $d_v$ ,實際上在self-Attention中,$d_k = d_v = d_wordEmbedding / numHeads$,為了友善将Attention的計算轉化為矩陣運算,論文在這裡采用了點積的形式求相似度。常見的計算方法除了點積還有MLP網絡,但是點積能轉化為矩陣運算,計算速度更快。然而點積的方法面臨一個問題,當 $d_k$ 太大時,點積計算得到的内積會太大,這樣會導緻softmax的結果非0即1,是以引入了$\sqrt{d_k}$ 來對内積進行縮放。
Multi-Head Attention
這是本文中首次提出的概念,這裡的用法有點玄妙,但了解起來也很簡單,其表達式如下:
表達式的計算如下:
1)假設現在頭數為$h$,首先按照每一時序上的向量長度(如果是詞向量的形式輸入,可以了解為embedding size的值)等分成$h$份。
2)然後将上面等分後的$h$份資料分别通過不同的權重($W_i^Q, W_i^K, W_i^V$)映射得到新的Q, K, W的值。
3)将上述映射後的$h$份資料計算相應的Attention的值。
4)按照之前分割的形式重新拼接起來,再映射到原始的向量次元。就得到Multi-Head Attention的值。
在這裡每一次映射時的矩陣都不相同,是以映射之後再計算也就會得到不一樣的結果。其實認真來看Multi-Head Attention的機制有點類似與卷積中的多個卷積核,在卷積網絡中,我們認為不同的卷積核會捕獲不同的局部資訊,在這裡也是一樣,我們認為Multi-Head Attention主要有兩個作用:
1)增加了模型捕獲不同位置資訊的能力,如果你直接用映射前的Q, K, V計算,隻能得到一個固定的權重機率分布,而這個機率分布會重點關注一個位置或個幾個位置的資訊,但是基于Multi-Head Attention的話,可以和更多的位置上的詞關聯起來。
2)因為在進行映射時不共享權值,是以映射後的子空間是不同的,認為不同的子空間涵蓋的資訊是不一樣的,這樣最後拼接的向量涵蓋的資訊會更廣。
有實驗證明,增加Mult-Head Attention的頭數,是可以提高模型的長距離資訊捕捉能力的。
Feed Forward 層
Feed Forward 層采用了全連接配接層加Relu函數實作,用公式可以表示為:
$ FFN(x) = Relu(xW_1 + b_1) W_2 + b_2$
其實關于在這裡并不一定要用全連接配接層,也可以使用卷積層來實作。
Dropout 層
我們還可以在每個subLayers後面加上一個10%的Dropout層,則subLayers的輸出可以寫成:
$ LayerNorm(x + Dropout(Sublayer(x)))$
介紹到這裡可以來看下我們整體的模型結構了。
Encoder
Encoder 是有N=6個layers層組成的,每一層包含了兩個sub-layers。第一個sub-layer就是多頭注意力層(multi-head attention layer),第二個就是一個簡單的全連接配接層。在每個sub-layer層之間都用了殘差連接配接,根據resNet,我們知道殘差連接配接實際上是:
$H(x) = F(x) + x$
是以每個sub-layer的輸出都是:
$ LayerNorm(x + Sublayer(x)) $
在這裡LayerNorm中每個樣本都有不同的均值和方差,不像BatchNormalization是整個batch共享均值和方差。
注意:每個Layer的輸入和輸出的次元是一緻的。
Decoder
Decoder 同樣是N=6個layers層組成的,但是這裡的layer和Encoder不一樣,這裡的layer包含了三個sub-layers。第一個sub-layer就是多頭自注意力層,也是計算輸入的self-Attention,但是因為這是一個生成過程,是以在時刻 $t$ ,大于 $t$ 的時刻都沒有結果,隻有小于 $t$ 的時刻有結果,是以需要做masking,masking的作用就是防止在訓練的時候使用未來的輸出的單詞。第二個sub-layer是對encoder的輸入進行attention計算的,從這裡可以看出Decoder的每一層都會對Encoder的輸出做Multi Attention(這裡的Attention就是普通的Attention,非self-Attention)。第三個sub-layer是全連接配接層。
從上面的分析來看Attention在模型中的應用有三個方面:
1)Encoder-Decoder Attention
在這裡就和普通的Attention一樣運用,query來自Decoder,key和value來自Encoder。
2)Encoder Attention
這裡是self-Attention,在這裡query,key,value都是來自于同一個地方
3)Decoder Attention
這裡也是self-Attention,在這裡的query,key,value也都是來自于同一個地方。但是在這裡會引入masking。
Embedding and Softmax
和其他的序列傳導模型一樣,在這裡的source,target的輸入都會使用word embedding。也會用softmax來預測token
Positional Embedding
Positional Embedding 是一個很重要的東西,我們回過頭來看上面的self-Attention,我們發現self-Attention能提取詞與詞之間的依賴關系,但是卻不能提取詞的絕對位置或者相對位置關系。如果将K,V的順序打亂,獲得的Attention的結果還是一樣的。在NLP任務中詞之間的順序是很重要的,是以文章運用了Positional Embedding來保留詞的資訊,将每個位置編号,然後每個編号對應這一向量,最後将該向量和詞向量相加,這樣就給每個詞引入了一定的位置資訊。
在論文中使用不同頻率的正弦和餘弦函數來生成位置向量,表達式如下:
位置向量的次元和word embedding的一緻。上面公式中 $pos$ 表示序列中詞的位置,$i$ 表示位置向量中每個值的次元,也就是說$ i < d_{model}$。通過上面公式計算出每一個位置的位置向量。位置向量是可以被訓練的值,而且用上面的公式計算的位置向量并不是絕對的,你也可以用其他的方法求位置向量。
參考文獻:
深度學習中的注意力機制(2017版)
《Attention is All You Need》淺讀(簡介+代碼)