29. Transformer

柯頌竹
Programming with Data
14 min readJan 26, 2021

Transformer就是個 seq 2 seq model,將一個序列轉成另一個序列,就像是變壓器將一個電流轉成另一個電流。

可從Stanford線上課程Lecture 14 — Transformers and Self-Attention看看原作者介紹Transformer。

Transformer 的結構

我們在上一章 attention 機制賣了個關子,說 Self-attention and Multi-head attention 將在transformer 這邊說明,就是因為這兩個機制是 transformer 結構的重點,在這個部分,我們會一步步的說明和 transformer 結構相關的概念,希望大家可以更深入的了解 transformer。

首先,我們先從一個之前的機器翻譯 seq 2 seq 模型開始,如下圖所示:

這個模型是由兩個部分組成的,分別是 Encoder 編碼器 和 Decoder 解碼器,RNN seq 2 seq model 分別把 encoder 和 decoder 用 RNN 實作。

下圖展示的 Transformer 模型也是個 seq 2 seq 模型,同樣用類似的 encoder decoder 編碼器和解碼器結構,只是他是分別用 Transformer 層來實作 encoder 和 decoder,在這邊特別強調出來是因為 Transformer 在這邊有些不一樣的處理。

然而一層 Transfomer 層不足夠抓取語言的複雜資訊,在原來的論文中,encoder and decoder 兩邊都疊了六層,而下面的圖中只畫了三層。

Transformer中有三個重要的元素,包含Encoder編碼層、Input & Position Embedding及Decoder解碼層,以下會依序介紹。

Transformer encoder 編碼層

由論文中的圖可看出Transformer encoder 編碼層的內部結構,每層內含兩個子層:Multi-head self-attention sublayer 多頭自注意子層、Position-wise Feed Forward 位置前饋層

Multi-head self-attention sublayer 多頭自注意子層

Self-attention 自注意機制

甚麼是自注意力機制呢?就是將句子裡面的每個字和句子裡面的每個字(包括自己)做 ATTENTION,比如,”Mary had a little lamb.” 這句話做自注意機制,就是將 “Mary” 和 “Mary”,”had”, “a”, “little” 和 “lamb”。這五個字來做注意力。將 Mary 和這五個字分別作相似度,然後用 softmax 的結果加權平均 “Mary”,”had”, “a”, “little” 和 “lamb”的代表層求和。成為新的 Mary 的代表層。然後再做 “had” 和 “Mary”,”had”, “a”, “little” 和 “lamb” 的自注意成為新的 “had” 的代表層。直到做完整個句子,得到每個字的新代表層。

以Mary had a little lamb. She kept it in her backyard.為例,RNN 可能要處理 6 個字, 才能從Mary讀到She。Attention 只要一步就讀到兩個字並計算它們的關係了,因此原作者認為Attention在機器翻譯上比其他模型架構更有效率。

而Transformer 的 attention 機制是用 scaled dot product attention 標準化點積注意力(也有人翻譯縮放點積注意力)。

Transformer 的做法是透過線性轉換把代表一個字的勘入(embedding)轉換成我們要用的 Q,K 和 V.各位可以把它想像成用三個分開的神經網路,將原來代表一個字的embedding 轉換成分別 K,Q 和 V 的三個向量。計做

圖中scaled 標準化是針對大型的 attention 層做的調整,attention 維度越大的時候,Q dot K 的值會越大而影響學習的效率,transformer 的作法是將 Q dot K 除以 K 的維度開根號。接著是Mask層,這層是為了將我們不希望模型看到的attention藏起來,細節會在本文下半段Decoder解碼層中討論。Attention 數學表達式如下:

Multi-head attention 多頭注意機制

所謂的 multi-head attention,就是同時擁有多個 attention 機制在作業,如同CNN 透過很多組 kernal來擷取一張圖上不同的小特徵,如果 attention 也能像 CNN 一樣有多組的 attention 注意不同的句子特徵,然後再根據不同特徵組合起來分析句子,也可能會更有效率。

上方是multi-head attention 的概念圖,將原來做一次的 attention 改為做多次 attention。

最後再把所有的 attention 拼接起來,經過一次線性轉換,決定最後學到的內容。

實際上,為了限制使用的資源,transformer 實做的方法是將一個大的 attention 切成數個小的attention。然後每個小 attention 分開計算。 所以當我們決定 hidden dimension 隱藏維度後,transformer 會將這個 hidden dim 隱藏維度數除以 attention head 數,然後分成多個 attention 獨立計算。最後再結合起來。

Residual connection 殘差連接

借用 ResNet 的概念放到Transformer,公式:Residual (x) = x + Sublayer(x)

其中 Sublayer 就是原來使用不同學習層,比如 attention 或全連接層。

Layer normalization 層正規化

Layer normalization 是和 batch normalization 非常近似的一種正規化方法,不同的是 batch normalization 取的是不同樣本的同一個特徵,而 Layer normalization 取的是同一個樣本的不同特徵。根據實驗指出,Layer normalization 在 RNN 的架構中比較有效果, 在 CNN 的架構效果比較差。以結果論,Layer normalization在attention 中效果也很好。

layer normalization 和 residual connection 殘差連接在 transformer 中合稱 Add & Norm 公式可以被記為:

Add & Norm(x) = LayerNorm(x + Sublayer(x))

Position-wise Feed Forward 位置前饋層

在這邊實作方式就是就是全連接層再加上上面提過的殘差連接和 layer normalization (Add & Norm).全連接層是深度學習基本款,原文中的設定輸出層和輸入層都是 dimension 512。 中間層是輸出層的四倍 2048。在兩層的中間, 我們還會加一層 Relu 層。計做:

Input and position embedding 輸入和位址嵌入

embedding (嵌入) 是一個相對低維的向量空間,我們可以在 embedding 層中轉換高維向量到低維向量空間。embedding 讓我們轉換大型向量空間輸入(例如一個個的單詞或字元)到小型向量空間輸入。理想情況下,優良的 embedding 能夠做到更強的代表性。比如代表字義的 embedding 要能在向量空間將類似字義的放在一起,並且透過相對距離來表現字義。

在 transformer 中,我們將一個句子的資訊分成三個部分,字元,位址和分段。我們舉一個例子:Mary had a little lamb. She kept it in her backyard.

位址

RNN 處理的時候,是一個字一個字的處理字元的, 雖然這樣的處理方式是 RNN 最被大家詬病之處,但是它有一個明確的優點,字的位置很明確, 先後次序不會被打亂。 CNN 也對位置是敏感的。 但是 transfomer 的核心 attention 演算法對位址是不敏感的,舉個例子來說, 兩句話 “Mary had a little lamb.” 和 “lamb had a little Mary.” 兩個句子中 Mary 這個字的 self-attention 計算結果是一樣的,也就是字的位址資訊並沒有被 self-attention 考慮進來,因此,要標示出位置資訊加入計算。

Transformer 的作法是把句子的每個不同位子都給他一個編號, 而每個編號有一個 embedding。 只要這組 embedding 可以有效的把距離表達出來, 我們將輸入加入這個 embedding, 就能夠把字的位置訊息提供給模型。 有點像是把 Mary had a little lamb. 轉成 Mary[字1] had[字2] a[字3] little[字4] lamb[字5].[字6]。 lamb had a little Mary. 轉成 lamb[字1] had[字2] a[字3] little[字4] Mary[字5].[字6]。 這樣的轉換後, 兩個句子中Mary[字1] 和 Mary[字5] 的 self-attention 計算結果一定會不相同。

位置 embedding 可以用模型自學, 但是在 transformer 裏,我們是用以下兩個公式設定好的。 公式中 pos 是位址, i 是 embedding 的維度。

模型自學和公式設定兩種方法在原作都有嘗試過, 結果是效果幾乎一樣。

分段

分段則是偏向文章結構資訊。 transformer 將不同句子用一個 embedding 區分開來。如同在 BERT 中有一個工作的目標是區分不同句子的句意關聯性, 所以加入一個 embedding 來將不同句子分開, 以便模型找出不同句的句意關聯。

Transformer decoder 層

這張圖把 encoder 編碼器 和 decoder 解碼器對比出來,並且繪出資料流動方式, 左手邊是我們學過的 Transformer encoder 右手邊是 transformer decoder。 可以看出 Decoder 部分和 Encoder 很類似,但是 encoder 相比,decoder 多了一层。 現在我們把兩邊的不同在下面說明。

Masked multi-head self-attention Sublayer 遮罩多頭自注意子層

這層和 encoder 的 multi-head attention 子層很像都是 multi-head self attention,唯一不一樣的地方就是 masked,我們的 self-attention 是每個字分別和全句的每個字做 attention,所以在輸入的時候,是整句同時輸入,這樣在翻譯工作的 encoder 是沒有問題的,畢竟被翻譯句總是整句已知的句子, 但是要真正產生翻譯句的時候,我們是不知道全部的被翻譯句子的,只有已經被翻譯的部分是已知,所以,就算是在訓練期, 我們已經有被翻譯句的全文,但是不能讓模型偷看還沒有真正產生翻譯的部分,masked multi-head attention 就是一種技巧,將我們還沒有翻譯出來的部分句子遮蔽起來,其他部分和原來的 multi-head attention 層是一樣的,後面也要加 Add and Norm。

Multi-head encoder-decoder-Attention Sublayer 多頭編碼解碼注意子層

相比於上一層 masked multi-head attention,這層的 attention 目標不一樣。上一層是 self-attention,而這一層的 attention 目標是 encoder 也就是被翻譯句。 簡單來說, 就是 attention 中重要的 Q、K and V,三元素中,Q是 decoder 解碼器的Q,K和V是 encoder 編碼器的K and V。概念上就是翻譯文的每個已經產生字去對被翻譯文的每個字 attention。 也就是拿 Mary 去和 “瑪麗” “有” “一隻” 和 “小羊” 的 embedding 去做 attention。 之後就一樣是加 Add and Norm。

Position-wise Feed Forward Sublayer 位置前饋層

在這邊實作方式和 encoder 層相同,就是全連接層再加 Add and Norm。

Mask 遮罩的處理

Transformer 用的 mask(遮罩) 有兩種。 Padding mask 和 look ahead mask。用途都是把我們不想模型注意到的文字給遮住。讓模型轉而注意可以注意的地方。

Padding mask 填充遮罩

Padding 是 NLP 常用的處理,而深度學習的進行總是以批次進行的。每個批次的輸入值,資料的長度必須一致,這樣才能達到好的併行處理效率,但是自然語言處理的輸入是句子或文章,而句子和文章的長度總是不一定,所以我們每個輸入長度也不定,為了要將每個批次的輸入長度統一,最常用的做法就是填充一些沒有意義的字在短句的尾巴,直到短句和最長句的長度對齊,而這些沒有意義的填充字是我們不希望我們的模型注意的字,比如,”Mary had a little lamb.” 只有六個字元,如果我們的 batch 字長是 10, 補完填充後字串變成 “Mary had a little lamb. [pad] [pad] [pad] [pad] ” 。

Transformer 的做法就是將這些 [pad] 遮罩掉。在做 softmax 前,我們先把這些 [pad] 註記位置。然後將他們的 attention 數值處理到一個很小的數值,讓 softmax 計算過後這些 [pad] 的權重為 0。

Look ahead mask 前窺遮罩

這個遮罩只會用在 decoder ,主要的使用原因在「Masked multi-head self-attention Sublayer 遮罩多頭自注意子層」有說明過。這邊我們說明一下實踐的做法。

當 seq2seq 中翻英翻譯器在 encoder 端收到了”瑪麗有一隻小羊”,在 decoder 端我們要它產生第一個字,我們會向模型輸入一個固定的字 [SOS]。當模型要輸出字的時候,它只能參照所有的中文原句”瑪麗有一隻小羊”和 [SOS]。如果我們的模型訓練的好,它會輸出第一個字 Mary。 這時要輸出第二個字的時候,我們會在 decoder 端輸入兩個字 [SOS] 和第一個輸出字 Mary,我們的模型要輸出時就比上次要多一個字可以參照就是 [SOS] 和 Mary,以此類推。

這個表在上面的藍色表頭是我們的 decoder 的輸入值,而左手邊綠色區是我們每一步的輸出值,1 代表可以,0 代表不可以。

這個問題在推論階段可以用 padding mask 解決,但是在訓練階段,我們輸入的是一整句完整的句子,對於機器而言,如果不處理就會整句輸入進行 self-attention。 所以我們要設定一個 attention mask,讓輸出字永遠只能參照之前的字。這個方法就是將上面表格右上角為 0 的部份遮蔽 (mask) 起來。這個 mask 加在 decoder 後,會讓 decoder 裏的輸入永遠只會參照在它出現前的字。

Output layer 輸出層

輸出層就是一個全連結層,輸出值為 n vocabuary size。經過 softmax 之後可以預測最適合的翻譯詞。

--

--

柯頌竹
Programming with Data

熱愛自由行、參觀各種形式的展覽,踏上過20個國家的領土。歡迎詢問各種在歐洲自由行的問題。偶爾分享一下資料分析的讀書筆記。