【翻譯】圖解自注意力機制
theme: condensed-night-purple
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第12天,點選檢視活動詳情
這是我翻譯這位大佬的第二篇文章了。這篇文章是受到大佬認證的了。他的原文中有翻譯連結,直接指向我。
作者部落格:@Jay Alammar
重大宣告
-
這個文章是《圖解GPT-2 | The Illustrated GPT-2 (Visualizing Transformer Language Models)》的一部分,因為篇幅太長我就單獨拿出來了。
當然如果你只想瞭解自注意力機制也可以看看本文章的前半部分,這篇文章屬算是入門科普讀物了,不需要太多知識鋪墊。 後半部分主要是講masked self-attention在GPT-2中的應用,不瞭解GPT-2的可以忽略這部分內容。
-
我補充的內容格式如下:
這是我補充的內容。
正文
看一下下圖,下圖表示的是注意力處理輸入序列的it
單詞的時候。
接下來我們詳細介紹一下這一過程是如何實現的。
注意,接下來的圖解過程會用到很多 “向量” 來圖解演算法機制,而實際實現中是使用 矩陣 進行計算的。這個分析過程是想讓讀者瞭解在處理過程中每個單詞發生了什麼,因此本文的重點是單詞級(word-level)處理邏輯進行解析。
自注意力
我們從原始的自注意開始,它是在一個encoder元件中計算的。我們先來看看這個簡單的Transformer元件,它一次只能處理四個tokens。
僅需三步即可實現自注意力: 1. 為每個單詞路徑建立Query、Key、Value。 2. 對於每個輸入token,使用其Query向量對其他所有的token的Key向量進行評分。 3. 將Value向量乘以上一步計算的分數後加起來。
1. 建立Query、Key、Value
現在我們只關注第一個路徑,我們需要用它的Query和所有的Key比較,這一步驟會為每個路徑都生成一個注意力分數。
先不管什麼是多頭注意力,先看一個head 的情況。自注意力計算的第一步就是要計算出每個路徑的Query、Key、Value三個向量。
- 看一下下圖是一次處理四個tokens,每個token都有它單獨的路徑,第一路徑指的是$X_1$這個token。
- 對於每個詞來說對應的QKV是一個向量,而在實際計算中是使用整個輸入序列的矩陣。
- 獲得Query、Key、Value三個向量的方法是$每個單詞的表示向量×對應的權重矩陣(W^Q、W^K、W^V)$。
2. 計算注意力分數
現在我們已經有了那三個向量,在第二步我們只需要用到query和key向量。因為我們關注的是第一個token,所以我們將其第一個token的query乘以其他token的key向量,這樣計算會得到每一個token的注意力分數。
這裡是兩個向量做點乘積,不是按位乘。
3. 求和
我們現在可以將上一步得到的注意力分數乘以Value向量。將相乘之後的結果加起來,那些注意力分數大的佔比會更大。
看下圖,注意力分數乘以每個Value向量,原作者用不同深淺的藍色的框框表示計算之後的結果。可以看到$V_3$比較顯眼,$V_2$幾乎看不到了,然後將計算結果加起來得到$Z_1$。這個$Z_1$就是$X_1$新的表示向量,這個向量除了單詞本身,還涵蓋了上下文其他token的資訊。 這一過程可以認為注意力分數就是求不同單詞重要性權重的過程,這一步的計算就是求所有token的加權和。
對於Value向量,注意力分數越低,顏色越透明。這是為了說明乘以一個小數如何稀釋不同token的Value向量。
如果我們對每個路徑進行相同的操作,最終會得到每個token新的表示向量,其中包含該token的上下文資訊。之後會將這些資料傳給encoder元件的下一個子層(前饋神經網路):
圖解帶Mask的自注意力
現在我們已經瞭解了Transformer中普通的自注意機制,讓我們繼續看看帶mask的自注意。
帶mask的自注意和普通的自注意是一樣的,除了第二步計算注意力分數的時候。
假設模型只有兩個token作為輸入,我們當前正在處理第二個token。在下圖的例子中,最後兩個token會被mask掉。這樣模型就能干擾計算注意力分數這一步驟,它會讓未輸入的token的注意力得分為0,這樣未輸入的token就不會影響當前的計算,當前詞彙的注意力只會關注到在它之前輸入的序列。
這種遮蔽通常以矩陣的形式實現,稱為注意力遮蔽(attention mask)。
還是假設輸入序列由四個單片語成,例如robot must obey orders
。在語言建模場景中,這個序列包含四個處理步驟,每個單詞一個步驟(假設現在每個單詞都是一個token)。由於模型是按照批量(batch)進行處理的,我們可以假設這個模型的批量大小為4(batch_size = 4),然後模型將把整個序列作為一個batch處理進行四步處理。
假設現在每個單詞都是一個token,這個假設是因為單詞word ≠ token,在不同的分詞方式中同一個單詞可能會劃分為不同的token。
在矩陣形式中,我們通過將Query矩陣乘以Key矩陣來計算注意力分數。讓我們像下面這樣進行視覺化,注意,單詞無法直接進行矩陣運算,所以要把他們的Query和Key丟到矩陣中。
完成乘法運算後,我們要加上上三角形式的mask矩陣。它會將我們想要遮蔽的單元格設定為$-∞$或一個非常大的負數(GPT-2中的為負一億):
然後,對每一行進行softmax就會轉化成我們需要的注意力分數:
這個分數表的含義如下:
- 當模型處理資料集中的第一個單詞時,也就是第一行,其中只包含一個單詞robot
,它的注意力將100%集中在這個單詞上。
- 當模型處理資料集中的第二個單詞時(第二行),其中包含單詞
robot must
,當它處理單詞“must”時,48%的注意力會放在robot
上,52%的注意力會放在must
上。 - 以此類推……
GPT-2的 Masked Self-attention
讓我們更詳細地瞭解一下GPT-2的masked注意力。
現在假設模型做預測任務,每次處理一個 token。
我們用模型進行預測的時候,模型在每次迭代後都會增加一個新詞,對於已經處理過的token來說,沿著之前的路徑重新計算效率很低。
作者意思是比如
a robot must obey the rule
,如果第一次迭代時候只有a
,僅需要計算它的QKV,第二次迭代時候是a robot
,如果直接算二者的QKV,那就是重複計算了a
的,這樣會造成巨大的計算開銷。 GPT-2的高效處理方法如下:
假設我們處理輸入序列的第一個tokena
時(暫時忽略<s>
)。
GPT-2會保留a
token的Key和Value向量。每個自注意力層都有各自的Key和Value向量,不同的decoder元件中Key和Value向量不共享:
在下一次迭代中,當模型處理單詞robot
時,它不需要為a
重新生成Query、Key、Value,而是直接用第一次迭代中儲存的那些:
1. 建立queries, keys和values
讓我們假設這個模型正在處理單詞it
。如果我們討論的是最底層的decoder元件,那麼它接收的token的輸入是token的嵌入+ 第九個位置的位置編碼:
Transformer中的每個元件之權重不共享,都有自己的權重。我們首先要和權重矩陣進行計算,我們使用權重矩陣建立Query、Key、Value。
自注意力子層會將輸入乘以權值矩陣(還會加上bias,圖中沒表示出來),乘法會產生一個向量,這個向量是單詞it
的Query、Key、Value的拼接向量。
將輸入向量乘以注意力權重向量(然後新增一個偏差向量),就會得到這個token的Query、Key、Value向量。
1.5 劃分注意力頭
在前面的例子中,我們只專注於自注意力,忽略了“多頭”(muti-head)的部分。現在說一下什麼是“多頭”。 就是將原來一個長的Query、Key、Value向量按照不同位置擷取並拆分成短的向量。
前邊的例子中我們已經瞭解了一個注意力頭怎麼計算,現在我們考慮一下多頭注意力,如下圖考慮有三個head。
2. 注意力分數
現在我們可以開始打分了,你們應該知道,我們這隻畫出來一個注意力頭(head #1),其他的頭也是這麼計算的:
現在,該token可以針對其他token的所有Value進行評分:
3. 加和
和前邊講的一樣,我們現在將每個Value與它的注意力分數相乘,然後將它們相加,產生head #1的自我注意結果$Z$:
3.5 合併注意力頭
不同的注意力頭會得到不同的$Z$,我們處理不同注意力頭的方法是把這個$Z$連線成一個向量:
但是這個拼接結果向量還不能傳給下一個子層。
我們首先需要把這個拼接向量轉換成對齊表示。
作者原文寫的“We need to first turn this Frankenstein’s-monster of hidden states into a homogenous representation.” 直譯是“我們需要首先把這個隱藏狀態的弗蘭肯斯坦怪物變成對齊的表示。” 弗蘭肯斯坦是一個人造人,是個怪物,作者是瑪麗·雪萊,這本書可以看作是科幻小說開山之作。感興趣的可以看一下。
對映/投影
我們將讓模型學習如何將自注意力的拼接結果 更好地對映成前饋神經網路可以處理的向量。下面是我們的第二個大權重矩陣,它將注意力的結果投射到自注意力子層的輸出向量中:
之後我們就產生了可以傳送到下一層的向量:
GPT-2 全連線神經網路第一層
全連線神經網路的輸入是自注意力層的輸出,用於處理自注意力子層得到的token的新的表示,這個表示包含了原始token及其上下文的資訊。
它由兩層組成。第一層是模型大小的4倍(因為GPT-2 small是768,所以GPT-2中的全連線神經網路第一層會將其投影到768*4 = 3072個單位的向量中)。為什麼是四倍?因為原始Transformer的也是四倍,這裡就沒改。
上圖沒畫出bias。
GPT-2 全連線神經網路第二層:投影到模型維度
第二層將第一層的結果再投射回模型的維度(GPT-2 small為768)。這個計算結果就是整個decoder元件對token的處理結果。
上圖沒畫出bias。
You’ve Made It!
總結一下輸入向量都會遇到哪些權重矩陣:
每個Transformer元件都有自己的權重。另外,該模型只有一個token的嵌入矩陣和一個位置編碼矩陣:
如果你想看到模型的所有引數,我在這裡對它們進行了統計:
由於某種原因,它們加起來有124M的引數,而不是117M。我不知道為什麼,但這就是在釋出的程式碼中它們的數量(如果我錯了歡迎指正)。
上圖中部落格作者對GPT-2 small的引數進行了統計,計算結果和OpenAI開源的GPT-2模型的引數量不一樣。 作者算的是124M,實際程式碼中只有117M, 原因如下: OpenAI團隊說:“我們論文裡引數計算方法寫錯了。所以你現在可以看到GPT-2 small模型引數只有117M……” 截圖來源http://github.com/openai/gpt-2
- 【翻譯】最近興起的擴散模型
- 深扒torch.autograd原理
- 用一個影象分類例項拿捏Pytorch使用方法
- 帶你瞭解自然語言處理文字生成方向
- 你們居然還在用負樣本做對比學習?
- 4個例子幫你梳理PyTorch的nn module
- 幾個例子幫你梳理PyTorch知識點(張量、autograd)
- SimCSE,丹琦女神把對比學習用到了NLP中了!
- 兩個視角給你解讀 熵、交叉熵、KL散度
- 你們那種對比學習是辣雞,我SwAV今天就要開啟新局面!
- “軍備競賽”時期的對比學習
- 怎麼用PyTorch實現一個Encoder-Decoder框架?
- 公式程式碼都有了,速來學LSTM 長短期記憶網路
- 【翻譯】圖解自注意力機制
- 用pytorch寫個RNN 迴圈神經網路
- 用pytorch寫個 GRU 門控迴圈單元
- 手把手教你實現 seq2seq
- 突然火起來的diffusion model是什麼?
- TensorBoard 一行程式碼實現指標視覺化
- 【翻譯】圖解transformer