介紹
在上一篇文章中,我們介紹了機器翻譯遇到的難題,並且介紹了 Neural Machine Translation by Jointly Learning to Align and Translate 中提出的 Attention 雛形。
這篇文章將著重介紹 Transformer 背後的 Scaled Dot-Product Attention,並詳細解釋計算邏輯還有其設計理念,文章的最後也會提供一個使用 Attention 的例子,希望能讓讀者看完後對 Attention 有更全面的理解。
Scaled Dot-Product Attention
之前提到的方法雖然解決了 Context Vector 不管用的問題,但如果遇到很長的句子或文章,模型還是無法快速處理輸入 。為了加快運算,運用平行計算的優勢,理想的做法應該是摒棄一個字一個字讀的方法。在 Attention Is All You Need 這篇論文中,便提出了 Scaled Dot-Product Attention 來實現這樣的想法。它的計算方式如下:
公式看起來很複雜,為了說清楚背後的原理,我們一步一步來看究竟發生了什麼。
1. QKᵀ
在這一步中,Q (Query) 和 K (Key) 是兩個矩陣,我們假設 Q 裡面有三筆資料,K 裡面有四筆資料,那這兩個矩陣的維度分別是 3 * dₖ
和 4 * dₖ
,注意兩個矩陣要有一樣數量的 Column,解讀方式是:
- Q 矩陣裡面有三筆資料,每筆資料用一個長度為 dₖ 的向量表示
- K 矩陣裡面有四筆資料,每筆資料用一個長度為 dₖ 的向量表示
如果你原本用來表示 Q 和 K 的序列維度不一樣,又或者你想要制定某個特別的 dₖ,那可以分別用 Linear(input_q_dim, dₖ)
和 Linear(input_k_dim, dₖ)
來把原本的 Query 和 Key 做線性轉換成 dₖ 維。這兩個 layer 的作用是把兩個序列轉到同樣的向量空間。
現在你已經得到 Q 和 K 兩個矩陣了,他們長下面這樣(下面假設 dₖ = 4)
我們來看看 QKᵀ 在做的到底是什麼:
從上面的動圖可以發現,QKᵀ 會產生一個 3 * 4 (Query 的數量 * Key 的數量)的矩陣,這個矩陣的第 i, j 個元素是由 第 i 個 q 和第 j 個 k 內積 算出來的!
這個步驟其實對應了標題 Dot-Product 的部分,計算出來的矩陣 A 像是一個查詢表,第 i, j 個元素代表的是 第 j 個 key 對第 i 個 query 的重要性。
對這一段做個結論。從輸入到做 QKᵀ 運算的這部分,模型在做的事情其實是
- 將輸入的 Query 以及 Key 轉換到同一個向量空間,在這個向量空間裡面,越相關的 Query 和 Key 內積的值會越大(模型會自己學會要怎麼做這個轉換)
- 用內積算出 Attention 表,我們把這個表取名為 A。
2. softmax(A /√dₖ)
這部分其實對應了 Scaled 的部分,要看懂的話我們必須先了解 softmax 函式
對於 A 裡面每個 row,softmax 會把裡面每個元素轉換成 0 到 1 的之間的數值,而每個 row 的數值加起來會等於 1。我們仔細觀察 row 裡面某個元素,在其他數值不變的情況下,單一數值的座標會長下面這樣:
可以發現在特別大或特別小的地方梯度(斜率)幾乎為 0,導致參數沒辦法更新,而如果你設定的 dₖ 特別大,上面利用內積計算出來的 A 就有比較高的可能性出現落在這些地方的數值(因為總共有 dₖ 個東西要相乘後加總)
除以 √dₖ 就是為了讓數值落在這些地方的可能變小,降低訓練時受到的阻礙。
我們把通過 softmax 的矩陣稱作 A’
進階(可略過):
假設你的 q 和 k 向量裡面每個數值都是獨立從 N(0, 1) 這個常態分布抽取出來的,根據內積的算式
q ⋅ k 的期望值會是 0,但變異數會是 dₖ,除以 √dₖ 可以把變異數拉回 1。
3. A’V
在開始這段之前,先複習一下 A’ 是什麼,A’
- 有跟 Query 數量一樣多的 row
- 有跟 Key 數量一樣多的 column
- 每個 row 裡面的數值都介於 0 和 1 之間,第 j 個元素代表第 j 個 Key 對這個 Query 的重要性
- 單一 row 裡面所有數值加起來等於 1
假設 A’ 長下面這樣
接下來要討論 V,代表的意義是 Key 背後真正的數值,可以把 Key 想像成學號,Value 想像成姓名、班級、成績等資訊,你用學號來找到這個人,但是他的相關資訊才是你真正需要的東西,對模型來說也是一樣,他真正用來計算的東西是 V 的數值。
V 的維度用 dᵥ 表示,你可以把它設成任何你認為合適的數值。一樣可以用 Linear(input_k_dim, dᵥ)
來將輸入向量轉換到這個維度。
注意上面這行指令中我把第一個參數設成 input_k_dim
,這是因為 K 和 V 的源頭應該要是同一個向量,只是一個被轉去 Q 的空間和它比對,另一個被轉譯成真實的數值。換句話說,Key 和 Value 是有一對一的對應關係的,第一個 Value 對應到第一個 Key,第二個 Value 對應到第二個 Key ……
V 的樣子長下面這樣:
最後我們來看看 A’V 代表什麼
從上面的算式可以發現,A’V 會:
- 產生一個矩陣,這個矩陣 row 的數量就跟 Query 的數量一樣多
- 對於每個 Query 來說,它的最終數值是將 V 裡面的 row 向量做加權平均
- 加權平均的權重依據是 Query 和其對應的 Key 做內積
Scale Dot-Product Attention 小結
其實就是在做兩件事
- 建立查詢表(Query 和 Key 內積算權重,再把權重轉換成 0 和 1 之前的數值)
- 根據查詢表,用 Value 矩陣的加權平均算出 Query 的最後數值
你也可以把 Key-Value 想像成某種資料庫,而 Attention 在做的事情其實就是 根據資料庫裡的內容,找出一組合適的向量來代表每個 Query。
Query 和 Key-Value 在上面的介紹是兩種不同的序列,但其實兩者的輸入可以是同一個序列,在這樣的情況下就被稱為 Self-Attention。
Self-Attention 在自然語言處理特別常用到,根據上面的邏輯,可以把輸出看做考量前後文後每個字對應的 word-embedding。
舉例
文章的最後提供讀者一個使用 Attention 的例子,加深大家的理解。
假設今天我想要將資訊工程系和哲學系(兩個 Query)轉換成模型可以理解的向量,而資料庫裡面有英文、社會、數學、物理四個科目(四個 Key-Value pair),模型算出來的 Attention table 可能會長下面這樣:
解讀方式如下,對於 XX 系,這四個科目的重要性分別為 ……
接下來我們需要 Value 的數值,這裡我設定 dᵥ = 3
,Value 的三個數值分別代表記憶力、語言能力、邏輯推理能力。
(注意:真實情況下我們沒辦法知道 Value 的三個 column 分別代表什麼,模型會自己找出它們該表示什麼。)
解讀方式如下,對於 XX 科目,記憶力、語言、邏輯推理分別需要 OO 分才能念好。
(分數純屬虛構)
將上面的兩個矩陣相乘
最後算出的如下,解讀方式是 XX 系的 OO 能力分別需要達到多少分才能念好。
而模型也會分別用 6.9 7.5 10.1
和 8.3 8.7 7.3
兩個向量來代表這兩個科系。
希望這個例子能讓你更了解 Attention 在做什麼,以及該如何設定 Attention 的維度。
結論
這篇文章詳細介紹了 Scaled Dot-Product Attention 的計算細節,設計邏輯並且提供了一個使用 Attetion 的例子,若仔細比對前一篇的模型,就會發現兩個架構雖然看起來很不一樣,大致上的邏輯卻是差不多的
實際上的 Transformer 除了 Attention 外還有許多細節,除了 Encoder 和 Decoder 的架構外,還有 MultiHead、Positional Encoding 等,日後若有機會再好好介紹這個主題。