---
# System prepended metadata

title: Transformer Note
tags: [Paper Note]

---

# Transformer Note

:::info
非文本內容的補充格式:
寫在文本翻譯之前
- 專有名詞、概念 1 [link](#) (此link for 大概念)
    - 敘述 1 [link](#)(此link for 單一概念)
    - 敘述 2
- 專有名詞、概念 2 [link](#)
    - 敘述 1
    - ...
:::

:::danger
有看不懂、有疑義的地方，請用 
"::: danger"
":::"
包住，如此段
:::

## 1 Introduction

:::spoiler 補充
- short-term memory
    - 對於單一份data(example)，可以記得序列前面的內容
- long-term memory
    - 可以記得不同份data內的內容(accross example)
- 注意力機制 [link](https://medium.com/programming-with-data/28-%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%A9%9F%E5%88%B6-attention-mechanism-f3937f289023)
    - 然後根據symbol向量與Question向量的相關度(點積值等等)，決定與該symbol的權重
    - 再把每個symbol的向量做加權相加(有時候會再除以向量數做平均)(避免RNN的位置問題，只與相關度有關)
- RNN
    - ![image](https://hackmd.io/_uploads/SJappRSyA.png)

:::

RNN跟GRU(優化記憶方式的RNN)已經有很大的發展，他們通常根據symbol位置來分解資料成sequence，用這種序列化的方式做輸入輸出

但這種方式因為不支援平行的輸入輸出，所以對於long-term memory很難有好表現(越遠的context權重越低，類似股票的KD線吧)

注意力機制可以不管資料在sequence中的位置

然而注意力機制通常仍是跟RNN一起使用(輸入或許有用到注意力，但輸出仍是遞迴方式考慮前一個輸出值)(所以transformer最大的改變，就是multihead且連輸出也用注意力)

這篇paper提出的Transformer避免使用像RNN的遞迴方式，也避免使用CNN的卷積方式，而是完全依賴注意力機制，可以達到更好的平行運算，也可以減少大量的訓練時間。

本篇paper的兩組翻譯實驗都有顯著的結果。

Transformer 能夠在僅僅使用八塊 P100 GPU ，且訓練 12 個小時的情況下就能達到翻譯質量的最新技術水平。

## 2 Background

為了減少序列運算(避免遠處被忽略)，有很多模型(見論文)被提出，但是這些模型還是會受到signal距離(N)的限制，運算量少到O(N),O(log(N))有少但不多

Transformer則可以直接把他變成O(1)的常數，雖然會因為平均注意力權重降低resolution效率就是了，但這問題在3.2會提到怎麼解決

自注意力(Self-attention)是對於sequence中的signal距離的注意力機制。
目前自注意力有成功被運用的例子有：
* 閱讀理解
* 抽象摘要 Abstractive summarization
* 文本蘊涵
* 學習與任務無關的句子表示
* ![image](https://hackmd.io/_uploads/H1V4EsL1C.png)


端到端記憶網路End-to-end memory networks(包含encode, memory, decoder)是基於遞迴注意力機制(把很多注意力機制疊在一起)，而非序列遞迴(RNN那個)。在簡單語言問答和語言建模任務上都有良好的表現。

Transformer是第一個完全依賴注意來計算其輸入和輸出表示的轉換模型。

## 3 Model Architecture

:::spoiler 補充
- point-wise(逐點)
    - 一次只處理一個point，不與其他point相關
    - 也可以指用1 * 1卷積核
:::


Encoder將符號表示的輸入序列（x1，…，xn）(離散的,ex: 字母)映射到連續表示的序列 z = (z1，…，zn)(映射到向量空間，所以連續)

給定 z，Decoder隨後生成一次生成一個符號的輸出序列（y1，…，ym）。

每一步，Transformer都是自我回歸的，也就是在生成下一個符號時，它會使用先前生成的符號作為additional input。

Transformer使用堆疊式(stacked)的自我注意力機制和point-wise的全連接層來遵循這種整體架構


### 3.1 Encoder and Decoder Stacks

:::spoiler 補充
- residual connection(殘差連接) [link](https://blog.csdn.net/weixin_42253689/article/details/110450298)
    - 假設一個layer輸入x輸出H(x), x -> H(x)
    - Residual殘差: F(x) = H(x) - x, 也就是輸出與輸入的差異
    - 殘差連接的重點在於，H(x) = F(x) + x，讓layer學習到的東西是F(x)，也就是學習殘差，然後再透過skip connection把輸入值x加回去
    - 這是用來避免多層數下，梯度消失、梯度爆炸、網路退化的問題(詳見link)
:::


![image](https://hackmd.io/_uploads/SJWeVEJk0.png =70%x)

#### Encoder: 

左邊的部分，由N=6個identical layer疊在一起組成(stacked)，每個區塊包含2個sublayer，一個multi-head self-attention layer(後面會講)，一個point-wise全連接層(圖上的Feed Forward)

在sublayer之間有一個residual connection，為了讓殘差可以順利加上去，網路的輸入輸出都會固定在$d_{model}=512$的維度

Residual connection後還有layer normalization。這樣每一層sublayer的輸出會是 $LayerNorm(x+Sublayer(x))$
* $Sublayer(x)$ 是下一層(sublayer)使用的函數
$LayerNorm$就是把數字標準化，讓他服從常態分佈((x-mean)/SD)

#### Decoder:

右邊的部分，也是N=6個identical layer，但是有三個sublayer。基本上跟左邊只差在第二sublayer(中間那個)，跟第一層的一些

第二個sublayer，一樣是multi-head self-attention，不過吃了encoder的輸出作為輸入。

第一層則是把multi-head self-attention改成masked multi-head self-attention，其實就是讓輸出的位置移動1格，保證第i個只會參照<i的位置


### 3.2 Attention

Attention function是以query, set of pair(key,value)為參數，映射到output的函數

基本上是一種用於準確評估輸入序列的不同部分對於全局(global context)的重要性的一種機制

其中出現的變數都是向量

其中output的計算是藉由value乘上weight，而weight是由對應的key跟query算出來的

基本上就是用來計算query跟value關聯度，並給與加權的函數

可以讓計算時，相關度越高的signal(ex: 跟問題更相關的字詞)，能有更高的權重

#### 3.2.1 Scaled Dot-Product Attention

input:  keys: ${d_k}$, querys: ${d_k}$,   values: ${d_v}$代表著輸入進去的key, query, value的總量 

這個算式的關鍵在於，拿k跟q向量做點積，求其在向量空間的相關度，再除以$\sqrt{d_k}$(有點像是取平均的概念，因為矩陣相乘會導致數值被放大)，然後丟進softmax變成0~1，再做為value的權重

在實務上，key跟value很常是同個東西(以字詞來說，value本身就是字詞映射到向量空間的向量，本來就可以拿來直接點積求相關度)

基本上計算時，會平行進行計算，所以會把向量放在一起變成矩陣Q,K,V
$K \in R^{tokens*d_k}$, $Q \in R^{tokens*d_k}$, $V \in R^{tokens*d_v}$


![image](https://hackmd.io/_uploads/Sku27-lJC.png)
算式中，對於KQ做dot-product，利用他們在向量空間的的角度，來求他們的相似度
這裡的software對於矩陣中每個element做，出來的還是矩陣


soft-max得出的會是一個$R^{d_k * d_k}$的矩陣 ($d_{model}$即文字轉成向量的維度)

:::info
所以這樣的計算結果下，$d_k$一定要等於$d_v$才能做計算???

解決了，作者Ch6有提，如果不同的話，就不能用點積，而要用其他的更複雜的function，還有提到，讓他不同的話，效果會比較差

:::

常用的attention function: addititive與dot-product，dot-product是相對適合的，因為dot-product可以用矩陣方式來加速，但是additive不行，在實務上會更慢

而再{d_k}小的情況，additive跟dot-product的效果差不多，但{d_k}一大，additive就會明顯較好，可能是因為dot-product再高維度會加得太快，所以作者引入了$/\sqrt{d_K}$來減緩這問題

![image](https://hackmd.io/_uploads/SJrMytgyA.png)

#### 3.2.2 Multi-Head Attention

比起把向量的維度全部設成$d_{model}$，作者發現經過線性投影(乘上一個權重，然後降維)之後會更好

作者對於向量做h次處理，每次稱為一個head

處理中，用學習過的線性投影(權重$W_i$來自於學習)成$d_k, d_v$會更好，接著，這些投影過後的向量，會輸出$d_v$的output，這樣

然後再把輸出串聯起來(concat)，做最後一次線性投影，就會得到$維度d_{model}$的最終值

計算式如下:
![image](https://hackmd.io/_uploads/S1tYYV-kA.png)
每個head都是一個attention function，裡面包了乘上權重的三個向量矩陣
透過維度，可以看出，concat的方式，是把h個head($R^{d_v*d_v}$)橫向接起來，變成一個大的$R^{d_v*hd_v}$的矩陣，再去做最後一次線性投影成model中標準化的輸入輸出維度$d_{model}$

論文使用了h=8個(h是超參數)平行attention layer(亦可稱為heads)。每一個head，使用了$d_k=d_v=\dfrac{d_{model}}{h}=64$

因為每一個head的維度縮減，所以最後總運算時間(時間複雜度)和只使用一個head(也就是h=1)且完整維度的一樣，並且這h次會進行平行運算，可以讓運算效率比起直接算單個$d_{model}$head還高。

![image](https://hackmd.io/_uploads/r1kE1KxyC.png)

:::info
更正，這裡的W應該就是後面梯度下降要去學習的東西了
:::

#### 3.2.3 Applications of Attention in our Model
Transformer有三種不同的使用Multi-head attention方式：

![image](https://hackmd.io/_uploads/SJWeVEJk0.png =70%x)

1. 在編碼器-解碼器注意力層(Encoder-Decoder Attention Layer)：
    * decoder中的第二層 
    * 查詢(queries)來自前一個decoder layer
    * 記憶鍵(memory keys)和值(values)來自encoder的輸出
    * 這使得解碼器中的每個位置都可以關注輸入序列中的所有位置
    * 這模仿了序列到序列模型中的典型編碼器-解碼器注意力機制
3. 在編碼器中的自我注意力層：
    * 在自我注意力層中，所有的鍵、值和查詢都來自相同位置，也就是encoder中的前一層的輸出
    * Encoder中的每個位置都可以關注(attend to)encoder輸入中的所有位置，讓輸出是參考過前後文的結果
    * 主要目的是讓Decoder得到的輸入，每個位置其實都包含了全局的訊息
5. 在解碼器中的自我注意力層：
    * 自我注意力層允許decoder中的每個位置關注decoder中包括該位置在內的所有位置，讓輸出是參考過前後文的結果(對於第一個decoder部件可能沒啥用，但對於後面2~6個就會有很大用處)
    * 需要防止deocder中的左向信息流(sequence中，較後面(右)的資訊被較前面(左)的資訊使用到)，以保持自回歸特性(auto-regressive property)
    * 論文的實作方式是：通過點積注意力遮罩(把不合法(左向資訊)的值改掉，將其設置為-∞）
    * ![image](https://hackmd.io/_uploads/S1dnqDZJC.png)

### 3.3 Position-wise Feed-Forward Networks

逐點的全連接層，可以看做1 * 1捲積核的捲積層

![image](https://hackmd.io/_uploads/HkDE_sfyC.png)
max(0,...)即ReLU，所以可以看出，全連接層做的事是，線性變換->ReLU->線性變換

算式中可以看到分成$W_1$, $W_2$，也就是不同的線性變化會有不同的參數，帶來不一樣的學習成果(feature channel中不同的部分會被強調出來)

然後兩次線性變換(全連接層裡的兩層)用的kneral數不同，第一層用2048個kernel，所以會輸出feature channel 2048的向量，第二層則是用512個kernel，輸出512 feature channel的向量

所以過程會是512(input) -> 2048 -> 512(output)，保持了整個model都在$d_{model}$的維度

### 3.4 Embeddings and Softmax

[參考link](https://zhuanlan.zhihu.com/p/372279569)
Embedding基本上，就是把資料變成可以輸入的向量，那一般來講方法會是讓字詞向量乘上一個學習過後的權重矩陣(就一般NLP那套)

在輸出成字詞的機率時，作者用的權重矩陣也是一樣的

基本上，這部分都是拿現成的東西來用，不過作者把那個現成的矩陣乘上了$\sqrt{d_{model}}$(蛤，這是為啥)
:::danger
乘上$\sqrt{d_{model}}$是為了可以和Positional Encoding 後的向量做相加嗎？ 乘了$\sqrt{d_{model}}$之後，值也會介於-1和1之間
:::

### 3.5 Positional Encoding

model內沒有遞迴(RNN那套)或捲積的概念，只有用注意力機制找字詞相關性，但是輸入之間的位置關係還是很重要的(像文章在同個段落內的內容，會比較有相關性)

所以在輸入時，作者使用了positional encoding

[參考link](https://zhuanlan.zhihu.com/p/372279569)
![image](https://hackmd.io/_uploads/BypPHhzJA.png)

透過不同週期的sin, cos，來確保不同的位置，在所有維度上，都不會有相同值，也就因此納入了位置的訊息
![image](https://hackmd.io/_uploads/r1Wtwnfy0.png)

這個positional encoding得到的值，是直接加在向量上的

作者也試過，用學習的方式來做positional encoding
不過發現，用function做跟用學習做得到的結果差不太多，所以選用了function，就可以適應更長的sequence

在輸入的資料，帶有位置的資訊之後，model就會自己去學習出他們的關係了

## 4 Why Self-Attention

這章主要比較Self-Attention與recurrent、convolution方法之間，在對於sequence轉換的差別

比較的點有: 1. 每層的運算複雜度 2 可平行運算的數量(即找最少的序列運算) 3 long range depency的path length(即位置很遠時，要把它納入考量，需要的資源)

第3點是當時，其他sequence transduction模型最大的挑戰

以下是不同模型間的比較
![image](https://hackmd.io/_uploads/SJWfT6GyC.png)

Self-Attnetion(restrict)是只看附近r個position的資料，被限制後的模型
可以降低每層的運算量，但相對path len就會變長

除了這些，self-attention的可解釋性更高，可以看出不同的head學會了不同的任務，並且對於文句的文法、語意結構有有做出相關行為

剩下的不是很重要

## 5 Training

### 5.1 Training Data and Batching

WMT 2014 English-German dataset
WMT 2014 English-French dataset

### 5.2 Hardware and Schedule

one machine with 8 NVIDIA P100 GPUs

基本的model(用論文中提到的參數):
each training step(一個batch做完): 0.4s
train for 100,000 steps or 12 hours

大型model:

each training step(一個batch做完): 1s
train for 300,000 steps or 3.5 days
![image](https://hackmd.io/_uploads/rJXyWeVJC.png)

![image](https://hackmd.io/_uploads/HkKClgEyA.png)


### 5.3 Optimizer

[關於各種optomizer](https://medium.com/%E9%9B%9E%E9%9B%9E%E8%88%87%E5%85%94%E5%85%94%E7%9A%84%E5%B7%A5%E7%A8%8B%E4%B8%96%E7%95%8C/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92ml-note-sgd-momentum-adagrad-adam-optimizer-f20568c968db)
使用adam optomizer(會自動調整學習率，並參考以前變化的向量的梯度下降)

以下是超參數($\beta_1, \beta_2, \epsilon, warmup_step$)，以及學習率設定的數據
![image](https://hackmd.io/_uploads/BJoXMgEJ0.png)
學習率會先漸升再漸降，受warmup決定學習率的波型

:::danger
為什麼需要乘-0.5次方和-1.5次方？

by YouZhe: 我感覺這只是他們嘗試出來，結果比較好的，不然這個數字感覺不太能用數學去解釋
:::

### 5.4 Regularization

每個sublayer都有加上dropout(殘差連接之後，normalization之前)
enbedding跟positional encoding之後也有加上dropout

機率是$P_{dropout} = 0.1$

## 6 Results

### 6.1 Machine Translation

總之就是自賣自誇環節，在WMT 2014 English-to-German translation task第一名


### 6.2 Model Variations

在講調不同參數的結果，基本上就是圖呈現的(以英翻德為例)
![image](https://hackmd.io/_uploads/r10QUlVJA.png)

[link](https://blog.csdn.net/vivi_cin/article/details/134808955)
BLEU(bilingual evaluation understudy): 越接近大代表翻譯的越好，基於Precision，也就是輸出中，正確結果比重越高越好(越少錯辭、冗言贅字)

公式:
![image](https://hackmd.io/_uploads/HJEzOlEyR.png)

[link](https://medium.com/nlp-tsupei/perplexity%E6%98%AF%E4%BB%80%E9%BA%BC-426f52897513)
PPL(Perplexity): 困惑度，越小越好，代表對於model輸出結果的信心(機率多高)，公式中的$l$其實就是cross-entropy function(把機率視為平等後的結果)
公式:
![image](https://hackmd.io/_uploads/HkN5uxEyC.png)


## 7 Conclusion

在翻譯方面，Transformer的訓練速度比基於循環或卷積層的架構要快得多。

在WMT 2014英德翻譯和WMT 2014英法翻譯任務中，Transformer都取得了新的技術水平。

作者打算將Transformer擴展到涉及文本以外的輸入和輸出模式的問題，並研究局部、受限的注意機制，以有效處理諸如圖像、音頻和視頻之類的大型輸入和輸出。

使生成變得不那麼順序化是他們的另一個研究目標。
