今天要講的重點是 Transformer ,現代許多知名的模型都是奠基於他之上,包括 BERT 與 GPT-2 等等。這部分由於李宏毅教授實在講得太好了,這篇文章的形式我把它調整成課程的重點整理與筆記。
先來看看 Transformer 模型的全圖。看起來很可怕,別擔心,讓我們一一來了解他用到的機制與架構。
圖片出處:Attention is all you need
Self-Attention
首先,我們再度來談談 RNN 的缺點。
回顧一下 RNN ,他就是輸入一個序列,得到另一個序列。之前提到他難以記得久遠之前資訊的問題,可以用注意力機制改善,但他仍有一個缺點,處理這個序列時必須一個詞一個詞處理,無法丟到 GPU 平行化運算,導致運算時間可能會拉得很長。
有人就提出以 CNN 取代 RNN 的做法,CNN 非常適合以平行化加速。但他需要疊多層的才能涵蓋句子的所有資訊,而且後來的表現也不比 RNN 佳,所以我們這邊就不多做討論。如果對 CNN 有興趣的朋友可以參考連結的課程哦。
圖片來源:李宏毅教授 Transformer 課程
所以,後來有人提出另一個方式來平行化 RNN 的運算 - 自注意力機制(Self-Attention),這個機制有兩大優點,一是他可以平行化運算,二是每一個輸出的向量,都看過整個輸入的序列。更重要的是:
我們可以把所有 RNN 架構做得到的事,都換成以 Self-Attention 來達成。
我們也不再需要 RNN 和 Attention 機制搭配,只用 Attention 就可以達成一樣的任務了。這也是 Google 發表 Transformer 論文時所下的標題 - Attention is all you need
圖片來源:李宏毅教授 Transformer 課程
自注意力機制有三大主角: Query, Key, Value ,分別表示用來匹配的值、被匹配的值、以及抽取出來的資訊。
接著詳細來介紹自注意力機制的運算細節, Input x
經由矩陣 W
轉換成 Embedding a
,乘以三個不同的矩陣得到 Query q
, Key k
, Value v
,也就是說每個輸入的詞,都會同時被轉換成 q
, k
, v
三種向量。
圖片來源:李宏毅教授 Transformer 課程
接著,我們將每個 Query q
對每個 Key k
做 Attention,也就是求兩者的內積,並將內積的結果除以 q
, k
兩向量的維度開根號,以避免維度越大,內積的變異數就越大(也就是做 normalization 啦)。以上的做法稱為 Scaled Dot-Product Attention ,得到的結果 α 就是之前提到的 Attention Score。同樣的,我們會把這些 α 經過 Softmax 轉換成機率分佈,得到 Attention Distribution,
利用 Attention Distribution 對所有的 Value u
相乘後相加,(是一個加權的概念),就可以得到輸出的序列了。 q1
對所有 k
, v
運算後的結果可以得到輸出的第一個向量 b1
, q2
對所有 k
, v
運算後的結果是 b2
依此類推。
圖片來源:李宏毅教授 Transformer 課程
Self-Attention 看似複雜,其實可以簡化成一堆矩陣運算,而矩陣運算非常適合以 GPU 平行運算加速。到這邊,只要記得他可以平行化運算,以及每一個輸出的向量,都看過整個輸入的序列這兩大優點,還有我們可以把所有 RNN 架構做得到的事,都換成以 self-attention 來達成,這樣就夠了。
運算的細節太複雜,聽不下去沒關係,因為後面只會更複雜XD
Multi-Head Attention
接下來是 Transformer 用到的第二個機制 - Multi-Head Attention 。一言以蔽之這個機制的好處:
Multi-Head 中每個 Head 可能會關注不同的部分,有些關注鄰居,有些關注比較長時間的資訊,每個 Head 各司其職。
我舉個簡單的例子來說明:
今天天氣非常好,我想找小明一起去爬山
爬山
這個詞跟我
還有小明
具有某種關係,跟天氣
、好
也有另一種關係,如果只有一種 Attention Distribution,可能無法處理句子中詞與詞各種複雜的關係,而這就是我們希望 Multi-Head 做到的:處理詞與詞之間各種不同關聯的資訊。
接著講講他的細節。我們把 q
, k
, v
各自乘以多個不同的矩陣,轉換到更低維度的向量(如:qi,1
, qi,2
),進行和之前一樣的 Attention 運算。但是 qi,1
只和 ki,1
、kj,1
、vi,1
、vj,1
運算,qi,2
只和 ki,2
、kj,2
、vi,2
、vj,2
運算,也就是說,不同低維度向量空間之間不會互相做 attention 的運算。
接著將 Multi-Head 運算完的結果接起來,變成一個更大的向量,若是想要調整維度,可以(也通常會)再接一層 Linear Layer ,就得到了這一個階段的輸出。
圖片來源:李宏毅教授 Transformer 課程
Positional Encoding
在 Self-Attention Layer 中,輸入序列的順序不重要,天涯的資訊和比鄰的資訊其實是一樣的。
嗯...聽起來不太合理,我們希望模型去考慮序列的順序,因此有了 Positional Encoding。
做法是對於每個位置都有一個特殊的位置向量 ei
,把 ei
加上原本的 Embedding ai
當作新的 Embedding 向量,進行原本的 Self-Attention 運算。
Encoder and Decoder
最後,讓我們把這些機制組合起來,看看完整的 Transformer 吧。Transformer 可以分成兩大部分,左半部是 Encoder ,右半部是 Decoder (下圖是老師舉的例子,把 Transformer 拿來進行翻譯,輸入與輸出分別會像這樣)
圖片來源:李宏毅教授 Transformer 課程
先來看看 Encoder ,輸入的序列進入模型後,先進行一次 Embedding 再加上 Positional Encoding 得到一向量。接著,這個向量會進入一個重複 N 次的區塊,區塊內依序有這些結構:
- Multi-Head Attention: 輸入的序列經過這一層後,經過剛剛講解的運算,得到另一個序列。
- Add & Norm
- Add: 將 Multi-Head Attention 的輸入與輸出相加,得到另一序列
- Norm: 將相加而得的序列進行 Layer Normalization ,也就是將每一筆資料不同維度的數值調整成平均為 0 ,標準差為 1 。
- Feed forward: 這一層相對單純,向量會經過兩層線性轉換,更精確一點來說,是經過兩層 Linear Layer 。
- Add & Norm: 將 Feed Forward 的輸入與輸出相加,進行 Layer Normalization
拆開來看,其實沒有這麼可怕。以上步驟重複 N 次,就是 Encoder 的輸出了。
接著來看看 Decoder ,輸入前一個時間得到的序列 (eg: <BOS>
),同樣進行 Embedding 與 Positional Encoding ,接著進入重複 N 次的區塊,這個區塊比 Encoder 多了一些東西,他的架構是這樣的:
- Masked Multi-Head Attention: 同樣的 Multi-Head Attention 機制,只是多了遮罩 Mask。Masked 的意思是,模型只會關注他已經產生出來的部分,不會不小心關注未來產生的詞,聽起來很合理,不過卻是容易被忽略的一個部分。
- Add & Norm: Masked Multi-Head Attention 的輸入與輸出相加,進行 Layer Normalization
- Multi-Head Attention: 這裡的 Multi-Head Attention 是關注 Encoder 輸出的序列。
- Add & Norm: 一樣相加再做 Normalization
- Feed Forward, Add & Norm: 與 Encoder 相同,線性轉換、相加、 Normalization 。
重複 N 次後,經過 Linear Layer 與 Softmax ,就可以得到我們要的,輸出詞的機率分佈,我們可以依據這個分佈抽樣或是取機率最大的值,來得到輸出的序列。
小結
到這邊, Transformer 的介紹告一段落了,其實他新引入的機制只有 Self-Attention , Multi-Head Attention 與 Positional Encoding ,其他的都是在過往的深度學習中會看到的結構哦。
後來出現的許多強大的模型,都使用了 Transformer 的架構,從 Paper 發表提及的關鍵字來看,他已經變成一個取代 RNN 的架構了。明天會跟大家介紹最近的模型如何透過 Transformer 再創高峰,我們明天見!