Transformer論文逐段精讀【論文精讀】

transformer
- 最近三年以內(nèi)深度學(xué)習(xí)里面最重要的文章之一
- 可以認為是開創(chuàng)了繼MLP、CNN、RNN之后的第四大類模型
1、標(biāo)題:Attention is all you need
作者后面打上星號表示同等貢獻

2、摘要
在主流的序列轉(zhuǎn)錄模型里面,主要是依賴于比較復(fù)雜的循環(huán)或者是卷積神經(jīng)網(wǎng)絡(luò),一般是使用encoder和decoder的架構(gòu)
- 序列轉(zhuǎn)錄模型:給定一個序列,然后生成另外一個序列,比如機器翻譯
在性能最好的模型之中,通常也會在編碼器和解碼器之間使用注意力機制
這篇文章提出了一個新的簡單的架構(gòu)(simple,之前都傾向于寫成novel),這個模型僅僅依賴于注意力機制,而沒有用之前的循環(huán)或者卷積
做了兩個機器翻譯的實驗,顯示這個模型在性能上特別好,可以并行度更好然后使用更少的時間來訓(xùn)練
模型達到了28.4的BLEU
- BLEU score:機器翻譯里面常用的一個衡量標(biāo)準(zhǔn)
這篇文章一開始寫的時候是針對機器翻譯這個小任務(wù)寫的,但是隨著之后BERT、GPT把這個架構(gòu)用在更多的語言處理的任務(wù)上的時候,整個工作就出圈了,最近用在了圖片和video上面,幾乎什么東西都能用
3、結(jié)論
transformer這個模型是第一個僅僅使用注意力機制做序列轉(zhuǎn)錄的模型,將之前的循環(huán)層全部換成了multi-headed self-attetion
在機器翻譯的這個任務(wù)上面,transformer能夠訓(xùn)練的比其他的架構(gòu)都要快很多,而且在實際的結(jié)果上確實是效果更好
作者對于這種純基于注意力機制的模型感到非常激動,作者想要把它用在文本以外的別的數(shù)據(jù)上面,使得生成不那么時序化也是另外的一個研究方向
這篇文章所有的代碼放在tensor2tensor這個庫里面,作者將整個代碼放在了結(jié)論的最后(如果有代碼的話,通常會把這個代碼放在摘要的最后一句話,因為現(xiàn)在神經(jīng)網(wǎng)絡(luò)的文章里面細節(jié)通常是比較多的,簡簡單單的一篇文章很難把所有的細節(jié)都講清楚,所以最好第一時間公布代碼,讓別人能夠很方便地復(fù)現(xiàn)文章,然后這樣就能夠擴大文章的影響力)
4、導(dǎo)言
這里的導(dǎo)言寫的比較短,基本可以認為是前面摘要的前面一半的擴充
在時序模型里面,2017最常用的是RNN、LSTM、GRU,有兩個比較主流的模型:
- 一個叫做語言模型
- 另一個是當(dāng)輸出結(jié)構(gòu)化信息比較多的時候會使用編碼器和解碼器架構(gòu)
RNN的特點
- RNN中給定一個序列,它的計算是把這個序列從左到右一步一步往前做,假設(shè)序列是一個句子的話,就是一個一個詞,對第t個詞會計算出一個輸出叫做ht(也叫做它的隱藏狀態(tài)),ht是由前面一個詞的隱藏狀態(tài)(h(t-1))和當(dāng)前第t個詞本身決定的,這樣就可以把前面學(xué)到的歷史信息通過h(t-1)放到當(dāng)下,然后和當(dāng)前的詞做一些計算,然后得到輸出
RNN如何有效處理時序信息的關(guān)鍵:他將之前的信息全部放在隱藏狀態(tài)里,然后一個一個放下去。他的問題也來自于這里:
- 他是一個一步一步計算(時序)的過程,比較難以并行,在時間上難以并行,使得在計算上性能比較差
- 歷史信息是一步一步地往后傳遞的,如果時序比較長的話,那么很早期的時序信息在后面的時候可能丟掉,如果不想丟掉的話,可能需要ht要比較大,如果要做比較大的ht,在每一個時間步都得把他存下來,導(dǎo)致內(nèi)存開銷比較大。
attention在RNN上的應(yīng)用
- 在這篇文章之前,attention已經(jīng)成功地用在編碼器和解碼器里面了,主要是用在怎么樣把編碼器的東西有效地傳給解碼器
這篇文章提出來的transformer是一個新的模型,不再使用之前被大家使用的循環(huán)神經(jīng)層,而是純基于注意力機制,并行度比較高,這樣的話它能夠在比較短的時間之內(nèi)做到比之前更好的結(jié)果
NeurIPS是一個篇幅比較短的會議,單列八頁
5、相關(guān)工作
如何使用卷積神經(jīng)網(wǎng)絡(luò)替換循環(huán)神經(jīng)網(wǎng)絡(luò),減少時序的計算
主要問題:用卷積神經(jīng)網(wǎng)絡(luò)的話,對于比較長的序列難以建模
- 卷積做計算的時候每次是去看一個比較小的窗口,如果兩個像素相隔比較遠的話,需要用很多層卷積堆積起來,最后才能夠把這兩個隔得比較遠的像素融合起來。但是如果是使用transformer里面的注意力機制的話,每一次都能夠看到所有的像素,使用一層就能看到整個序列
- 卷積的好處是可以做多個輸出通道,一個輸出通道可以認為是識別不一樣的模式,作者也想要實現(xiàn)這種效果,所以提出了一個叫做multi-headed attention(多頭注意力機制),用于模擬卷積神經(jīng)網(wǎng)絡(luò)多輸出通道的一個效果
自注意力機制
memory networks
6、模型
序列模型里面比較好的是編碼器和解碼器的架構(gòu)
- 編碼器:將一個長為n的x1到xn的輸入,編碼器會把它表示成為一個也是長為n但是其中每一個zt對應(yīng)xt的向量的表示,這就是編碼器的輸出,就是將原始的輸入變成機器學(xué)習(xí)可以理解的一系列向量
- 解碼器:拿到編碼器的輸出,然后生成一個長為m的一個序列(n和m是不一樣長的,可以一樣,也可以不一樣)。他和編碼器最大的不同之處在于,在解碼器中,詞是一個一個生成的(因為對于編碼器來講,很可能是一次性能看全整個句子,但是在解碼的時候只能一個一個的生成),即自回歸(auto-regressive),在這里面輸入又是輸出,在過去時刻的輸出也會作為當(dāng)前時刻的輸入?18:13?
- transformer是使用了編碼器和解碼器的架構(gòu),具體來講它是將自注意力和point-wise、fully connected layers一個一個堆在一起

- 寫論文的話,有一張比較漂亮的能夠把整個全局話清楚的圖是非常重要的

- 上圖是一個編碼器和解碼器的架構(gòu)

- 左邊圈出來的部分是編碼器,右邊圈出來的部分是解碼器
- 左下角的input是編碼器的輸入,如果是中文翻英文的話,輸入就是中文的句子
- 右下角的outputs是解碼器的輸入,解碼器在做預(yù)測的時候是沒有輸入的,實際上就是解碼器在之前時刻的一些輸出作為輸入
- shifted right就是一個一個往右移
- input embedding:嵌入層。進來的是一個一個的詞,需要將它們表示成向量
- poositional encoding:
- Nx:N代表層數(shù)

- 紅色圓圈圈出來的部分可以看作transformer block
- multi-headed attention
- feed forward:前饋神經(jīng)網(wǎng)絡(luò)
- add&norm:add表示殘差的連接

- 編碼器的輸出會作為解碼器的輸入

- 解碼器和編碼器有點像,紅色圓圈圈出來的部分是一樣的,但是多了下面的masked multi-headed attention(多頭注意力機制)

- 解碼器可以認為是紅色圓圈中的三部分組成的一個塊重復(fù)n次
- 解碼器的輸出進入一個輸出層,然后做一個softmax就能得到最終的輸出

- 紅色方括號所擴起來的部分就是標(biāo)準(zhǔn)的神經(jīng)網(wǎng)絡(luò)的做法
- 上圖所示的確是一個標(biāo)準(zhǔn)的編碼器解碼器的架構(gòu),只是說中間的每一塊有所不同,然后是編碼器和解碼器之間的連接有所不同
具體模塊的實現(xiàn)
編碼器
編碼器是用一個n等于6的一個完全一樣的層,下圖中的紅色陰影部分算作一層,然后重復(fù)6次
- 每一個layer中會有2個sub-layer
- 第一個sub-layer叫做multi-headed self-attention
- 第二個sub-layer是一個simple position-wise fully connected feed-forward network,說白了就是一個MLP
- 對于每一個子層采用了一個殘差連接,最后再使用layer normalization

- 子層的公式如下圖中黃色高亮部分所示

- sublayer(x):輸入進來以后先進入子層
- x+sublayer(x):因為是殘差連接,所以將輸入和輸出加在一起,最后進入他的layernorm
- 因為殘差連接需要輸入和輸出是一樣大小的,如果大小不一樣的話,需要做投影,為了簡單起見,講么一個層的輸出維度變成512(固定長度表示是的模型相對來說是比較簡單的,調(diào)參的話只需要調(diào)一個參數(shù)就行了,就是模型的輸出維度,另外一個參數(shù)是要復(fù)制多少塊n)
layernorm
通過和batchnorm對比來解釋一下什么是layernorm
考慮一個最簡單的二維輸入的情況,在二維輸入的情況下輸入是一個矩陣,每一行是一個樣本,每一列是一個特征

batchnorm所干的事情就是每一次將每一列(特征)在它的一個小mini-batch里面的均值變成零,方差變成1
- 把這個向量本身的均值減掉,然后再除以他的方差就可以了
- 在計算均值的時候,是在每個小批量里面(一條向量里面算出他的均值和方差)
- 在訓(xùn)練的時候可以做小批量,在預(yù)測的時候會把全局的均值算出來
- 在預(yù)測的時候會把全局的均值算出來,整個數(shù)據(jù)掃一遍之后,在所有數(shù)據(jù)上平均的均值方差存起來,在預(yù)測的時候再使用

- batchnorm還會學(xué) lambda和beta 出來:可以把向量通過學(xué)習(xí)放成一個方差為任意某個值,均值為任意某個值的東西
layernorm和batpchnorm在很多時候幾乎是一樣的
- 對于一個同樣的二維輸入來說(最簡單的情況),layernorm對每個樣本做normalization而不是對每個特征做normalization(之前是將每個列的均值變?yōu)?,方差變?yōu)?,現(xiàn)在是把每一個行變成均值為0,方差為1,這里的每一個行表示一個樣本,所以可以認為layernorm就是把整個數(shù)據(jù)轉(zhuǎn)置一下放到batchnorm里面出來的結(jié)果,再轉(zhuǎn)置回去)
- 在transformer或者正常的RNN里面,輸入是一個三維的東西,輸入的是一個序列的樣本,每一個樣本其實里面有很多元素(比如一個句子里面有n個詞,每個詞有個向量hebatch的話,就是一個3D的東西)。最大的正方形表示batch(樣本),但是列不再是特征了,而是序列的長度(sequence),對每個sequence(每個詞)都有自己的向量,即feature

- 如果還是用batchnorm的話,每次是取一根特征,然后把他的每個樣本里面的所有元素,以及他的整個batch取出來,如下圖立方體中藍色正方形所示,然后把他的均值變?yōu)?方差變成1,就相當(dāng)于是切一塊下來然后拉成一個向量,然后再進行運算

- 如果是laynorm的話,就是對每個樣本進行橫切,如上圖立方體中橘黃色正方形所示
切法不一樣會帶來不同的效果,為什么layernorm用的多一點?
- 在時序序列模型中,每個樣本的長度可能會發(fā)生變化,如下圖中紅色陰影所示,沒有的東西一般是會放零進去

- 如果是用batchnorm的話,切出來的效果如下圖中所示,其余地方補零

- 如果是layernorm的話,切出來的效果如下圖所示

- 這里主要的問題是在算均值和方差上面,對于batchnorm來說,會對上圖中切出來的階梯形的部分進行求解(只有這部分是有效值,其他地方因為是補零,所以其實沒有太多作用),如果樣本長度變化比較大的時候,每次做小批量的時候,算出來的均值和方差的抖動相對來說是比較大的
- 另外,在做預(yù)測的時候要把全局的均值和方差記錄下來,這個全局的均值和方差如果碰到一個新的預(yù)測樣本,如果碰到一個特別長的,因為在訓(xùn)練的時候沒有見過這種長度的,那么在之前計算的均值和方差可能就不那么好用了。
- 相反,對于layernorm相對來說沒有太多的問題,因為他是按照每個樣本來進行均值和方差的計算,同時也不需要存下一個全局的均值和方差(不管樣本的長短,均值和方差的計算都是以樣本為單位的),這樣的話相對來講更穩(wěn)定一些
解碼器
解碼器跟編碼器很像,跟編碼器一樣是由(n=6)個同樣的層構(gòu)成的,每個層里面跟編碼器一樣有兩個子層
解碼器和編碼器的不同之處在于解碼器里面用了第三個子層,他同樣是多頭的注意力機制,跟編碼器一樣同樣用了殘差連接,用了layernorm
解碼器中做的是自回歸,也就是說當(dāng)前的輸出的輸入集是上面一些時刻的輸出,意味著在做預(yù)測的時候不能看到之后的那些時刻的輸出
- 在注意力機制中,每一次能夠看到完整的輸入,這里要避免這個情況的發(fā)生,也就是說在解碼器訓(xùn)練的時候,在預(yù)測第t個時刻的輸出時候不應(yīng)該看到t時刻以后的那些輸入,他的做法是通過一個帶掩碼的注意力機制,如下圖中的masked所示,這也是與解碼器其他地方的不同之處,這個masked的作用是保證輸入進來的時候,在t時間是不會看到t時間以后的那些輸入,從而保證訓(xùn)練和預(yù)測的時候行為是一致的

子層
注意力層
注意力:注意力函數(shù)是一個將 query 和一些 key-value對 映射成輸出的函數(shù)
- 里面所有的query、key-value、輸出都是向量
- 輸出是value的加權(quán)和,所以輸出的維度和value的維度是一樣的
- 對于每一個value的權(quán)重,他是value對應(yīng)的key和query的相似度(compatibility function,不同的注意力機制有不同的算法,不同的相似度函數(shù)導(dǎo)致不一樣的注意力的版本)計算得來的?34:45?
transformer中使用到的注意力機制:
scaled dot-product attention
- query和key長度是等長的,都等于dk(可以不等長的,不等長有別的計算方法)
- value的長度等于dv(輸出的長度也應(yīng)該是dv)
- 具體的計算方法:對每一個query和key最內(nèi)積,然后將其作為相似度(如果兩個向量做內(nèi)積的話,如果這兩個向量的 long 是一樣的,那么內(nèi)積的值(余弦值)越大,就表示這兩個向量的相似度就越高,如果內(nèi)積等于零(兩個向量正交),就是說這兩個向量沒有相似度),算出來之后再除以根號dk(即向量的長度),然后再用softmax來得到權(quán)重。因為對于一個query,假設(shè)給n個key、value對的話,就會算出n個值,因為這個query會跟每個key做內(nèi)積,算出來之后再放進softmax就會得到n個非負的和為1的權(quán)重(對于權(quán)重來說,非負、和為1是比較好的權(quán)重),然后將這些權(quán)重作用在value上面,就能得到輸出了。
- 在實際中不能一個一個做運算,運算起來比較慢,文章提出query可以寫成矩陣,可能不只是一個query,也可能有n個query,query的個數(shù)和key value的個數(shù)可能是不一樣的,但是長度一定是一樣的,這樣才能做內(nèi)積
- 給定query和key這兩個矩陣,相乘就會得到一個n*m的矩陣,如下圖所示,他的每一行(如圖中藍色的線所示),就是一個query對所有key的內(nèi)積值,再除以根號dk后做softmax(對每一行做softmax,行與行之間是獨立的),這樣就能得到權(quán)重,然后再乘V(V是一個m行dv列的矩陣),得到一個n*dv的矩陣(這個矩陣的每一行就是所需要的輸出)

- 對于key、value對和n個query,可以通過兩次矩陣乘法來做整個計算,key和value在實際中對應(yīng)的就是序列,這樣就等價于是在并行地計算里面的每個元素(矩陣乘法便于并行)
文中所提出的注意力機制和其他注意力機制的區(qū)別
一般有兩種比較常見的注意力機制
- 加型注意力機制:可以處理query和key不等長的情況
- 點積注意力機制:點積注意力機制和文中所提出的注意力機制是一樣的(唯一的區(qū)別就是文中所提出來的注意力機制多除以了一個根號dk,這個根號dk就是命名中提到的scaled)
這兩種注意力機制其實都差不多,文章選用的是點積注意力機制,因為實現(xiàn)起來比較簡單,而且效果比較好,兩次矩陣乘法就能算好
這里為什么要除以根號dk?
- 當(dāng)dk不是很大的時候除不除都沒關(guān)系,但是當(dāng)dk比較大的時候,也就是兩個向量長度比較長的時候,做點積的時候值可能比較大也可能比較小
- 當(dāng)值比較大的時候,向量之間相對的差距就會變大,就導(dǎo)致值最大的那個值進行softmax操作后就會更接近1,剩下的值就會更靠近于0,值就會向兩極分化,當(dāng)出現(xiàn)這種情況后,在算梯度的時候,梯度會比較?。╯oftmax最后的結(jié)果是所希望的預(yù)測值置信的地方盡量靠近1,不置信的地方盡量靠近0,這樣就差不多收斂了,梯度就會變得比較小,就會跑不動)
- 在transformer里面一般用的dk比較大(512),所以除以根號dk是一個不錯的選擇
整個注意力機制的計算過程如下圖左圖所示

- Q代表query矩陣
- K代表key矩陣
- mask主要是為了避免在第t時刻的時候看到以后時間的東西,具體來說,假設(shè)query和key是等長的,長度都為n,而且在時間上是能對應(yīng)起來的,對第t時刻的qt在做計算的時候,應(yīng)該只是看到k1一直到k(t-1),而不應(yīng)該看到kt和它之后的東西,因為kt在當(dāng)前時刻還沒有。
- 但是在做注意力機制的時候,會發(fā)現(xiàn)其實qt在跟所有k里面的東西全部做運算,從k1一直算到kn,只要保證在計算權(quán)重的時候,不要用到后面的東西就可以了
- mask是說對于qt和kt之后的用于計算的那些值,把他們替換成非常大的負數(shù),這些大的負數(shù)在進入softmax做指數(shù)的時候就會變成0,所以導(dǎo)致softmax之后出來對應(yīng)的權(quán)重都會變成0,而kt之前所對應(yīng)的值會有權(quán)重
- 這樣在計算輸出的時候就只用到了v對應(yīng)的v1一直到v(t-1)的結(jié)果,而vt后面的東西并沒有用到
- 所以mask的效果是在訓(xùn)練的時候,讓第t個時間的query只看到對應(yīng)的前面的那一些key、value對,使得在做預(yù)測的時候能夠進行一一對應(yīng)
multi-head
與其做一個單個的注意力函數(shù),不如把整個query、key、value投影到一個低維,投影h次,然后做h次的注意力函數(shù),再將每一個函數(shù)并在一起,再投影回來得到最終的輸出,如下圖右圖所示

- 原始的value、key、query進入一個線性層(線性層將其投影到比較低的維度),然后再做一個scaled dot-product attention(如上圖左圖所示),做h次,得到h個輸出,再把這些輸出向量全部合并到一起,最后做一次線性的投影,然后回到multi-head attetion
為什么要做多頭注意力機制?
- dot-product的注意力中沒有什么可以學(xué)的參數(shù),具體函數(shù)就是內(nèi)積。有時候為了識別不一樣的模式,希望有一些不一樣的計算像素的辦法
- 如果是用加型attention的話,里面其實是有一個權(quán)重可以學(xué)習(xí)到的,但是本文使用的是內(nèi)積,它的做法是先投影到低維,這個投影的w是可以學(xué)的,也就是說,有h次機會希望可以學(xué)到不一樣的投影方法,使得再投影進去的度量空間中能夠匹配不同模式所需要的相似函數(shù),然后最后把所得到的東西再做一次投影(這里有點像在卷積神經(jīng)網(wǎng)絡(luò)里面有多個輸出通道的感覺)
- 具體的計算(公式如下圖):在multi-head的情況下,還是以前的Q、K、V,但是輸出已經(jīng)是不同頭的輸出做contact運算再投影到一個WO里面,對每一個頭,就是把Q、K、V通過不同的可以學(xué)習(xí)的WQ、WK、WV投影到dv上面,再做注意力函數(shù),然后再出來就可以了

- 實際上h是等于8的,就是用8個頭
- 注意力的時候,因為有殘差連接的存在,使得輸入和輸出的維度是一樣的,所以他投影的時候,投影的就是輸出的維度除以h(因為輸出維度是512,除以8之后,就是每一次把它投影到64維的維度,然后在這個維度上面計算注意力函數(shù),最后再投影回來)
- 雖然公式中看起來有很多小矩陣的乘法,實際上在實現(xiàn)的時候也可以通過一次矩陣的乘法來實現(xiàn)(可以作為一個練習(xí)題來練習(xí)如何實現(xiàn))
在transformer模型中是如何實現(xiàn)注意力的?
三種實現(xiàn)情況

- 上圖中三個陰影表示三個注意力層,這三個注意力層各不相同
第一個注意力曾的使用:

- 上圖中紅色圈出來的部分是編碼器的注意力層。編碼器的輸入(假設(shè)句子長度是n的話,他的輸入其實是n個長為d的向量,每一個輸入的詞對應(yīng)的是一個長為d的向量,一共有n個)
- 這個注意力層有三個輸入,分別表示的是key、value、query。這里一根線復(fù)制成三根線表示同樣一個東西,既作為key,也作為value和query,這個東西叫做自注意力機制,就是說key、value和query其實是一個東西,就是他自己本身
- 這里輸入了n個query,每個query會得到一個輸出,最終會得到n個輸出,而且這個輸出和value因為長度是一樣的,所以輸出的維度其實也是d,即輸入和輸出的大小其實是一樣的,輸出長也為n。
- 輸出其實就是value的加權(quán)和,權(quán)重來自query和key?49:48?
- 假設(shè)不考慮多頭和有投影的情況,輸出其實是輸入的加權(quán)和,權(quán)重來自于自己本身跟各個向量之間的相似度。如果有多頭的話,因為有投影,會學(xué)習(xí)出h個不一樣的距離空間出來,使得得出來的東西會有點不一樣
第二個注意力層的使用:

- 如上圖中紅色圓圈圈出的部分所示
- 解碼器也是一樣的,也是同一個東西復(fù)制了三次
- 解碼器的輸入也是一樣的,只是長度可能變成了m,維度其實也是一樣的,所以它跟編碼器一樣的也是自注意力,唯一不一樣的是里面有一個mask(mask的作用:在解碼器計算query對應(yīng)的輸出的時候,不應(yīng)該看到第t時刻后面的東西,意味著后面的東西要設(shè)為0)
第三個注意力層:

- 如上圖中紅線箭頭所指的部分
- 它不再是自注意力了,key和value來自編碼器的輸出,query來自解碼器下一個attention的輸入
- 編碼器最后一層的輸出就是n個長為d的向量
- 解碼器的masked attention的輸出是m個長為d的向量
- 編碼器的輸出作為key和value傳入到這個注意力層中,解碼器的下一層輸出作為query傳入到這個注意力層中,意味著對于解碼器的每一個輸出,作為query要計算出一個所要的輸出,這個輸出是來自于value的一個加權(quán)和(來自于編碼器的輸出的加權(quán)和,權(quán)重的粗細程度取決于query與編碼器輸出的相似度,如果相似度比較高的話,權(quán)重就會大一點,相反,如果相似度比較低的話,權(quán)重就會小一點)
- 這個attention中所要做的其實就是有效地把編碼器里面的輸出根據(jù)需要截取出來。例如?53:20?
- attention如何在編碼器和解碼器之間傳遞信息的時候起作用:根據(jù)在解碼器輸入的不同,根據(jù)當(dāng)前的向量在編碼器的輸出里面挑選感興趣的東西,也就是去注意感興趣的東西,那些不那么感興趣的東西就可以忽略掉
feed forward:
其實就是一個fully connected feed-forward network,就是一個MLP,但是不同之處在于他是applied to each position seperately and identically(就是把同一個MLP對每個詞作用一次,即position-wise,說白了就是MLP只是作用在最后一個維度)
- position:輸入序列中有很多個詞,每一個詞就是一個點,這些點就是position
- 具體公式如下圖所示,xW1+b1就是一個線性層,max就是relu激活層,最后再有一個線性層

- 在注意力層的輸入(每一個query對應(yīng)的輸出)的長為512,x就是一個512的向量,W1會把512投影成2048(等價于將他的維度擴大了4倍),以為最有有殘差連接,所以還需要投影回去,所以W2又把2048投影回512
- 這其實就是一個單隱藏層的MLP,中間的隱藏層將輸入擴大4倍,最后輸出的時候又回到輸入的大?。ㄈ绻胮ytorch來實現(xiàn)的話其實就是把兩個線性層放在一起,而不需要改任何參數(shù),因為pytorch在輸入是3d的時候,默認就是在最后一個維度做計算)
整個transformer是如何抽取序列信息,然后把這些序列信息加工成最后所想要的語義空間向量?
首先考慮一個最簡單的情況(沒有殘差連接、attention也是單頭、沒有投影),如下圖所示

輸入就是長為n的向量,在進入attention之后,就會得到同樣長度的輸出,最簡單的attention其實就是對輸入進行加權(quán)求和,加權(quán)和之后進入MLP,每個MLP對每一個輸入的點做運算會得到輸出,最后就得到整個transformer塊的輸出(輸入和輸出的大小都是一樣的)
- 在整個過程中attetion所起到的作用就是把整個序列里面的信息抓取出來做一次匯聚(aggregation),因為已經(jīng)抓取序列中感興趣的信息,所以在做投影、MLP、映射成為更想要的語義空間的時候,因為加權(quán)之后的結(jié)果已經(jīng)包含了序列種的信息,所以每個MLP只要再每個點獨立進行運算就行了,因為序列信息已經(jīng)匯聚完成,所以在做MLP的時候是可以分開做的
作為對比,RNN(沒有隱藏層的MLP,純線性)的實現(xiàn)過程
RNN的輸入也是向量,對于第一個點也是做一個線性層
對于下一個點,如何利用序列信息,還是用之前的MLP(權(quán)重跟之前是一樣的),但是時序信息(下圖中綠色曲線表示之前的信息,藍色曲線表示當(dāng)前的信息)方面,是將上一個時刻的輸出放回來作為輸入的一部分與第二個點一起作為輸入,這樣就完成了信息的傳遞
RNN和transformer都是用一個線性層或者MLP來進行語義空間的轉(zhuǎn)換,但是不同之處在于傳遞序列信息的方式:RNN十八上一時刻信息的輸出傳入下一時候做輸入,但是在transformer中是通過attention層全局地拉取整個序列里面的信息,然后再用MLP做語義轉(zhuǎn)換
- 他們的關(guān)注點都是如何有效地使用序列信息
embeding
因為輸入是一個一個的詞(或者叫詞源,token),需要將其映射成向量。embeding的作用就是給任何一個詞,學(xué)習(xí)一個長為d的向量來表示它(本文中d等于512)
- 編碼器的輸入需要embeding
- 解碼器的輸入也需要embeding
- 在softmax前面的線性也需要embeding
本文中這3個embeding是一樣的權(quán)重,這樣子訓(xùn)練起來會簡單一點
另外還將權(quán)重乘了根號d:維度一大的話,權(quán)重值就會變小,之后要加上positional encoding,他不會隨著長度變長把他的long固定住,因此乘上了根號d之后,使得他們在scale差不多
positional encoding
attention不會有時序信息,輸出是value的加權(quán)和,權(quán)重是query和key之間的距離,和序列信息無關(guān)(也就是說給定一句話,把順序任意打亂之后,attetion出來的結(jié)果都是一樣的,順序會變,但是值不會變,這樣是存在問題的,所以需要把時序信息加入進來)
RNN是如何添加時序信息的?RNN將上一個時刻的輸出作為下一個時刻的輸入來傳遞歷史信息
attention是在輸入里面加入時序信息,將輸入詞所在的位置信息加入到輸入里面(positional encoding),具體公式如下圖所示

- 在計算機中,數(shù)字是用一定長度的向量來表示的
- 詞在嵌入層會表示成一個長為d的向量,同樣用一個長為d的向量來表示數(shù)字,也就是詞的位置,這些數(shù)字的不同計算方法是用周期不一樣的sin和cos函數(shù)的值來算出來的,所以說任何一個值可以用長為d的向量來表示,然后這個長為d的記錄了時序信息的向量和嵌入層相加,就完成了將時序信息加進數(shù)據(jù)中的操作,如下圖中的紅色線團所示,因為是cos和sin的函數(shù)所以是在+1和-1之間抖動的,所以乘了一個根號d,使得每個數(shù)字也是差不多在正負1的數(shù)值區(qū)間里面

4、為什么要用自注意力?
相對于使用循環(huán)層或者卷積層,使用自注意力有多好
下表比較了四種不一樣的層

- 第一個是自注意力層
- 第二個是循環(huán)層
- 第三個是卷積層
- 第四個是構(gòu)造出來的受限的自注意力
- 第一列是計算復(fù)雜度,越低越好
- 第二列是順序的計算,越少越好。指的是在算layer的時候,下一步計算必須要等前面多少步計算完成。相當(dāng)于是說非并行度
- 第三列說的是信息從一個數(shù)據(jù)點走到另一個數(shù)據(jù)點要走多遠,越短越好
- n是序列的長度
- d是向量的長度
- 整個自注意力就是幾個矩陣做運算,其中一個矩陣運算時query矩陣(n行,n個query,列數(shù)是d,也就是維度是d)乘以key矩陣(也是n*d),兩個矩陣相乘,算法復(fù)雜度就是n平方乘以d,別的矩陣運算復(fù)雜度也是一樣的。因為只是牽涉到矩陣的運算,矩陣中可以認為并行度是比較高的,所以是o(1),最大長度是說從一個點的信息想跳到另一個點要走多少步,在attention里面,一個query可以跟所有的key做運算,而且輸出是所有value的加權(quán)和,所以query跟任何一個很遠的key、value對只要一次就能過來,所以長度是比較短的
- 對循環(huán)層來說,如果序列是乘了n的話就一個一個做運算,每個里面主要的計算就是n*n的矩陣的dense layer然后再乘以長為d的輸入,所以是n平方,然后要做n次,所以是n*d平方
- 對比自注意力和RNN的計算復(fù)雜度,其實是有一定的區(qū)別的,取決于n大還是d大。在本文中d是512,n也差不多是幾百,現(xiàn)在比較大的模型d可以做到2048甚至更大,n相對來說也會做的比較多,所以現(xiàn)在看起來其實這兩種的計算復(fù)雜度是差不多的(n和d在差不多的數(shù)據(jù)上面),但是在循環(huán)的時候因為要一步一步做運算,當(dāng)前時刻的值需要等待前面完成,所以導(dǎo)致了是一個長為n的序列化的操作,在并行上比較吃虧。在最初點的那個歷史信息到最后一個點的時候需要走過n步才能過去,所以循環(huán)的最長距離是o(n),即RNN對特別長的序列的時候做的不夠好,因為信息從一開始走,走著走著就走丟了,而不是像attention一樣直接一步就能到
- 卷積在序列上的具體做法是用一個1d的卷積,所以它的kernel就是k,n是長度,d就是輸入的通道數(shù)和輸出的通道數(shù),所以這里是k乘n乘d的平方。k一般不大(一般是3或者5,所以一般可以認為是常數(shù)),所以導(dǎo)致卷積的復(fù)雜度和RNN的復(fù)雜度差不多,但是卷積的好處在于只用卷積就完成了,并行度很高,所以卷積做起來通常比RNN要快一點,另外卷積每一次一個點是由一個長為k的窗口來看,所以信息在k距離內(nèi)是能夠一次完成傳遞的,如果超過k的話,傳遞信息就需要通過多層一層一層上去,但是由于是log的操作,所以也不會有太大的麻煩
- 最后一個層是在做注意力的時候,query只跟最近的r個鄰居做運算,這樣就不用算n平方了,但是問題在于這樣的話,兩個比較長的遠一點的點需要走幾步才能過來
- 一般來說使用attetion主要是關(guān)心對于特別長的序列是否能將整個信息揉的比較好一點所以在實際過程中,帶限制的自注意力使用的不是特別多,一般都是用最原始的版本,而不做受限,所以基本就是考慮前三種層
- 實際中,當(dāng)序列的長度和整個模型的寬度差不多而且深度都一樣的話的時候,基本上前三個模型的算法復(fù)雜度都是差不多的,attention和卷積相對來說計算會好一點,attention在信息的糅合性上會好一點,所以用了self-attention看上去對長數(shù)據(jù)處理更好一些,但是實際上attention對整個模型做了更少的假設(shè),導(dǎo)致需要更多的數(shù)據(jù)和更大的模型才能訓(xùn)練出來跟RNN和CNN同樣的效果,所以導(dǎo)致現(xiàn)在基于transformer的模型都特別大
7、實驗
訓(xùn)練的一些設(shè)置
訓(xùn)練數(shù)據(jù)集和batching
使用了兩個任務(wù):
- 英語翻德語標(biāo)準(zhǔn)的WMT 2014的數(shù)據(jù),里面有4.5w個句子,使用了byte-pair encoding(bpe,不管是英語還是德語,一個詞里面有很多種變化,如果直接把每個詞做成一個token的話,會導(dǎo)致字典里面的東西會比較多,而且一個動詞可能有好幾種不同的變化形式,在做成不一樣的詞的時候,它們之間的區(qū)別模型是不知道的,bpe相對來說就是把詞根給提出來,這樣的好處是整個字典比較?。@里使用的是37000個token的字典,他是在英語和德語之間共享的,也就是說不再為英語構(gòu)造一個字典也不再為德語構(gòu)造一個字典,這樣的好處是整個編碼器和解碼器的embeding就可以使用同一個東西,而且整個模型變得更加簡單,也就是之前說的編碼器和解碼器的embeding是權(quán)重共享的
- 英語翻法語:使用了一個更大的數(shù)據(jù)集
硬件和schedule
- 訓(xùn)練使用了8個P100的GPU,后來使用tpu(tpu更適合做大的矩陣乘法)
- base模型使用小一點的參數(shù),每一個batch訓(xùn)練的時間是0.4秒,一共訓(xùn)練了10w步,一共在8臺gpu上訓(xùn)練了12個小時(基本上一個模型訓(xùn)練12個小時也是一個不錯的性能)
- 這個大的模型,一個batch訓(xùn)練需要一秒鐘,一共訓(xùn)練了30W步,最后一臺機器訓(xùn)練了3.5天,其實也是一個可以承受的范圍
在訓(xùn)練器上使用的是Adam
學(xué)習(xí)率是根據(jù)以下公式計算出來的:學(xué)習(xí)律是根據(jù)模型寬度的-0.5次方(就是說當(dāng)模型越寬的時候,學(xué)習(xí)的向量越長的時候,學(xué)習(xí)率會低一點)

- 存在一個warmup,就是從一個小的值慢慢地爬到一個高的值,爬到之后,再根據(jù)步數(shù)按照0.5次方衰減,最后warmup是4000
- 學(xué)習(xí)率幾乎是不用調(diào)的:第一,adam對學(xué)習(xí)率不敏感;學(xué)習(xí)率已經(jīng)把模型考慮進來了,schedule也已經(jīng)算是不錯的schedule了,所以學(xué)習(xí)率是不需要調(diào)的
正則化
總共使用了三個正則化
residual dropout:對每一個子層(包括多頭的注意力層和之后的MLP),在每個層的輸出上,在進入殘差連接之前和進入到layernorm之前,使用dropout(dropout率為0.1,也就是把輸出的10%的那些元素值乘0.1,剩下的值乘1.1)。另外在輸入加上詞嵌入再加上position encoding的時候,也用了一個dropout。也就是說,基本上對于每一個帶權(quán)重的層,在輸出上都使用了dropout,雖然dropout率不是特別高,但是使用了大量的dropout層來對模型做正則化
label smoothing(inception v3)
使用softmax去學(xué)東西的時候,正確的標(biāo)號是1,錯誤的標(biāo)號是0,對于正確的label的softmax值,讓他去逼近于1,但是softmax的值是很難去逼近于1的,因為他里面是指數(shù),比較soft(需要輸出接近無限大的時候,才能逼近于1),這樣使得訓(xùn)練比較困難。
一般的做法是不要搞成特別難的0和1,可以把1的值往下降一點,比如降成0.9,本文中是直接降成了0.1,就是說對于正確的那個詞,只需要softmax的輸出(置信度)到0.1就可以了,而不需要特別高,剩下的值就可以是0.9除以字典大小,這里會損失perplexity(log lost做指數(shù)),基本上可以認為是模型的不確信度(正確答案只要10%是對的就行了,不確信度會增加,所以這個值會變高),但是在模型不那么確信的情況下會提升精度和BLUE的分數(shù)(這兩個才是真正所要關(guān)心的點)
下表表示的是不同的超參數(shù)之間的對比

- n表示要堆多少層
- d表示模型的寬度,即token進來要表示成一個多長的向量
- dff表示MLP中間隱藏層的輸出的大小
- h表示注意力層的頭的個數(shù)
- dk、dv分別是一個頭里面key和value的維度
- Pdrop表示dropout的丟棄率
- els表示最后label smoothing的時候要學(xué)的label的真實值是多少
- train steps表示要訓(xùn)練多少個batch?01:19:55?
- 整個模型參數(shù)相對來說還是比較簡單的,基本上能調(diào)的就是上面的這些超參數(shù)剩下的東西基本上都是可以按比例算過來的,這也是transformer的一個好處,雖然看上出模型比較復(fù)雜,但是實際上沒有太多可以調(diào)的東西,這個設(shè)計對后面的人來說相對更加方便一點
8、評價
寫作
- 非常簡潔,每一句上基本上在講一個事情
- 沒有使用太多的寫作技巧
- 這種寫法并不是很推薦,因為對一篇文章來說,需要講一個故事來讓讀者有代入感,能夠說服讀者
- 一般說可以選擇把東西減少一點,甚至把一些不那么重要的東西放在附錄里面,但是在正文的時候,最好還是講個故事:為什么做這些事情以及設(shè)計的理念、對整個文章的一些思考,這讓會使得文章更加有深度
transformer模型
- 現(xiàn)在不僅僅是用在機器翻譯上,也能夠用在幾乎所有的NLP任務(wù)上面,在bert,gpt,后續(xù)能夠訓(xùn)練很大的預(yù)訓(xùn)練模型,能夠極大提升所有NLP任務(wù)的性能,類似于CNN對整個計算機視覺的改變:能夠訓(xùn)練一個大的CNN模型,使得別的任務(wù)也能夠從中受益,CNN使得整個計算機視覺的研究者提供了一個同樣的框架,使得只要學(xué)會CNN就行了,而不需要去管以前跟任務(wù)相關(guān)的海量專業(yè)知識(比如特征提取、任務(wù)建模等)
- 對于transformer來說,之前需要做各種各樣的數(shù)據(jù)文本的預(yù)處理,然后根據(jù)NLP的任務(wù)設(shè)計不也一樣的架構(gòu),現(xiàn)在不需要了,使用了整個transforner架構(gòu)就能夠在各個任務(wù)上取得非常好的成績,而且它的預(yù)訓(xùn)練模型也讓大家的訓(xùn)練變得更加簡單
- 現(xiàn)在transformer不僅僅是用在自然語言上面,也在圖片、語音、video上面取得了很大的進展
- 之前計算機視覺的研究者使用CNN,而在語言處理使用RNN,在別的方面用別的模型,現(xiàn)在發(fā)現(xiàn)同樣一個模型能夠在所有領(lǐng)域都能用,讓大家的語言的一樣了,任何一個領(lǐng)域的研究做的一些突破能夠很快地在別的領(lǐng)域被使用,能夠極大地減少一個新的技術(shù)在機器學(xué)習(xí)里面各個領(lǐng)域被應(yīng)用的時間
- 人對世界的感知是多模態(tài)的:圖片、文字、語音,現(xiàn)在transformer能夠把這些所有不同的數(shù)據(jù)給融合起來,因為大家都用一個同樣的架構(gòu)抽取特征的話,就可以抽取到一個同樣的語義空間,使得我們可以用文本、圖片、語音、視頻等訓(xùn)練更好更大的模型
- 雖然transformer這些模型取得了非常好的實驗性的結(jié)果,但是對它的理解還是處于比較初級的階段。
- 雖然標(biāo)題說只需要attention就夠了,但是最新的研究表明,attention只是在transformer里面起到把整個序列的信息聚合起來的作用,但是后面的MLP以及殘差連接是缺一不可的,如果把這些東西去掉的話,attention基本上什么東西都訓(xùn)練不出來所以模型也不只是說只需要attention就夠了
- attention根本就不會對數(shù)據(jù)的順序做建模,為什么能夠打贏RNN呢?RNN能夠顯示建模的序列信息理論上應(yīng)該比MLP效果更好現(xiàn)在大家覺得它使用了一個更廣泛的歸納偏置,使得他能夠處理一些更一般化的信息,這也是為什么說attetion并沒有做任何空間上的一些假設(shè),它也能夠跟CNN甚至是比CNN取得更好的結(jié)果,但是他的代價是因為他的假設(shè)更加一般,所以他對數(shù)據(jù)里面抓取信息的能力變差了,以至于說需要使用更多的數(shù)據(jù)、更大的模型,才能訓(xùn)練出想要的效果,這也是為什么現(xiàn)在transformer模型越來越大
- attention也給了研究者一些鼓勵,原來CNN和RNN之外也會有新的模型能打敗他們?,F(xiàn)在也有一些工作說,就用MLP或者就用一些更簡單的架構(gòu)也能夠在圖片或者文本上面取得很好的結(jié)果
- 未來肯定會有很多新的架構(gòu)出現(xiàn),讓整個領(lǐng)域更加有意思一些
----end----