GPT-2 sihirli bir şey değildir, PyTorch kodu yeniden üretebilir

"Açıklamalı GPT-2" ye hoş geldiniz.

Okuduğum en heyecan verici ve açıkça anlatılan makalelerden biri "The Annotated Transformer" https://nlp.seas.harvard.edu/2018/04/03/attention.html. Benzeri görülmemiş bir ilgi çekmiştir ve basit bir fikir, ihtiyacınız olan koda açıklama eklemek için bir dosya kullanmaktır.

Makine öğrenimindeki deneyimim, bir şeyleri koda yazdığınızda, uygulamanın ve sırların sihir değil, daha net hale geleceğini fark etmemi sağladı.

Sihir hakkında büyülü hiçbir şey yoktur. Sihirbaz bazı basit şeyleri anlar ve bu şeyler eğitimsiz bir izleyici için basit görünmez. Sihirli kartları nasıl kullanacağınızı öğrendikten sonra sihir de yapabilirsiniz.

Jeffrey Friedl "Normal İfadelerde Uzmanlaşmak"

GPT-2 ilk bakışta sihir gibi görünüyor, çok güzel görünüyor ama umarım sihri size açıklayabilirim ve bu makaleyi okumayı bitirdiğinizde tüm püf noktalarını ortaya çıkarabilirim. Amacım budur. GPT-2 modelinin nasıl çalıştığını anlamak isteyenler için daha iyi hale getirin.

Not: Hemen hemen tüm kod, Hugging Face'in GPT-2 uygulamasından (https://github.com/huggingface/transformers/blob/master/src/transformers/modeling_gpt2.py) kopyalanır, esinlenir ve referans alınır, yalnızca Basit temel öğeler. GPT-2 modellerini paralel GPU'larda eğitmek, ince ayar sırasında kontrol noktalarını kaydetmek, birden çok CPU'da çıkarım görevleri çalıştırmak vb. İstiyorsanız Hugging Face API'yi kullanmanızı öneririm. Son zamanlarda, Hugging Face, bunu nasıl yapacağınızı öğreten basit bir eğitim yayınladı: https://huggingface.co/blog/how-to-train.

Bu makalede, tekerleği yeniden icat etmeye çalışmıyorum, ancak okuyucuların GPT-2'de ustalaşmasını kolaylaştırmak için zaten var olan bir dizi mükemmel kaynağı bir araya getiriyorum. Okurlardan, seçtikleri alanda bu temelleri daha da inşa etmelerini istiyorum.

Zayıf bir temel üzerine harika bir bina inşa edemezsiniz. Güçlü bir üst yapı istiyorsanız, sağlam bir temele sahip olmalısınız.

Gordon B. Hinckley

Bu öğretici için ön koşullar

Bu makale, okuyucunun dikkat mekanizmaları ve tansformerler hakkında sağlam bir anlayışa sahip olduğunu varsaymaktadır. GPT-2, yalnızca kod çözücüler içeren 12 katmanlı bir transformatör mimarisi kullanır. Dikkat mekanizmalarını ve dönüştürücüleri incelemek veya öğrenmek istiyorsanız, işte kaynakların iyi bir listesi:

  • Jay Alammar'ın çizdiği Transformer:

  • Harvard Üniversitesi Açıklamalı Transformatör: https://nlp.seas.harvard.edu/2018/04/03/attention.html

  • Transformer'a Giriş, Rachel Thomas ve Jeremy Howard: https://www.youtube.com/watch?v=AFkGPmU16QAlist=PLtmWHNX-gukKocXQOkQjuVxglSDYWsSh9index=18t=0s

NLP yolculuğunuza yeni başlıyorsanız veya bir uzmansanız, Rachel Thomas ve Jeremy Howard tarafından verilen fast.ai NLP kursunu kesinlikle tavsiye ederim (https://www.fast.ai/2019/07/08/fastai -nlp /). Bu ders, naif Bayes ve Logistic regresyon kullanarak semantik sınıflandırma, ardından RNN ve daha sonra transfer öğrenme, ULMFiT, Seq2Seq çeviri ve transformatörler dahil olmak üzere temellerden başlar. Fast.ai ekibi tarafından ücretsiz olarak sağlanan mükemmel bir kaynaktır.

GPT-2'nin kendisi ile ilgili bir başka mükemmel kaynak, Jay Alammar'ın Resimli GPT-2'sidir ( Bu makale, dil modeline temel bir girişle başlar ve GPT-2 modelini anlaşılması çok kolay bir şekilde adım adım açıklar. Okuyucuların bu makaleyi okumalarını şiddetle tavsiye ediyorum.

Harvard Üniversitesi Açıklamalı Transformatör, transformatörü anlamanın iyi bir yolu olan eksiksiz bir transformatör mimarisi uygulamak için PyTorch'u kullanıyor.

Ardından, GPT-2'yi bu mükemmel mevcut kaynaklar temelinde kodla uygulayalım ~

Özet

Soru cevaplama, makine çevirisi, okuduğunu anlama, vb. Gibi doğal dil işleme görevleri genellikle belirli görevler için veri kümeleri üzerinde öğrenim olarak denetlenir. Bir dil modelinin, WebText adı verilen milyonlarca web sayfasından oluşan yeni bir veri kümesi üzerinde eğitildiğinde, bu görevleri herhangi bir açık denetim olmaksızın öğrenmeye başladığını gösteriyoruz. En büyük modelimiz olan GPT-2, en gelişmiş dil modelleme sonuçlarını elde edebilen 1.5B parametreli bir transformatördür, ancak yine de WebText için uygun değildir. Modeldeki örnekler bu gelişmeleri yansıtır ve tutarlı metin paragrafları içerir. Bu bulgular, doğal olarak meydana gelen gösterilerden görevleri gerçekleştirmeyi öğrenebilen dil işleme sistemleri oluşturmak için umut verici bir yol sağlar.

Sıfır atış ayarı, dil modelinde ince ayar yapmayan ve doğrudan hedef veri kümesi üzerinde çıkarım yapan bir ayardır. Örneğin, WebText'te bir LM'yi önizleyin ve doğrudan Amazon film inceleme veri kümesindeki bir sonraki kelimeyi tahmin etmeye çalışın.

Model mimarisi (GPT-2)

LM'miz transformatör tabanlı bir mimari kullanır. Model, bazı değişikliklerle birlikte temel olarak OpenAI GPT modelinin ayrıntılarını takip eder. Katman normalizasyonu, önceden etkinleştirilen artık ağa benzer şekilde her bir alt bloğun girişine taşınır ve son kendinden odaklı bloktan sonra ek katman normalizasyonu eklenir. Kalan katmanların ağırlıklarını başlatma sırasında 1 / N faktörü ile ölçeklendiriyoruz, burada N kalan katman sayısıdır. Kelime dağarcığı 50257 kelimeye genişletildi. Ayrıca bağlam boyutunu 512'den 1024'e çıkardık ve daha büyük bir parti boyutu-512 kullandık.

Model özellikleri (GPT)

Modelimiz temelde orijinal transformatörün çalışma prensibini takip etmektedir. Gizli öz-dikkat başlıkları (768 boyutlu durumlar ve 12 dikkat kafası) olan 12 katmanlı bir yalnızca kod çözme transformatörü eğittik. Konum ileri besleme ağı için 3072 boyutlu dahili durum kullandık. Adam optimizasyon şemasını maksimum öğrenme oranı 2.5e-4 olarak kullanıyoruz. Öğrenme hızı, ilk 2000 güncellemede sıfırdan doğrusal olarak artar ve kosinüs çizelgeleme kullanılarak sıfıra tavlanır. 64 rastgele örneklenmiş mini grupta sürekli 512 jeton dizisi üzerinde 100 aşamayı eğittik. Layernorm, model boyunca yaygın olarak kullanıldığından, basit bir N (0, 0.02) ağırlık başlatma yeterlidir. Bir bytepair kodlama (BPE) sözlüğü kullanıyoruz. Ayrıca, içinde önerilen, tüm tarafsız veya kazanç ağırlıkları için w = 0.01 olan, geliştirilmiş bir L2 regülasyonu versiyonunu benimsedik. Aktivasyon fonksiyonu için Gauss Hatalı Doğrusal Birim (GELU) kullanıyoruz.

İthalat

meşale ithal

kopyayı içe aktar

torch.nn'yi nn olarak içe aktar

Torch.nn.F olarak işlevsel içe aktar

Torch.nn.modules'den ModuleList içe aktarma

torch.nn.modules.normalization'dan import LayerNorm

numpy'yi np olarak içe aktar

işletim sistemini içe aktar

tqdm'den içe aktar tqdm_notebook, trange

içe aktarma günlük kaydı

logging.basicConfig (düzey = logging.INFO)

logger = logging.getLogger

GPT-2 içinde transformatör kod çözücü

Transformatörü tanımlamak için kullanılan terimi yeniden kullanmak için, bunun bir sorgu (Q) ve bir dizi anahtar (K) ve değer (V) çiftlerinin bir işlevi olduğuna dikkat edin. Daha uzun dizileri işlemek için, Q ve K arasındaki nokta çarpımını sınırlayarak bellek kullanımını azaltmak için transformatörün çok başlı öz-dikkat mekanizmasını değiştirdik:

Dikkat, sorgu, anahtar ve değerin birleşimidir

sınıf Conv1D (nn.Module):

def __init __ (self, nx, nf): super .__ init__

self.nf = nf

w = meşale. boş (nx, nf)

nn.init.normal_ (w, std = 0,02)

self.weight = nn.Parameter (w)

self.bias = nn.Parameter (torch.zeros (nf))

def ileri (öz, x):

size_out = x.size + (self.nf,)

x = torch.addmm (self.bias, x.view (-1, x.size (-1)), self.weight)

x = x.view (* size_out)

dönüş x

CONV1D katman açıklaması

CONV1D katmanının kendisi doğrusal bir katman olarak kabul edilebilir. Esasen, bir başlangıç tensörü x (son boyut x.size (-1)) yansıtmak ve ona iletmektir ve son boyut self.nf'dir.

İşte aynı çıktının bir örneği:

d_model = 768

conv1d = Dönş1D (d_model, d_model * 3)

x = torch.rand (1,4, d_model) # batch_size = 1, seq_len = 4 ve embedding_sz = 768 dizisini temsil eder, "Merhaba nasılsın" gibi bir şey

x = dönş1d (x)

x.shape

> > torch.Size ()

Yukarıdaki örnekte gösterildiği gibi, CONV1D tarafından döndürülen tensörün son boyutu, başlangıç boyutunun 3 katıdır. Bunu girdiyi bir sorgu, anahtar ve değer matrisine dönüştürebilmek için yapıyoruz.

Daha sonra sorguyu, anahtarı ve değer matrisini aşağıdaki gibi alabilirsiniz:

sorgu, anahtar, değer = x.split (d_model, dim = -1)

query.shape, key.shape, value.shape

> > (torch.Size (), torch.Size (), torch.Size ())

Girişi Q, K ve V matrislerine dönüştürmenin başka bir yolu, ayrı Wq, Wk ve Wv matrislerine sahip olmaktır. Bunu bu makalenin altındaki ek bölümde açıkladım. Bu yöntemi daha sezgisel ve alakalı buluyorum, ancak bu makalede CONV1D katmanını kullandık çünkü Hugging Face'in CONV1D antrenman öncesi ağırlıklarını yeniden kullandık.

İleri katman yorumu

sınıf FeedForward (nn.Module):

def __init __ (self, dropout, d_model = 768, nx = 768 * 4):

super .__ init__

self.c_fc = Dönş1D (d_model, nx)

self.c_proj = Dönş1D (nx, d_model)

self.act = F.gelu

self.dropout = nn.Dropout (bırakma)

def ileri (öz, x):

dönüş self.dropout (self.c_proj (self.act (self.c_fc (x))))

Jay Alammar'ın makalesinde iyi bir açıklama var, yani yukarıda bahsedildiği gibi girdinin ilk önce dikkat katmanından nasıl geçtiği ve sonra ön katmana girdiği. İleri besleme ağı normal bir ağdır, dikkat katmanından (768) gelen çıktıyı kabul eder, nx (768 × 4) boyutlarına yansıtır, self.act (GELU) etkinleştirme işlevi ekler ve d_model'e geri yansıtır ( 768) ve bırakma (0.1) ekleyin.

Dikkat düzeyi yorumu

Aşağıdaki alıntı gazeteden alınmıştır: https://arxiv.org/abs/1706.03762.

Ölçek noktası ürün dikkatini

Dikkatimize "ölçek noktası ürün dikkati" diyoruz. Girdi, dk boyutunun sorgusunu ve anahtarını ve dv boyutunun değerini içerir. Sorgunun iç çarpımını hesaplamak için tüm tuşları kullanırız, dk'yi her bir tuşa böleriz ve ardından değerin ağırlığını elde etmek için softmax işlevini uygularız.

Pratik uygulamalarda, bir grup sorgunun dikkat fonksiyonunu aynı anda hesaplıyoruz, bunları bir Q matrisinde birleştiriyoruz ve anahtarları ve değerleri K ve V matrislerinde birleştiriyoruz. Çıktı matrisini şu şekilde hesaplıyoruz:

Çıktı matrisi Q, K ve V'nin bir kombinasyonudur

En sık kullanılan iki dikkat işlevi, toplamsal dikkat işlevi ve iç çarpım (çarpımsal) kuvvet işlevi dikkattir. Ölçek faktörü 1 / dk dışında, nokta ürün dikkati bizim algoritmamızla aynıdır. Ek dikkat, uyumluluk işlevini hesaplamak için tek bir gizli katmana sahip ileri beslemeli bir ağ kullanır. İkisi teorik karmaşıklıkta benzer olsa da, pratik uygulamalarda, nokta ürün dikkat hızı daha hızlıdır ve alan verimliliği daha yüksektir, çünkü yüksek düzeyde optimize edilmiş matris çarpım kodları kullanılarak uygulanabilir. Dk değeri küçük olduğunda, iki mekanizmanın performansı benzerdir, ancak dk değeri büyük olduğunda, ek dikkat, nokta ürün dikkatinden daha iyidir. Daha büyük dk değerleri için, iç çarpım sayısının artarak softmax işlevini minimum gradyanlı bir alana ittiğinden şüpheleniyoruz. Bu etkiye karşı koymak için iç çarpımı 1 / dk olarak ölçeklendirdik.

Dikkat katmanını kodda uygulamak için, daha önce açıklanan Q, K ve V matrislerini elde etmek için önce CONV1D katmanını kullanıyoruz.

Q, K ve V matrislerine sahip olduğumuzda, dikkat yapmak için _attn fonksiyonunu kullanabiliriz. Bu işlev, yukarıdaki dikkat nokta çarpımı formülünü tekrarlar.

sınıf Dikkat (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 = Dönş1D (d_model, d_model * 3)

self.scale = ölçek

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 = Dönş1D (d_model, d_model)

def split_heads (self, x):

"dönüş şekli"

new_shape = x.size + (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 = Yok):

puanlar = torch.matmul (q, k.transpose (-2, -1))

self.scale ise: puanlar = puanlar / math.sqrt (v.size (-1))

nd, ns = puanlar.size (-2), puanlar.size (-1)

attn_mask None değilse: puanlar = puanlar + attn_mask

puanlar = self.softmax (puanlar)

puanlar = self.dropout (puanlar)

çıktılar = torch.matmul (puanlar, v)

dönüş çıktıları

def merge_heads (self, x):

x = x.permute (0, 2, 1, 3). bitişik

new_shape = x.size + (x.size (-2) * x.size (-1),)

return x.view (* new_shape)

def ileri (öz, x):

x = self.c_attn (x) #yeni `x` şekil-``

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 (çıkış)

geri dönmek

Dikkat çekmenin başka bir yolu bu blogun altındaki ek bölümde açıklanmıştır. Araştırma makaleleri ile karşılaştırmayı daha sezgisel ve daha kolay buluyorum. Girişi Q, K ve V matrislerine dönüştürmek için CONV1D yerine doğrusal katmanlar kullanır. Kullanmamamızın nedeni, Hugging Face'ten tek boyutlu bir katmana dönüştürmek için önceden eğitilmiş ağırlıklar kullanmamızdır.

Çok başlı dikkat

Aşağıdaki paragraf, "Tek ihtiyacın olan dikkat" makalesinden alınmıştır.

Sırasıyla dk, dk ve dv boyutlarına sorguları, anahtarları ve değerleri doğrusal olarak eşlemek için farklı, öğrenilmiş doğrusal eşlemeler kullanmanın daha iyi olduğunu bulduk. Daha sonra, bu sorguların, anahtarların ve değerlerin örtük versiyonunda, dv boyutlu çıktı değerleri oluşturmak için dikkat fonksiyonunu paralel olarak yürütürüz. Bu değerler bağlanır ve ardından aşağıdaki şekilde gösterildiği gibi nihai değeri elde etmek için tekrar eşlenir:

Çok başlı dikkat mekanizması, modelin farklı konumlardaki farklı temsil alt uzaylarından gelen bilgilere odaklanmasına izin verir.

Çok başlı dikkat denklemi

Bu çalışmada h = 8 paralel dikkat katmanları veya başları kullandık. Bunların arasında hepimiz dk = dv = dmodel / h = 64 kullanıyoruz. Her bir kafanın boyutsallığı azaltıldığından, toplam hesaplama maliyeti, tam boyutlu tek bir kafa dikkatine benzer.

Kafanızı karıştırmayın, esasen yaptığımız şey Q, K ve V matrislerine bir boyut eklemektir. Diğer bir deyişle, eğer bu matrislerin önceki boyutu ise, yani bu matrisler projelendirilir ve boyutu olur. GPT-2, 12 paralel kafa kullanır. Q, K ve V matrislerini split_heads fonksiyonuna ayırıyoruz. Son olarak, paralel dikkat uygulayarak bir çıktı aldığımızda, onu birleştirme başlığına bağlayıp boyut matrisine geri dönüyoruz.

Kodda GPT-2 model mimarisi

Şimdiye kadar, çok başlı dikkat ve ileri besleme katmanını uyguladık. Yukarıdaki şekilde gösterildiği gibi, bu iki katman, transformatör şifre çözücü bloğunun yapı bloklarını oluşturur. GPT-2, 12 trafo grubundan oluşur.

Bu, Jay Alammar'ın makalesinde şu şekilde gösterilmektedir:

12 kod çözme bloğundan oluşan GPT mimarisi

trafo kod çözücü blok açıklaması

sınıf TransformerBlock (nn.Module):

def __init __ (self, d_model = 768, n_head = 12, dropout = 0.1):

super (TransformerBlock, self) .__ init__

self.attn = Dikkat (d_model = 768, n_head = 12, d_head = 64, n_ctx = 1024, bias = True, scale = False)

self.feedforward = FeedForward (bırakma = 0.1, d_model = 768, nx = 768 * 4)

self.ln_1 = LayerNorm (d_model)

self.ln_2 = LayerNorm (d_model)

def ileri (öz, x):

x = x + self.attn (self.ln_1 (x))

x = x + self.feedforward (self.ln_2 (x))

dönüş x

Transformatör grubu, GPT-2 mimari modeli spesifikasyonunda belirtildiği gibi, bir dikkat katmanından ve bir ileri besleme katmanından oluşur: katman normalizasyonu, alt blokların dikkat ve ileri beslendiği her bir alt bloğun girişine taşınır.

Bu nedenle, transformatör kod çözücü bloğunda, önce girişi bir LayerNorm'a ve ardından ilk alt dikkat bloğuna geçiririz. Daha sonra, bu alt bloğun çıktısını tekrar LayerNorm'a ve son olarak feedforward katmanına iletiyoruz.

GPT-2 mimarisi açıklaması

GPT belgesinde belirtildiği gibi: Gizli öz-ilgi kafaları olan (768 boyut ve 12 dikkat kafası) 12 katmanlı bir yalnızca kod çözme transformatörü eğittik.

Bu nedenle, eksiksiz GPT-2 mimarisi 12 kez kopyalanan bir TransformerBlock'tur.

def _get_clones (modül, n): ModuleList () döndür

sınıf GPT2 (nn.Module):

def __init __ (self, nlayers = 12, n_ctx = 1024, d_model = 768, vcb_sz = 50257):

super (GPT2, self) .__ init__

self.nlayers = nlayers

blok = TransformerBlock (d_model = 768, n_head = 12, dropout = 0.1)

self.h = _get_clones (blok, 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 (öz):

self.out.weight = self.wte.weight

self.apply (self._init_weights)

def _init_weights (öz, modül):

örnek ise (modül, (nn.Linear, nn.Embedding, Conv1D)):

module.weight.data.normal_ (ortalama = 0.0, std = 0.02)

isinstance (module, (nn.Linear, Conv1D)) ve module.bias None değilse:

module.bias.data.zero_

elif isinstance (modül, nn.LayerNorm):

module.bias.data.zero_

module.weight.data.fill_ (1.0)

def forward (self, src, etiketler = Yok, pos_ids = Yok):

pos_ids None ise: pos_ids = torch.arange (0, src.size (-1)). unsqueeze (0)

inp = self.drop ((self.wte (src) + self.wpe (pos_ids)))

aralıktaki i için (self.nlayers): inp = self.h (inp)

inp = self.ln_f (inp)

logits = self.out (inp)

çıktılar = (günlükler,) + (inp,)

etiketler Yok değilse:

shift_logits = logits.contiguous

shift_labels = labels.contiguous

kayıp = self.loss_fn (shift_logits.view (-1, shift_logits.size (-1)), shift_labels.view (-1))

çıktılar = (kayıp,) + çıktılar

dönüş çıktıları

dönüş günlükleri

Bahsetmediğim şey konum kodlama ve işaret yerleştirmedir. "Hey" veya "merhaba" gibi kelimeleri doğrudan modele geçiremediğimiz için, önce girdiyi belirtiyoruz. Ardından, işareti bir sayı olarak göstermek için yerleştirmeyi kullanırız. Jay Alammar tarafından yazılan bu makale ( yerleştirmeyi çok iyi açıklıyor.

Ek olarak, giriş kelimelerini sırayla geçiren RNN'den farklı olarak, transformatör giriş matrisini paralel olarak kabul eder ve böylece giriş kelimelerinin konum anlamını kaybeder. Bu kaybı telafi etmek için, jetonları modele yerleştirmeden önce, dizideki kelimelerin sırasını belirten bir sinyal olan Konumsal Kodlama ekledik. Daha önce de belirtildiği gibi, GPT-2'nin bağlam boyutu 1024 olduğundan, konum kodunun boyutu.

Alıntılanan konumdan kodlayın (

Bu nedenle, GPT-2 mimarisinin girdisi, bir bırakma yoluyla etiket gömme ve konum kodlamasının toplamıdır. Giriş matrisini elde ettikten sonra, GPT-2 mimarisinin her biri iki alt katmandan oluşan dikkat ve ileri beslemeden oluşan bir transformatör kod çözücü bloğu olan 12 katmanından geçmesine izin veriyoruz. İnternet.

Dil modelleme veya sınıflandırma

GPT-2'yi dil modeli olarak kullanırken, girdiyi son katman formuna geçiririz ve boyut çıktısını almak için son boyut (50257) olan doğrusal katmanı geçiririz. Bu çıktı, bir sonraki kelime haznesi girdisini temsil eder Artık bir softmax katmanını kolayca geçebilir ve kelimenin kelime haznesindeki konumunu en büyük olasılıkla elde etmek için argmax kullanabiliriz.

Sınıflandırma görevleri için, GPT-2 mimarisinden alınan çıktıyı, her kategorinin olasılığını (burada n, kategori sayısını temsil eder) elde etmek için doğrusal bir boyut katmanından geçirebilir ve ardından en yüksek tahmin edilen kategoriyi elde etmek için softmax'ten geçebiliriz , Ve sınıflandırma için mimariyi eğitmek için CrossEntropyLoss'u kullanın.

GPT-2'nin arkasındaki tüm sihir budur. RNN'den farklı, kod çözücü tabanlı bir transformatör yapısıdır.Konum kodlamasına paralel giriş kullanır ve 12 transformatör kod çözücü katmanının her biri aracılığıyla geri döner (çok başlı dikkat ve ileri beslemeli ağlardan oluşur) Nihai çıktı.

Bu modelin dil modeli görevindeki gerçek etkisine bakalım.

Örnek metin oluşturmak için Hugging Face önceden eğitilmiş ağırlıkları kullanın

Öncelikle modeli Hugging Face tarafından sağlanan önceden eğitilmiş ağırlıklarla başlatalım.

model = GPT2

# yüzü sarılmaktan önceden eğitilmiş ağırlıkları yükle

# https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-pytorch_model.bin dosyasını "."

model_dict = model.state_dict #currently with random initializationstate_dict = torch.load ("./ gpt2-pytorch_model.bin") # önceden eğitilmiş ağırlıklar

old_keys =

new_keys =

state_dict.keys içindeki anahtar için:

anahtarda "mlp" ise: # Kucaklayan yüz durumu diktesi, ileri besleme ağına mlp olarak başvurursa, bu ağırlıkları yeniden kullanabilmek için "ileri besleme" için değiştirilmesi gerekir

new_key = key.replace ("mlp", "ileri besleme")

new_keys.append (new_key)

old_keys.append (anahtar)

old_key, zip içinde new_key için (eski_anahtarlar, yeni_anahtarlar): state_dict = state_dict.pop (eski_key)

pretrained_dict = {k için k: v, state_dict.items içinde v, model_dict içinde k ise}

model_dict.update (pretrained_dict)

model.load_state_dict (model_dict)

model.eval #model, şimdi önceden eğitilmiş ağırlıklarla başlatıldığı için çıkarım modunda

Şimdi metni oluşturalım. Kelimeleri giriş düğünlerine dönüştürmek için Hugging Face'in önceden eğitilmiş jetonlaştırıcısını kullanacağız.

transformatörlerden GPT2Tokenizer ithal

tokenizer = GPT2Tokenizer.from_pretrained ("gpt2")

bağlam = torch.tensor ()

def üretmek (bağlam, ntok = 20):

aralıktaki _ için (ntok):

out = model (bağlam)

logits = out

indices_to_remove = günlük kayıtları = np.NINF

next_tok = torch.multinomial (F.softmax (logits, dim = -1), num_samples = 1) .squeeze (1)

bağlam = torch.cat (, dim = -1)

dönüş bağlamı

out = generate (bağlam, ntok = 20) tokenizer.decode (out)

> > Hükümetin yapacağı çalışma, "Dünya gezegeni tüm ışığın kaynağıdır" diyor.

Ek içerik

Dikkat çekmenin bir başka yolu da fast.ai'nin NLP kursudur (https://github.com/fastai/course-nlp/blob/master/8-translation-transformer.ipynb), bunu daha sezgisel buldum Yöntem aşağıdaki gibidir:

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 = ölçek

self.atn_drop = nn.Dropout (0.1)

self.wq, self.wk, self.wv =

def split_heads (self, x, layer, bs):

x = katman (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 = Yok):

puanlar = torch.matmul (q, k.transpose (-2, -1))

self.scale ise: puanlar = puanlar / math.sqrt (v.size (-1))

attn_mask None değilse:

puanlar = score.float.masked_fill (attn_mask, -float ('inf')). type_as (puanlar)

attn_prob = self.atn_drop (self.softmax (puanlar))

attn_vec = attn_prob @ v

attn_vec döndür

def merge_heads (self, x, bs, seq_len):

x = x.permute (0, 2, 1, 3). bitişik

return x.view (bs, seq_len, -1)

def ileri (öz, q, k, v, maske = Yok):

bs, seq_len = q.size (0), q.size (1)

wq, wk, wv = harita (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)

attn_vec döndür

Yukarıdaki uygulama ile benimsediğimiz uygulama yöntemi arasındaki temel fark, bu uygulamanın CONV1D kullanmaması, ancak önce x girdisini self.wq, self.wk ve self.wv doğrusal katmanlarına geçirerek wq, wk ve wv matrislerini elde etmesidir, Sonra bir sonraki adım öncekiyle aynı.

Sonuna yaz

Açık kaynaklı bir NLP kitaplığı oluşturduğu ve kullanılabilecek birçok önceden eğitilmiş model sağladığı için Hugging Face'e özel teşekkürler. Daha önce de belirtildiği gibi, bu makaledeki kod doğrudan Hugging Face kitaplığından geliyor. Resimli GPT-2 ( GPT-2 ile ilgili en kapsamlı bloglardan biridir. Son olarak, Harvard NLP's The Annotated Transformer (https://nlp.seas.harvard.edu/2018/04/03/attention.html), PyTorch'ta Transformers'ın harika ve öğrenmesi kolay bir uygulamasını tamamladı.

aracılığıyla: https://amaarora.github.io/2020/02/18/annotatedGPT2.html

Lei Feng Ağı Lei Feng Ağı Lei Feng Ağı

"Hey! ne yapıyorsun? Bu haftadan itibaren
önceki
Jilin: Tarımsal üretim için hazırlık, önce tarım makineleri
Sonraki
Dingding "sosyal" ve "çevre" den asla vazgeçmedi
Süt endüstrisi "salgın hastalıkla" mücadele ediyor Çin Feihe ve diğer önde gelen süt şirketleri milyonlarca anne ve bebeği korumak için adım atıyor
Guizhou Weng'an'dan Kaiyang Otoyolu projesine devam edildi
Xishanju'nun "Jianwang 3 "'ü daha fazla bulut oyunu ekliyor, piyasadaki boşluğu dolduracak mı?
Hefei Yüksek Teknoloji Bölgesi: Belirlenen boyutun üzerindeki işletmelerin% 90'ından fazlası özgeçmiş çalışmaya başlıyor
Video | 609 Nujiang çalışanı Zhuhai'ye geldi! İş trenine dönüş, şirketlerin çalışmaya devam etmesine yardımcı olur
Zhuhai'den 84 yaşındaki bir sürücü dışarı çıktı ve bir Wuling God arabasına çarptı! Ehliyetsiz araba kullanmaktan mahkum edildi ...
Gişe rekorları kıran başladı! Devlete ait işletmeler "İş ve Üretimin Yeniden Başlaması" Resimli Hikaye Sergisi sizleri katkıda bulunmaya davet ediyor
Aktif bölgedeki 4 doğrulanmış vaka listesine bağlı olarak, Pekin Xindejiayuan Topluluğu şöyle
Kore salgınını doğrudan vurmak | Seul'ün savunma savaşı, en çok etkilenen bölge olan Daegu'da kritik bir haftaya denk geliyor, istikrarın sağlanması için dört hafta gerekiyor
Kasabanın sokaklarını görmek için çalışma ve üretime yeniden başlama Chen Yuying: Yeni malzeme endüstrisi zincirini genişletmek için bir "örtü" oluşturmak ve Jun'an Köyü "atı hızlandırmak" için yen
Kunming, Yunnan: İlaç şirketleri pazar talebini sağlamak için üretimi artırıyor
To Top