Ana içeriğe geç

Orta9 dk

Attention fikri

Önkoşul:Sekans modellerinin sınırı

Kanca

“I did not say he stole the money” — bu 7 kelimelik cümle, hangi kelimeye vurgu yaptığınıza göre 7 farklı anlama gelir. “Attention” (dikkat) kelimesi tam olarak buradan geliyor: bir çıktı üretirken, girdinin hangi parçalarına ne kadar “dikkat” edileceği.

Aynı cümle, 7 farklı vurgu, 7 farklı anlam

# "Attention" (dikkat) kelimesi, insan dilinden ödünç alınmış bir kavramdır.
# Klasik bir İngilizce örnek: aynı 7 kelimelik cümle, hangi kelimeye vurgu
# yapıldığına göre 7 farklı anlama gelir.
cumle = "I did not say he stole the money"
yorumlar = [
    ("I", "Başkası söyledi, BEN söylemedim."),
    ("did not", "Hiçbir şekilde söylemedim -- düz bir inkar."),
    ("say", "Söylemedim ama BAŞKA bir yolla ima ettim."),
    ("he", "Parayı O çalmadı, BAŞKASI çaldı dedim."),
    ("stole", "Parayı BAŞKA bir yolla (örn. ödünç) aldı dedim."),
    ("the", "BU parayı değil, BAŞKA bir parayı çaldı dedim."),
    ("money", "Parayı değil, BAŞKA bir şeyi çaldı dedim."),
]
print(f'Cümle: "{cumle}"\n')
for kelime, anlam in yorumlar:
    print(f'  Vurgu "{kelime}"de olursa -> {anlam}')
print("\n7 kelime, 7 farklı anlam -- sadece hangi kelimeye 'dikkat' ettiğine göre.")
print("ML'deki attention da aynı fikri matematikselleştiriyor: bir çıktı üretirken,")
print("girdinin hangi kısımlarına ne kadar 'dikkat' edileceğini öğreniyor.")
Cümle: "I did not say he stole the money"

  Vurgu "I"de olursa -> Başkası söyledi, BEN söylemedim.
  Vurgu "did not"de olursa -> Hiçbir şekilde söylemedim -- düz bir inkar.
  Vurgu "say"de olursa -> Söylemedim ama BAŞKA bir yolla ima ettim.
  Vurgu "he"de olursa -> Parayı O çalmadı, BAŞKASI çaldı dedim.
  Vurgu "stole"de olursa -> Parayı BAŞKA bir yolla (örn. ödünç) aldı dedim.
  Vurgu "the"de olursa -> BU parayı değil, BAŞKA bir parayı çaldı dedim.
  Vurgu "money"de olursa -> Parayı değil, BAŞKA bir şeyi çaldı dedim.

7 kelime, 7 farklı anlam -- sadece hangi kelimeye 'dikkat' ettiğine göre.
ML'deki attention da aynı fikri matematikselleştiriyor: bir çıktı üretirken,
girdinin hangi kısımlarına ne kadar 'dikkat' edileceğini öğreniyor.

Sezgi

8. derste gördük: RNN/LSTM tüm diziyi sabit boyutlu tek bir vektöre sıkıştırmak zorunda — bu bir darboğaz. Attention’ın ilk fikri basit: sıkıştırma yerine, her kelimenin durumunu ayrı ayrı sakla, sonra ihtiyaca göre bunların arasından seç.

Tek vektör yerine, tüm durumları sakla

# 8. derste RNN'in tüm diziyi tek bir vektöre sıkıştırdığını gördük. Attention'ın
# ilk fikri basit: sıkıştırma yerine, tüm ara durumları sakla.
KELIMELER = ["kral", "ülkeyi", "adaletle", "yönetti"]
BOYUT = 3
# Her kelimenin "hafızası" (gerçekte bir RNN/embedding'den gelir, burada öğretici
# amaçlı elle tasarlanmış):
encoder_durumlari = torch.tensor([
    [1.6, 0.6, 0.0],   # kral
    [1.1, 1.1, 0.0],   # ülkeyi (kral'a kısmen benzer -- konuyla ilgili)
    [0.0, 0.0, 1.6],   # adaletle (farklı bir "eksende")
    [-0.6, 0.3, 0.6],  # yönetti
])
print(f"\n{len(KELIMELER)} kelimenin her birinin gizli durumu saklandı -- 8. dersteki gibi tek bir vektöre indirgenmedi.")
print(f"Saklanan veri şekli: {tuple(encoder_durumlari.shape)} (kelime sayısı × boyut)")

4 kelimenin her birinin gizli durumu saklandı -- 8. dersteki gibi tek bir vektöre indirgenmedi.
Saklanan veri şekli: (4, 3) (kelime sayısı × boyut)

“Seçmek” kelimesi burada yanıltıcı — attention aslında tek bir kelimeyi seçmez, her kelimeye bir ağırlık verir (0 ile 1 arası, toplamları 1) ve ağırlıklı ortalamasını alır. İlgisiz kelimeler ~0 ağırlık, ilgili kelimeler yüksek ağırlık alır.

Mekanizma

“kral ülkeyi adaletle yönetti” cümlesinde, “kral”a yakın bir sorgu (query) ile her kelimenin durumu arasındaki benzerliği (nokta çarpım) hesaplayıp softmax’tan geçirelim:

Sorgu ile her kelime arasındaki benzerlik -> ağırlık

# Şimdi bir "sorgu" (query) -- örn. "özne kim?" sorusuna en yakın bir vektör --
# ile her encoder durumu arasındaki benzerliği (nokta çarpım) hesaplayalım.
sorgu = torch.tensor([1.7, 0.5, 0.1])  # "kral"a yakın bir sorgu

puanlar = encoder_durumlari @ sorgu
agirliklar = F.softmax(puanlar, dim=0)

print(f"\nDikkat puanları (ham nokta çarpım): {[round(v,3) for v in puanlar.tolist()]}")
print(f"Dikkat ağırlıkları (softmax sonrası): {[round(v,3) for v in agirliklar.tolist()]}")
print(f"Ağırlıkların toplamı: {agirliklar.sum().item():.4f}")
for k, a in zip(KELIMELER, agirliklar.tolist()):
    print(f"  {k:<10} ağırlık={a:.3f}")
print(f"\nEn yüksek ağırlık '{KELIMELER[agirliklar.argmax().item()]}'de -- sorgu, ona en yakın.")
print("'ülkeyi' de anlamlı bir ağırlık (0.337) alıyor -- konuyla ilgili olduğu için.")

Dikkat puanları (ham nokta çarpım): [3.02, 2.42, 0.16, -0.81]
Dikkat ağırlıkları (softmax sonrası): [0.614, 0.337, 0.035, 0.013]
Ağırlıkların toplamı: 1.0000
  kral       ağırlık=0.614
  ülkeyi     ağırlık=0.337
  adaletle   ağırlık=0.035
  yönetti    ağırlık=0.013

En yüksek ağırlık 'kral'de -- sorgu, ona en yakın.
'ülkeyi' de anlamlı bir ağırlık (0.337) alıyor -- konuyla ilgili olduğu için.

“kral” en yüksek ağırlığı (0.614) alıyor çünkü sorguya en yakın. Ama “ülkeyi” de anlamsız değil — 0.337 gibi anlamlı bir ağırlık alıyor çünkü konuyla ilgili. “adaletle” ve “yönetti” ise neredeyse göz ardı ediliyor (0.035, 0.013).

Matematik

Dikkat puanı ve ağırlığı
puani=q⋅ki\text{puan}_i = q \cdot k_iai=softmax(puan)i=epuani∑jepuanja_i = \text{softmax}(\text{puan})_i = \frac{e^{\text{puan}_i}}{\sum_j e^{\text{puan}_j}}
SembolAnlamı
qqSorgu (query) — “neyi arıyorum?” vektörü
kik_iii. kelimenin durumu (encoder çıktısı)
puani\text{puan}_iqq ile kik_i arasındaki ham benzerlik (nokta çarpım)
aia_iii. kelimenin nihai dikkat ağırlığı (softmax sonrası, ∑iai=1\sum_i a_i = 1)

Nokta çarpım, [Ek: Matematik Temelleri] bölümündeki “benzerliğin matematiği” dersiyle aynı fikir — iki vektör ne kadar aynı yöne bakıyorsa, çarpımları o kadar büyük.

Kod

Bu ağırlıklar, encoder durumlarının ağırlıklı ortalamasını almak için kullanılır — buna “bağlam vektörü” (context vector) denir:

Ağırlıklı ortalama: bağlam vektörü

# Dikkat ağırlıkları, encoder durumlarının ağırlıklı ortalamasını almak için kullanılır --
# buna "bağlam vektörü" (context vector) denir.
baglam_vektoru = agirliklar @ encoder_durumlari
print(f"\nBağlam vektörü: {[round(v,3) for v in baglam_vektoru.tolist()]}")
print("Bu vektör, 'kral' durumuna çok yakın ama 'ülkeyi'den de biraz etkilenmiş --")
print("tek bir kelimeyi seçmek yerine, ilgili kelimelerin bir karışımını oluşturuyor.")
print("\nBu, 8. dersteki 'tek vektöre sıkıştırma' sorununa cevap: artık tek bir sabit vektör yok --")
print("her adımda, ihtiyaca göre yeniden hesaplanan, dinamik bir bağlam vektörü var.")

Bağlam vektörü: [1.346, 0.743, 0.064]
Bu vektör, 'kral' durumuna çok yakın ama 'ülkeyi'den de biraz etkilenmiş --
tek bir kelimeyi seçmek yerine, ilgili kelimelerin bir karışımını oluşturuyor.

Bu, 8. dersteki 'tek vektöre sıkıştırma' sorununa cevap: artık tek bir sabit vektör yok --
her adımda, ihtiyaca göre yeniden hesaplanan, dinamik bir bağlam vektörü var.

Bu vektör “kral” durumuna çok yakın ama “ülkeyi”den de biraz etkilenmiş — 8. dersteki “tek sabit vektör” sorununa cevap: artık her adımda ihtiyaca göre yeniden hesaplanan, dinamik bir bağlam vektörü var.

Nerede işe yarar

Bu basit fikir, Bahdanau (2014) ve Luong (2015) makine çevirisi makaleleriyle NLP’ye girdi ve 2017’de “Attention is All You Need” (18. ders) ile merkeze taşındı:

  • Sorgu (query), anahtar (key) ve değer (value) burada henüz ayrı vektörler değil — bu ayrım, 10. dersin (“Self-attention mekaniği: Q, K, V”) konusu. Burada sadece fikri görüyoruz.
  • Ağırlıklar burada elle tasarlandı — gerçek bir modelde, sorgu/anahtar vektörleri eğitim sırasında öğrenilir, böylece model hangi kelimelere ne zaman dikkat edeceğini kendisi keşfeder.
  • Bu mekanizma, RNN’in içine eklenmiş bir “yama” olarak başladı (encoder-decoder attention) — 2017’de RNN’i tamamen attention ile değiştirme fikri (self-attention) geldi.

Bu 2 hatayı yaparsın:

  1. Dikkat ağırlıklarının bir kelimeyi “seçtiğini” düşünmek — aslında hepsinin ağırlıklı bir karışımını alır, tek bir seçim yapmaz.
  2. Bu örnekteki sorgu/anahtar vektörlerinin elle tasarlandığını unutup, gerçek modellerde de “biri bunları yazdı” sanmak — hayır, eğitimle öğrenilirler.

Kendini test et

1. Attention mekanizması, 8. dersteki 'tek vektöre sıkıştırma' sorununu nasıl çözüyor?
  1. Vektörün boyutunu büyüterek
  2. Tüm ara durumları ayrı ayrı saklayıp, her adımda bunların ağırlıklı ortalamasını (ihtiyaca göre değişen) alarak -- tek bir sabit vektöre güvenmek yerine (doğru cevap)
  3. Diziyi kısaltarak
  4. RNN katman sayısını artırarak

Neden: Notebook'ta encoder_durumlari (4, 3) şeklinde tüm kelimelerin durumunu saklıyor; her sorgu için bağlam vektörü bu durumların ağırlıklı ortalamasıyla yeniden hesaplanıyor -- sabit tek vektör yok.

2. Notebook'taki örnekte 'kral' 0.614, 'ülkeyi' 0.337, 'adaletle' 0.035, 'yönetti' 0.013 ağırlık alıyor. Bu ne anlama gelir?
  1. Model sadece "kral" kelimesini kullanıyor, diğerlerini siliyor
  2. Sorgu 'kral'a en yakın olduğu için en yüksek ağırlığı o alıyor, ama 'ülkeyi' de konuyla ilgili olduğu için anlamlı bir ağırlık alıyor -- bağlam vektörü ikisinin de karışımı (doğru cevap)
  3. Ağırlıklar rastgele atanmıştır
  4. 'adaletle' ve 'yönetti' kelimeleri cümleden çıkarılmalıdır

Neden: Softmax sonrası ağırlıklar toplamı 1 olan bir olasılık dağılımı oluşturur; yüksek ağırlık "en çok dikkat edilen" anlamına gelir, sıfırlama değil -- bağlam vektörü baglam-vektoru bloğunda görüldüğü gibi tüm kelimelerin ağırlıklı toplamıdır.

3. Bu derste sorgu (query) ve anahtar (key) vektörleri nasıl elde edildi, gerçek bir Transformer'da bu nasıl değişir?
  1. Aynı şekilde, elle tasarlanır
  2. Burada öğretici amaçlı elle tasarlandı; gerçek bir modelde bu vektörler eğitim sırasında öğrenilen ağırlık matrisleriyle (Q, K, V projeksiyonları) hesaplanır -- bu da 10. dersin konusu (doğru cevap)
  3. Gerçek modellerde de elle yazılır, bu yüzden aynı
  4. Sadece büyük modellerde öğrenilir, küçük modellerde elle yazılır

Neden: Kullanım bölümünde vurgulandığı gibi, buradaki encoder_durumlari ve sorgu vektörleri öğretici amaçlı elle seçildi; 10. ders ('Self-attention mekaniği: Q, K, V') bunların eğitilebilir ağırlık matrisleriyle nasıl üretildiğini gösterecek.

Özet

Özet

  • Attention fikri, "aynı cümle vurguya göre farklı anlama gelir" sezgisini matematikselleştirir.
  • Tüm ara durumları tek bir vektöre sıkıştırmak yerine ayrı ayrı saklamak, 8. dersteki darboğazı çözer.
  • Dikkat ağırlıkları = sorgu ile her durum arasındaki benzerliğin (nokta çarpım) softmax'ı; toplamları her zaman 1.
  • Bağlam vektörü, bu ağırlıklarla alınan ağırlıklı ortalama -- her adımda ihtiyaca göre yeniden hesaplanır.
  • Burada sorgu/anahtar vektörleri elle tasarlandı -- 10. derste bunların eğitimle nasıl öğrenildiğini (Q, K, V) göreceğiz.
Sonraki adım: Self-attention mekaniği (Q, K, V) →