# Transformer ## Attention is all you need ![](https://i.imgur.com/1gpYVnP.png =450x600) **Attention** 架構即為模仿人類專注的行為,有點類似挑重點,目的是為了讓電腦能更專心地在處理目前任務的中心。舉例來說 <font color="red">[ 胖虎叫大雄去買漫畫,回來慢了就打他 ]</font> ,這句話最後的他在我們人類的看法裡是指大雄,但對電腦來說文章中有三個名詞,它不知道 <font color="red">[ 他 ]</font> 指的是誰,這時就需要注意力機制讓電腦去觀察上下文。 ![](https://i.imgur.com/nG3hJut.png =300x380) >本句的 **self-Attention(自專注)** 結果,從圖中可以看到,電腦認為 <font color="red">[ 他 ]</font> 跟 <font color="red">[ 雄 ]</font> 的關係最為接近(顏色也最深)。 論文中提到的 **Scaled Dot-Product Attention** 的算法: ![](https://i.imgur.com/bs4tmAc.png) ### Abstract **Transformer** 的主要架構分為 **Encoder** 跟 **Decoder** ,粗淺的說 **Encoder** 的功能為編碼, **Decoder** 為解碼。 **Encoder** : **Encoder** 的任務是將輸入轉化為語意向量,透過 **self-Attention** 的機制,讓向量中包含的語意能更完整,在後續的解碼中,也能更精確。 **Decoder** : (以語言翻譯為例) **Decoder** 在接收到 **Encoder** 輸出的語意向量後藉由 **Multi-head Attention** 選擇出字典中 **Decoder** 認為機率高的單字或詞。 ### Input : Input Embedding, Positional Encoding 在進入主要模型前,<font color="red">我們需要先讓文字轉換成電腦能看懂的表示方式。</font>在這裡我們會處理文字本身和順序的意義。 #### Input Embedding : ![](https://i.imgur.com/kVdAo8R.png) > 每個 **Row** 儲存 **Vocabulary** 中對應字詞的 **Embedding** 。 **Vocabulary Size** 和 **Embedding Size** 會隨著不同模型有所變化。 > > 圖片出處https://jalammar.github.io/illustrated-gpt2/ 文字在到這之前,需<font color="red">先經過 **Tokenization** (文字斷詞 => ID)</font>。 再由<font color="red">ID對應 **Row** 取得 **Embedding** 。 **Embedding** 會隨著模型訓練逐漸完善</font>,可以想像成每個字的 **Embedding** 都是由n個神經元來做紀錄,而 **Token Embedding** 則是裝著整個 **Vocabulary Embedding** 的矩陣。 每次ID對應到的 **Row** 因為被啟動,資料通過,會在 **Backpropagation** 被更新。 #### Positional Encoding : ![](https://i.imgur.com/acCzu05.png) > **Row**儲存對應順序的**Embedding**。**Context Size**和**Embedding Size** 同樣會隨著不同模型有所變化。 > > 圖片出處https://jalammar.github.io/illustrated-gpt2/ <font color="red">因為 **Attention** 是一次處理整個輸入,沒有前後關係,所以在這裡我們需要自己加上去。</font> 取得序意義很簡單,由文字先後順序對應 **Row** 取得 **Embedding** 。不過要注意一點,<font color="red">這裡的 **Embedding Size** 要和先前 **Token Embedding** 相同。</font>我們會<font color="red">做相加的動作</font>,將先前的 **Token Embedding** 和 **Positional Encoding** 加起來(第一維和第一維相加...)。 <font color="red">這樣Input就有了文字本生和順序的意義。(非常神奇:open_mouth:)</font> **Positional Encoding** 同樣也會隨著模型訓練逐漸完善。 ### # **Encoder** ![](https://i.imgur.com/GJIez2w.png =200x) >Encoder主體為灰色框框的範圍。 ## Abstract 如同一開始所說,**Encoder** 主要功能為分析語意,利用 **Self-Attention** 找出文字之間的關西,再經過 **Feed-Forward** 調適,讓語意更為飽滿,以下會解釋是如何達成的。 ## Self-Attention 開使講解實際操作以前,我們先將主要概念講清楚。 我們先回顧一下先前 **Input** 那邊的概念。<font color="red">我們為了讓電腦看得懂文字,每個字都由 **n** 維的向量表示</font>(**n = Embedding size**),再來<font color="red">為了賦予順序的意義</font>,我們<font color="red">將 **Position Encoding** 以加法的方式加上去</font>,至此那些文字就擁有了順序意義。 <font color="red">這裡的重點是加法這個動作</font>,想要讓他有順序意義,就<font color="red">先產生了單純表示順序的 **Embedding** ,再合原資料作相加賦予上去。</font> 到了 **Self-Attention** 這裡,<font color="red">我們想讓資料加上字和字之間的關西</font>,從而讓電腦理解類似於"他"這種文字,在文章中出現時到底在指什麼事物。 延續賦予 **Position Encoding** 的想法。假如我們想要讓<font color="red">[ 胖虎叫大雄去買漫畫,回來慢了就打他 ]</font> 之中的 <font color="red">[ 他 ]</font>,有和其他字的關係,只要有每個字的 **Embedding** ,還有他們對於[ 他 ]的權重,在和權重相乘後,和[ 他 ]的 **Embedding** 做相加便是賦予了[ 他 ]和其他字之間的關係。 實際操作共有三個步驟: 1. 產生 **Query、Key、Value**。 2. **Query** 和 **Key** 做點積得到每個 **Key** 對於 **Query** 的 **權重**。 3. **Value** 和 **權重** 做點積後和 **Query** 相加得到 **Self-Attention** 結果。 **Query** : 我們想賦予關系的字詞。 **Key、Value** : **Query**所在的文章or句子or前後文...。 ### 1. Create Query、Key、Value **Query、Key、Value** 分別有各自對應的 **Weight Matrix** ,用來對 **Embedding** 做調適。(同樣會隨著模型訓練成長) 和對應的資料作點積後得到正式的 **Query、Key、Value**。 ![](https://i.imgur.com/IFRcyN7.png) >**x1~x4** 為字詞的語意向量。因為我們其實要對每個字都賦予字詞之間的關西,所以大家都會有一組**Q、K、V**。 > >圖片出處https://jalammar.github.io/illustrated-gpt2/ ### 2. Score **Query** 和 **Key** 做點積得到每個 **Key** 對於 **Query** 的 **權重(Score)**。 會經過 **Softmax** 讓加總為 **100%**。 ![](https://i.imgur.com/E9GQ7tC.png) > >圖片出處https://jalammar.github.io/illustrated-gpt2/ ### 3. Sum **Value** 和對應的 **權重** 做相乘,再將他們做總和(**Z**),也就是我們計算出的字詞關西。之後把它和 **X** 相加就是賦予意義了(**Add & Norm**)。 ![](https://i.imgur.com/i5FkdZ6.png) > 有一排 **Value** 深淺不一,用來表示他們在最終結果所佔的比例。 > > 圖片出處https://jalammar.github.io/illustrated-gpt2/ 以上都是以單一字詞做舉例,實際上是一次處理全部,**Query、Key、Value** 都是矩正,不過步驟是一樣的。 ![](https://i.imgur.com/06sfgXS.png =400x) >**Attention** 的計算(以陣列表示) > >圖片出處https://jalammar.github.io/illustrated-transformer/ ### Multi-head Attention **Encoder** 的圖上寫的是 **Multi-head Attention** ,我們到目前說的都是單一 **Head** 的處理方式,不過 **Multi-head** 實際上也是做一樣的事,只是在做上續處理的時候,會先 **Reshape Q、K、V**,原本每個字都是 **1 x N** 維表示,改成 **Heads x (N / Heads)**。 ![](https://i.imgur.com/zaiwdrZ.png) >這裡 **Heads** = 12,原 **Embedding size** = 768 > >圖片出處https://jalammar.github.io/illustrated-gpt2/ 完事後再 **Reshape** 回去。 ![](https://i.imgur.com/QLrN43x.png) > >圖片出處https://jalammar.github.io/illustrated-gpt2/ 不過其實 **Reshape** 不能算是真的復原,畢竟就只是把已經分開處理的東西頭尾相接而已,**Embedding** 要再經過調適才可以。(調適用的 **Weight Martix** 同樣會隨著訓練成長) ![](https://i.imgur.com/EzNwBbt.png) > >圖片出處https://jalammar.github.io/illustrated-gpt2/ ## Feed Forward 經過 **Attention** 之後,**Encoder** 會利用 **Feed Forward** 部分再次對 **Embedding** 做調適。 **Feed Forward** 分為兩個部分: 1. 將 **Embedding** 擴充到四倍大的 **Weight Matrix**。用以分析、調適前面 **Attention** 所學知識。 ![](https://i.imgur.com/OFs5qys.png) >圖片出處https://jalammar.github.io/illustrated-gpt2/ 2. 將 **Embedding** 復原成正常大小的 **Weight Matrix**,做最後的整合。 ![](https://i.imgur.com/HiLTL4b.png) >這裡的結果會再次以相加的動作將所學賦予到資料上(**Add & Norm**) > >圖片出處https://jalammar.github.io/illustrated-gpt2/ 到這裡 **Encoder** 就算是結束了。輸出的資料看是要接到下一個 **Encoder**,精益求精。還是將這經過多次優化的語意向量拿來做後續運用就看各人了。 ## Model Implementation : BERT # **Decoder** ![](https://i.imgur.com/3W6YrLY.png =200x) >Decoder主體為灰色框框的範圍。 ## Abstract **Decoder** 和 **Encoder** 的架構差不多,只是多了一層的 **Attention** 。**Decoder** 接收到 **Encoder** 所產生的語意空間 **(所有的)** 後, **Decoder** 會透過 **Multi-Head Attention** 決定產生哪些新的句子,並決定 **Encoder** 傳過來的資訊那些部分是重要的。 **Decoder** 的運作: 1. **輸入** : **Decoder** 有兩端輸入,<font color='red'>一端來自 **Encoder** 輸出的 **Key** 跟 **Value**,一端則為跟 **Encoder** 一樣的原資料。</font>來自 **Encoder** 的資料輸入中間的 **Attention Section**,而 **Query** 則來自 **Decoder** 的原生資料 (前一個 **Attention** ,訓練時帶有答案,預測並沒有) 。 2. **解碼** : 在實務的解碼上,<font color='red'>訓練和預測不一樣。</font>訓練時將資料一次解碼出來,因為解碼出來的資料是整筆的,所以會用 **Mask** 遮蔽未來的答案。而預測沒有答案,所以會一個一個預測。 3. **輸出** : 輸出則隨著 **time_step** <font color='red'>逐步輸出</font>,以中文處理為例,則為一個詞一個詞輸出。 >詳細的模型運作請見 **Output** ## Mask **Mask** 的主要功用是將陣列中的某部分 **Vector** 遮蔽,就像考試的時候不會知道正確答案一樣,將一部分的答案失效。在 **Transformer** 中有兩種 **Mask** ,分別為在 **Encoder** **Scaled Dot-Product Attention** 區塊中的 **Padding-Mask** 跟 **Decoder Self-Attention** 的 **Sequence Mask**。總而言之, **Mask** 的主要功用為 <font color="red">**1. 處理非特定長度的資料 2. 遮蔽特定標籤**。</font> 1. **Padding Mask(處理非特定長度)** 在處理資料的時候常會遇到非特定長度的資料 (e.g. 語言) ,神經元的數量是特定的,以文章為例,第一句話為10個字,第二句話為15個字,但是神經元有15個,那在處理第一句話的時候就會出錯。**Padding** 就是為了處理上述情況而誕生。 在實務上的實現方式就是在不足的地方補0。 **Padding Mask** 中的值皆為布林值,false即為資料存在的地方。 2. **Sequence Mask(遮蔽特定資料)** **Sequence Mask** 的目的是為了讓模型不能參考未來的資訊,在訓練的時候, **Decoder** 會將所有的資訊先解碼,造成模型能夠參考,但是基於順序,模型不該在時間 **T** 的時候就知道時間 **T+1** 的內容,就像人在讀書的時候,還在讀第一章的內容不可能知道第二章的內容。 在實務上我們會先生成一個矩陣,將上三角的值全部設為0,再將這個矩陣套用在每一筆資料上。 ![](https://i.imgur.com/uLQYGPi.png =100x) ![](https://i.imgur.com/0cdKE5g.png =400x) >實際的 **Sequence Mask** 應用範例。 > >圖片出處https://zhuanlan.zhihu.com/p/139595546 ## Output ![](https://i.imgur.com/KVYhggt.gif =600x) >圖片出處http://jalammar.github.io/illustrated-transformer/ 當 **Encoder** 處理完語意的包裝,會將數據傳送給 **Decoder** 中間的 **Multi-Head Attention** ,成為 **Key** 和 **Value** ,而 **Multi-Head Attention** 的 **Query** 則由上一級的 **Masked Multi-Head Attention** 提供 **Decoder** 的 **Self-Attention**,最後再由 **Feed Forward** 做調適。 以上就是 **Decoder** 模型中的數據流,但是 **Decoder** 最後的輸出是一個向量,要怎麼成為我們所看到的句子呢? <font color='red'>**所以我們會在後端接上一個Linear和Softmax。**</font> ![](https://i.imgur.com/XMMjGMb.png =300x) >**Linear** : 通常為一個 **Fully Connected Layer(全連接層)** 在 **Transformer** 中的功能就像分類器一樣,決定在時間 **T** 的格子應該填入哪組詞。 > >圖片出處https://kknews.cc/code/bmmxp5m.html ![](https://i.imgur.com/mB2y3NA.png) >**Softmax** : 激活函數,將前端神經元的輸出轉成0到1之間的數值,目的是將輸入映射為輸出,它會將 **Linear** 算出的概率轉換為0到1之間。例如我的字典中有100個詞,則 **Linear** 會算出100個數字,在藉由 **Softmax** 轉換成機率。( 100個數字經由 **Softmax** 轉換以後加起來為1,視為機率 ) ![](https://i.imgur.com/4hQeuCw.png =500x) >不管是 **Encoder** 還是 **Decoder** 都不是孤軍奮戰。上述都是在說當 **Encoder** 和 **Decoder** 只有一層的情況,其實 **Encoder** 和 **Decoder** 可以多層疊加,以增加精準度。 > >圖片出處http://jalammar.github.io/illustrated-transformer/ ## Model Implementation : GPT-2! ```python= import os print("hello") ``` ###### tags: `AI`