Transformer 是 Google 團隊在 17 年 6 月提出的 NLP 經典之作,
由 Ashish Vaswani 等人在 2017 年發表的論文 Attention Is All You Need 中提出。
Transformer 在機器翻譯任務上的表現超過了 RNN,CNN,只用 encoder-decoder 和 attention 機制就能達到很好的效果,最大的優點是可以高效地并行化。
Transformer 是一種基于 encoder-decoder 結構的模型,
在 Encoder 中,
- Input 經過 embedding 后,要做 positional encodings,
- 然后是 Multi-head attention,
- 再經過 position-wise Feed Forward,
- 每個子層之間有殘差連接。
在 Decoder 中,
- 如上圖所示,也有 positional encodings,Multi-head attention 和 FFN,子層之間也要做殘差連接,
- 但比 encoder 多了一個 Masked Multi-head attention,
- 最后要經過 Linear 和 softmax 輸出概率。
下面我們具體看一下其中這幾個概念,這里主要參考 Jay Alammar,他在 The Illustrated Transformer 中給出了很形象的講解。
1. 整體結構
例如我們要進行機器翻譯任務,輸入一種語言,經過 Transformer,會輸出另一種語言。
Transformer 的 encoder 由 6 個編碼器疊加組成,
decoder 也由 6 個解碼器組成,
在結構上都是相同的,但它們不共享權重。
每一個 encoder 都分為兩個子層:
- 先流經 self-attention 層,這一層可以幫助編碼器在編碼某個特定單詞時,也會查看其他單詞
- self-attention 層的輸出再傳遞給一個前饋神經網絡層,在每個位置的前饋網絡都是完全相同的,
每一個 decoder 也具有這兩個層,但還有一個注意力層,用來幫助解碼器關注輸入句子的相關部分
2. Encoder
- Input 經過 embedding 后,要做 positional encodings,
- 然后是 Multi-head attention,
- 再經過 position-wise Feed Forward,
- 每個子層之間有殘差連接。
首先使用嵌入算法將輸入的 word 轉換為 vector,
最下面的 encoder ,它的輸入就是 embedding 向量,
在每個 encoder 內部,
輸入向量經過 self-attention,再經過 feed-forward 層,
每個 encoder 的輸出向量是它正上方 encoder 的輸入,
向量的大小是一個超參數,通常設置為訓練集中最長句子的長度。
在這里,我們開始看到 Transformer 的一個關鍵性質,
即每個位置的單詞在 encoder 中都有自己的路徑,
self-attention 層中的這些路徑之間存在依賴關系,
然而在 feed-forward 層不具有那些依賴關系,
這樣各種路徑在流過 feed-forward 層時可以并行執行。
2.1 positional encodings
Positional Encoding 是一種考慮輸入序列中單詞順序的方法。
encoder 為每個輸入 embedding 添加了一個向量,這些向量符合一種特定模式,可以確定每個單詞的位置,或者序列中不同單詞之間的距離。
例如,input embedding 的維度為4,那么實際的positional encodings如下所示:
在下圖中,是20個單詞的 positional encoding,每行代表一個單詞的位置編碼,即第一行是加在輸入序列中第一個詞嵌入的,每行包含 512 個值, 每個值介于 -1 和 1 之間,用顏色表示出來。
可以看到在中心位置分成了兩半,因為左半部分的值由一個正弦函數生成,右半部分由余弦函數生成,然后將它們連接起來形成了每個位置的編碼向量。
當然這并不是位置編碼的唯一方法,只是這個方法能夠擴展到看不見的序列長度處,例如當我們要翻譯一個句子,這個句子的長度比我們訓練集中的任何一個句子都長時。
2.2 Multi-head attention
2.2.1 先看什么是 Self-Attention
例如我們要翻譯:”The animal didn't cross the street because it was too tired” 這句話
這句話中的“it”是指什么?它指的是 street 還是 animal?
這對人類來說是一個簡單的問題,但對算法來說并不簡單。
而 Self-Attention 讓算法知道這里的 it 指的是 animal
2.2.2 self-attention 的作用
當模型在處理每個單詞時,self-attention 可以幫助模型查看 input 序列中的其他位置,尋找相關的線索,來達到更好的編碼效果。它的作用就是將對其他相關單詞的“understanding”融入我們當前正在處理的單詞中。
例如上圖中,在第5層時,我們就知道 it 大概指的是 animal 了。
2.2.3 self-attention 具體原理
第一步,為編碼器的每個輸入單詞創建三個向量,
即 Query vector, Key vector, Value vector
這些向量通過 embedding 和三個矩陣相乘得到,
請注意,這些新向量的尺寸小于嵌入向量。它們的維數為64,而嵌入和編碼器輸入/輸出向量的維數為512.它們不一定要小,這是一種架構選擇,可以使多頭注意力計算(大多數)不變。
將x1乘以WQ得到Query向量 q1,同理得到Key 向量 和, Value 向量
這三個向量對 attention 的計算有很重要的作用
第二步,是計算一個得分
假設我們要計算一個例子中第一個單詞 “Thinking” 的 self-attention,就需要根據這個單詞,對輸入句子的每個單詞進行評分,這個分數決定了對其他單詞放置多少關注度。
分數的計算方法是,
例如我們正在考慮 Thinking 這個詞,就用它的 q1 去乘以每個位置的 ki
第三步和第四步,是將得分加以處理再傳遞給 softmax
將得分除以 8(因為論文中使用的 key 向量的維數是 64,8 是它的平方根)
這樣可以有更穩定的梯度,
然后傳遞給 softmax,Softmax 就將分數標準化,這樣加起來保證為 1。
這個 softmax 分數決定了每個單詞在該位置bbei表達的程度。
很明顯,這個位置上的單詞將具有最高的softmax分數,但有時候注意與當前單詞相關的另一個單詞是有用的。
第五步,用這個得分乘以每個 value 向量
目的讓我們想要關注單詞的值保持不變,并通過乘以 0.001 這樣小的數字,來淹沒不相關的單詞
第六步,加權求和這些 value 向量
這就是第一個單詞的 self-attention 的輸出
得到的向量接下來要輸入到前饋神經網絡,在實際實現中用矩陣乘法的形式完成
2.2.4 multi-headed 機制
論文中還增加一種稱為 multi-headed 注意力機制,可以提升注意力層的性能
它使得模型可以關注不同位置
雖然在上面的例子中,z1 包含了一點其他位置的編碼,但當前位置的單詞還是占主要作用, 當我們想知道“The animal didn’t cross the street because it was too tired” 中 it 的含義時,這時就需要關注到其他位置
這個機制為注意層提供了多個“表示子空間”。下面我們將具體介紹,
1. 經過 multi-headed , 我們會得到和 heads 數目一樣多的 Query / Key / Value 權重矩陣組
論文中用了8個,那么每個encoder/decoder我們都會得到 8 個集合。
這些集合都是隨機初始化的,經過訓練之后,每個集合會將input embeddings 投影到不同的表示子空間中。
2. 簡單來說,就是定義 8 組權重矩陣,每個單詞會做 8 次上面的 self-attention 的計算
這樣每個單詞會得到 8 個不同的加權求和 z
3. 但在 feed-forward 處只能接收一個矩陣,所以需要將這八個壓縮成一個矩陣
方法就是先將8個z矩陣連接起來,然后乘一個額外的權重矩陣WO
下圖顯示了在例句中,it 的不同的注意力 heads 所關注的位置,一個注意力的焦點主要集中在“animal”上,而另一個注意力集中在“tired”,換句話說,it 是 “animal”和“tired”的一種表現形式。
當然如果選了8個層,將所有注意力 heads 都添加到圖片中,就有點難以解釋了。
2.3 Residuals
這里有一個細節,
即在每個 encoders 和 decoders 里面的 self-attention, ffnn,encoders-decoders attention 層,都有 residual 連接,還有一步 layer-normalization
3. Decoder
下面我們看一下 Decoder 部分
- 如上圖所示,也有 positional encodings,Multi-head attention 和 FFN,子層之間也要做殘差連接,
- 但比 encoder 多了一個 Masked Multi-head attention,
- 最后要經過 Linear 和 softmax 輸出概率。
1. 輸入序列經過編碼器部分,然后將最上面的 encoder 的輸出變換成一組 attention 向量 K和V
這些向量會用于每個 decoder 的 encoder-decoder attention 層,有助于解碼器聚焦在輸入序列中的合適位置
重復上面的過程,直到 decoder 完成了輸出,每個時間步的輸出都在下一個時間步時喂入給最底部的 decoder,同樣,在這些 decoder 的輸入中也加入了位置編碼,來表示每個字的位置。
2. 解碼器中的 self attention 層與編碼器中的略有不同
在解碼器中,在 self attention 的 softmax 步驟之前,將未來的位置設置為 -inf 來屏蔽這些位置,這樣做是為了 self attention 層只能關注輸出序列中靠前的一些位置。
Encoder-Decoder Attention 層的工作方式與 multiheaded self-attention 類似,只是它用下面的層創建其 Queries 矩陣,從編碼器棧的輸出中獲取 Keys 和 Values 矩陣。
3. 解碼器最后輸出的是一個向量,如何把它變成一個單詞,這就要靠它后面的線性層和 softmax 層
線性層就是一個很簡單的全連接神經網絡,將解碼器輸出的向量映射成一個更長的向量。
例如我們有 10,000 個無重復的單詞,那么最后輸出的向量就有一萬維。
每個位置上的值代表了相應單詞的分數。
softmax 層將這個分數轉換為了概率。
我們選擇概率最大的所對應的單詞,就是當前時間步的輸出。
學習資源:
https://arxiv.org/pdf/1706.03762.pdf
https://jalammar.github.io/illustrated-transformer/
https://ai.googleblog.com/2017/08/transformer-novel-neural-network.html