簡介
Transformer模型最早是由Google于2017年在“Attention is all you need”一文中提出蜒秤,在論文中該模型主要是被用于克服機器翻譯任務(wù)中傳統(tǒng)網(wǎng)絡(luò)訓練時間過長,難以較好實現(xiàn)并行計算的問題帅刊。后來蚤假,由于該方法在語序特征的提取效果由于傳統(tǒng)的RNN袍嬉、LSTM而被逐漸應(yīng)用至各個領(lǐng)域,如GPT模型以及目前Google最新出品的新貴Bert模型等罐监。相較于傳統(tǒng)的RNN、LSTM或注意力集中機制吆你,Transformer模型已經(jīng)拋棄了以往的時序結(jié)構(gòu)(這也是其為何能夠很好的并行,且訓練速度較快的原因),更準確的來說其實際上是一種編碼機制七问,該編碼同時包括了語義信息(Multi-Head Attention)和位置信息(Positional Encoding)。
transformer 直觀認識:
1. transformer 實質(zhì)上就是一個 encoder decoder 的模型結(jié)構(gòu)有勾,在翻譯任務(wù)中,就是把一個源語言翻譯成對應(yīng)的目標語言雇逞,首先將原句子進行編碼處理encoder 提取句子里的特征势誊,然后將提取到的特征輸入到 decoder 結(jié)構(gòu)進行解碼處理查近,最終輸出結(jié)果目標語言册烈。
2. 跟 seq2seq 模型的處理任務(wù)目標本質(zhì)上是一致的,只不過跟 傳統(tǒng)的循環(huán)神經(jīng)網(wǎng)絡(luò) RNN挽绩,LSTM等最大的區(qū)別是肩民,LSTM 的訓練是迭代的灶搜、串行的,必須要等當前字處理完薪者,才可以處理下一個字。而 Transformer 的訓練時并行的取试,即所有字是同時訓練的悬槽,這樣就大大增加了計算效率。同時 transformer 引入了位置嵌入(Positional Encoding)來處理語言的位置順序瞬浓,使用? 自注意力機制(Self Attention Mechanism)和全連接層進行計算初婆。下面主要從encoder decoder兩部分來記錄其中的模型結(jié)構(gòu)細節(jié)。
Encoder:
encoder部分核心要做的就是:把自然語言序列映射為隱藏層的數(shù)學表達式的過程猿棉。
首先上一張圖:
下面按照圖中的標號記錄:
1. Positional Encoding
1)前面提到了 transformer 跟傳統(tǒng)的循環(huán)神經(jīng)網(wǎng)絡(luò)不同的是它可以并行處理語言序列杖爽,但是這個也帶來另一個問題就是不能像 串行的RNN,LSTM等序列模型一樣帶有語言順序信息元莫,所以google 引入了 位置嵌入的概念。
2)位置嵌入的維度跟詞向量的維度一樣:[max_seq_len, emb_dim ]
max_seq_len:是指定輸入序列為相同的最大長度陡鹃,如果輸入句子不夠的會進行 padding 操作
emb_dim?:是指詞向量和位置向量的維度
transformer 一般會以 字?為單位訓練藕咏,初始化字編碼的大小為:[vocab_size, emb_dim]瓣铣,vocab_size是字庫中所有字的數(shù)量循捺,對應(yīng)到pytorch 中 的實現(xiàn)就是:nn.Embedding(src_vocab_size, emb_dim)
關(guān)于 nn.Embedding 的理解 可以查看我的這篇博客:nn.Embedding - 簡書
3)具體的實現(xiàn)論文中使用的是 和 函數(shù)的線性變換來提供給模型位置信息:
上式中 指的是一句話中某個字的位置,取值范圍是[0, max_seq_len] 裆泳,?指的是字向量的維度序號,取值范圍是 [0 , emb_dim/2 ], ?指的是? emb_dim? 的值
上圖的公式 ,對應(yīng)著? 維度的一組奇數(shù)和偶數(shù)的序列的維度,例如一組,一組,分別用上面的和 函數(shù)處理,從而產(chǎn)生不同的周期變化烈拒,而位置嵌入在? 維度上隨著維度序號增大,周期變化會越來越慢蛋叼,最終產(chǎn)生一種包含位置信息的紋理暴浦,論文原文所講的位置嵌入的周期從 到 變化色鸳,而每一個位置在 ?維度都會得到不同周期的 和 函數(shù)的取值組合社痛,從而產(chǎn)生獨一的紋理位置信息,最終使得模型學到位置之間的依賴關(guān)系和自然語言的時序特性
可以看到圖中每一行對應(yīng)一個詞向量的位置編碼命雀,所以第一行對應(yīng)著輸入序列的第一個詞蒜哀。每行包含512個值,每個值介于1和-1之間吏砂。20字(行)的位置編碼實例撵儿,詞嵌入大小為512(列)『可以看到它從中間分裂成兩半淀歇。這是因為左半部分的值由一個函數(shù)(使用正弦)生成,而右半部分由另一個函數(shù)(使用余弦)生成匈织。然后將它們拼在一起而得到每一個位置編碼向量浪默。位置編碼的方式還有很多,選擇這一種的優(yōu)點是能夠擴展到未知的序列長度(例如缀匕,當我們訓練出的模型需要翻譯遠比訓練集里的句子更長的句子時)纳决,因為這種方式總能體現(xiàn)出序列之間的相對位置關(guān)系。
作者寫了一段代碼取位置編碼向量的四個維度進行可視化:
plt.figure(figsize=(15, 5))
pe = PositionalEncoding(20, 0)
y = pe.forward(Variable(torch.zeros(1, 100, 20)))
plt.plot(np.arange(100), y[0, :, 4:8].data.numpy())
plt.legend(["dim %d"%p for p in [4,5,6,7]])
可以看出乡小,位置編碼基于不同位置添加了正弦波阔加,對于每個維度,波的頻率和偏移都有不同满钟。也就是說對于序列中不同位置的單詞胜榔,對應(yīng)不同的正余弦波胳喷,可以認為他們有相對關(guān)系。
關(guān)于這個位置編碼詳細的可以看看知乎這篇回答:
如何理解Transformer論文中的positional encoding苗分,和三角函數(shù)有什么關(guān)系厌蔽? - 知乎
4) 輸入的句子序列通過了 詞嵌入之后,轉(zhuǎn)換成了word embedding 得到每個字的向量摔癣,然后通過位置編碼層(Positional Encoding)之后得到每個字的位置向量奴饮,將這兩個向量進行直接相加,不是拼接concat择浊,兩個向量的維度一樣:[batch_size,?src_len,?emb_dim]戴卜,得到每個字的最終編碼向量,然后進入下一層琢岩。
2. Self Attention Mechanism
1)關(guān)于自注意力機制的原理投剥,首先是定義三個矩陣:,使用這三個矩陣對每個字向量進行三次線性變換,使得每個字向量衍生出三個新的向量:;接著把所有的向量拼成一個大矩陣糕篇,叫做查詢矩陣啄育,將所有的向量拼接成鍵矩陣記作,將所有的向量拼接成值矩陣記作。這個對應(yīng)到里就是使用一個 nn.Linear()進行? ??
2)然后自注意力機制就是把每個字向量對應(yīng)的查詢向量去跟每個字對應(yīng)的鍵向量(包括自己的)做點積得到一個值拌消,這里得到的值就可以體現(xiàn)兩個字之間的相關(guān)程度挑豌,為什么呢?首先在數(shù)學里面的定義墩崩,向量之間的內(nèi)積就是表示兩個向量之間的關(guān)系氓英,內(nèi)積越大,表示兩個向量越相關(guān)鹦筹,所以這個地方每個向量跟其他向量的點積就可以代表跟序列中的每個詞的相關(guān)程度铝阐。這就是自注意力的核心。下圖以第一個詞為例去做點積:
每個字向量衍生出三個向量:
然后將點積得到的結(jié)果經(jīng)過一個盛龄,是的其相加為1
得到權(quán)重之后將這個權(quán)重分別乘以對應(yīng)的字的值向量
最后將這些權(quán)重化后的值向量求和饰迹,得到第一個字的輸出:
整個過程下面這張圖可以看到:
其他字向量經(jīng)過同樣的操作就可以得到通過 self-attention 之后的全部輸出:
3)上面是以一句話為例,依次遍歷每個字向量經(jīng)過 attention 操作余舶,實際中這樣效率不高,可以采取矩陣相乘的方式進行批量操作锹淌,不是計算出某一個時刻的,而是一次性計算出所有時刻的,計算過程如下:
這里的是矩陣代表一句話匿值,每一行代表一個字的向量表示
然后將,然后除以,經(jīng)過之后再乘得到輸出
這種通過 query 和 key 的相似性程度來確定 value 的權(quán)重分布的方法被稱為scaled dot-product attention赂摆,這里為什么要除以一個?進行縮放呢挟憔?實際上是的最后一個維度钟些,當越大,就越大绊谭,可能會將softmax函數(shù)推入梯度極小的區(qū)域政恍,所以引引入一個調(diào)節(jié)因子,使得內(nèi)積不至于太大.
Multi-Head Attention:
論文中提出了一個多頭注意力機制达传,實際上是一樣的篙耗,就是定義多組,分別去關(guān)注不同的上下文,計算過程完全一樣宪赶,只是線性變換從一組變成多組而已宗弯,如圖:
? ? 然后每一組得到一個輸出矩陣,多組就得到多組,最后將多組進行concat:
實際上Multi-Head-Attention 就是將 embedding 之后的按維度切割成個搂妻,分別做self-attention之后再合并在一起.
padding mask:
transformer的計算過程了解之后蒙保,里面有一個細節(jié)需要注意就是,在進行詞嵌入的時候欲主,通常會根據(jù)一個??進行補0的 padding 操作邓厕,但是在計算上面一系列相關(guān)權(quán)重的時候,是每個維度都參與計算扁瓢,并且都會經(jīng)過一個:
,這樣的話 padding 的部分就會參與運算详恼,這樣顯然不行,于是需要做一個 mask 操作涤妒,讓這些無效的區(qū)域不參與運算单雾,一般是給無效區(qū)域加一個很大的負數(shù)偏置,即:
3. 殘差連接和歸一化:
殘差連接就是她紫,將輸入注意力層之前的字向量硅堆,與經(jīng)過自注意力層之后的輸出層的向量相加:
? ??????????????????????
至于為什么要加這么一層呢?殘差連接到底啥意思:
一般來說贿讹,深度學習的套路就是依靠誤差的鏈式反向傳播來進行參數(shù)更新渐逃,隨著深度網(wǎng)絡(luò)層數(shù)的加深,帶來了一系列問題民褂,如梯度消失茄菊,梯度爆炸,模型容易過擬合赊堪,計算資源的消耗等問題面殖。隨著網(wǎng)絡(luò)層數(shù)的增加發(fā)生了網(wǎng)絡(luò)退化現(xiàn)象,loss先是下降并趨于飽和哭廉,然后loss增加脊僚。
這些問題有一些解決方案,比如 drop_out 層用來防止過擬合遵绰,隨機丟棄神經(jīng)元對網(wǎng)絡(luò)結(jié)構(gòu)進行輕量化處理辽幌,一定程度上解決數(shù)據(jù)集小和網(wǎng)絡(luò)復雜的情況下的過擬合問題增淹。或者Rule層(y=max(0乌企,x))主要用來防止梯度消失問題虑润。
先看看殘差網(wǎng)絡(luò)的百度百科定義:
?殘差網(wǎng)絡(luò)的特點是容易優(yōu)化,并且能夠通過增加相當?shù)纳疃葋硖岣邷蚀_率加酵。其內(nèi)部的殘差塊使用了跳躍連接拳喻,緩解了在深度神經(jīng)網(wǎng)絡(luò)中增加深度帶來的梯度消失問題。
深入理解可以看原論文:《Deep Residual Learning for Image Recognition》
直觀理解就是:我們可以使用一個非線性變化函數(shù)來描述一個網(wǎng)絡(luò)的輸入輸出虽画,即輸入為X舞蔽,輸出為F(x),F(xiàn)通常包括了卷積码撰,激活等操作渗柿,強行將一個輸入添加到函數(shù)的輸出;
為什么這么做脖岛,深度學習的套路就是依靠誤差的鏈式反向傳播來進行參數(shù)更新朵栖,鏈式法則求導的過程中一旦其中某一個導數(shù)很小,多次連乘后梯度可能越來越小柴梆,就是常說的梯度消散陨溅,對于深層網(wǎng)絡(luò),傳到淺層幾乎就沒了绍在。但是如果使用了殘差门扇,每一個導數(shù)就加上了一個恒等項1,此時就算原來的導數(shù)df/dx很小偿渡,這時候誤差仍然能夠有效的反向傳播臼寄,這就是核心思想。
具體的理解可以看這篇:【模型解讀】resnet中的殘差連接溜宽,你確定真的看懂了吉拳? - 知乎
Layer Normalization
Layer Normalization 的作用是把神經(jīng)網(wǎng)絡(luò)中隱藏層歸一為標準正態(tài)分布,也就是??獨立同分布适揉,以起到加快訓練速度留攒,加速收斂的作用。
因為神經(jīng)網(wǎng)絡(luò)的訓練過程本質(zhì)就是對數(shù)據(jù)分布的學習嫉嘀,因此訓練前對輸入數(shù)據(jù)進行歸一化處理顯得很重要炼邀。我們知道,神經(jīng)網(wǎng)絡(luò)有很多層剪侮,每經(jīng)過一個隱含層汤善,訓練數(shù)據(jù)的分布會因為參數(shù)的變化而發(fā)生改變,導致網(wǎng)絡(luò)在每次迭代中都需要擬合不同的數(shù)據(jù)分布票彪,這樣子會增加訓練的復雜度以及過擬合的風險红淡。
因此我們需要對數(shù)據(jù)進行歸一化處理(均值為0,標準差為1)降铸,把數(shù)據(jù)分布強制統(tǒng)一在一個數(shù)據(jù)分布下在旱,而且這一步不是一開始做的,而是在每次進行下一層之前都需要做的推掸。也就是說桶蝎,在網(wǎng)絡(luò)的每一層輸入之前增加一個當前數(shù)據(jù)歸一化處理,然后再輸入到下一層網(wǎng)路中去訓練谅畅。
layer normalization 的做法是在每一個樣本上計算均值和方差登渣;用每一列的每一個元素減去這列的均值,再除以這列的標準差毡泻,從而得到歸一化后的數(shù)值胜茧。圖中另外一種是 batch normalization,是在batch 上計算均值和方差仇味,可以使得數(shù)據(jù)收斂更快呻顽,但是缺點會比較明顯,比如當Batch size很小的適合丹墨,BN的效果就非常不理想了廊遍。在很多情況下,Batch size大不了贩挣,因為你GPU的顯存不夠喉前。
Feed Forward:
前饋神經(jīng)網(wǎng)絡(luò),進行兩次線性變換加上一個激活函數(shù)王财,信息流向下一個block卵迂,起到提取特征的作用,序列此時的模塊可以并行的流向獨立的前饋神經(jīng)單元搪搏,不像self-attention 層狭握,每個序列單元之間不是獨立的,存在某種關(guān)聯(lián)疯溺。
下面是整個encoder部分的結(jié)構(gòu)圖:
輸入?x1,x2?經(jīng) self-attention 層之后變成?z1,z2论颅,然后和輸入?x1,x2?進行殘差連接,經(jīng)過 LayerNorm 后輸出給全連接層囱嫩。全連接層也有一個殘差連接和一個 LayerNorm恃疯,最后再輸出給下一個 Encoder(每個 Encoder Block 中的 FeedForward 層權(quán)重都是共享的),多個這樣的層堆疊起來墨闲,最后才得到輸出今妄,其中每個block的內(nèi)容都是一樣的。
下面是關(guān)于encoder部分的總結(jié):
1)字向量與位置編碼:
? ??????????????
2)自注意力機制:
? ??????????????
? ??????????????
? ??????????????
? ??????????????
3)self-attention 殘差連接與 Layer Normalization
? ??????????????
? ??????????????
4)下面進行 Encoder block 結(jié)構(gòu)圖中的第 4 部分,也就是 FeedForward盾鳞,就是兩層線性映射并用激活函數(shù)激活犬性,比如說?ReLU
? ??????????????
5)FeedForward 殘差連接與 Layer Normalization:
? ??????????????
? ??????????????
Decoder:
終于來到decoder了,跟encoder實際上差不多腾仅,先看看整體的圖:
1. Masked Multi-Head Attention:
1)跟encoder一樣乒裆,以翻譯任務(wù)為例,首先會將目標句子推励,圖中就是 Outputs 進行自編碼轉(zhuǎn)換成字向量鹤耍,再經(jīng)過位置編碼(Positional Encoding),然后經(jīng)過一個 decoder 部分的 self-attention,這里的自注意力機制跟encoder的操作基本一樣验辞,除了為補齊句子長度而做的padding 部分進行 mask之外稿黄,還有一個 mask,這個mask是為了防止作弊的跌造,一般叫做 sequence mask.
2)傳統(tǒng) Seq2Seq 中 Decoder 使用的是 RNN 模型杆怕,因此在訓練過程中輸入?t?時刻的詞,根據(jù)之前序列來處理句子的每一個時刻的輸入鼻听,模型無法看到未來時刻的詞财著,因為循環(huán)神經(jīng)網(wǎng)絡(luò)是時間驅(qū)動的,只有當?t?時刻運算結(jié)束了撑碴,才能看到?t+1?時刻的詞撑教。
而 Transformer Decoder 拋棄了 RNN,改為 Self-Attention醉拓,由此就產(chǎn)生了一個問題伟姐,在訓練過程中,整個 ground truth 都暴露在 Decoder 中亿卤,這顯然是不對的愤兵,我們需要對 Decoder 的輸入進行一些處理,見下圖:
decoder的輸入同樣經(jīng)過attention之后產(chǎn)生的矩陣稱為:Scaled Scores排吴,例如輸入句子:
"<start> I am fine"秆乳,當我們輸入 "I" 時,模型目前僅知道包括 "I" 在內(nèi)之前所有字的信息钻哩,即?
"<start>" 和 "I" 的信息屹堰,不應(yīng)該讓其知道 "I" 之后詞的信息,因為做預測的時候是一個詞預測完了之后再根據(jù)之前的信息街氢,然后好預測下一個詞的信息扯键,所以如果此時模型實現(xiàn)就知道之后的信息板辽,那就是作弊了呀圣拄,所以這個時候的處理是:首先生成一個下三角全 0,上三角全為負無窮的矩陣骏令,然后將其與 Scaled Scores 相加即可,之后再做 softmax厉亏,就能將 - inf 變?yōu)?0董习,得到的這個矩陣即為每個字之間的權(quán)重:
2)Masked Encoder-Decoder Attention:
模型經(jīng)過了Decoder Self-Attention 層之后就進入下一個模塊,這也是一個 masked attention叶堆,只不過這里的是encoder的輸出阱飘,是 Decoder 的 Masked Self-Attention,操作跟前面一樣虱颗,直接看圖就好:
在訓練過程中,模型沒有收斂得很好時蔗喂,Decoder預測產(chǎn)生的詞很可能不是我們想要的忘渔。這個時候如果再把錯誤的數(shù)據(jù)再輸給Decoder,就會越跑越偏缰儿。這個時候怎么辦畦粮?decoder 的時候是把上一個時刻的輸出和當前時刻的輸入一起傳給下一個解碼單元網(wǎng)絡(luò)。
(1)在訓練過程中可以使用 “teacher forcing”乖阵。因為我們知道應(yīng)該預測的word是什么宣赔,那么可以給Decoder喂一個正確的結(jié)果作為輸入。
(2)除了選擇最高概率的詞 (greedy search)瞪浸,還可以選擇是比如 “Beam Search”儒将,可以保留topK個預測的word。 Beam Search 方法不再是只得到一個輸出放到下一步去訓練了对蒲,我們可以設(shè)定一個值钩蚊,拿多個值放到下一步去訓練,這條路徑的概率等于每一步輸出的概率的乘積蹈矮。
Ending part:
整個 transform 就梳理完了砰逻,用一張圖直觀的表示其結(jié)構(gòu)就是 多個encoder 和 decoder 層的堆疊 特征提取器具:
優(yōu)點:
(1)每層計算復雜度比RNN要低。
(2)可以進行并行計算泛鸟。
(3)從計算一個序列長度為n的信息要經(jīng)過的路徑長度來看, CNN需要增加卷積層數(shù)來擴大視野蝠咆,RNN需要從1到n逐個進行計算,而Self-attention只需要一步矩陣計算就可以北滥。Self-Attention可以比RNN更好地解決長時依賴問題刚操。當然如果計算量太大,比如序列長度N大于序列維度D這種情況碑韵,也可以用窗口限制Self-Attention的計算數(shù)量赡茸。
(4)從作者在附錄中給出的例子可以看出,Self-Attention模型更可解釋祝闻,Attention結(jié)果的分布表明了該模型學習到了一些語法和語義信息占卧。