Transformer mimarisi: bütün resim
Önkoşul:GPT ile "Attention is All You Need" farkı
Kanca
- dersten beri, bir Transformer’ın parçalarını tek tek inceledik: attention, çoklu başlık, pozisyonel kodlama, layer norm, FFN, encoder-decoder. Bu ders hiçbir yeni parça eklemiyor — sadece hepsini, gerçekten eğitilmiş tek bir modelde bir araya getiriyor.
Sezgi
Aşağıdaki boru hattı, gerçekten eğitilmiş (kayıp 0.0001’e inmiş) bir mini-GPT’nin “ABCAB” girdisini işleyişini gösteriyor — her sayı, gerçek bir ileri geçişten yakalandı, elle tasarlanmadı. Bir aşamaya tıkla ilgili derse git; “Transformer Bloğu”na tıkla, içini aç ve gerçek dikkat matrisini gör.
Gerçekten eğitilmiş, 6.179 parametrelik bir mini-GPT'nin "ABCAB" girdisini işleyişi (eğitim kaybı: 0.000091). Bir aşamaya tıkla, ilgili derse git; Transformer Bloğu'na tıkla, içini aç.
Model'in tahmini: "C"
Mekanizma
Bu tam model, 9-18. derste kurduğumuz her parçayı birleştiriyor:
Tam mimari: tüm parçalar bir arada
# Bu ders, 9-18. derste tek tek kurduğumuz her parçayı, N blok üst üste yığarak
# birleştiriyor: gömme + pozisyonel kodlama (13. ders) -> N x [maskeli self-attention
# (11. ders) -> artık bağlantı + layer norm (14. ders) -> FFN (15. ders) -> artık
# bağlantı + layer norm] -> son layer norm -> çıktı projeksiyonu (dil modeli başlığı).
class TransformerBlogu(nn.Module):
def __init__(self, d_model):
super().__init__()
self.Wq = nn.Linear(d_model, d_model, bias=False)
self.Wk = nn.Linear(d_model, d_model, bias=False)
self.Wv = nn.Linear(d_model, d_model, bias=False)
self.norm1 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(nn.Linear(d_model, 4 * d_model), nn.GELU(), nn.Linear(4 * d_model, d_model))
self.norm2 = nn.LayerNorm(d_model)
def forward(self, h, maske):
Q, K, Vv = self.Wq(h), self.Wk(h), self.Wv(h)
puanlar = (Q @ K.transpose(-2, -1)) / (h.shape[-1] ** 0.5)
puanlar = puanlar.masked_fill(maske == 0, float("-inf"))
agirliklar = F.softmax(puanlar, dim=-1)
h = self.norm1(h + agirliklar @ Vv)
h = self.norm2(h + self.ffn(h))
return h, agirliklar
class MiniGPT(nn.Module):
def __init__(self, vocab_size, d_model, pencere, n_blok):
super().__init__()
self.gomme = nn.Embedding(vocab_size, d_model)
self.pos = nn.Embedding(pencere, d_model)
self.bloklar = nn.ModuleList([TransformerBlogu(d_model) for _ in range(n_blok)])
self.son_norm = nn.LayerNorm(d_model)
self.cikis = nn.Linear(d_model, vocab_size)
def forward(self, x_ids):
B, T = x_ids.shape
h = self.gomme(x_ids) + self.pos(torch.arange(T))
tum_agirliklar = []
maske = torch.tril(torch.ones(T, T))
for blok in self.bloklar:
h, agirliklar = blok(h, maske)
tum_agirliklar.append(agirliklar)
h = self.son_norm(h)
logit = self.cikis(h)
return logit, tum_agirliklar
model = MiniGPT(V, D, PENCERE, N_BLOK)
parametre_sayisi = sum(p.numel() for p in model.parameters())
print(f"MiniGPT: {N_BLOK} blok, d_model={D}, toplam parametre: {parametre_sayisi:,}")
print("Mimari: Gömme+PozKodlama -> [Maskeli Self-Attn -> Add&Norm -> FFN -> Add&Norm] x 2 -> Son Norm -> Çıktı")MiniGPT: 2 blok, d_model=16, toplam parametre: 6,179
Mimari: Gömme+PozKodlama -> [Maskeli Self-Attn -> Add&Norm -> FFN -> Add&Norm] x 2 -> Son Norm -> ÇıktıGerçek eğitim: kayıp 0.0001'e iniyor
optimize_edici = torch.optim.Adam(model.parameters(), lr=0.01)
for adim in range(400):
baslangic = torch.randint(0, len(ids) - PENCERE - 1, (8,))
girdi = torch.stack([ids[b:b + PENCERE] for b in baslangic])
hedef = torch.stack([ids[b + 1:b + PENCERE + 1] for b in baslangic])
logit, _ = model(girdi)
kayip = F.cross_entropy(logit.reshape(-1, V), hedef.reshape(-1))
optimize_edici.zero_grad()
kayip.backward()
optimize_edici.step()
print(f"400 adım sonra kayıp: {kayip.item():.6f}")400 adım sonra kayıp: 0.000091Şimdi bu eğitilmiş modeli, tek bir örnekten geçirip tüm ara çıktıları yakalayalım:
'ABCAB' girdisi, uçtan uca
# Şimdi tek bir örneği, tüm boru hattından (pipeline) geçirip, her aşamada ne
# olduğunu yakalayalım -- bu veri, sayfadaki TransformerBoruHatti bileşenini besleyecek.
model.eval()
ORNEK_METIN = "ABCAB"
ornek_ids = torch.tensor([[stoi[c] for c in ORNEK_METIN]])
with torch.no_grad():
logit, tum_agirliklar = model(ornek_ids)
olasiliklar = F.softmax(logit[0, -1], dim=-1)
print(f"\nGirdi: '{ORNEK_METIN}' ({len(ORNEK_METIN)} token)")
print(f"Blok 1 dikkat matrisi şekli: {tuple(tum_agirliklar[0][0].shape)}")
print(f"Blok 2 dikkat matrisi şekli: {tuple(tum_agirliklar[1][0].shape)}")
print(f"\nSon token'dan sonraki kelime dağarcığı olasılıkları:")
for tok, p in zip(VOCAB, olasiliklar.tolist()):
print(f" {tok:<4} {p:.4f}")
tahmin = VOCAB[olasiliklar.argmax().item()]
print(f"\nModel '{ORNEK_METIN}'den sonra '{tahmin}' geleceğini tahmin ediyor -- örüntüye ({ORNEK_METIN} -> C) uyumlu.")
Girdi: 'ABCAB' (5 token)
Blok 1 dikkat matrisi şekli: (5, 5)
Blok 2 dikkat matrisi şekli: (5, 5)
Son token'dan sonraki kelime dağarcığı olasılıkları:
A 0.0000
B 0.0000
C 0.9999
Model 'ABCAB'den sonra 'C' geleceğini tahmin ediyor -- örüntüye (ABCAB -> C) uyumlu.Matematik
Tam boru hattı, tek formülde
| Sembol | Anlamı |
|---|---|
| Girdi token dizisi | |
| Blok sayısı (bu modelde 2; GPT-3’te 96) | |
| Maskeli self-attention + Add&Norm + FFN + Add&Norm (10-15. ders) |
Her aynı yapıyı taşır ama kendi ağırlıklarını öğrenir — bu yüzden Blok 1 ve Blok 2’nin dikkat matrisleri (yukarıdaki bileşende inceleyebileceğin gibi) farklı örüntüler gösterebilir.
Kod
Modelin “ABCAB”den sonra ne geleceğini nasıl bu kadar emin tahmin ettiğine bak: yukarıdaki bileşenin altındaki “Kelime dağarcığı olasılıkları” panelinde, kelime dağarcığındaki 3 token üzerinde bir olasılık dağılımı görüyorsun — “C” %99.99 ile açık ara önde, çünkü eğitim verisindeki “ABC” örüntüsü tutarlı şekilde tekrarlanıyordu. Bloklardan birine tıklayıp içini açtığında, o bloğun “AB” bağlamını nasıl işlediğini gerçek sayılarla görebilirsin.
Nerede işe yarar
Bu ders, teoriyle pratik arasındaki köprüyü tamamladı:
- Gerçek büyük dil modelleri, aynı mimariyi (bu dersteki 2 blok yerine) 32-120 blokla, (16 boyut yerine) 4096-12288 boyutla çalıştırır — yapı aynı, sadece ölçek farklı.
- “Tahmin” kelimesi burada yanıltıcı olabilir: model bir sonraki token’ı seçmiyor, tüm kelime dağarcığı üzerinde bir olasılık dağılımı üretiyor — 22. ders bu dağılımdan nasıl örnekleme yapıldığını (her zaman en olası olanı seçmek yerine) ele alacak.
- Bu boru hattı, dil modelinin (20. ders) çekirdeğidir — “dil modeli nedir” sorusunun cevabı, tam olarak burada gördüğün mekanizmadır: bir dizi verildiğinde, bir sonraki token üzerinde bir olasılık dağılımı üretmek.
Bu 2 hatayı yaparsın:
- Her Transformer bloğunun aynı çıktıyı ürettiğini sanmak — hayır, her blok kendi ağırlıklarını öğrenir, bu yüzden dikkat örüntüleri bloktan bloğa değişebilir (12. dersteki çoklu başlık uzmanlaşmasına benzer şekilde).
- Bu ders “yeni” bir şey öğrettiğini düşünmek — hayır, bu ders sadece 9-18. dersin parçalarını birleştirdi; hiçbir yeni matematik yok, sadece bütün resim.
Kendini test et
1. Bu derste gösterilen TransformerBoruHatti bileşenindeki sayılar nasıl üretildi?
- Elle, öğretici amaçlı tasarlandı (9-16. dersteki gibi)
- Gerçekten eğitilmiş (gradyan inişiyle, 400 adım) bir mini-GPT modelinin 'ABCAB' girdisi üzerindeki gerçek bir ileri geçişinden yakalandı -- ilk kez bu kategoride, hiçbir vektör elle tasarlanmadı (doğru cevap)
- Rastgele üretildi, gerçek bir anlamı yok
- İnternetten indirilen bir modelden alındı
Neden: egitim bloğunda model 400 adımda gerçekten eğitiliyor (kayıp 0.000091); tek-ornek-akisi bloğu bu eğitilmiş modelin gerçek bir forward pass'inden veri yakalıyor -- 9-18. dersteki hand-crafted örneklerden farklı olarak.
2. Notebook'ta model 'ABCAB' girdisinden sonra 'C' token'ını %99.99 olasılıkla tahmin ediyor. Bu nereden geliyor?
- Rastgele bir tesadüf
- Eğitim verisi ('ABC' tekrar eden bir örüntü) tutarlı olduğu için, model gradyan inişiyle bu örüntüyü öğrendi -- 'AB'den sonra her zaman 'C' geldiğini gördüğü için, softmax çıktısı bu token'da neredeyse 1'e yakınsıyor (doğru cevap)
- Model rastgele tahmin yapıyor
- 'C' harfi alfabetik olarak son sırada olduğu için
Neden: egitim bloğunda kayıp 0.000091'e kadar düşüyor -- bu, modelin eğitim örüntüsünü neredeyse mükemmel öğrendiğini gösterir; tek-ornek-akisi bloğunda C olasılığı 0.9999 bu öğrenmenin doğrudan sonucudur.
3. İki Transformer bloğu (Blok 1, Blok 2) aynı mimariyi paylaşıyor. Bileşende ikisinin dikkat matrisi farklı görünebilir mi?
- Hayır, mimari aynı olduğu için matrisler de her zaman özdeştir
- Evet -- her blok kendi Wq/Wk/Wv ağırlıklarını bağımsız öğrenir (12. dersteki çoklu başlık uzmanlaşmasına benzer şekilde), bu yüzden farklı katmanlar farklı örüntüler yakalayabilir (doğru cevap)
- Sadece ilk blok dikkat matrisi üretir
- Bloklar sırayla değil, paralel çalışır, bu yüzden karşılaştırılamaz
Neden: tam-model bloğunda her TransformerBlogu kendi Wq/Wk/Wv parametrelerine sahip; MathBox'ta belirtildiği gibi aynı yapı ama farklı öğrenilmiş ağırlıklar taşırlar, bu da bileşende Blok 1/Blok 2 arasında geçiş yaparak gözlemlenebilir.
Özet
Özet
- Bu ders, 9-18. derste tek tek kurduğumuz tüm parçaları (attention, FFN, layer norm, artık bağlantı) birleştirip gerçekten eğitti.
- Boru hattı: Gömme+PozKodlama -> N x [Maskeli Self-Attention -> Add&Norm -> FFN -> Add&Norm] -> Son Norm -> Linear+Softmax.
- Model, 'ABCAB' girdisinden sonra 'C'yi %99.99 olasılıkla tahmin etti -- eğitim verisindeki tutarlı örüntüyü gerçekten öğrendiğinin kanıtı.
- Her Transformer bloğu aynı yapıyı paylaşır ama kendi ağırlıklarını öğrenir -- bloktan bloğa farklı dikkat örüntüleri ortaya çıkabilir.
- Gerçek büyük dil modelleri aynı mimariyi çok daha büyük ölçekte (32-120 blok, binlerce boyut) çalıştırır.