1 概述git
在介紹Transformer模型以前,先來回顧Encoder-Decoder中的Attention。其實質上就是Encoder中隱層輸出的加權和,公式以下:github
將Attention機制從Encoder-Decoder框架中抽出,進一步抽象化,其本質上以下圖 (圖片來源:張俊林博客):網絡
以機器翻譯爲例,咱們能夠將圖中的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 $spa
其中 $L_x$ 表明source中句子的長度。.net
再詳細化將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的,能夠認爲下面公式中
$ Attention(Query, source) = \sum_{i=1}^{L_x} Similarity(Query, Key_i) * Value_i $
上面公式中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}$。經過上面公式計算出每個位置的位置向量。位置向量是能夠被訓練的值,並且用上面的公式計算的位置向量並非絕對的,你也能夠用其餘的方法求位置向量。
參考文獻:
《Attention is All You Need》淺讀(簡介+代碼)