<label id="jgr5k"></label>
    <legend id="jgr5k"><track id="jgr5k"></track></legend>

    <sub id="jgr5k"></sub>
  1. <u id="jgr5k"></u>
      久草国产视频,91资源总站,在线免费看AV,丁香婷婷社区,久久精品99久久久久久久久,色天使av,无码探花,香蕉av在线
      您正在使用IE低版瀏覽器,為了您的雷峰網(wǎng)賬號(hào)安全和更好的產(chǎn)品體驗(yàn),強(qiáng)烈建議使用更快更安全的瀏覽器
      此為臨時(shí)鏈接,僅用于文章預(yù)覽,將在時(shí)失效
      人工智能開(kāi)發(fā)者 正文
      發(fā)私信給skura
      發(fā)送

      0

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      本文作者: skura 2020-02-25 09:18
      導(dǎo)語(yǔ):讓我們?cè)诂F(xiàn)有資源的基礎(chǔ)上,用代碼實(shí)現(xiàn) GPT-2 吧~

      歡迎來(lái)到「帶注釋的 GPT-2」。              

      我讀過(guò)的最精彩、解釋最清楚的文章之一是「The Annotated Transformer」https://nlp.seas.harvard.edu/2018/04/03/attention.html 。它引起了前所未有的關(guān)注,一個(gè)簡(jiǎn)單的想法就是用一個(gè)文件注釋你所需要的代碼。

      我在機(jī)器學(xué)習(xí)方面的經(jīng)驗(yàn)讓我意識(shí)到,當(dāng)你將事情寫成代碼的時(shí)候,其實(shí)現(xiàn)和秘密會(huì)變得更清晰,而不再是魔法了。              

      魔法沒(méi)有什么神奇的。魔術(shù)師只是理解一些簡(jiǎn)單的東西,而這些東西對(duì)未經(jīng)訓(xùn)練的觀眾來(lái)說(shuō)似乎并不簡(jiǎn)單。一旦你學(xué)會(huì)了操作魔術(shù)卡片,你也可以變魔術(shù)。 

      ——Jeffrey Friedl 在《Mastering Regular Expressions》一書中寫道              

      GPT-2 一開(kāi)始看起來(lái)像是魔術(shù),它的看起來(lái)太美麗了,但希望我能為你解釋魔術(shù),在你讀完這篇文章時(shí)揭示所有的技巧,這是我的目標(biāo)。使那些熱衷于理解 GPT-2 模型是如何工作的人更好理解。 

      注:幾乎所有代碼都是從Hugging Face(https://github.com/huggingface/transformers/blob/master/src/transformers/modeling_gpt2.py )的 GPT-2 實(shí)現(xiàn)中復(fù)制、啟發(fā)和引用的,只保留了簡(jiǎn)單的基本要素。如果你想在并行 GPU 上訓(xùn)練 GPT-2 模型,在微調(diào)時(shí)保存檢查點(diǎn),在多個(gè) CPU 上運(yùn)行推理任務(wù)等等,我建議你使用 Hugging Face API。最近,Hugging Face 發(fā)布了一個(gè)簡(jiǎn)單的教程,它教你如何做到這一點(diǎn):https://huggingface.co/blog/how-to-train 。              

      在這篇文章中,我并不是在試圖重新發(fā)明輪子,而是僅僅把一系列已經(jīng)存在的優(yōu)秀資源放在一起,讓讀者更容易掌握 GPT-2。我讓讀者在他們所選擇的任何領(lǐng)域進(jìn)一步建立這些基礎(chǔ)。              

      你不能在弱小的基礎(chǔ)上建造一座偉大的建筑。如果你要有一個(gè)強(qiáng)大的上層建筑,你必須有堅(jiān)實(shí)的基礎(chǔ)。    

      ——Gordon B. Hinckley        

      學(xué)習(xí)本教程的先決條件              

      本文假設(shè)讀者對(duì)注意力機(jī)制和 tansformers 有著扎實(shí)的理解。GPT-2 采用 12 層的,僅有解碼器的 transformer 架構(gòu)。如果你想復(fù)習(xí)一下或了解注意力機(jī)制和 transformers,這里有一個(gè)很好的資源列表:

      如果你剛剛開(kāi)始你的 NLP 之旅,或者你是一個(gè)專家,我絕對(duì)會(huì)推薦 Rachel Thomas 和 Jeremy Howard 教授的 fast.ai NLP 課程(https://www.fast.ai/2019/07/08/fastai-nlp/ )。本課程從基礎(chǔ)開(kāi)始,包括使用樸素貝葉斯和 Logistic 回歸進(jìn)行語(yǔ)義分類,接著是 RNN,后面還討論了遷移學(xué)習(xí)、ULMFiT、Seq2Seq 翻譯和 transformers 等。它是 fast.ai 團(tuán)隊(duì)免費(fèi)提供的優(yōu)秀資源。 

      另一個(gè)關(guān)于 GPT-2 本身的優(yōu)秀資源,是 Jay Alammar 的 The Illustrated GPT-2(http://jalammar.github.io/illustrated-gpt2/ )。本文從語(yǔ)言模型的基本介紹開(kāi)始,以一種非常容易理解的方式逐步解釋 GPT-2 模型。我強(qiáng)烈建議讀者閱讀這篇文章。              

      哈佛大學(xué) The Annotated Transformer 使用 PyTorch 實(shí)現(xiàn)了完整的 transformer 架構(gòu),是深入理解 transformer 的好方法。 

      然后,讓我們?cè)谶@些優(yōu)秀的現(xiàn)有資源的基礎(chǔ)上,用代碼實(shí)現(xiàn) GPT-2 吧~              

      摘要              

      自然語(yǔ)言處理任務(wù),如問(wèn)答、機(jī)器翻譯、閱讀理解等,通常是在特定任務(wù)的數(shù)據(jù)集上進(jìn)行有監(jiān)督的學(xué)習(xí)。我們證明,當(dāng)語(yǔ)言模型在一個(gè)名為 WebText 的數(shù)百萬(wàn)網(wǎng)頁(yè)的新數(shù)據(jù)集上訓(xùn)練時(shí),它開(kāi)始學(xué)習(xí)這些任務(wù),而不需要任何明確的監(jiān)督。我們最大的模型,GPT-2,是一個(gè) 1.5B 參數(shù)的 transformer,它可以獲得最先進(jìn)的語(yǔ)言建模成果,但仍然不適合 WebText。模型中的示例反映了這些改進(jìn),并包含連貫的文本段落。這些發(fā)現(xiàn)為構(gòu)建語(yǔ)言處理系統(tǒng)提供了一條有希望的途徑,該系統(tǒng)可以從自然發(fā)生的演示中學(xué)習(xí)執(zhí)行任務(wù)。              

      Zero-shot 設(shè)置是不微調(diào)語(yǔ)言模型并直接在目標(biāo)數(shù)據(jù)集上運(yùn)行推理的設(shè)置。例如,在 WebText 上預(yù)覽一個(gè) LM,并直接嘗試預(yù)測(cè) Amazon 影評(píng)數(shù)據(jù)集的下一個(gè)單詞。              

      模型架構(gòu)(GPT-2)              

      我們的 LM 使用基于 transformer 的架構(gòu)。該模型主要遵循 OpenAI GPT 模型的細(xì)節(jié),并進(jìn)行了一些修改。層規(guī)范化被移動(dòng)到每個(gè)子塊的輸入,類似于預(yù)激活剩余網(wǎng)絡(luò),并且在最終的自關(guān)注塊之后添加了額外的層規(guī)范化。我們?cè)诔跏蓟瘯r(shí)將剩余層的權(quán)重按 1/√N(yùn) 的因子進(jìn)行縮放,其中 N 是剩余層的數(shù)量。詞匯量擴(kuò)大到 50257 個(gè)單詞。我們還將上下文大小從 512 增加到 1024 個(gè),并使用更大的批大小——512。 

      模型規(guī)格(GPT)              

      我們的模型基本上遵循了最初 transformer 的工作原理。我們訓(xùn)練了一個(gè) 12 層的只解碼的 transformer,它有隱藏的自注意力頭(768 維狀態(tài)和 12 個(gè)注意力頭)。對(duì)于位置前饋網(wǎng)絡(luò),我們使用了 3072 維的內(nèi)部狀態(tài)。我們使用 Adam 優(yōu)化方案,最大學(xué)習(xí)速率為 2.5e-4。學(xué)習(xí)速率在前 2000 次更新中從零線性增加,并使用余弦調(diào)度將其退火為 0。我們?cè)?64 個(gè)隨機(jī)抽樣的小批量、512 個(gè)令牌的連續(xù)序列上訓(xùn)練了 100 個(gè)階段。由于 layernorm 在整個(gè)模型中廣泛使用,簡(jiǎn)單的 N(0,0.02)權(quán)重初始化就足夠了。我們使用了一個(gè) bytepair 編碼(BPE)詞匯表。我們還采用了在中提出的 L2 正則化的改進(jìn)版本,在所有非偏倚或增益權(quán)重上的 w=0.01。對(duì)于激活函數(shù),我們使用高斯誤差線性單位(GELU)。  

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      導(dǎo)入

      import torch
      import copy
      import torch.nn as nn
      import torch.nn.functional as F
      from torch.nn.modules import ModuleList
      from torch.nn.modules.normalization import LayerNorm
      import numpy as np
      import os
      from tqdm import tqdm_notebook, trange
      import logging
      logging.basicConfig(level = logging.INFO)
      logger = logging.getLogger()

      GPT-2 內(nèi)部的 transformer 解碼器              

      要重用用于描述 transformer 的術(shù)語(yǔ),注意是一個(gè)查詢(Q)和一組鍵(K)和值(V)對(duì)的函數(shù)。為了處理更長(zhǎng)的序列,我們修改了 transformer 的多頭自注意力機(jī)制,通過(guò)限制 Q 和 K 之間的點(diǎn)積來(lái)減少內(nèi)存使用:

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      注意力是查詢、鍵和值的組合

      class Conv1D(nn.Module):
          def __init__(self, nx, nf):        super().__init__()
              self.nf = nf
              w = torch.empty(nx, nf)
              nn.init.normal_(w, std=0.02)
              self.weight = nn.Parameter(w)
              self.bias = nn.Parameter(torch.zeros(nf))

          def forward(self, x):
              size_out = x.size()[:-1] + (self.nf,)
              x = torch.addmm(self.bias, x.view(-1, x.size(-1)), self.weight)
              x = x.view(*size_out)
              return x

      CONV1D 層解釋              

      CONV1D 層本身可以看作是一個(gè)線性層。本質(zhì)上,它是投射一個(gè)初始張量 x(最終尺寸為 x.size(-1))并傳遞給它,最終尺寸為 self.nf。              

      下面是相同的輸出示例:

      d_model = 768
      conv1d  = Conv1D(d_model, d_model*3)
      x       = torch.rand(1,4,d_model) #represents a sequence of batch_size=1, seq_len=4 and embedding_sz=768, something like "Hello how are you"
      x       = conv1d(x)
      x.shape

      >> torch.Size([1, 4, 2304])

      如上例所示,CONV1D 返回的張量的最終維數(shù)是初始大小的 3 倍。我們這樣做是為了能夠?qū)⑤斎朕D(zhuǎn)換為查詢、鍵和值矩陣。              

      然后可以檢索查詢、鍵和值矩陣,如下所示:

      query, key, value = x.split(d_model, dim=-1)

      query.shape, key.shape, value.shape
      >> (torch.Size([1, 4, 768]), torch.Size([1, 4, 768]), torch.Size([1, 4, 768]))

      將輸入轉(zhuǎn)換為 Q、K 和 V 矩陣的另一種方法是必須有單獨(dú)的 Wq、Wk 和 Wv 矩陣。我已經(jīng)在這篇文章底部的附加部分解釋了這一點(diǎn)。我發(fā)現(xiàn)這種方法更直觀、更具相關(guān)性,但在本文中我們使用了 CONV1D 層,因?yàn)槲覀冎赜昧?Hugging Face 的 CONV1D 預(yù)訓(xùn)練權(quán)重。              

      前向?qū)咏忉?/strong>

      class FeedForward(nn.Module):
          def __init__(self, dropout, d_model=768, nx=768*4):
              super().__init__()
              self.c_fc    = Conv1D(d_model, nx)
              self.c_proj  = Conv1D(nx, d_model)
              self.act     = F.gelu
              self.dropout = nn.Dropout(dropout)
             
          def forward(self, x):
              return self.dropout(self.c_proj(self.act(self.c_fc(x))))

      在 Jay Alammar 的文章中有一個(gè)很好的解釋,也就是上面提到的,輸入是如何先經(jīng)過(guò)注意力層,然后再進(jìn)入前向?qū)拥摹G梆伨W(wǎng)絡(luò)是一個(gè)正常的網(wǎng)絡(luò),它接受來(lái)自注意力層(768)的輸出,將其投射到 nx(768×4)維,添加一個(gè)激活函數(shù) self.act(GELU),將其投射回 d_model (768) 并添加 dropout(0.1)。            

      注意力層解釋              

      下面的摘錄是從論文上摘取的:https://arxiv.org/abs/1706.03762 。              

      標(biāo)度點(diǎn)產(chǎn)品注意力              

      我們稱我們的注意力為「標(biāo)度點(diǎn)產(chǎn)品注意力」。輸入包括維度 dk 的查詢和鍵以及維度 dv 的值。我們使用所有鍵計(jì)算查詢的點(diǎn)積,用√dk除以每個(gè)鍵,然后應(yīng)用 softmax 函數(shù)獲得值的權(quán)重。

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      在實(shí)際應(yīng)用中,我們同時(shí)計(jì)算一組查詢的注意力函數(shù),將它們組合成一個(gè)矩陣 Q,并將鍵和值組合成矩陣 K 和 V。我們將輸出矩陣計(jì)算為:

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      輸出矩陣為 Q、K 和 V 的組合

      最常用的兩個(gè)注意力函數(shù)是加性注意力函數(shù)和點(diǎn)積(乘法)力函數(shù)注意。除了比例因子 1/√dk 外,點(diǎn)積注意力與我們的算法相同。附加注意力使用具有單個(gè)隱藏層的前饋網(wǎng)絡(luò)計(jì)算兼容性函數(shù)。雖然二者在理論復(fù)雜度上相似,但在實(shí)際應(yīng)用中,點(diǎn)積注意力速度更快,空間效率更高,因?yàn)樗梢允褂酶叨葍?yōu)化的矩陣乘法碼來(lái)實(shí)現(xiàn)。當(dāng) dk 值較小時(shí),兩種機(jī)制的表現(xiàn)相似,但在 dk 值較大時(shí),加性注意力優(yōu)于點(diǎn)積注意力。我們懷疑,對(duì)于 dk 的較大值,點(diǎn)積在數(shù)量上增長(zhǎng)較大,將 softmax 函數(shù)推入具有極小梯度的區(qū)域。為了抵消這一影響,我們將網(wǎng)點(diǎn)產(chǎn)品縮放至 1/√dk。              

      為了在代碼中實(shí)現(xiàn)注意力層,我們首先利用 CONV1D 層,得到前面解釋的 Q、K 和 V 矩陣。              

      一旦我們有了 Q、K 和 V 矩陣,我們就可以使用函數(shù) _attn 來(lái)執(zhí)行注意力。此函數(shù)復(fù)制了上述注意力點(diǎn)積公式。

      class Attention(nn.Module):
          def __init__(self, d_model=768, n_head=12, n_ctx=1024, d_head=64, bias=True, scale=False):
              super().__init__()
              self.n_head  = n_head
              self.d_model = d_model
              self.c_attn  = Conv1D(d_model, d_model*3)
              self.scale   = scale
              self.softmax = nn.Softmax(dim=-1)
              self.register_buffer("bias", torch.tril(torch.ones(n_ctx, n_ctx)).view(1, 1, n_ctx, n_ctx))
              self.dropout = nn.Dropout(0.1)
              self.c_proj  = Conv1D(d_model, d_model)
             
          def split_heads(self, x):
              "return shape [`batch`, `head`, `sequence`, `features`]"
              new_shape = x.size()[:-1] + (self.n_head, x.size(-1)//self.n_head)
              x = x.view(*new_shape)
              return x.permute(0, 2, 1, 3)
         
          def _attn(self, q, k, v, attn_mask=None):
              scores  = torch.matmul(q, k.transpose(-2, -1))
              if self.scale: scores = scores/math.sqrt(v.size(-1))
              nd, ns  = scores.size(-2), scores.size(-1)
              if attn_mask is not None: scores = scores + attn_mask
              scores  = self.softmax(scores)
              scores  = self.dropout(scores)
              outputs = torch.matmul(scores, v)
              return outputs
         
          def merge_heads(self, x):
              x         = x.permute(0, 2, 1, 3).contiguous()
              new_shape = x.size()[:-2] + (x.size(-2)*x.size(-1),)
              return x.view(*new_shape)
             
          def forward(self, x):
              x        = self.c_attn(x) #new `x` shape - `[1,3,2304]`
              q, k, v  = x.split(self.d_model, dim=2)
              q, k, v  = self.split_heads(q), self.split_heads(k), self.split_heads(v)
              out      = self._attn(q, k, v)
              out      = self.merge_heads(out)
              out      = self.c_proj(out)
              return out

      另一種實(shí)現(xiàn)注意力的方法在本博客底部的附加部分進(jìn)行了說(shuō)明。我發(fā)現(xiàn)它更直觀,更容易與研究論文進(jìn)行比較。它利用線性層而不是 CONV1D 將輸入轉(zhuǎn)換為 Q、K 和 V 矩陣。我們之所以沒(méi)有使用它,是因?yàn)槲覀兪褂昧祟A(yù)訓(xùn)練的權(quán)重,從 Hugging Face 轉(zhuǎn)換為一維層。              

      多頭注意力              

      下面一段是從論文「Attention is all you need」上摘取的。              

      我們發(fā)現(xiàn),使用不同的、學(xué)習(xí)到的線性映射將查詢、鍵和值分別線性映射到 dk、dk 和 dv 維度更好。然后,在這些查詢、鍵和值的隱射版本中,我們并行地執(zhí)行注意力函數(shù),生成 dv 維輸出值。這些值被連接起來(lái),然后再次進(jìn)行映射,得到最終值,如下圖所示:

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      多頭注意力機(jī)制允許模型在不同的位置共同關(guān)注來(lái)自不同表示子空間的信息。

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      多頭注意力等式              

      在這項(xiàng)工作中,我們使用了 h=8 個(gè)平行的注意力層,或者說(shuō)頭。其中,我們使用的都是 dk=dv=dmodel/h=64。由于每個(gè)頭的維數(shù)減少,總的計(jì)算成本與全維度的單頭部注意的計(jì)算成本相似。              

      不要被這個(gè)弄糊涂了,本質(zhì)上,我們所做的就是給 Q,K 和 V 矩陣增加一個(gè)維數(shù)。也就是說(shuō),如果這些矩陣之前的大小是 [1, 4, 768],表示 [bs, seq_len, d_model],則這些矩陣被投影到[bs, n_head, seq_len, d_model//n_head],大小為 [1, 12, 4, 64]。GPT-2 使用 12 個(gè)平行頭。我們將 Q,K,V 矩陣分解到 split_heads 函數(shù)中。最后,當(dāng)我們通過(guò)應(yīng)用并行注意力得到一個(gè)輸出時(shí),我們將它連接到合并頭中,返回到維度矩陣 [bs,seq_len,d_model]。              

      代碼中的 GPT-2 模型體系結(jié)構(gòu)

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      到目前為止,我們已經(jīng)實(shí)現(xiàn)了多頭注意和前饋層。如上圖所示,這兩層構(gòu)成 transformer 解碼器塊的構(gòu)建塊。GPT-2 由 12 個(gè) transformer 組組成。              

      這在 Jay Alammar 的文章中顯示如下:

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      由 12 個(gè)解碼塊組成的 GPT 體系結(jié)構(gòu)              

      transformer 解碼器塊說(shuō)明

      class TransformerBlock(nn.Module):
          def __init__(self, d_model=768, n_head=12, dropout=0.1):
              super(TransformerBlock, self).__init__()
              self.attn        = Attention(d_model=768, n_head=12, d_head=64, n_ctx=1024, bias=True, scale=False)
              self.feedforward = FeedForward(dropout=0.1, d_model=768, nx=768*4)
              self.ln_1        = LayerNorm(d_model)
              self.ln_2        = LayerNorm(d_model)
                     
          def forward(self, x):
              x = x + self.attn(self.ln_1(x))
              x = x + self.feedforward(self.ln_2(x))
              return x

      transformer 組由注意力層和前饋層組成,如 GPT-2 架構(gòu)模型規(guī)范所述:層規(guī)范化被移動(dòng)到每個(gè)子塊的輸入,這里的子塊是注意力和前饋。              

      因此,在 transformer 解碼器塊中,我們首先將輸入傳遞給一個(gè) LayerNorm,然后是第一個(gè)子注意力塊。接下來(lái),我們將這個(gè)子塊的輸出再次傳遞給 LayerNorm,最后傳遞給前饋層。              

      GPT-2架構(gòu)說(shuō)明              

      如 GPT 論文所述:我們訓(xùn)練了一個(gè) 12 層的只解碼的 transformer,它有隱藏的自注意力頭(768 個(gè)維度和 12 個(gè)注意力頭)。              

      因此,完整的 GPT-2 體系結(jié)構(gòu)是經(jīng)過(guò) 12 次復(fù)制的 TransformerBlock。

      def _get_clones(module, n):
          return ModuleList([copy.deepcopy(module) for i in range(n)])

      class GPT2(nn.Module):
          def __init__(self, nlayers=12, n_ctx=1024, d_model=768, vcb_sz=50257):
              super(GPT2, self).__init__()
              self.nlayers = nlayers
              block        = TransformerBlock(d_model=768, n_head=12, dropout=0.1)
              self.h       = _get_clones(block, 12)
              self.wte     = nn.Embedding(vcb_sz, d_model)
              self.wpe     = nn.Embedding(n_ctx, d_model)
              self.drop    = nn.Dropout(0.1)
              self.ln_f    = LayerNorm(d_model)
              self.out     = nn.Linear(d_model, vcb_sz, bias=False)
              self.loss_fn = nn.CrossEntropyLoss()
              self.init_weights()
         
          def init_weights(self):
              self.out.weight = self.wte.weight
              self.apply(self._init_weights)
         
          def _init_weights(self, module):
              if isinstance(module, (nn.Linear, nn.Embedding, Conv1D)):
                  module.weight.data.normal_(mean=0.0, std=0.02)
                  if isinstance(module, (nn.Linear, Conv1D)) and module.bias is not None:
                      module.bias.data.zero_()
              elif isinstance(module, nn.LayerNorm):
                  module.bias.data.zero_()
                  module.weight.data.fill_(1.0)
         
          def forward(self, src, labels=None, pos_ids=None):
              if pos_ids is None: pos_ids = torch.arange(0, src.size(-1)).unsqueeze(0)
              inp = self.drop((self.wte(src)+self.wpe(pos_ids)))
              for i in range(self.nlayers): inp = self.h[i](inp)
              inp     = self.ln_f(inp)
              logits  = self.out(inp)
              outputs = (logits,) + (inp,)
             
              if labels is not None:
                  shift_logits = logits[..., :-1, :].contiguous()
                  shift_labels = labels[..., 1:].contiguous()
                  loss = self.loss_fn(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
                  outputs = (loss,) + outputs
                  return outputs
              return logits

      我還沒(méi)有提到的是位置編碼和標(biāo)記嵌入。因?yàn)椋覀儾荒軐⒅T如「hey」或「hello」之類的詞直接傳遞給模型,所以我們首先將輸入標(biāo)記化。接下來(lái),我們使用嵌入將標(biāo)記表示為數(shù)字。Jay Alammar 的這篇文章(http://jalammar.github.io/illustrated-word2vec/ )很好地解釋了嵌入。              

      此外,與按順序傳遞輸入詞的 RNN 不同,transformer 并行地接受輸入矩陣,從而失去了被輸入詞的位置感。為了彌補(bǔ)這一損失,在將標(biāo)記嵌入處理到模型之前,我們添加了 Positional Encoding——一種指示序列中單詞順序的信號(hào)。如前所述,由于 GPT-2 的上下文大小是 1024,因此位置編碼的維度是 [1024, 768]。

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      從[The Illustrated GPT-2]引用的位置編碼(http://jalammar.github.io/Illustrated-gpt2/)              

      因此,GPT-2 體系結(jié)構(gòu)的輸入是通過(guò)一個(gè) Dropout 的標(biāo)記嵌入和位置編碼的總和。一旦我們有了輸入矩陣,我們就讓其通過(guò) GPT-2 架構(gòu)的 12 層中的每一層,其中每一層都是一個(gè)由兩個(gè)子層組成的 transformer 譯碼器塊——注意力和前饋網(wǎng)絡(luò)。              

      語(yǔ)言建模或分類              

      當(dāng)使用 GPT-2 作為語(yǔ)言模型時(shí),我們將輸入傳遞到最終層形式,并通過(guò)最終大小為[768, vocab_sz](50257)的線性層,得到大小為[1,4,50257]的輸出。這個(gè)輸出表示下一個(gè)詞匯輸入,我們現(xiàn)在可以很容易地通過(guò)一個(gè) softmax 層,并使用 argmax 以最大的概率獲得單詞在詞匯表中的位置。              

      對(duì)于分類任務(wù),我們可以通過(guò)大小為 [768, n] 的線性層來(lái)傳遞從 GPT-2 架構(gòu)接收到的輸出,以獲得每個(gè)類別的概率(其中 n 表示類別的數(shù)量),然后通過(guò) softmax 傳遞,得到最高的預(yù)測(cè)類別,并使用 CrossEntropyLoss 來(lái)訓(xùn)練架構(gòu)進(jìn)行分類。              

      這就是 GPT-2 背后的全部魔法。它是一種基于解碼器的 transformer 式結(jié)構(gòu),與 RNN 不同,它采用與位置編碼并行的輸入,通過(guò) 12 個(gè) transformer 解碼器層(由多頭注意力和前饋網(wǎng)絡(luò)組成)中的每一層來(lái)返回最終輸出。   

      讓我們?cè)谡Z(yǔ)言模型任務(wù)中看看這個(gè)模型的實(shí)際作用。              

      使用 Hugging Face 預(yù)訓(xùn)練權(quán)重生成示例文本              

      首先,讓我們用 Hugging Face 提供的預(yù)訓(xùn)練權(quán)重初始化模型。

      model = GPT2()
      # load pretrained_weights from hugging face
      # download file https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-pytorch_model.bin to `.`

      model_dict = model.state_dict() #currently with random initialization
      state_dict = torch.load("./gpt2-pytorch_model.bin") #pretrained weights

      old_keys = []
      new_keys = []
      for key in state_dict.keys():
          if "mlp" in key: #The hugging face state dict references the feedforward network as mlp, need to replace to `feedforward` be able to reuse these weights
              new_key = key.replace("mlp", "feedforward")
              new_keys.append(new_key)
              old_keys.append(key)

      for old_key, new_key in zip(old_keys, new_keys):
          state_dict[new_key]=state_dict.pop(old_key)

      pretrained_dict = {k: v for k, v in state_dict.items() if k in model_dict}

      model_dict.update(pretrained_dict)
      model.load_state_dict(model_dict)
      model.eval() #model in inference mode as it's now initialized with pretrained weights

      現(xiàn)在讓我們生成文本。我們將使用 Hugging Face 的預(yù)訓(xùn)練標(biāo)記器將單詞轉(zhuǎn)換為輸入嵌入。

      from transformers import GPT2Tokenizer
      tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
      context   = torch.tensor([tokenizer.encode("The planet earth")])


      def generate(context, ntok=20):
          for _ in range(ntok):
              out = model(context)
              logits = out[:, -1, :]
              indices_to_remove = logits < torch.topk(logits, 10)[0][..., -1, None]
              logits[indices_to_remove] = np.NINF
              next_tok = torch.multinomial(F.softmax(logits, dim=-1), num_samples=1).squeeze(1)
              context = torch.cat([context, next_tok.unsqueeze(-1)], dim=-1)
          return context

      out = generate(context, ntok=20)
      tokenizer.decode(out[0])

      >> 'The planet earth is the source of all of all the light," says the study that the government will'

      附加內(nèi)容              

      另一種實(shí)現(xiàn)注意力的方法,在 fast.ai 的 NLP 課程(https://github.com/fastai/course-nlp/blob/master/8-translation-transformer.ipynb )中有,我發(fā)現(xiàn)更直觀的方法如下:

      class Attention_FASTAI(nn.Module):
          def __init__(self, d_model=768, n_head=12, d_head=64, n_ctx=1024, bias=True, scale=False):
              super().__init__()
              self.n_head   = n_head
              self.d_head   = d_head
              self.softmax  = nn.Softmax(dim=-1)
              self.scale    = scale
              self.atn_drop = nn.Dropout(0.1)
              self.wq, self.wk, self.wv = [nn.Linear(d_model, n_head*d_head,
                                                     bias=bias) for o in range(3)]
         

          def split_heads(self, x, layer, bs):
              x = layer(x)
              return x.view(bs, x.size(1), self.n_head, self.d_head).permute(0,2,1,3)
             
          def _attn(self, q, k, v, attn_mask=None):
              scores  = torch.matmul(q, k.transpose(-2, -1))
              if self.scale: scores = scores/math.sqrt(v.size(-1))
              if attn_mask is not None:
                  scores = scores.float().masked_fill(attn_mask, -float('inf')).type_as(scores)
              attn_prob  = self.atn_drop(self.softmax(scores))
              attn_vec   = attn_prob @ v
              return attn_vec
         
          def merge_heads(self, x, bs, seq_len):
              x         = x.permute(0, 2, 1, 3).contiguous()
              return x.view(bs, seq_len, -1)
             
          def forward(self, q, k, v, mask=None):
              bs, seq_len = q.size(0), q.size(1)
              wq, wk, wv  = map(lambda o:self.split_heads(*o, bs),
                              zip((q,k,v), (self.wq, self.wk, self.wv)))
              attn_vec    = self._attn(wq, wk, wv)
              attn_vec    = self.merge_heads(attn_vec, bs, seq_len)
              return attn_vec

      上面的實(shí)現(xiàn)與我們采用的實(shí)現(xiàn)方法的關(guān)鍵區(qū)別在于,這個(gè)實(shí)現(xiàn)沒(méi)有使用 CONV1D,而是先將輸入 x 傳遞給 self.wq、self.wk 和 self.wv 線性層,得到 wq、wk 和 wv 矩陣,然后接下來(lái)和前面一樣。              

      寫在最后             

      特別感謝 Hugging Face 創(chuàng)建了一個(gè)開(kāi)源的 NLP 庫(kù),并提供了許多可使用的預(yù)訓(xùn)練模型。如前所述,本文中的代碼直接來(lái)自 Hugging Face 庫(kù)。The Illustrated GPT-2(http://jalammar.github.io/illustrated-gpt2/ )是關(guān)于 GPT-2 知識(shí)最全的博客之一。最后,Harvard NLP 的 The Annotated Transformer(https://nlp.seas.harvard.edu/2018/04/03/attention.html )完成了一個(gè)很棒且易于學(xué)習(xí)的 PyTorch 中 Transformers 的實(shí)現(xiàn)。          

      via:https://amaarora.github.io/2020/02/18/annotatedGPT2.html

      雷鋒網(wǎng)雷鋒網(wǎng)雷鋒網(wǎng) 

      雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見(jiàn)轉(zhuǎn)載須知

      GPT-2沒(méi)什么神奇的,PyTorch 就可以復(fù)現(xiàn)代碼

      分享:
      相關(guān)文章
      當(dāng)月熱門文章
      最新文章
      請(qǐng)?zhí)顚懮暾?qǐng)人資料
      姓名
      電話
      郵箱
      微信號(hào)
      作品鏈接
      個(gè)人簡(jiǎn)介
      為了您的賬戶安全,請(qǐng)驗(yàn)證郵箱
      您的郵箱還未驗(yàn)證,完成可獲20積分喲!
      請(qǐng)驗(yàn)證您的郵箱
      完善賬號(hào)信息
      您的賬號(hào)已經(jīng)綁定,現(xiàn)在您可以設(shè)置密碼以方便用郵箱登錄
      主站蜘蛛池模板: 影音先锋成人A片| 久久人妻少妇嫩草av| 亚洲精品97久久中文字幕无码 | 国产欧美一区二区三区在线| 极品美女扒开粉嫩小泬图片| 538AV| 亚洲成人精选| 性色在线视频精品| 精品亚洲韩国一区二区三区| 亚洲欧美日韩一区二区| 久久精品久久电影免费理论片| 欧美性受xxxx黑人猛交| 51精品视频| 国产精品人人妻人人爽| 富婆熟妇熟女二区三区| 久久91精品久久91综合| 亚洲国产美女精品久久久| 精品无码人妻夜人多侵犯18| 国产999精品成人网站| 日本xxxx裸体xxxx| 乱熟女高潮一区二区在线| a在线视频| 国产96在线 | 亚洲| 亚洲AVAV天堂Av在线播放| 久久综合激情网| 亚洲av专区一区| 精品亚洲人伦一区二区三区| 亚洲性av网站| 福利cosplayh裸体の福利| 色二区| 成人国产亚洲欧美成人综合网| 国产91精品丝袜美腿在线| 久久国产精99精产国高潮| 国产男女免费完整视频| 日韩美女av二区三区四区| 精品一区二区三区无码免费直播| 同江市| 国产精品天天狠天天看| 亚洲成人影片| 狠狠人妻久久久久久| 99热精这里只有精品|