机器学习笔记:Transformer
1 傳統Seq2Seq的不足
? ? ? 傳統seq2seq 使用 bi-direction RNN,那么生成每個b的時候,對于輸入的整個序列,模型都需要看過一遍。
? ? ? 問題在于,這樣的用bi-direction RNN 實現的seq2seq,它卻沒有辦法并行操作,也就是說,我b1~b4必須一個一個計算。
1.1 改進1 使用CNN代替RNN
一個三角形代表一個filter,每個filter處理輸入的一小段(在這里,比如說我每個filter處理輸入的單個vector,輸出一個數值)
我們同一層可以有多個filter,每個filter對每一段輸入,輸出一個標量數值。
把這些標量concat起來,就成了一個sequence,每個sequence對應了一個輸出的vector
但如果CNN的改進只到這里,是沒有太多的意義的。因為雖然也是seq2seq,但我們output的每一個只受到相對應的input的影響,我們的output并不會由其他的vector-input左右。
于是這時候我們可以疊加幾層CNN(但這樣參數就會變多了):
高層CNN可以看到更多的“output vector”(比如這里,我們藍色的filter處理b1~b3,那么相當于這時候的輸出會綜合考慮a1~a3的信息)
CNN的問題在于,想要獲得更多點的信息,就需要多層CNN,一層肯定是不夠的。那么此時的參數量是非常大的。
2 和self-attention的對比
?3 transformer 逐結構講解
3.1 總覽
機器學習筆記:神經網絡層的各種normalization_UQI-LIUWJ的博客-CSDN博客
layer normalization:每個變量分別進行歸一化?
?
3.2 input embedding
輸入一個句子(batch_size,sequence_length)【后者表示一個sequence有幾個字】,
再經過一個字編碼 ,把維度變成三維的(batch_size,sequence_length,embedding_dimension) 【每一個字編碼長度為 embedding dimension】
3.3?positional encoding
在前面的self-attention中,我們發現,我們并沒有利用到input的各個元素的位置信息(就是不管你在哪個位置,不管兩個點是遠還是近,兩個點誰在前面等等,我只做加權求和而已)。
為了使用vector-input 的位置信息,我們引入了positional encoding(每個字位置嵌入的維數和詞向量的維數是一樣的,都是embedding_dimension)。
我們從xi 經過input embedding后,得到ai。然后對每個ai加上一個位置嵌入ei,將這個求和結果進行之后的運算,生成的q,k,v。
理論上ei也可以學,在“attention is all you need”中,ei直接人為設定了。
3.3.1 臺大李宏毅教授對ei的理解
假設每個位置一開始我們有一個one-hot的embedding pi。哪個位置為1,就表示它在那個位置。
我們把pi 拼接到原來的xi下面 將整個vector進行embedding(乘上的矩陣W,一部分是xi需要乘的W,另一部分是pi相對應的Wp)
那么結果一部分是input embedding ai,另一部分是positional embedding ei
3.3.2 位置嵌入的思想
比較容易想到的第一個方法是取 [0,1] 之間的數分配給每個字,其中 0 給第一個字,1 給最后一個字,具體公式就是 ?PE=pos/(seq_l?1)。
這樣做的問題在于,假設在較短文本中任意兩個字位置編碼的差為 0.0333,同時在某一個較長文本中也有兩個字的位置編碼的差是 0.0333。假設較短文本總共 30 個字,較長文本總共 90 個字。那么較短文本中的這兩個字其實是相鄰的,而較長文本中這兩個字中間實際上隔了兩個字。
這顯然是不合適的,因為相同的差值,在不同的句子中卻不是同一個含義。
另一個想法是線性的給每個時間步分配一個數字,也就是說,第一個單詞被賦予 1,第二個單詞被賦予 2,依此類推。
這種方式也有很大的問題:
1. 它比一般的字嵌入的數值要大,難免會搶了字嵌入的「風頭」,對模型可能有一定的干擾;
2. 最后一個字比第一個字大太多,和字嵌入合并后難免會出現特征在數值上的傾斜。
3.3.3 理想情況下的位置嵌入
理想情況下,位置嵌入的設計應該滿足以下條件:
- 它應該為每個字輸出唯一的編碼
- 不同長度的句子之間,任何兩個字之間的差值應該保持一致
- 它的值應該是有界的
3.3.4?位置編碼的實現
pos是一句話中某個字的位置,取值范圍是[0,max_sequence_length](一個輸入sequence的最大長度,理論上所有的sequence都需要補齊至這個長度)。
i?指的是字向量的維度序號,取值范圍是?[0,?embedding_dimension/2)。位置嵌入隨著維度序號的增大,周期性變化會越來越慢(周期變大)。
?dmodel指的就是?embedding_dimension?的值。
也就是說,我這個字在sequence中是第幾位確定了之后,字里面的每一位信息我們都需要進行處理(奇數歸奇數,偶數歸偶數)。
每一個位置在?embedding?dimension?維度上都會得到不同周期的?sin?和?cos?函數的取值組合,從而產生獨一的紋理位置信息,最終使得模型學到位置之間的依賴關系和自然語言的時序特性。
3.3.5?位置編碼舉例
舉一個例子,假設我們每一個word用16維表示(embedding_dimension),一個sequence最大100個word(max_sequence_length),那么我們positional encoding的維度為(100,16)
#導入庫 import numpy as npmax_len_seq=100 embedding_dim=16positional_encoding=[]for pos in range(max_len_seq):#對sequence中每個元素進行操作lst=[]for i in range(embedding_dim): #分奇偶分別考慮if(i%2==0):lst.append(np.sin(pos/np.power(10000,i/embedding_dim)))else:lst.append(np.cos(pos/np.power(10000,i-1/embedding_dim))) positional_encoding.append(lst) positional_encoding=np.array(positional_encoding) positional_encoding.shape #(100, 16)可視化:
import seaborn import matplotlib.pyplot as plt seaborn.heatmap(positional_encoding) plt.xlabel('dimension') plt.ylabel('seq_len')3.4 SELF-ATTENTION
對于輸入的句子?X,通過 WordEmbedding 得到該句子中每個字的字向量,同時通過 Positional Encoding 得到所有字的位置向量。將兩者相加(維度相同,可以直接相加),得到該字真正的向量表示。第?t?個字的向量記作?xt。
接著我們定義三個矩陣?Wq,Wk,Wv,使用這三個矩陣分別對所有的字向量進行三次線性變換,于是所有的字向量又衍生出三個新的向量?qt,kt,vt。(乘以一個矩陣,相當于一次線性變換)
我們將所有的?qt?向量拼成一個大矩陣,記作查詢矩陣?Q。
3.4.1 self-attention舉例:
記q1=[1,0,2] 、K=[[0,4,2], [1,4,3], [1,0,1]]
之后還需要將得到的值經過 softmax,使得它們的和為 1(見下圖)。為了方便起見,我們將權重設置為[0,0.5,0.5]
即V=[[1,2,3] , [2,8,0], [2,6,3]]
對其它的輸入向量也執行相同的操作,即可得到通過 self-attention 后的所有輸出。
3.4.2 self-attention 矩陣計算
第一步就不是計算某個時刻的?qt,kt,vt?了,而是一次計算所有時刻的?Q,K?和?V。計算過程如下圖所示,這里的輸入是一個矩陣?X,矩陣第?t?行表示第?t?個詞的向量表示?xt。
(這里配圖錯了,V應該在softmax的左邊,左乘softmax的結果
Z的每一行都是X的每一個sequence的embedding
3.4.3?Multi-Head Attention
"Attention is all you need"中說到,進行 Multi-head Attention 的原因是將模型分為多個頭,形成多個子空間,可以讓模型去關注不同方面的信息,最后再將各個方面的信息綜合起來。
其實直觀上也可以想到,如果自己設計這樣的一個模型,必然也不會只做一次 attention,多次 attention 綜合的結果至少能夠起到增強模型的作用,也可以類比 CNN 中同時使用多個卷積核的作用。
直觀上講,多頭的注意力有助于網絡捕捉到更豐富的特征 / 信息。
3.4.4?padding mask
上面 Self Attention 的計算過程中,我們通常使用 mini-batch 來計算,也就是一次計算多句話。?X?的維度是?[batch_size, sequence_length],sequence_length?是句長,而一個 mini-batch 是由多個不等長的句子組成的。我們需要按照這個 mini-batch 中最大的句長(也就是3.3.4中所說的max_sequence_length)對剩余的句子進行補齊,一般用 0 進行填充,這個過程叫做 padding。
但這時在進行 softmax 就會產生問題?;仡?softmax 函數?,其中=1,是有值的。這樣的話 softmax 中被 padding 的部分就參與了運算,相當于讓無效的部分參與了運算,這可能會產生很大的隱患。
因此需要做一個 mask 操作,讓這些無效的區域不參與運算(也就是為0),一般是給無效區域加一個很大的負數偏置,即
原來的矩陣(比如):
padding矩陣(padding的部分填負無窮,原來有值的部分填0):
mask之后的結果:
這樣,所以padding部分不參與權重的計算(計算權重的時候是softmax,也就是Q和K乘積的結果,但是X padding部分為負無窮,進行線性變化后還是負無窮。傳到Q和K里面還是負無窮。乘積結果也是負無窮。所以到softmax的時候也是負無窮)?
3.5 殘差連接
這是一個cv ResNet里面的應用,這邊就直接搬運過來了。
我們在上一步得到了經過 self-attention 加權之后的輸出,也就是?Attention(Q,?K,?V),然后把他和原來X的embedding加起來做殘差連接。
3.6 layer normalization
layer normalization的作用——每一個特征都滿足標準正態分布
batch normalization的作用——每一個training example的各個特征之間滿足正態分布
3.7 feed forward?
linear——>relu——>linear
作用是提取特征(先維度增加,再維度減少,以保證輸出和輸入的維度一模一樣【因為還要送入下一個encoder】)
3.8?decoder-masked self-attention
decoder的大部分在前面 Encoder 里我們已經介紹過了,但是 Decoder 由于其特殊的功能,因此在訓練時會涉及到一些和encoder不同的細節。
具體來說,傳統 Seq2Seq 中 Decoder 使用的是 RNN 模型,因此在訓練過程中輸入?t?時刻的詞,模型無論如何也看不到未來時刻的詞,因為循環神經網絡是時間驅動的,只有當?t?時刻運算結束了,才能看到?t+1?時刻的詞。
而 Transformer Decoder 拋棄了 RNN,改為 Self-Attention,由此就產生了一個問題,在訓練過程中,整個 ground truth 的sequence都暴露在 Decoder 中,不過不加以限制的話,任何時刻decoder都可以看到整個序列。這顯然是不對的,我們需要對 Decoder 的輸入進行一些處理,該處理被稱為 decoder的Mask。
記V=
| V11 | V12 | V13 | V14 |
| V21 | V22 | V23 | V24 |
| V31 | V32 | V33 | V34 |
| V41 | V42 | V43 | V44 |
然后V左乘softmax的結果
| V11 | V12 | V13 | V14 | 1 | 0 | 0 | 0 | |
| V21 | V22 | V23 | V24 | × | 0.37 | 0.62 | 0 | 0 |
| V31 | V32 | V33 | V34 | 0.26 | 0.31 | 0.43 | 0 | |
| V41 | V42 | V43 | V44 | 0.21 | 0.26 | 0.26 | 0.26 |
第一個元素送入decoder之后,兩者相乘的方式如下所示。也就是說,第一個送入decoder的元素,會影響到之后所有的output(因為之后的元素都可以知道這個元素的信息)
| V11 | V12 | V13 | V14 | 1 | 0 | 0 | 0 | |
| V21 | V22 | V23 | V24 | × | 0.37 | 0.62 | 0 | 0 |
| V31 | V32 | V33 | V34 | 0.26 | 0.31 | 0.43 | 0 | |
| V41 | V42 | V43 | V44 | 0.21 | 0.26 | 0.26 | 0.26 |
第二個元素送入decoder之后,兩者相乘的方式如下所示。也就是說,第二個送入decoder的元素,會影響到之后所有的output(因為之后的元素都可以知道這個元素的信息)。但不可以影響第一個元素的output,因為第一個元素送入decoder的時候,還不知道第二個元素的信息。
| V11 | V12 | V13 | V14 | 1 | 0 | 0 | 0 | |
| V21 | V22 | V23 | V24 | × | 0.37 | 0.62 | 0 | 0 |
| V31 | V32 | V33 | V34 | 0.26 | 0.31 | 0.43 | 0 | |
| V41 | V42 | V43 | V44 | 0.21 | 0.26 | 0.26 | 0.26 |
3.9 Decoder-Masked Encoder-Decoder Attention
前面的masked self-attention指的是3.8節的mask方法,即上三角矩陣都是-inf。
4 transformer 總結
->encoder板塊,我們的input先進行embedding,然后加上位置向量ei。
->之后的結果放入mult-head attention。
->接著進行add&layer norm(基本上RNN有的地方都有layer norm,transformer和RNN作用上可以互相代替)。
->decoder板塊,首先我們最底下的輸入是上一個time step的輸出(一開始就是句子起始符)。
->然后也是加上位置向量ei。
->結果放入masked multihead attention
為什么要masked呢,因為我們輸出的部分是一點一點變多的,這里我們只能看到我們目前已經生成了的部分的sequence。
->將這個sequence和encoder的輸出放到一塊,經過一個mult-head attention
->然后又是add&layer norm Linear output等等
4.1 stacked?
輸入?x1,x2?經 self-attention 層之后變成?z1,z2,然后和輸入?x1,x2?進行殘差連接,經過 LayerNorm 后輸出給全連接層。
全連接層也有一個殘差連接和一個 LayerNorm,最后再輸出給下一個 Encoder(每個 Encoder Block 中的 FeedForward 層權重都是共享的)。
decoder也是一樣,每層decoder將自己的輸出,以及encoder的輸出并在一塊,送給下一個decoder,作為下一層decoder的Q,K,V。
總結
以上是生活随笔為你收集整理的机器学习笔记:Transformer的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文巾解题 10. 正则表达式匹配
- 下一篇: 文巾解题 26. 删除有序数组中的重复项