熱文:原創(chuàng) | Attention is all you need 論文解析(附代碼)
作者:楊金珊審校:陳之炎本文約4300字,建議閱讀8分鐘“Attention is all you need”一文在注意力機(jī)制的使用方面取得了很大的進(jìn)步,對(duì)Transformer模型做出了重大改進(jìn)。
目前NLP任務(wù)中的最著名模型(例如GPT-2或BERT),均由幾十個(gè)Transformer或它們的變體組成。
背景
(資料圖片僅供參考)
減少順序算力是擴(kuò)展神經(jīng)網(wǎng)絡(luò)GPU、ByteNet和ConvS2S的基本目標(biāo),它們使用卷積神經(jīng)網(wǎng)絡(luò)作為基本構(gòu)建塊,并行計(jì)算所有輸入和輸出位置的隱含表示。在這些模型中,將來(lái)自兩個(gè)任意輸入或輸出位置的信號(hào)關(guān)聯(lián)起來(lái),所需的操作數(shù)量隨著位置距離的增加而增加,對(duì)于ConvS2S來(lái)說(shuō),二者是線性增長(zhǎng)的;對(duì)于ByteNet來(lái)說(shuō),二者是對(duì)數(shù)增長(zhǎng)的。這使得學(xué)習(xí)遙遠(yuǎn)位置之間的依賴(lài)關(guān)系變得更加困難。在Transformer中,將操作數(shù)量減少到一個(gè)恒定數(shù)值,這是以降低有效分辨率為代價(jià)的,因?yàn)樾枰獙?duì)注意力權(quán)重位置做平均,多頭注意力(Multi-Head Attention)抵消了這一影響。
為什么需要transformer
在序列到序列的問(wèn)題中,例如神經(jīng)機(jī)器翻譯,最初的建議是基于在編碼器-解碼器架構(gòu)中使用循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)。這一架構(gòu)在處理長(zhǎng)序列時(shí)受到了很大的限制,當(dāng)新元素被合并到序列中時(shí),它們保留來(lái)自第一個(gè)元素的信息的能力就喪失了。在編碼器中,每一步中的隱含狀態(tài)都與輸入句子中的某個(gè)單詞相關(guān)聯(lián),通常是最鄰近的那個(gè)單詞。因此,如果解碼器只訪問(wèn)解碼器的最后一個(gè)隱含狀態(tài),它將丟失序列的第一個(gè)元素相關(guān)的信息。針對(duì)這一局限性,提出了注意力機(jī)制的概念。
與通常使用RNN時(shí)關(guān)注編碼器的最后狀態(tài)不同,在解碼器的每一步中我們都關(guān)注編碼器的所有狀態(tài),從而能夠訪問(wèn)有關(guān)輸入序列中所有元素的信息。這就是注意力所做的,它從整個(gè)序列中提取信息,即過(guò)去所有編碼器狀態(tài)的加權(quán)和,解碼器為輸出的每個(gè)元素賦予輸入的某個(gè)元素更大的權(quán)重或重要性。從每一步中正確的輸入元素中學(xué)習(xí),以預(yù)測(cè)下一個(gè)輸出元素。
但是這種方法仍然有一個(gè)重要的限制,每個(gè)序列必須一次處理一個(gè)元素。編碼器和解碼器都必須等到t-1步驟完成后才能處理第t-1步驟。因此,在處理龐大的語(yǔ)料庫(kù)時(shí),計(jì)算效率非常低。
什么是Transformer
Transformer是一種避免遞歸的模型架構(gòu),它完全依賴(lài)于注意力機(jī)制來(lái)繪制輸入和輸出之間的全局依賴(lài)關(guān)系。Transformer允許顯著的并行化……Transformer是第一個(gè)完全依靠自注意力來(lái)計(jì)算輸入和輸出的表示,而不使用序列對(duì)齊的RNN或卷積的傳導(dǎo)模型。
圖1Transformer架構(gòu)從圖1可以觀察到,左邊是一個(gè)編碼器模型,右邊是一個(gè)解碼器模型。兩者都包含一個(gè)重復(fù)N次的“一個(gè)注意力和一個(gè)前饋網(wǎng)絡(luò)”的核心塊。但為此,首先需要深入探討一個(gè)核心概念:自注意力機(jī)制。
Self-Attention基本操作
Self-attention是一個(gè)序列到序列的操作:一個(gè)向量序列進(jìn)去,一個(gè)向量序列出來(lái)。我們稱(chēng)它們?yōu)檩斎胂蛄? ,…,和相應(yīng)的輸出向量, ,…,。這些向量的維數(shù)都是k。要產(chǎn)生輸出向量,Self-attention操作只需對(duì)所有輸入向量取加權(quán)平均值,最簡(jiǎn)單的選擇是點(diǎn)積。在我們的模型的Self-attention機(jī)制中,我們需要引入三個(gè)元素:查詢、值和鍵(Queries, Values and Keys)。
class SelfAttention(nn.Module):def __init__(self, embed_size, heads):super(SelfAttention,self).__init__()self.embed_size=embed_sizeself.heads=headsself.head_dim=embed_size//headsassert(self.head_dim*heads==embed_size),"Embed size needs to be div by heads"self.values=nn.Linear(self.head_dim, self.head_dim, bias=False)self.keys=nn.Linear(self.head_dim, self.head_dim, bias=False)self.queries=nn.Linear(self.head_dim, self.head_dim, bias=False)self.fc_out=nn.Linear(heads*self.head_dim, embed_size)def forward(self,values,keys,query,mask):N=query.shape[0]value_len,key_len,query_len=values.shape[1],keys.shape[1],query.shape[1]#split embedding into self.heads piecesvalues=values.reshape(N,value_len,self.heads,self.head_dim)keys=keys.reshape(N,key_len,self.heads,self.head_dim)queries=query.reshape(N,query_len,self.heads,self.head_dim)values=self.values(values)keys=self.keys(keys)queries=self.queries(queries)energy=torch.einsum("nqhd,nkhd->nhqk",[queries,keys])#queries shape: (N,query_len, heads, heads_dim)#keys shape: (N,key_len, heads, heads_dim)#energy shape: (N,heads,query_len,key_len)if mask is not None:energy=energy.masked_fill(mask==0,float("-1e20"))#close it ,0attention=torch.softmax(energy/(self.embed_size**(1/2)),dim=3)#softmaxout=torch.einsum("nhql,nlhd->nqhd",[attention,values]).reshape(N,query_len,self.heads*self.head_dim)#attention shape: (N,heads, query_len,key_len)#values shape: (N,value_len,heads,head_dim)#key_len=value_len=l#after einsum(N,query_len,heads,head_dim) then flatten last two dimout=self.fc_out(out)return out
Queries,Values和Keys
在自注意力機(jī)制中,通常輸入向量以三種不同的方式使用:查詢、鍵和值。在每個(gè)角色中,它將與其他向量進(jìn)行比較,以獲得自己的輸出(Query),獲得第j個(gè)輸出(Key),并在權(quán)重建立后計(jì)算每個(gè)輸出向量(Value)。為了得到這些,我們需要三個(gè)維數(shù)為k * k的權(quán)重矩陣,并為每個(gè)計(jì)算三個(gè)線性變換:
圖2 查詢、值和鍵(Queries, Values and Keys)三元素
通常稱(chēng)這三個(gè)矩陣為K、Q和V,這三個(gè)可學(xué)習(xí)權(quán)值層應(yīng)用于相同的編碼輸入。因此,由于這三個(gè)矩陣都來(lái)自相同的輸入,可以應(yīng)用輸入向量本身的注意力機(jī)制,即“Self-attention”。
TheScaledDot-ProductAttention(帶縮放的點(diǎn)積注意力)
輸入由維的“查詢”和“鍵”以及維的“值”值組成。我們用所有“鍵”計(jì)算“查詢”的點(diǎn)積,每個(gè)“鍵”除以的平方根,應(yīng)用一個(gè)softmax函數(shù)來(lái)獲得值的權(quán)重。
使用Q, K和V矩陣來(lái)計(jì)算注意力分?jǐn)?shù)。分?jǐn)?shù)衡量的是對(duì)輸入序列的其他位置或單詞的關(guān)注程度。也就是說(shuō),查詢向量與要評(píng)分的單詞的鍵向量的點(diǎn)積。對(duì)于位置1,我們計(jì)算和的點(diǎn)積,然后是、2, 、等等,…
接下來(lái)應(yīng)用“縮放”因子來(lái)獲得更穩(wěn)定的梯度。softmax函數(shù)在大的值下無(wú)法正常工作,會(huì)導(dǎo)致梯度消失和減慢學(xué)習(xí)速度[1]。在“softmax”之后,我們乘以“值”矩陣,保留想要關(guān)注的單詞的值,并最小化或刪除無(wú)關(guān)單詞的值(它在V矩陣中的值應(yīng)該非常小)。
這些操作的公式為:
Multi-head Attention(多頭注意力)
在前面的描述中,注意力分?jǐn)?shù)一次集中在整個(gè)句子上,即使兩個(gè)句子包含相同的單詞,但順序不同,也將產(chǎn)生相同的結(jié)果。相反,如果想關(guān)注單詞的不同部分,”self-attention”的辨別能力則比較大,通過(guò)組合幾個(gè)自注意力頭,將單詞向量分成固定數(shù)量(h,頭的數(shù)量)的塊,然后使用Q, K和V子矩陣將自注意力應(yīng)用到相應(yīng)的塊。
圖3 多頭注意力機(jī)制
由于下一層(前饋層)只需要一個(gè)矩陣,每個(gè)單詞的一個(gè)向量,所以“在計(jì)算每個(gè)頭部的點(diǎn)積之后,需要連接輸出矩陣,并將它們乘以一個(gè)附加的權(quán)重矩陣Wo”[2]。最后輸出的矩陣從所有的注意力頭部獲取信息。
PositionalEncoding(位置編碼)
前文已經(jīng)簡(jiǎn)單地提到,由于網(wǎng)絡(luò)和self-attention機(jī)制是排列不變的,句子中單詞的順序是該模型中需要解決的問(wèn)題。如果我們打亂輸入句子中的單詞,會(huì)得到相同的解。需要?jiǎng)?chuàng)建單詞在句子中位置的表示,并將其添加到單詞嵌入(embedding)中。
為此,我們?cè)诰幋a器和解碼器棧底部的輸入嵌入中添加了“位置編碼”。位置編碼與嵌入具有相同的維數(shù),因此兩者可以求和,位置編碼有多種選擇。
應(yīng)用一個(gè)函數(shù)將句子中的位置映射為實(shí)值向量之后,網(wǎng)絡(luò)將學(xué)習(xí)如何使用這些信息。另一種方法是使用位置嵌入,類(lèi)似于單詞嵌入,用向量對(duì)每個(gè)已知位置進(jìn)行編碼?!八枰?xùn)練循環(huán)中所有被接受的位置的句子,但位置編碼允許模型外推到比訓(xùn)練中遇到的序列長(zhǎng)度更長(zhǎng)的序列”,[1]。
TransformerBlock(Transformer代碼塊)
class TransformerBlock(nn.Module):def __init__(self, embed_size,heads,dropout,forward_expansion):super(TransformerBlock,self).__init__()self.attention=SelfAttention(embed_size,heads)self.norm1=nn.LayerNorm(embed_size)self.norm2=nn.LayerNorm(embed_size)self.feed_forward=nn.Sequential(nn.Linear(embed_size, forward_expansion*embed_size),nn.ReLU(),nn.Linear(forward_expansion*embed_size,embed_size))self.dropout=nn.Dropout(dropout)def forward(self,values,keys,query,mask):attention=self.attention(values,keys,query,mask)x=self.dropout(self.norm1(attention+query))forward=self.feed_forward(x)out=self.dropout(self.norm2(forward+x))return out
Theencoder(編碼器)
位置編碼:將位置編碼添加到輸入嵌入(將輸入單詞被轉(zhuǎn)換為嵌入向量)。
N=6個(gè)相同的層,包含兩個(gè)子層:一個(gè)多頭自注意力機(jī)制,和一個(gè)全連接的前饋網(wǎng)絡(luò)(兩個(gè)線性轉(zhuǎn)換與一個(gè)ReLU激活)。它按位置應(yīng)用于輸入,這意味著相同的神經(jīng)網(wǎng)絡(luò)會(huì)應(yīng)用于屬于句子序列的每一個(gè)“標(biāo)記”向量。
每個(gè)子層(注意和FC網(wǎng)絡(luò))周?chē)加幸粋€(gè)殘余連接,將該層的輸出與其輸入相加,然后進(jìn)行歸一化。
在每個(gè)殘余連接之前,應(yīng)用正則化:“對(duì)每個(gè)子層的輸出應(yīng)用dropout,然后將其添加到子層輸入并正則化。
圖4 編碼器結(jié)構(gòu)
class Encoder(nn.Module):def __init__(self,src_vocab_size,embed_size,num_layers,heads,device,forward_expansion,dropout,max_length):super(Encoder,self).__init__()self.embed_size=embed_sizeself.device=deviceself.word_embedding=nn.Embedding(src_vocab_size,embed_size)self.position_embedding=nn.Embedding(max_length,embed_size)self.layers=nn.ModuleList([TransformerBlock(embed_size,heads,dropout=dropout,forward_expansion=forward_expansion) for _ in range(num_layers)])self.dropout=nn.Dropout(dropout)def forward(self,x,mask):N,seq_length=x.shapepositions=torch.arange(0,seq_length).expand(N,seq_length).to(self.device)out=self.dropout(self.word_embedding(x)+self.position_embedding(positions))for layer in self.layers:out=layer(out,out,out,mask) #key,query,value all the samereturn out
DecoderBlock(解碼器代碼塊)
位置編碼:編碼器的編碼相類(lèi)似。
N=6個(gè)相同的層,包含3個(gè)子層。第一,屏蔽多頭注意力或屏蔽因果注意力,以防止位置注意到后續(xù)位置。禁用點(diǎn)積注意力模塊的軟最大層,對(duì)應(yīng)的值設(shè)置為?∞。第二個(gè)組件或“編碼器-解碼器注意力”對(duì)解碼器的輸出執(zhí)行多頭注意力,“鍵”和“值”向量來(lái)自編碼器的輸出,但“查詢”來(lái)自前面的解碼器層,使得解碼器中的每個(gè)位置都能覆蓋輸入序列中的所有位置。,最后是完連接的網(wǎng)絡(luò)。
每個(gè)子層周?chē)臍埐钸B接和層歸一化,類(lèi)似于編碼器。
然后重復(fù)在編碼器中執(zhí)行的相同殘差dropout。
class DecoderBlock(nn.Module):def __init__(self, embed_size,heads,dropout,forward_expansion,device):super(DecoderBlock,self).__init__()self.attention=SelfAttention(embed_size,heads)self.norm=nn.LayerNorm(embed_size)self.transformer_block=TransformerBlock(embed_size, heads, dropout, forward_expansion)self.dropout=nn.Dropout(dropout)def forward(self,x,value,key,src_mask,trg_mask):#source mask and target maskattention=self.attention(x,x,x,trg_mask)#trg_mask is the mask mult-headed attention the first one in decoder blockquery=self.dropout(self.norm(attention+x))out=self.transformer_block(value,key,query,src_mask)return out
在N個(gè)堆疊的解碼器的最后,線性層,一個(gè)全連接的網(wǎng)絡(luò),將堆疊的輸出轉(zhuǎn)換為一個(gè)更大的向量,logits。
圖5 解碼器結(jié)構(gòu)
Joining all the pieces: the Transformer(全部拼接起來(lái)構(gòu)成Transformer)
定義并創(chuàng)建了編碼器、解碼器和linear-softmax最后一層等部件之后,便可以將這些部件連接起來(lái),形成Transformer模型。
值得一提的是,創(chuàng)建了3個(gè)掩碼,包括:
編碼器掩碼:它是一個(gè)填充掩碼,從注意力計(jì)算中丟棄填充標(biāo)記。
解碼器掩碼1:該掩碼是填充掩碼和前向掩碼的結(jié)合,它將幫助因果注意力丟棄“未來(lái)”的標(biāo)記,我們?nèi)√畛溲诖a和前向掩碼之間的最大值。
解碼器掩碼2:為填充掩碼,應(yīng)用于編碼器-解碼器注意力層。
class Transformer(nn.Module):def __init__(self,src_vocab_size,trg_vocab_size,src_pad_idx,trg_pad_idx,embed_size=256,num_layers=6,forward_expansion=4,heads=8,dropout=0,device="cuda",max_length=100):super(Transformer,self).__init__()self.encoder=Encoder(src_vocab_size,embed_size,num_layers,heads,device,forward_expansion,dropout,max_length)self.decoder=Decoder(trg_vocab_size,embed_size,num_layers,heads,forward_expansion,dropout,device,max_length)self.src_pad_idx=src_pad_idxself.trg_pad_idx=trg_pad_idxself.device=devicedef make_src_mask(self,src):src_mask=(src!= self.src_pad_idx).unsqueeze(1).unsqueeze(2)#(N,1,1,src_len)return src_mask.to(self.device)def make_trg_mask(self,trg):N,trg_len=trg.shapetrg_mask=torch.tril(torch.ones((trg_len,trg_len))).expand(N,1,trg_len,trg_len)return trg_mask.to(self.device)def forward(self,src,trg):src_mask=self.make_src_mask(src)trg_mask=self.make_trg_mask(trg)enc_src=self.encoder(src,src_mask)out=self.decoder(trg, enc_src,src_mask, trg_mask)return out參考文獻(xiàn):[1] Peter Bloem,“Transformers from scratch”blog post, 2019.[2] Jay Alammar,“The Ilustrated Transformer”blog post, 2018.編輯:王菁校對(duì):林亦霖
數(shù)據(jù)派研究部介紹
數(shù)據(jù)派研究部成立于2017年初,以興趣為核心劃分多個(gè)組別,各組既遵循研究部整體的知識(shí)分享和實(shí)踐項(xiàng)目規(guī)劃,又各具特色:
算法模型組:積極組隊(duì)參加kaggle等比賽,原創(chuàng)手把手教系列文章;
調(diào)研分析組:通過(guò)專(zhuān)訪等方式調(diào)研大數(shù)據(jù)的應(yīng)用,探索數(shù)據(jù)產(chǎn)品之美;
系統(tǒng)平臺(tái)組:追蹤大數(shù)據(jù)&人工智能系統(tǒng)平臺(tái)技術(shù)前沿,對(duì)話專(zhuān)家;
自然語(yǔ)言處理組:重于實(shí)踐,積極參加比賽及策劃各類(lèi)文本分析項(xiàng)目;
制造業(yè)大數(shù)據(jù)組:秉工業(yè)強(qiáng)國(guó)之夢(mèng),產(chǎn)學(xué)研政結(jié)合,挖掘數(shù)據(jù)價(jià)值;
數(shù)據(jù)可視化組:將信息與藝術(shù)融合,探索數(shù)據(jù)之美,學(xué)用可視化講故事;
網(wǎng)絡(luò)爬蟲(chóng)組:爬取網(wǎng)絡(luò)信息,配合其他各組開(kāi)發(fā)創(chuàng)意項(xiàng)目。
點(diǎn)擊文末“閱讀原文”,報(bào)名數(shù)據(jù)派研究部志愿者,總有一組適合你~
轉(zhuǎn)載須知
如需轉(zhuǎn)載,請(qǐng)?jiān)陂_(kāi)篇顯著位置注明作者和出處(轉(zhuǎn)自:數(shù)據(jù)派THUID:DatapiTHU),并在文章結(jié)尾放置數(shù)據(jù)派醒目二維碼。有原創(chuàng)標(biāo)識(shí)文章,請(qǐng)發(fā)送【文章名稱(chēng)-待授權(quán)公眾號(hào)名稱(chēng)及ID】至聯(lián)系郵箱,申請(qǐng)白名單授權(quán)并按要求編輯。
未經(jīng)許可的轉(zhuǎn)載以及改編者,我們將依法追究其法律責(zé)任。
點(diǎn)擊“閱讀原文”加入組織~
關(guān)鍵詞: 神經(jīng)網(wǎng)絡(luò) 輸入向量 輸出向量
相關(guān)閱讀
-
熱文:原創(chuàng) | Attention is all yo...
作者:楊金珊審校:陳之炎本文約4300字,建議閱讀8分鐘“Attentioni... -
速訊:天才交易員SBF的謝幕:或?qū)⒚媾R終...
原力區(qū)原作眼看著你起高樓,眼看著你酬賓客,眼看著樓塌了——賈平... -
干貨 | 數(shù)字經(jīng)濟(jì)創(chuàng)新創(chuàng)業(yè)——軟件研究...
下文整理自清華大學(xué)大數(shù)據(jù)能力提升項(xiàng)目能力提升模塊課程“Innovatio... -
世界熱文:含對(duì)乙酰氨基酚的中成藥
【本文只提供官方信息,不是購(gòu)買(mǎi)建議】【本文也不表達(dá)對(duì)中藥和中成... -
精選!Docker進(jìn)階-Dockerfile建立一個(gè)自...
前言docker對(duì)我來(lái)說(shuō)是一個(gè)很方便的工具,,上一篇文章也寫(xiě)了docker... -
天天熱消息:無(wú)限滾動(dòng)效應(yīng)——設(shè)計(jì)如何...
點(diǎn)擊▲三分設(shè)關(guān)注,和10萬(wàn)設(shè)計(jì)師一起成長(zhǎng)三分設(shè)x翻閱計(jì)劃正文共:99...