1. 程式人生 > >[閱讀筆記]Attention Is All You Need - Transformer結構

[閱讀筆記]Attention Is All You Need - Transformer結構

例如 position 頻率 product 結構圖 上一個 預測 獲得 line

Transformer

本文介紹了Transformer結構, 是一種encoder-decoder, 用來處理序列問題, 常用在NLP相關問題中. 與傳統的專門處理序列問題的encoder-decoder相比, 有以下的特點:

  • 結構完全不依賴於CNN和RNN
  • 完全依賴於self-attention機制, 是一種堆疊的self-attention
  • 使用全連接層
  • 逐點point-wise計算的

整個Transformer的結構圖如下所示:

技術分享圖片

Encoder and Decoder Stacks

如上所說, Transformer是基於stacked self-attention的, stack

方式具體為:

Encoder

Encoder是由\(N=6\)個獨立的層堆疊而成的, 每層有兩個子層:

  • 第一個層為multi-head self-attention結構
  • 第二層為simple, position-wise fully connected feed-forward network, 即基於位置的簡單全連接反饋網絡

在每個子層又引入了residual connection, 具體的做法為每個子層的輸入與輸出相加, 這就要求每個子層的輸入與輸出的維度是完全相等的. 然後再使用layer normalization. 因此每個子層的最終輸出為:

\[LayerNorm(x + Sublayer(x))\]

此外, 論文中限定了Embeding層的輸出和兩個子層的輸入輸出的維度都是\(d_{model}=512\).

Decoder

Decoder也是由\(N=6\)個獨立的層堆疊而成的, 除了與Encoder層中的兩個完全相同的子層外, 在兩層之間又加入了一個multi-head attention, 這裏是對Encoder的輸出做attention處理.

與Encoder相同, 每個子層也引入了residual connection, 並且相加之後使用layer normalization得到每個子層最後的輸出.

此外, 為了防止序列中元素的位置主導輸出結果, 對Decoder層的multi-head self-attention

層增加了mask操作, 並且結合對output embedding結果進行右移一位的操作, 保證了每個位置\(i\)的輸出, 只會依賴於\(i\)位之前(不包括\(i\)位, 因為右移一位和mask).

Attention

論文中將常用的Attention結構從新的一種角度進行了描述:

Attention作為一種函數, 接受的輸入為:

  • 一個query
  • 一組key-value pairs

即包含三部分, query, keysvalues. 三者都是向量.

輸出就是對組中所有values的加權之和, 其中的權值是使用compatibility function(如內積), 對組內的每一個keysquery計算得到的.

例如, 對於常見的self-attention來說, 這裏值的就是對於序列中的某一個元素對應的向量, 求得經過self-attention之後對應的向量. query指的是這個元素對應的向量(如NLP任務中句子序列中某一個單詞對應的embedding向量), key-value pairs就是這個序列的所有元素, 其中的每個元素對應的key和value是完全相同的向量, 對於要比較的那個元素, 與query也是完全相同的. 然後使用當前向量和所有向量做內積得到權值, 最後的數據就是這個權值和對應向量的加權和.

論文中使用了兩種Attention方法, 分別為Scaled Dot-Product AttentionMulti-Head Attention
Instead
.

技術分享圖片

Scaled Dot-Product Attention

我們假設querykey這兩個用來比較的向量, 長度都為\(d_k\); value向量的長度為\(d_v\). 對query和所有keys進行點積得到值, 再對這裏得到的每個點積結果除以\(\sqrt{d_k}\), 完成scale, 最後應用一個softmax function獲得每個value對應的權值, 加權求得最後的輸出向量.

這是對於一個query的情況. 實際中是直接對一個序列對應的所有querys直接進行計算, 將所有querys拼接成一個大的\(Q\)矩陣, 對應的keysvalues也拼接成\(K\)\(V\)矩陣, 則Scaled Dot-Product Attention對應的計算公式為:

\[\text{Attention}(Q,K,V)=\text{softmax}(\frac{QK^T}{\sqrt{d_k}})V\]

需要註意的點是: \(d_k\)較大時, 向量之間的點積結果可能就會非常大, 這回造成softmax函數陷入到梯度很小的區域. 為了應對這種情況, 適應了縮放因子\(\sqrt{d_k}\), 將點積結果盡量縮小到梯度敏感的區域內.

Multi-Head Attention

之前的方法都是對\(d_{model}\)維度的querys, keysvalues直接使用一個Attention函數, 得到結果, 在Multi-Head Attention方法中, 我們如下操作:

  • querys, keysvalues都分別進行\(h\)次的線性映射(類似於SVM中的線性核), 得到\(h\)組維度為分別為\(d_k\), \(d_k\), \(d_v\)的三種向量.

    需要註意的是, 這\(h\)次映射都是不同的映射, 每次線性映射使用的參數是不相同的, 而且這個映射是可學習的, 相當於得到了\(h\)個不同空間(雖然這些空間的維數是相等的)中的表征.

  • 然後並行的對這\(h\)組維度為分別為\(d_k\), \(d_k\), \(d_v\)querys, keysvalues向量執行Attention函數, 每組都產生一個\(d_v\)維的輸出結果.
  • 最後將這\(h\)個維度為\(d_k\)向量拼接起來.
  • 通過線性轉換還原成\(d_{model}\)維度的向量.

公式表示為:

\[\text{MultiHead}(Q,K,V)=\text{Concat}(\text{head}_1, \cdots, \text{head}_h)W^O\]

其中:

\[\text{head}_i=\text{Attention}(QW_i^Q,KW_i^K,VW_i^V)\]

\(W_i^Q \in \mathbb{R}^{d_{model} \times d_k}\), \(W_i^K \in \mathbb{R}^{d_{model} \times d_k}\), \(W_i^V \in \mathbb{R}^{d_{model} \times d_v}\), 以及\(W_i^O \in \mathbb{R}^{hd_v \times d_{model}}\)都是可學習的線性映射參數. 在論文中超參數的選擇為\(h=8\), 又由於\(d_{model}=512\), 因此\(d_k=d_v=d_{model}/h=64\).

因為中間計算的降維, 總體計算的消耗與直接使用Attention函數的消耗相近.


Transformer模型中Attention使用的特殊點

對於Multi-Head Attention, 在Transformer模型中有三個不同點:

  • encoder-decoder attention層中, 即Encoder和Decoder兩者之間的Attention中(對應於Decoder結構中的中間子層部分), queries來自於Decoder結構中上一個子層的輸出. 這保證了對於Decoder中的每一個位置, 都能捕獲input sequence各個位置的信息.

  • Encoder中對應的是self-attention, 對應一個位置上的query, key, value是完全相同的一個向量. 每個位置的輸出結果, 都會參考輸入的所有位置.
  • 相似的, Decoder中第一個子層也是self-attention. 因此對於某個位置的元素, 會獲取序列中所有序列的信息. 但為了防止leftward information flow(左側信息泄露), 即防止出現自回歸屬性, 我們對這種Scaled Dot-Product Attention通過mask進行了限制, 屏蔽從第一個元素到當前元素(包含), 然後再進行Attention操作.

Position-wise Feed-Forward Networks

Encoder和Decoder都含有一個fully connected feed-forward network, 特殊的是, 這個網絡分別對每個位置的attention層的輸出向量單獨地進行作用. 整個過程包含了兩次線性變換以及中間夾雜的一次ReLU激活:

\[FFN(x) = \max(0, xW_1 + b_1)W_2 + b_2\]

對於不同位置的線性變換是完全一樣的, 即使用相同的參數.

這一層的輸入輸出都是\(d_{model}=512\), 中間隱層的維度為\(d_{ff}=2048\).

Embeddings and Softmax

使用已經訓練好的embeddings將input token和output token轉換成\(d_{model}\)維度的向量.

在最後Decoder的輸出時, 將Decoder的輸出通過一層線性變換層和一個softmax層, 轉換成預測下一個token的概率向量. 這兩個層中的參數也是提前訓練好的.

在模型中, 兩個embedding layers以及最後的softmax之前的線性變換, 這三者共享使用相同的矩陣權值.

對於embedding層, 裏面的權值需要乘以\(\sqrt{d_{model}}\)之後再使用.

Positional Encoding

因為模型完全沒有使用循環(RNN)和卷積(CNN), 而又想使用序列中的順序信息, 就必須加入一些關於token相對位置絕對位置的信息. 因此我們加入Positional Encoding, 作為Encoder和Decoder的輸入. 需要註意的是Positional Encoding產生的向量的維度為\(d_{model}\), 與原本的embedding向量維度相同, 從而兩者可以被相加使用.

對位置進行embedding的方法很多, 有訓練方法和指定方法, 本文中, 采用**頻率不同的\(\sin\)\(\cos\)函數:

\[PE_{pos,2i} = \sin(pos/10000^{2i/d_model})\]

\[PE_{pos,2i+i} = \cos(pos/10000^{2i/d_model})\]

其中\(pos\)代表位置, \(i\)代表第\(i\)維. 每個維度對應於不同頻率不同的正弦函數. 使用這種方法, 我們認為能夠反應相對位置中包含的信息, 這是因為: 對於一個固定的偏移量\(k\), \(PE_{pos+k}\)能表示成\(PE_{pos}\)線性函數.

Why Self-Attention

之所以使用Self-Attention而沒有使用循環或卷積的結構, 主要出於以下三點的考慮:

  • 每層的計算復雜度
  • 計算可以並行的程度
  • 對於序列問題, 長序列是一個難點. Self-Attention方法對於長短序列都有較好的表現. 這是由於我們認為在模型中, 前向後向傳播的路徑越短, 就更容易學習到其中的關系. 對於循環和卷積, 距離當前較遠的位置, 在傳播過程中都要經過較長的距離. 但對於Self-Attention結構, 無論兩個元素在序列中的相對距離如何, 傳播的距離總是相等的.

參考資料

  • Attention Is All You Need
  • Kyubyong/transformer

[閱讀筆記]Attention Is All You Need - Transformer結構