網(wǎng)上有很多關(guān)于pos機(jī)出現(xiàn)代碼04,PyTorch 就可以復(fù)現(xiàn)代碼的知識,也有很多人為大家解答關(guān)于pos機(jī)出現(xiàn)代碼04的問題,今天pos機(jī)之家(www.rcqwhg.com)為大家整理了關(guān)于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
pos機(jī)出現(xiàn)代碼04
歡迎來到「帶注釋的 GPT-2」。
我讀過的最精彩、解釋最清楚的文章之一是「The Annotated Transformer」https://nlp.seas.harvard.edu/2018/04/03/attention.html。它引起了前所未有的關(guān)注,一個簡單的想法就是用一個文件注釋你所需要的代碼。
我在機(jī)器學(xué)習(xí)方面的經(jīng)驗讓我意識到,當(dāng)你將事情寫成代碼的時候,其實現(xiàn)和秘密會變得更清晰,而不再是魔法了。
魔法沒有什么神奇的。魔術(shù)師只是理解一些簡單的東西,而這些東西對未經(jīng)訓(xùn)練的觀眾來說似乎并不簡單。一旦你學(xué)會了操作魔術(shù)卡片,你也可以變魔術(shù)。
——Jeffrey Friedl 在《Mastering Regular Expressions》一書中寫道
GPT-2 一開始看起來像是魔術(shù),它的看起來太美麗了,但希望我能為你解釋魔術(shù),在你讀完這篇文章時揭示所有的技巧,這是我的目標(biāo)。使那些熱衷于理解 GPT-2 模型是如何工作的人更好理解。
注:幾乎所有代碼都是從Hugging Face(https://github.com/huggingface/transformers/blob/master/src/transformers/modeling_gpt2.py)的 GPT-2 實現(xiàn)中復(fù)制、啟發(fā)和引用的,只保留了簡單的基本要素。如果你想在并行 GPU 上訓(xùn)練 GPT-2 模型,在微調(diào)時保存檢查點,在多個 CPU 上運行推理任務(wù)等等,我建議你使用 Hugging Face API。最近,Hugging Face 發(fā)布了一個簡單的教程,它教你如何做到這一點:https://huggingface.co/blog/how-to-train。
在這篇文章中,我并不是在試圖重新發(fā)明輪子,而是僅僅把一系列已經(jīng)存在的優(yōu)秀資源放在一起,讓讀者更容易掌握 GPT-2。我讓讀者在他們所選擇的任何領(lǐng)域進(jìn)一步建立這些基礎(chǔ)。
你不能在弱小的基礎(chǔ)上建造一座偉大的建筑。如果你要有一個強(qiáng)大的上層建筑,你必須有堅實的基礎(chǔ)。
——Gordon B. Hinckley
學(xué)習(xí)本教程的先決條件
本文假設(shè)讀者對注意力機(jī)制和 tansformers 有著扎實的理解。GPT-2 采用 12 層的,僅有解碼器的 transformer 架構(gòu)。如果你想復(fù)習(xí)一下或了解注意力機(jī)制和 transformers,這里有一個很好的資源列表:
Jay Alammar 的 The illustrated Transformer:http://jalammar.github.io/illustrated-transformer/
哈佛大學(xué) The Annotated Transformer:https://nlp.seas.harvard.edu/2018/04/03/attention.html
Rachel Thomas 和 Jeremy Howard的 Introduction to the Transformer:https://www.youtube.com/watch?v=AFkGPmU16QA&list=PLtmWHNX-gukKocXQOkQjuVxglSDYWsSh9&index=18&t=0s
如果你剛剛開始你的 NLP 之旅,或者你是一個專家,我絕對會推薦 Rachel Thomas 和 Jeremy Howard 教授的 fast.ai NLP 課程(https://www.fast.ai/2019/07/08/fastai-nlp/)。本課程從基礎(chǔ)開始,包括使用樸素貝葉斯和 Logistic 回歸進(jìn)行語義分類,接著是 RNN,后面還討論了遷移學(xué)習(xí)、ULMFiT、Seq2Seq 翻譯和 transformers 等。它是 fast.ai 團(tuán)隊免費提供的優(yōu)秀資源。
另一個關(guān)于 GPT-2 本身的優(yōu)秀資源,是 Jay Alammar 的 The Illustrated GPT-2(http://jalammar.github.io/illustrated-gpt2/)。本文從語言模型的基本介紹開始,以一種非常容易理解的方式逐步解釋 GPT-2 模型。我強(qiáng)烈建議讀者閱讀這篇文章。
哈佛大學(xué) The Annotated Transformer 使用 PyTorch 實現(xiàn)了完整的 transformer 架構(gòu),是深入理解 transformer 的好方法。
然后,讓我們在這些優(yōu)秀的現(xiàn)有資源的基礎(chǔ)上,用代碼實現(xiàn) GPT-2 吧~
摘要
自然語言處理任務(wù),如問答、機(jī)器翻譯、閱讀理解等,通常是在特定任務(wù)的數(shù)據(jù)集上進(jìn)行有監(jiān)督的學(xué)習(xí)。我們證明,當(dāng)語言模型在一個名為 WebText 的數(shù)百萬網(wǎng)頁的新數(shù)據(jù)集上訓(xùn)練時,它開始學(xué)習(xí)這些任務(wù),而不需要任何明確的監(jiān)督。我們最大的模型,GPT-2,是一個 1.5B 參數(shù)的 transformer,它可以獲得最先進(jìn)的語言建模成果,但仍然不適合 WebText。模型中的示例反映了這些改進(jìn),并包含連貫的文本段落。這些發(fā)現(xiàn)為構(gòu)建語言處理系統(tǒng)提供了一條有希望的途徑,該系統(tǒng)可以從自然發(fā)生的演示中學(xué)習(xí)執(zhí)行任務(wù)。
Zero-shot 設(shè)置是不微調(diào)語言模型并直接在目標(biāo)數(shù)據(jù)集上運行推理的設(shè)置。例如,在 WebText 上預(yù)覽一個 LM,并直接嘗試預(yù)測 Amazon 影評數(shù)據(jù)集的下一個單詞。
模型架構(gòu)(GPT-2)
我們的 LM 使用基于 transformer 的架構(gòu)。該模型主要遵循 OpenAI GPT 模型的細(xì)節(jié),并進(jìn)行了一些修改。層規(guī)范化被移動到每個子塊的輸入,類似于預(yù)激活剩余網(wǎng)絡(luò),并且在最終的自關(guān)注塊之后添加了額外的層規(guī)范化。我們在初始化時將剩余層的權(quán)重按 1/√N(yùn) 的因子進(jìn)行縮放,其中 N 是剩余層的數(shù)量。詞匯量擴(kuò)大到 50257 個單詞。我們還將上下文大小從 512 增加到 1024 個,并使用更大的批大小——512。
模型規(guī)格(GPT)
我們的模型基本上遵循了最初 transformer 的工作原理。我們訓(xùn)練了一個 12 層的只解碼的 transformer,它有隱藏的自注意力頭(768 維狀態(tài)和 12 個注意力頭)。對于位置前饋網(wǎng)絡(luò),我們使用了 3072 維的內(nèi)部狀態(tài)。我們使用 Adam 優(yōu)化方案,最大學(xué)習(xí)速率為 2.5e-4。學(xué)習(xí)速率在前 2000 次更新中從零線性增加,并使用余弦調(diào)度將其退火為 0。我們在 64 個隨機(jī)抽樣的小批量、512 個令牌的連續(xù)序列上訓(xùn)練了 100 個階段。由于 layernorm 在整個模型中廣泛使用,簡單的 N(0,0.02)權(quán)重初始化就足夠了。我們使用了一個 bytepair 編碼(BPE)詞匯表。我們還采用了在中提出的 L2 正則化的改進(jìn)版本,在所有非偏倚或增益權(quán)重上的 w=0.01。對于激活函數(shù),我們使用高斯誤差線性單位(GELU)。
導(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ù)語,注意是一個查詢(Q)和一組鍵(K)和值(V)對的函數(shù)。為了處理更長的序列,我們修改了 transformer 的多頭自注意力機(jī)制,通過限制 Q 和 K 之間的點積來減少內(nèi)存使用:
注意力是查詢、鍵和值的組合
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 層本身可以看作是一個線性層。本質(zhì)上,它是投射一個初始張量 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 矩陣的另一種方法是必須有單獨的 Wq、Wk 和 Wv 矩陣。我已經(jīng)在這篇文章底部的附加部分解釋了這一點。我發(fā)現(xiàn)這種方法更直觀、更具相關(guān)性,但在本文中我們使用了 CONV1D 層,因為我們重用了 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 的文章中有一個很好的解釋,也就是上面提到的,輸入是如何先經(jīng)過注意力層,然后再進(jìn)入前向?qū)拥摹G梆伨W(wǎng)絡(luò)是一個正常的網(wǎng)絡(luò),它接受來自注意力層(768)的輸出,將其投射到 nx(768×4)維,添加一個激活函數(shù) self.act(GELU),將其投射回 d_model (768) 并添加 dropout(0.1)。
注意力層解釋
下面的摘錄是從論文上摘取的:https://arxiv.org/abs/1706.03762。
標(biāo)度點產(chǎn)品注意力
我們稱我們的注意力為「標(biāo)度點產(chǎn)品注意力」。輸入包括維度 dk 的查詢和鍵以及維度 dv 的值。我們使用所有鍵計算查詢的點積,用√dk除以每個鍵,然后應(yīng)用 softmax 函數(shù)獲得值的權(quán)重。
在實際應(yīng)用中,我們同時計算一組查詢的注意力函數(shù),將它們組合成一個矩陣 Q,并將鍵和值組合成矩陣 K 和 V。我們將輸出矩陣計算為:
輸出矩陣為 Q、K 和 V 的組合
最常用的兩個注意力函數(shù)是加性注意力函數(shù)和點積(乘法)力函數(shù)注意。除了比例因子 1/√dk 外,點積注意力與我們的算法相同。附加注意力使用具有單個隱藏層的前饋網(wǎng)絡(luò)計算兼容性函數(shù)。雖然二者在理論復(fù)雜度上相似,但在實際應(yīng)用中,點積注意力速度更快,空間效率更高,因為它可以使用高度優(yōu)化的矩陣乘法碼來實現(xiàn)。當(dāng) dk 值較小時,兩種機(jī)制的表現(xiàn)相似,但在 dk 值較大時,加性注意力優(yōu)于點積注意力。我們懷疑,對于 dk 的較大值,點積在數(shù)量上增長較大,將 softmax 函數(shù)推入具有極小梯度的區(qū)域。為了抵消這一影響,我們將網(wǎng)點產(chǎn)品縮放至 1/√dk。
為了在代碼中實現(xiàn)注意力層,我們首先利用 CONV1D 層,得到前面解釋的 Q、K 和 V 矩陣。
一旦我們有了 Q、K 和 V 矩陣,我們就可以使用函數(shù) _attn 來執(zhí)行注意力。此函數(shù)復(fù)制了上述注意力點積公式。
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
另一種實現(xiàn)注意力的方法在本博客底部的附加部分進(jìn)行了說明。我發(fā)現(xiàn)它更直觀,更容易與研究論文進(jìn)行比較。它利用線性層而不是 CONV1D 將輸入轉(zhuǎn)換為 Q、K 和 V 矩陣。我們之所以沒有使用它,是因為我們使用了預(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 維輸出值。這些值被連接起來,然后再次進(jìn)行映射,得到最終值,如下圖所示:
多頭注意力機(jī)制允許模型在不同的位置共同關(guān)注來自不同表示子空間的信息。
多頭注意力等式
在這項工作中,我們使用了 h=8 個平行的注意力層,或者說頭。其中,我們使用的都是 dk=dv=dmodel/h=64。由于每個頭的維數(shù)減少,總的計算成本與全維度的單頭部注意的計算成本相似。
不要被這個弄糊涂了,本質(zhì)上,我們所做的就是給 Q,K 和 V 矩陣增加一個維數(shù)。也就是說,如果這些矩陣之前的大小是 [1, 4, 768],表示 [bs, seq_len, d_model],則這些矩陣被投影到[bs, n_head, seq_len, d_model//n_head],大小為 [1, 12, 4, 64]。GPT-2 使用 12 個平行頭。我們將 Q,K,V 矩陣分解到 split_heads 函數(shù)中。最后,當(dāng)我們通過應(yīng)用并行注意力得到一個輸出時,我們將它連接到合并頭中,返回到維度矩陣 [bs,seq_len,d_model]。
代碼中的 GPT-2 模型體系結(jié)構(gòu)
到目前為止,我們已經(jīng)實現(xiàn)了多頭注意和前饋層。如上圖所示,這兩層構(gòu)成 transformer 解碼器塊的構(gòu)建塊。GPT-2 由 12 個 transformer 組組成。
這在 Jay Alammar 的文章中顯示如下:
由 12 個解碼塊組成的 GPT 體系結(jié)構(gòu)
transformer 解碼器塊說明
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ī)范化被移動到每個子塊的輸入,這里的子塊是注意力和前饋。
因此,在 transformer 解碼器塊中,我們首先將輸入傳遞給一個 LayerNorm,然后是第一個子注意力塊。接下來,我們將這個子塊的輸出再次傳遞給 LayerNorm,最后傳遞給前饋層。
GPT-2架構(gòu)說明
如 GPT 論文所述:我們訓(xùn)練了一個 12 層的只解碼的 transformer,它有隱藏的自注意力頭(768 個維度和 12 個注意力頭)。
因此,完整的 GPT-2 體系結(jié)構(gòu)是經(jīng)過 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
我還沒有提到的是位置編碼和標(biāo)記嵌入。因為,我們不能將諸如「hey」或「hello」之類的詞直接傳遞給模型,所以我們首先將輸入標(biāo)記化。接下來,我們使用嵌入將標(biāo)記表示為數(shù)字。Jay Alammar 的這篇文章(http://jalammar.github.io/illustrated-word2vec/)很好地解釋了嵌入。
此外,與按順序傳遞輸入詞的 RNN 不同,transformer 并行地接受輸入矩陣,從而失去了被輸入詞的位置感。為了彌補(bǔ)這一損失,在將標(biāo)記嵌入處理到模型之前,我們添加了 Positional Encoding——一種指示序列中單詞順序的信號。如前所述,由于 GPT-2 的上下文大小是 1024,因此位置編碼的維度是 [1024, 768]。
從[The Illustrated GPT-2]引用的位置編碼(http://jalammar.github.io/Illustrated-gpt2/)
因此,GPT-2 體系結(jié)構(gòu)的輸入是通過一個 Dropout 的標(biāo)記嵌入和位置編碼的總和。一旦我們有了輸入矩陣,我們就讓其通過 GPT-2 架構(gòu)的 12 層中的每一層,其中每一層都是一個由兩個子層組成的 transformer 譯碼器塊——注意力和前饋網(wǎng)絡(luò)。
語言建?;蚍诸?
當(dāng)使用 GPT-2 作為語言模型時,我們將輸入傳遞到最終層形式,并通過最終大小為[768, vocab_sz](50257)的線性層,得到大小為[1,4,50257]的輸出。這個輸出表示下一個詞匯輸入,我們現(xiàn)在可以很容易地通過一個 softmax 層,并使用 argmax 以最大的概率獲得單詞在詞匯表中的位置。
對于分類任務(wù),我們可以通過大小為 [768, n] 的線性層來傳遞從 GPT-2 架構(gòu)接收到的輸出,以獲得每個類別的概率(其中 n 表示類別的數(shù)量),然后通過 softmax 傳遞,得到最高的預(yù)測類別,并使用 CrossEntropyLoss 來訓(xùn)練架構(gòu)進(jìn)行分類。
這就是 GPT-2 背后的全部魔法。它是一種基于解碼器的 transformer 式結(jié)構(gòu),與 RNN 不同,它采用與位置編碼并行的輸入,通過 12 個 transformer 解碼器層(由多頭注意力和前饋網(wǎng)絡(luò)組成)中的每一層來返回最終輸出。
讓我們在語言模型任務(wù)中看看這個模型的實際作用。
使用 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 initializationstate_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 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)容
另一種實現(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
上面的實現(xiàn)與我們采用的實現(xiàn)方法的關(guān)鍵區(qū)別在于,這個實現(xiàn)沒有使用 CONV1D,而是先將輸入 x 傳遞給 self.wq、self.wk 和 self.wv 線性層,得到 wq、wk 和 wv 矩陣,然后接下來和前面一樣。
寫在最后
特別感謝 Hugging Face 創(chuàng)建了一個開源的 NLP 庫,并提供了許多可使用的預(yù)訓(xùn)練模型。如前所述,本文中的代碼直接來自 Hugging Face 庫。The Illustrated GPT-2(http://jalammar.github.io/illustrated-gpt2/)是關(guān)于 GPT-2 知識最全的博客之一。最后,Harvard NLP 的 The Annotated Transformer(https://nlp.seas.harvard.edu/2018/04/03/attention.html)完成了一個很棒且易于學(xué)習(xí)的 PyTorch 中 Transformers 的實現(xiàn)。
via:https://amaarora.github.io/2020/02/18/annotatedGPT2.html
雷鋒網(wǎng)雷鋒網(wǎng)雷鋒網(wǎng)
以上就是關(guān)于pos機(jī)出現(xiàn)代碼04,PyTorch 就可以復(fù)現(xiàn)代碼的知識,后面我們會繼續(xù)為大家整理關(guān)于pos機(jī)出現(xiàn)代碼04的知識,希望能夠幫助到大家!