<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          原創(chuàng) | Attention is all you need 論文解析(附代碼)

          共 9678字,需瀏覽 20分鐘

           ·

          2022-12-17 21:37

          作者:楊金珊
          審校:陳之炎

          本文約4300字,建議閱讀8分鐘
          “Attention is all you need”一文在注意力機(jī)制的使用方面取得了很大的進(jìn)步,對Transformer模型做出了重大改進(jìn)。


          目前NLP任務(wù)中的最著名模型(例如GPT-2或BERT),均由幾十個Transformer或它們的變體組成。

           

          背景

           

          減少順序算力是擴(kuò)展神經(jīng)網(wǎng)絡(luò)GPU、ByteNet和ConvS2S的基本目標(biāo),它們使用卷積神經(jīng)網(wǎng)絡(luò)作為基本構(gòu)建塊,并行計算所有輸入和輸出位置的隱含表示。在這些模型中,將來自兩個任意輸入或輸出位置的信號關(guān)聯(lián)起來,所需的操作數(shù)量隨著位置距離的增加而增加,對于ConvS2S來說,二者是線性增長的;對于ByteNet來說,二者是對數(shù)增長的。這使得學(xué)習(xí)遙遠(yuǎn)位置之間的依賴關(guān)系變得更加困難。在Transformer中,將操作數(shù)量減少到一個恒定數(shù)值,這是以降低有效分辨率為代價的,因為需要對注意力權(quán)重位置做平均,多頭注意力 (Multi-Head Attention)抵消了這一影響。

           

          為什么需要transformer

           

          在序列到序列的問題中,例如神經(jīng)機(jī)器翻譯,最初的建議是基于在編碼器-解碼器架構(gòu)中使用循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)。這一架構(gòu)在處理長序列時受到了很大的限制,當(dāng)新元素被合并到序列中時,它們保留來自第一個元素的信息的能力就喪失了。在編碼器中,每一步中的隱含狀態(tài)都與輸入句子中的某個單詞相關(guān)聯(lián),通常是最鄰近的那個單詞。因此,如果解碼器只訪問解碼器的最后一個隱含狀態(tài),它將丟失序列的第一個元素相關(guān)的信息。針對這一局限性,提出了注意力機(jī)制的概念。


          與通常使用RNN時關(guān)注編碼器的最后狀態(tài)不同,在解碼器的每一步中我們都關(guān)注編碼器的所有狀態(tài),從而能夠訪問有關(guān)輸入序列中所有元素的信息。這就是注意力所做的,它從整個序列中提取信息,即過去所有編碼器狀態(tài)的加權(quán)和,解碼器為輸出的每個元素賦予輸入的某個元素更大的權(quán)重或重要性。從每一步中正確的輸入元素中學(xué)習(xí),以預(yù)測下一個輸出元素。


          但是這種方法仍然有一個重要的限制,每個序列必須一次處理一個元素。編碼器和解碼器都必須等到t-1步驟完成后才能處理第t-1步驟。因此,在處理龐大的語料庫時,計算效率非常低。

           

          什么是Transformer

           

          Transformer是一種避免遞歸的模型架構(gòu),它完全依賴于注意力機(jī)制來繪制輸入和輸出之間的全局依賴關(guān)系。Transformer允許顯著的并行化……Transformer是第一個完全依靠自注意力來計算輸入和輸出的表示,而不使用序列對齊的RNN或卷積的傳導(dǎo)模型。

           


          圖1  Transformer 架構(gòu)


          從圖1可以觀察到,左邊是一個編碼器模型,右邊是一個解碼器模型。兩者都包含一個重復(fù)N次的“一個注意力和一個前饋網(wǎng)絡(luò)”的核心塊。但為此,首先需要深入探討一個核心概念:自注意力機(jī)制。

           

          Self-Attention基本操作

           

          Self-attention是一個序列到序列的操作:一個向量序列進(jìn)去,一個向量序列出來。我們稱它們?yōu)檩斎胂蛄?/span>, ,…,和相應(yīng)的輸出向量, ,…,。這些向量的維數(shù)都是k。要產(chǎn)生輸出向量,Self-attention操作只需對所有輸入向量取加權(quán)平均值,最簡單的選擇是點積。在我們的模型的Self-attention機(jī)制中,我們需要引入三個元素:查詢、值和鍵(Queries, Values and Keys)。


          class SelfAttention(nn.Module):  def __init__(self, embed_size, heads):    super(SelfAttention,self).__init__()    self.embed_size=embed_size    self.heads=heads    self.head_dim=embed_size//heads
          assert(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 pieces values=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 ,0 attention=torch.softmax(energy/(self.embed_size**(1/2)),dim=3)#softmax out=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 dim
          out=self.fc_out(out) return out

           

          Queries,Values和Keys

           

          在自注意力機(jī)制中,通常輸入向量以三種不同的方式使用:查詢、鍵和值。在每個角色中,它將與其他向量進(jìn)行比較,以獲得自己的輸出(Query),獲得第j個輸出(Key),并在權(quán)重建立后計算每個輸出向量(Value)。為了得到這些,我們需要三個維數(shù)為k * k的權(quán)重矩陣,并為每個計算三個線性變換:

          圖2  查詢、值和鍵(Queries, Values and Keys)三元素


          通常稱這三個矩陣為K、Q和V,這三個可學(xué)習(xí)權(quán)值層應(yīng)用于相同的編碼輸入。因此,由于這三個矩陣都來自相同的輸入,可以應(yīng)用輸入向量本身的注意力機(jī)制,即“Self-attention”。

           

          TheScaledDot-ProductAttention(帶縮放的點積注意力)

           

          輸入由維的“查詢”和“鍵”以及維的“值”值組成。我們用所有“鍵”計算“查詢”的點積,每個“鍵”除以的平方根,應(yīng)用一個softmax函數(shù)來獲得值的權(quán)重。


          使用Q, K和V矩陣來計算注意力分?jǐn)?shù)。分?jǐn)?shù)衡量的是對輸入序列的其他位置或單詞的關(guān)注程度。也就是說,查詢向量與要評分的單詞的鍵向量的點積。對于位置1,我們計算的點積,然后是2, 、等等,…


          接下來應(yīng)用“縮放”因子來獲得更穩(wěn)定的梯度。softmax函數(shù)在大的值下無法正常工作,會導(dǎo)致梯度消失和減慢學(xué)習(xí)速度[1]。在“softmax”之后,我們乘以“值”矩陣,保留想要關(guān)注的單詞的值,并最小化或刪除無關(guān)單詞的值(它在V矩陣中的值應(yīng)該非常小)。


          這些操作的公式為:

           


          Multi-head Attention(多頭注意力)


          在前面的描述中,注意力分?jǐn)?shù)一次集中在整個句子上,即使兩個句子包含相同的單詞,但順序不同,也將產(chǎn)生相同的結(jié)果。相反,如果想關(guān)注單詞的不同部分,”self-attention”的辨別能力則比較大,通過組合幾個自注意力頭,將單詞向量分成固定數(shù)量(h,頭的數(shù)量)的塊,然后使用Q, K和V子矩陣將自注意力應(yīng)用到相應(yīng)的塊。

           

          圖3 多頭注意力機(jī)制


          由于下一層(前饋層)只需要一個矩陣,每個單詞的一個向量,所以“在計算每個頭部的點積之后,需要連接輸出矩陣,并將它們乘以一個附加的權(quán)重矩陣Wo”[2]。最后輸出的矩陣從所有的注意力頭部獲取信息。

           

          PositionalEncoding(位置編碼)

           

          前文已經(jīng)簡單地提到,由于網(wǎng)絡(luò)和self-attention機(jī)制是排列不變的,句子中單詞的順序是該模型中需要解決的問題。如果我們打亂輸入句子中的單詞,會得到相同的解。需要創(chuàng)建單詞在句子中位置的表示,并將其添加到單詞嵌入(embedding)中。


          為此,我們在編碼器和解碼器棧底部的輸入嵌入中添加了“位置編碼”。位置編碼與嵌入具有相同的維數(shù),因此兩者可以求和,位置編碼有多種選擇。


          應(yīng)用一個函數(shù)將句子中的位置映射為實值向量之后,網(wǎng)絡(luò)將學(xué)習(xí)如何使用這些信息。另一種方法是使用位置嵌入,類似于單詞嵌入,用向量對每個已知位置進(jìn)行編碼。“它需要訓(xùn)練循環(huán)中所有被接受的位置的句子,但位置編碼允許模型外推到比訓(xùn)練中遇到的序列長度更長的序列”,[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個相同的層,包含兩個子層:一個多頭自注意力機(jī)制,和一個全連接的前饋網(wǎng)絡(luò)(兩個線性轉(zhuǎn)換與一個ReLU激活)。它按位置應(yīng)用于輸入,這意味著相同的神經(jīng)網(wǎng)絡(luò)會應(yīng)用于屬于句子序列的每一個“標(biāo)記”向量。

           

          • 每個子層(注意和FC網(wǎng)絡(luò))周圍都有一個殘余連接,將該層的輸出與其輸入相加,然后進(jìn)行歸一化。

          • 在每個殘余連接之前,應(yīng)用正則化:“對每個子層的輸出應(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_size    self.device=device    self.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.shape    positions=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 same return out


          DecoderBlock(解碼器代碼塊)


          • 位置編碼:編碼器的編碼相類似。

          • N=6個相同的層,包含3個子層。第一,屏蔽多頭注意力或屏蔽因果注意力,以防止位置注意到后續(xù)位置。禁用點積注意力模塊的軟最大層,對應(yīng)的值設(shè)置為?∞。第二個組件或“編碼器-解碼器注意力”對解碼器的輸出執(zhí)行多頭注意力,“鍵”和“值”向量來自編碼器的輸出,但“查詢”來自前面的解碼器層,使得解碼器中的每個位置都能覆蓋輸入序列中的所有位置。,最后是完連接的網(wǎng)絡(luò)。

          • 每個子層周圍的殘差連接和層歸一化,類似于編碼器。

          • 然后重復(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 mask    attention=self.attention(x,x,x,trg_mask)#trg_mask is the mask mult-headed attention the first one in decoder block    query=self.dropout(self.norm(attention+x))    out=self.transformer_block(value,key,query,src_mask)    return out

           

          在N個堆疊的解碼器的最后,線性層,一個全連接的網(wǎng)絡(luò),將堆疊的輸出轉(zhuǎn)換為一個更大的向量,logits。

           

          圖5 解碼器結(jié)構(gòu)


          Joining all the pieces: the Transformer(全部拼接起來構(gòu)成Transformer)


          定義并創(chuàng)建了編碼器、解碼器和linear-softmax最后一層等部件之后,便可以將這些部件連接起來,形成Transformer模型。


          值得一提的是,創(chuàng)建了3個掩碼,包括:


          編碼器掩碼:它是一個填充掩碼,從注意力計算中丟棄填充標(biāo)記。


          解碼器掩碼1:該掩碼是填充掩碼和前向掩碼的結(jié)合,它將幫助因果注意力丟棄“未來”的標(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_idx    self.trg_pad_idx=trg_pad_idx    self.device=device  def 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.shape    trg_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.
           
          編輯:王菁
          校對:林亦霖

          數(shù)據(jù)派研究部介紹




          數(shù)據(jù)派研究部成立于2017年初,以興趣為核心劃分多個組別,各組既遵循研究部整體的知識分享實踐項目規(guī)劃,又各具特色:


          算法模型組:積極組隊參加kaggle等比賽,原創(chuàng)手把手教系列文章;

          調(diào)研分析組:通過專訪等方式調(diào)研大數(shù)據(jù)的應(yīng)用,探索數(shù)據(jù)產(chǎn)品之美;

          系統(tǒng)平臺組:追蹤大數(shù)據(jù)&人工智能系統(tǒng)平臺技術(shù)前沿,對話專家;

          自然語言處理組:重于實踐,積極參加比賽及策劃各類文本分析項目;

          制造業(yè)大數(shù)據(jù)組:秉工業(yè)強(qiáng)國之夢,產(chǎn)學(xué)研政結(jié)合,挖掘數(shù)據(jù)價值;

          數(shù)據(jù)可視化組:將信息與藝術(shù)融合,探索數(shù)據(jù)之美,學(xué)用可視化講故事;

          網(wǎng)絡(luò)爬蟲組:爬取網(wǎng)絡(luò)信息,配合其他各組開發(fā)創(chuàng)意項目。


          點擊文末“閱讀原文”,報名數(shù)據(jù)派研究部志愿者,總有一組適合你~



          轉(zhuǎn)載須知


          如需轉(zhuǎn)載,請在開篇顯著位置注明作者和出處(轉(zhuǎn)自:數(shù)據(jù)派THUID:DatapiTHU),并在文章結(jié)尾放置數(shù)據(jù)派醒目二維碼。有原創(chuàng)標(biāo)識文章,請發(fā)送【文章名稱-待授權(quán)公眾號名稱及ID】至聯(lián)系郵箱,申請白名單授權(quán)并按要求編輯。

          未經(jīng)許可的轉(zhuǎn)載以及改編者,我們將依法追究其法律責(zé)任。



          點擊“閱讀原文”加入組織~


          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91大神网址 | 国产无遮挡又黄又爽又 | 成人午夜毛片 | 久久无码av | 99er在线 |