---
# System prepended metadata

title: Transformer
tags: [AI]

---

# 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`