感謝知乎大佬劉岩https://zhuanlan.zhihu.com/p/48508221,我的總結將主要來自於大佬文章。
英文版博客:http://jalammar.github.io/illustrated-transformer/
論文:《Attention is all you need》
為什么要使用attention,這也是本文中所以解決的問題:
1.時間片 t 的計算依賴於 t-1 時刻的計算結果,這樣限制了模型的並行能力;
2.雖然LSTM在一定程度上可以緩解了長期的依賴問題,但是對於特別長期的依賴現象LSTM任然是無能為力,也可以說在encoder和decoder之間的語義向量content無法保存太過多的信息。
Transformer的提出解決了上面兩個問題,首先它使用了Attention機制,將序列中的任意兩個位置之間的距離是縮小為一個常量;其次它不是類似RNN的順序結構,因此具有更好的並行性,符合現有的GPU框架。
在論文中,Transformer拋棄了傳統的CNN和RNN,整個網絡使用了Attention機制組成。 更准確的講,Transformer由且僅由self-Attenion和Feed Forward Neural Network組成。實驗中的編碼器和解碼器各由六層transform堆疊而成(解碼器與編碼器稍有不同),並在實驗中取得了BLEU值的新高。
1.Transform詳解
我們先看看總體的結構(我們以論文中的機器翻譯為例)

Transformer由Encoder-Decoder組成


編碼器和解碼器都是由六個塊組成,編碼器的輸出作為解碼器的輸入


在每個encoder中有self-attention和前饋神經網絡組成,數據先會經過self-attention模塊,得到一個加權之后的特征向量Z,這個Z就是Attention(Q,K,V):

得到的Z之后,他會被encoder送到前饋神經網絡。其中這個前饋神經網絡有兩層,第一層激活函數為Relu,第二層是一個線性激活函數,表示為:

Encoder的結構如下:


Decoder的結構如下圖5所示,與encoder的不同之處在於多了個Encoder-decoder Attention,兩個attention分別用於計算輸入和輸出的權值:
-
Self-Attention:當前翻譯和已經翻譯的前文之間的關系;
-
Encoder-Decnoder Attention:當前翻譯和編碼的特征向量之間的關系。
Decoder結構如下:

1.2輸入編碼
上面講解的是主要的網絡框架,現在我們介紹他的數據輸入。如下圖,一般的我們使用嵌入算法把每個輸入字轉化成向量。


嵌入只是發生在最下面一層的block中。所有的block詞嵌入的維度是dmodel = 512,但是在其他層的block(有六個,說其他5個),輸入直接是上個block的輸出。
我們嵌入單詞到輸入序列,每個單詞都會‘流經’每個編碼器的兩層。


Transform的關鍵屬性,每個位置的單詞在編碼器中只經過自己的路徑。self-attention中這些路徑存在依賴。但是前饋層沒有這些依賴,因此各種路徑在流過前饋層時並行執行。
1.21 編碼過程
簡單過程:一個向量序列作為encoder的輸入,將這些向量傳到 self-attention 來處理,在進入FFNN, 然后再將輸出向上傳到下一個Encoder。


1.3 Self-Attention
self-attention 是Transform最核心的內容,下面就做出詳細講解。Attention其核心內容也就是:輸入向量的每一個單詞學習一個權重。例如:
The animal didn't cross the street because it was too tired
加權后我們可以得到類似於下面的加權情況:


當我們在編碼器#5(堆棧中的頂部編碼器)中對“it”進行編碼時,注
意力機制的一部分集中在“animal”上,並將其表示形式的一部分融入到“it”的編碼中
1.31 self-attention細節
在self-attention中,每個單詞都是有3個不同的向量,它們分別是Query向量(
),Key向量(
)和Value向量(
),維度均是64。這三個不同的矩陣是由嵌入向量 X(512維)乘以三個不同的權值矩陣Wq,Wk,Wv(三矩陣尺寸相同,都是512 x 64)得到。


即:x1乘以WQ權重矩陣得到q1,即與該單詞相關的“query”向量。我們最終為
輸入語 句中的每個單詞創建一個“query”、一個“key”和一個“value”投影。
什么是Query,Key,Value呢?在Attention中扮演着什么角色呢?我們再看下Attention的計算方法,整個過程可以分為7步:
1.將單詞轉化為嵌入向量(Embedding)
2.根據嵌入向量得到三個輸入向量 q,k,v
3.為每個向量計算一個score:
(這點在論文也是有體現:如:(1x64) X (64x1)結果為一個數)
4.為了梯度的穩定,Transformer使用了score歸一化,即除以
;
5.對score施以softmax激活函數;
6.softmax點乘Value值
,得到加權的每個輸入向量的評分
;(2-6就是再講Scaled Dot-Product Attention)
7.相加之后得到最終的輸出結果
:
。
上面的步驟表示為下圖所示:


實際上計算過程都是基於矩陣來計算的,那么論文中的Q,K,V計算如下所示:


圖10總結為圖12所示的矩陣形式:

1.32殘差
在self-attention需要強調的最后一點是其采用了殘差網絡 [5]中的short-cut結構,目的當然是解決深度學習中的退化問題,得到的最終結果如圖13。


如果我們把向量和self-attention的相關圖層可視化如下圖:


這也是適用於Encoder的子層,Transformer是由兩個堆疊的encoder和decoder組成,可視化結果如下圖:


1.4 Multi-Head Attention
Multi-Head Attention相當於
個不同的self-attention的集成(ensemble),在這里我們以
舉例說明。Multi-Head Attention的輸出分成3步:
1.將數據 X 分別輸入到圖13所示的8個self-attention中,得到8個加權后的特征矩陣
2.將8個
按列拼成一個大的特征矩陣
3.特征矩陣經過一層全連接后得到輸出 Z。(因為得到的是幾個矩陣Zi,經過FFNN變成Z,其中Wo指的是FFNN中的權重)
整個過程如下:


同self-attention一樣,multi-head attention也加入了short-cut機制。
1.5 encoder-decoder Attention
在解碼器中,Transformer block比編碼器中多了個encoder-cecoder attention。在encoder-decoder attention中,
來之與解碼器的上一個輸出,
和
則來自於與編碼器的輸出。其計算方式完全和圖10的過程相同。
由於在機器翻譯中,解碼過程是一個順序操作的過程,也就是當解碼第
個特征向量時,我們只能看到第
及其之前的解碼結果,論文中把這種情況下的multi-head attention叫做masked multi-head attention。
1.6 損失層
解碼器解碼之后,解碼的特征向量經過一層激活函數為softmax的全連接層之后得到反映每個單詞概率的輸出向量。此時我們便可以通過CTC等損失函數訓練模型了。
而一個完整可訓練的網絡結構便是encoder和decoder的堆疊(各
個,
),我們可以得到圖15中的完整的Transformer的結構(即論文中的圖1):

2.位置編碼
我們的Transformer模型沒有捕捉順序序列的能力,也就是說無論句子怎么打亂,得到的結果都是類似的。為了解決這個問題,論文中提出了位置編碼的概念。
位置編碼常見模式有兩種:a:根據數據學習 b:自己設計編碼規則。在這里作者使用了第二種方式,通常位置編碼的長度為 dmodel 的特征向量,這樣便於和詞向量進行單位相加(聯想一下嵌入向量維度)。


論文給出下列公式:

上述公式中,pos表示單詞的位置,i表示單詞的維度。位置編碼的實現參見:https://link.zhihu.com/?target=https%3A//github.com/tensorflow/tensor2tensor/blob/23bd23b9830059fbc349381b70d9429b5c40a139/tensor2tensor/layers/common_attention.py
作者這么設計的原因是考慮到在NLP任務重,除了單詞的絕對位置,單詞的相對位置也非常重要。根據公式
以及
,這表明位置
的位置向量可以表示為位置
的特征向量的線性變化,這為模型捕捉單詞之間的相對位置關系提供了非常大的便利。
3.總結
使用了multi-headed self-attention 取代了encoder-decoder中的循環層。(論文)在機器翻譯過程中取得了很好的效果,訓練和評估代碼的模型可以見:
