搞懂Transformer

文爲李弘毅老師【Transformer】的課程筆記,課程視頻youtube地址,點這裏👈(需翻牆)。

下文中用到的圖片均來自於李宏毅老師的PPT,若有侵權,必定刪除。

1 內容簡述

拋開Transformer的內部結構,Transformer其實就是一個seq2seq的模型,其中用到了大量的self-attention layer。本文會試圖講明白什麼是self-attention layer。

2 seq2seq的常用模塊

之前使用最廣泛的seq2seq的模塊就是RNN。RNN可以分爲單向的和雙向的。如果是單向的RNN,輸出中的每個time step會有一些信息丟失,比如單向的RNN在下圖中產生b3b^3的時候就只考慮了[a1,a2,a3][a^1, a^2, a^3]。而雙向的RNN輸出的每個time step都考慮了輸入的所有信息,比如雙向的RNN在下圖中產生b3b^3的時候就考慮了[a1,a2,a3][a^1, a^2, a^3][a3,a4][a^3, a^4]

但是RNN有一個不好的地方就是它的計算很難並行化,比如我要算b4b^4的時候,就要等前幾個結果都出來了,才能算。爲了解決這個問題,就有人提出了CNN來替換RNN。

1-D CNN的模塊介紹可以參見這裏。雖然CNN的計算可以並行處理,但是,CNN的kernel_size一般會比較小,輸出的某個time step想要考慮到全局的信息,就要把CNN疊很多層。

然後本文的重點就由此引出了,self-attention可以同時解決這兩個問題,也就是既可以讓每個time step的輸出考慮了全局的輸入,又可以並行計算。
t1

左圖爲RNN,右圖爲CNN

3 Self-attention

self-attention最早出自google的這篇Attention Is All You Need,這篇文章比較難讀懂,但它本身並不是那麼神祕,一個非常直觀的理解就是,self-attention是一個可以替代RNN的東西。下面就來剖析一下這個self-attention。我們的目的是輸入一個序列aa的到一個序列bb
t0

假設我們的輸入是xx,首先要對xx進行一次embedding,讓它變到我們需要的維度,我們記這個embedding的結果爲aa

a=Wxa=Wx

然後,我們要讓這個aa再分別乘以三個矩陣,self-attention中最爲重要的三個東西query, key和value。

q:query(to match others)q=Wqak:key(to be matched)k=Wkav:value(information to be extracted)v=Wva q: query (to\ match\ others)\\ q = W^qa\\ k: key (to\ be\ matched)\\ k = W^ka\\ v: value(information\ to\ be\ extracted)\\ v = W^va\\

然後,我們會把每一個q去對k做attention,所謂的attention就是塞兩個向量進去,然後吐出來一個表示兩個向量相關性的數值α\alpha。attention的方法有很多種,在Attention Is All You Need中,所使用的叫做scaled dot-product attention。

α1,i=q1ki/d \alpha_{1, i} = q^1 \cdot k^i / \sqrt{d}

爲什麼要除以這個d\sqrt{d}呢?因爲當qqkk的維度很大時,它們內積的variance就會很大,所以要除以一個d\sqrt{d}來scale一下。

最後還要對α\alpha做一個softmax,得到α^\hat{\alpha}。大致的流程如下圖所示。
t2
這個α^\hat{\alpha}其實就是每一個time step的value的重要性。用這個α^\hat{\alpha}對每個time step的value進行一個加權,就得到了self-attention的結果bb。比如b1b^1就可以通過下式計算得到
b1=iα^1,ivi b^1=\sum_i{\hat{\alpha}_{1, i}v^i}

這樣得到的bb是考慮了所有的輸入的,而且無視輸入之間的遠近,完全通過學習attention來獲取需要的value,其示意圖如下所示。
t3
更重要的是,以上的過程都是可以並行計算的。因爲每個time step的計算都是獨立的,我們可以把它們concat到一個大的矩陣裏,然後一起計算,示意圖如下所示。
t4

4 Multi-head Self-attention

self-attention是可以做成multi-head的,所謂multi-head,其實就是把qqkkvv分裂成多個,然後每個分別在自己的head內做self-attention,然後把結果再concat起來,如果得到的結果維度不是我們想要的,那麼再乘以一個矩陣就可以了。

做成Multi-head的目的是讓不同的head去學到不同的東西,比如有的head學局部的信息,有的head學全局的信息。
t5

5 Positional Encoding

然而,從之前的整個流程可以看出來,self-attention是不會去關心輸入的time step順序的,任何一個輸出,time step是11還是TT,對self-attention來說都是一樣的,李老師很形象地稱之爲“天涯若比鄰”。

爲了增加位置的信息,就會給aa加上一個神奇的人爲預先設定好的向量ee,有了這個ee之後,模型就可以知道輸入的位置信息了。
t6
那爲什麼是e+ae+a,這樣不是把aa的信息給攪亂了嗎?會什麼不是直接concat上去變成[e,a][e, a]呢?我們不妨來試試concat的話會如何,不過既然是位置信息,我們需要concat到xx上。假設我們有一個和位置有關的向量pppp是一個one-hot的向量,表示當前的xix^i是在第ii個tme step上。那麼在做embedding的時候,我們也需要把embedding的矩陣WW變大,而WW又可以拆成WiW^iWpW^p。根據矩陣的計算方法,其結果就相當於給aa加了一個值,這個值也就是之前提到的ee的。可見,e+ae+a和對xx進行concat是等效的。
t7
這裏有一個比較神奇的地方,就是這個ee是個什麼東西,爲啥這麼靈?換成其他的靈不靈?這就不得而知了。

6 Transformer

從上文中可以看出,self-attention是可以替代RNN的,實際操作中,也就是把RNN替換成self-attention就結束了。

接下來讓我們來看看下面這幅經典的Transformer的圖,現在看起來應該是親切了不少。這個圖的左半個結構是Encoder,右半個結構是Decoder。把圖中的Multi-Head Attention想象成RNN就可以了。Emmm…感覺也不需要額外的說明了。值得注意的是,這裏的Masked Multi-Head Attention就是指是對已經產生的序列做attention,比如我們翻譯的時候,是塞一個起始符進去,然後一個字一個字生成,直到遇到終止符。
t8

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章