Ana içeriğe geç

Orta10 dk

Encoder-decoder yapısı

Önkoşul:Position-wise feed-forward ağ

Kanca

Şimdiye kadar tek bir cümle üzerinde çalıştık. Ama çeviri gibi görevlerde iki cümle var: kaynak (“Kedi masaya çıktı”) ve hedef (“The cat climbed…”). Model, hedefi üretirken kaynağa nasıl “bakıyor”?

Sezgi

Orijinal “Attention is All You Need” mimarisi iki parçadan oluşur: encoder (kaynağı okur) ve decoder (hedefi üretir). Decoder’ın yeni bir silahı var: “çapraz dikkat” (cross-attention) — sorgu kendisinden, ama anahtar/değer encoder’dan gelir. Böylece decoder, her kelimeyi üretirken kaynak cümlenin ilgili kısmına “bakabilir”.

Mekanizma

İki dizi: kaynak ve hedef

# 10-15. derste tek bir dizi (cümle) üzerinde çalıştık. Ama çeviri gibi görevlerde
# iki dizi var: kaynak (encoder'a girer) ve hedef (decoder üretir). Örnek: Türkçe'den
# İngilizce'ye çeviri.
KAYNAK = ["Kedi", "masaya", "çıktı"]       # Türkçe (encoder girdisi)
HEDEF_SIMDIYE_KADAR = ["The", "cat"]        # İngilizce, şu ana kadar üretilen (decoder girdisi)
print(f"Kaynak dizi (Türkçe, encoder): {KAYNAK}")
print(f"Hedef dizi (İngilizce, decoder, şimdiye kadar üretilen): {HEDEF_SIMDIYE_KADAR}")
print("\nEncoder, kaynak diziyi tamamen görebilir (bidirectional -- 10. dersteki self-attention gibi).")
print("Decoder ise hedef dizide sadece kendinden öncekileri görebilir (11. dersteki nedensel maske).")
Kaynak dizi (Türkçe, encoder): ['Kedi', 'masaya', 'çıktı']
Hedef dizi (İngilizce, decoder, şimdiye kadar üretilen): ['The', 'cat']

Encoder, kaynak diziyi tamamen görebilir (bidirectional -- 10. dersteki self-attention gibi).
Decoder ise hedef dizide sadece kendinden öncekileri görebilir (11. dersteki nedensel maske).

Önce encoder’ı çalıştıralım — 10. dersteki aynı self-attention, ama bu sefer kaynak cümle üzerinde:

Encoder: kaynağı oku

# Encoder: kaynak dizi üzerinde sıradan self-attention (maskesiz, tüm kaynak
# kelimeleri birbirini görebilir).
D = 4
X_kaynak = torch.tensor([
    [1.5, 0.0, 0.0, 0.0],   # Kedi
    [0.0, 1.5, 0.0, 0.0],   # masaya
    [0.3, 0.3, 1.2, 0.0],   # çıktı
])

torch.manual_seed(125)
Wq_enc, Wk_enc, Wv_enc = torch.randn(D, D) * 0.5, torch.randn(D, D) * 0.5, torch.randn(D, D) * 0.5
Q_enc, K_enc, V_enc = X_kaynak @ Wq_enc, X_kaynak @ Wk_enc, X_kaynak @ Wv_enc
encoder_ciktisi, _ = dikkat(Q_enc, K_enc, V_enc)
print(f"\nEncoder çıktısı şekli: {tuple(encoder_ciktisi.shape)} (= {len(KAYNAK)} kaynak token x {D} boyut)")
print("Bu çıktı, her kaynak kelimenin, diğer tüm kaynak kelimelerle 'zenginleştirilmiş' temsilidir --")
print("decoder, üretim boyunca bunu kullanacak.")

Encoder çıktısı şekli: (3, 4) (= 3 kaynak token x 4 boyut)
Bu çıktı, her kaynak kelimenin, diğer tüm kaynak kelimelerle 'zenginleştirilmiş' temsilidir --
decoder, üretim boyunca bunu kullanacak.

Şimdi yeni mekanizma: çapraz dikkat. Decoder’ın sorgusu, encoder’ın çıktısındaki anahtar/değerlerle eşleşiyor:

Çapraz dikkat: decoder, encoder'a bakar

# Decoder'ın ikinci (ve yeni) dikkat türü: "çapraz dikkat" (cross-attention).
# Sorgu (Q) decoder'dan gelir, ama Anahtar/Değer (K, V) encoder çıktısından gelir --
# yani decoder, kaynak cümleye 'bakar'.
X_hedef = torch.tensor([
    [0.1, 0.1, 0.1, 1.0],   # "The" -- genel bir kelime, belirli bir kaynağa odaklanmaz
    [1.4, 0.0, 0.0, 0.1],   # "cat" -- 'Kedi'ye yakın tasarlandı
])

torch.manual_seed(10146)
Wq_dec, Wk_capraz = torch.randn(D, D) * 0.5, torch.randn(D, D) * 0.5

Q_dec = X_hedef @ Wq_dec          # sorgu: decoder'dan
K_capraz = encoder_ciktisi @ Wk_capraz   # anahtar: encoder çıktısından (V_capraz = encoder_ciktisi)
capraz_ciktisi, capraz_agirliklar = dikkat(Q_dec, K_capraz, encoder_ciktisi)

print(f"\nÇapraz dikkat matrisi şekli: {tuple(capraz_agirliklar.shape)} (= {len(HEDEF_SIMDIYE_KADAR)} hedef x {len(KAYNAK)} kaynak)")
print("Dikkat: bu matris kare değil -- 10. dersteki self-attention'ın N×N matrisinden farklı,")
print("çünkü sorgu ve anahtar/değer iki farklı diziden geliyor.")
for hedef_kelime, agirlik_satiri in zip(HEDEF_SIMDIYE_KADAR, capraz_agirliklar.tolist()):
    print(f"\n  '{hedef_kelime}' hangi kaynak kelimelere bakıyor?")
    for kaynak_kelime, a in zip(KAYNAK, agirlik_satiri):
        print(f"    {kaynak_kelime:<10} ağırlık={a:.3f}")

en_yuksek = KAYNAK[capraz_agirliklar[1].argmax().item()]
print(f"\n'cat' üretilirken, en çok '{en_yuksek}' kaynak kelimesine bakılıyor ({capraz_agirliklar[1].max().item():.3f}) --")
print("model, 'cat' kelimesinin karşılığının kaynak cümlede 'Kedi' olduğunu, öğrenilmiş dikkat ile buluyor.")

Çapraz dikkat matrisi şekli: (2, 3) (= 2 hedef x 3 kaynak)
Dikkat: bu matris kare değil -- 10. dersteki self-attention'ın N×N matrisinden farklı,
çünkü sorgu ve anahtar/değer iki farklı diziden geliyor.

  'The' hangi kaynak kelimelere bakıyor?
    Kedi       ağırlık=0.476
    masaya     ağırlık=0.240
    çıktı      ağırlık=0.284

  'cat' hangi kaynak kelimelere bakıyor?
    Kedi       ağırlık=0.658
    masaya     ağırlık=0.138
    çıktı      ağırlık=0.204

'cat' üretilirken, en çok 'Kedi' kaynak kelimesine bakılıyor (0.658) --
model, 'cat' kelimesinin karşılığının kaynak cümlede 'Kedi' olduğunu, öğrenilmiş dikkat ile buluyor.

“cat” üretilirken model, kaynak cümledeki “Kedi”ye 0.658 ağırlıkla bakıyor — çeviri karşılığını, hiçbir sözlük olmadan, öğrenilmiş dikkat ile buluyor.

Matematik

Üç dikkat türü, aynı formül
Attention(Q,K,V)=softmax(QK⊤dk)V\begin{aligned} &\text{Attention}(Q, K, V) \\ &\quad = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V \end{aligned}
Dikkat türüQQ neredenK,VK, V nereden
Encoder self-attentionencoderencoder
Decoder maskeli self-attentiondecoderdecoder
Decoder çapraz dikkatdecoderencoder

Formül hiç değişmiyor — 9-11. derste kurduğumuz aynı dikkat() fonksiyonu. Değişen tek şey, QQ, KK, VV‘nin hangi diziden geldiği. Çapraz dikkatte QQ ve KK farklı dizilerden geldiği için, dikkat matrisi kare olmak zorunda değildir.

Kod

Üç dikkat türünün karşılaştırması

# Özet karşılaştırma: encoder'daki self-attention, decoder'daki maskeli self-attention,
# ve decoder'daki çapraz dikkat -- üçü de aynı dikkat() fonksiyonunu kullanıyor, ama
# Q/K/V'nin nereden geldiği değişiyor.
print(f"\n{'Dikkat türü':<28} {'Q nereden':<14} {'K, V nereden':<16} {'Matris şekli':<12}")
print(f"{'Encoder self-attention':<28} {'encoder':<14} {'encoder':<16} {'(3, 3)':<12}")
print(f"{'Decoder maskeli self-att.':<28} {'decoder':<14} {'decoder':<16} {'(2, 2)':<12}")
print(f"{'Decoder çapraz dikkat':<28} {'decoder':<14} {'Encoder':<16} {'(2, 3)':<12}")
print("\nAynı matematik (dikkat fonksiyonu), üç farklı 'nereden geliyor' kombinasyonu --")
print("bu üçü birlikte, bir Transformer encoder-decoder bloğunu oluşturuyor.")

Dikkat türü                  Q nereden      K, V nereden     Matris şekli
Encoder self-attention       encoder        encoder          (3, 3)      
Decoder maskeli self-att.    decoder        decoder          (2, 2)      
Decoder çapraz dikkat        decoder        Encoder          (2, 3)      

Aynı matematik (dikkat fonksiyonu), üç farklı 'nereden geliyor' kombinasyonu --
bu üçü birlikte, bir Transformer encoder-decoder bloğunu oluşturuyor.
2 hedef kelime x 3 kaynak kelimelik, kare olmayan çapraz dikkat matrisini gösteren ısı haritası; 'cat' satırı 'Kedi' sütununda en koyu.(grafiği tam boyutta, yeni sekmede aç)
Çapraz dikkat matrisi kare değil (2x3) -- 'cat' satırında en koyu hücre 'Kedi' sütununda, modelin çeviri karşılığını bulduğunu gösteriyor.

Nerede işe yarar

Encoder-decoder yapısı, orijinal 2017 Transformer’ının tam mimarisi — ama tek kullanım şekli değil:

  • Makine çevirisi, özetleme, soru-cevaplama gibi “bir diziyi başka bir diziye dönüştürme” görevleri encoder-decoder kullanır — kaynak ve hedef farklı uzunlukta, farklı dillerde/formatlarda olabilir.
  • GPT gibi modeller sadece decoder kullanır (18. ders) — çapraz dikkat yoktur, sadece maskeli self-attention; BERT gibi modeller sadece encoder kullanır (maskesiz self-attention, çeviri üretmez, temsil üretir).
  • Decoder’ın her bloğunda üç alt-katman sırayla çalışır: maskeli self-attention → çapraz dikkat → FFN (14-15. ders) — her birinin etrafında artık bağlantı + layer norm var.

Bu 2 hatayı yaparsın:

  1. Çapraz dikkatin de self-attention gibi kare bir matris ürettiğini sanmak — hayır, hedef ve kaynak uzunlukları farklı olabilir, matris dikdörtgen olabilir.
  2. Her Transformer modelinin encoder ve decoder içerdiğini düşünmek — GPT sadece decoder, BERT sadece encoder kullanır (18. ders bu farkı detaylandıracak).

Kendini test et

1. Çapraz dikkatin (cross-attention) self-attention'dan temel farkı nedir?
  1. Farklı bir matematiksel formül kullanır
  2. Sorgu (Q) bir diziden (decoder), anahtar/değer (K, V) başka bir diziden (encoder çıktısı) gelir -- self-attention'da üçü de aynı diziden gelir (doğru cevap)
  3. Sadece kısa cümlelerde çalışır
  4. Softmax kullanmaz

Neden: capraz-dikkat bloğunda Q_dec decoder'ın X_hedef'inden, K_capraz ise encoder_ciktisi'nden hesaplanıyor -- oz-vs-capraz tablosunda bu ayrım açıkça özetleniyor.

2. Notebook'ta çapraz dikkat matrisinin şekli (2, 3) -- yani kare değil. Bunun nedeni ne?
  1. Bir hesaplama hatası
  2. Hedef dizi (2 kelime, şimdiye kadar üretilen) ile kaynak dizi (3 kelime) farklı uzunlukta -- dikkat matrisinin şekli (hedef uzunluğu × kaynak uzunluğu) olduğu için kare olmak zorunda değil (doğru cevap)
  3. Sadece decoder'ın son katmanında bu şekil kare olmaz
  4. Matris her zaman kare olmalıydı, bu bir tasarım hatasıdır

Neden: capraz-dikkat bloğunun çıktısında matris şekli (2, 3) = (len(HEDEF_SIMDIYE_KADAR), len(kaynak)) -- self-attention'daki N×N kısıtlaması burada yoktur çünkü Q ve K farklı dizilerden geliyor.

3. 'cat' üretilirken çapraz dikkat neden kaynak cümledeki 'Kedi'ye en yüksek ağırlığı (0.658) veriyor?
  1. Rastgele bir sonuç
  2. Decoder'ın 'cat' sorgusu ile encoder çıktısındaki 'Kedi' anahtarı arasındaki nokta çarpım benzerliği en yüksek çıktığı için -- bu, gerçek modellerde eğitimle öğrenilen çeviri hizalamasının (alignment) küçük ölçekli bir örneği (doğru cevap)
  3. 'Kedi' kelimesi alfabetik olarak ilk sırada olduğu için
  4. Çapraz dikkat her zaman ilk kaynak kelimeye en yüksek ağırlığı verir

Neden: capraz-dikkat bloğunda 'cat' token'ının gömmesi öğretici amaçlı 'Kedi'ye yakın tasarlandı; softmax(QKᵀ/√d) formülü bu benzerliği en yüksek ağırlığa çeviriyor -- gerçek modellerde bu hizalama veri üzerinde eğitilir.

Özet

Özet

  • Encoder-decoder yapısı, kaynak diziyi (encoder) ve hedef diziyi (decoder) ayrı ele alır -- çeviri gibi "diziden diziye" görevler için tasarlanmıştır.
  • Decoder'ın iki dikkat türü var: maskeli self-attention (kendi ürettiklerine bakar) ve çapraz dikkat (encoder çıktısına bakar).
  • Çapraz dikkatte Q decoder'dan, K ve V encoder çıktısından gelir -- dikkat matrisi kare olmak zorunda değildir.
  • Notebook'ta 'cat' üretilirken, model 'Kedi'ye 0.658 ağırlıkla bakarak çeviri karşılığını buldu.
  • GPT sadece decoder, BERT sadece encoder kullanır -- her Transformer modelinin encoder ve decoder içermesi gerekmez (18. ders).
Sonraki adım: Transformer'ın eğitimi ve çıkarımı →