Ana içeriğe geç

Orta8 dk

Position-wise feed-forward ağ

Önkoşul:Layer norm ve artık bağlantılar

Kanca

Bir Transformer bloğunun YARISINI (attention) kurduk — token’lar birbirine BAKTI. Diğer yarı TAMAMEN farklı bir iş yapıyor: HER token’ı, DİĞERLERİNE hiç bakmadan, KENDİ İÇİNDE işliyor. Bu ne işe yarar?

Sezgi

“Position-wise feed-forward ağ” (FFN), DL Görüntü kategorisinde zaten gördüğün basit bir 2 katmanlı MLP (Linear → GELU → Linear) — YENİ olan tek şey, bunun HER token’a, AYNI ağırlıklarla, BİRBİRİNDEN BAĞIMSIZ uygulanması. Attention token’lar ARASINDA bilgi taşırken, FFN her token’ın TAŞIDIĞI bilgiyi İŞLER — ikisi TAMAMLAYICI iki farklı görev.

Mekanizma

Önce “position-wise” kelimesini SAYILARLA doğrulayalım: TÜM diziyi birden işlemek ile HER token’ı DÖNGÜYLE tek tek işlemek AYNI SONUCU vermeli:

'Position-wise' ne demek?

# 10-14. derste attention, token'ları BİRBİRİYLE karşılaştırdı. Şimdi Transformer
# bloğunun İKİNCİ yarısı: position-wise feed-forward ağ (FFN). "Position-wise" kelimesi
# TAM OLARAK ne demek? Test edelim: AYNI ağırlıkları HER token'a AYRI AYRI mı, yoksa
# TÜM diziye BİRDEN mi uyguluyor?
D, D_FF, N = 8, 32, 5
ffn = nn.Sequential(nn.Linear(D, D_FF), nn.GELU(), nn.Linear(D_FF, D))

X = torch.randn(N, D)

# Yöntem 1: TÜM diziyi TEK seferde işle.
cikti_toplu = ffn(X)

# Yöntem 2: HER token'ı TEK TEK, DÖNGÜYLE işle.
cikti_tek_tek = torch.stack([ffn(X[i]) for i in range(N)])

fark = (cikti_toplu - cikti_tek_tek).abs().max().item()
print(f"Tüm diziyi birden işlemek ile her token'ı tek tek işlemek arasındaki fark: {fark:.2e}")
print(f"torch.allclose: {torch.allclose(cikti_toplu, cikti_tek_tek, atol=1e-6)}")
print("\nFFN, AYNI ağırlıkları HER token'a BAĞIMSIZ uyguluyor -- 'position-wise' tam olarak bunu")
print("ifade ediyor: konum FARK ETMEZ, HER token AYNI dönüşümden geçer, TEK TEK işlenmiş gibi.")
Tüm diziyi birden işlemek ile her token'ı tek tek işlemek arasındaki fark: 5.96e-08
torch.allclose: True

FFN, AYNI ağırlıkları HER token'a BAĞIMSIZ uyguluyor -- 'position-wise' tam olarak bunu
ifade ediyor: konum FARK ETMEZ, HER token AYNI dönüşümden geçer, TEK TEK işlenmiş gibi.

Şimdi FFN’i attention’dan AYIRAN kritik farkı gösterelim: bir token’ı değiştirdiğimizde, DİĞER token’ların çıktısı ne olur?

Attention token'lar arası bilgi taşır, FFN taşımaz

# Peki bu, attention'dan NASIL farklı? Attention'da bir token'ın çıktısı, DİĞER
# token'lara BAĞLIDIR. FFN'de İSE değil. Bunu KANITLAYALIM: bir token'ı değiştirip,
# DİĞER token'ların çıktısının DEĞİŞİP DEĞİŞMEDİĞİNE bakalım.
def basit_attention(X, Wq, Wk, Wv):
    Q, K, V = X @ Wq, X @ Wk, X @ Wv
    puanlar = (Q @ K.transpose(-2, -1)) / (D ** 0.5)
    agirliklar = F.softmax(puanlar, dim=-1)
    return agirliklar @ V

Wq, Wk, Wv = torch.randn(D, D) * 0.5, torch.randn(D, D) * 0.5, torch.randn(D, D) * 0.5

X_degisik = X.clone()
X_degisik[0] = torch.randn(D) * 5  # SADECE 0. token'ı büyük ölçüde değiştir

attn_once = basit_attention(X, Wq, Wk, Wv)
attn_sonra = basit_attention(X_degisik, Wq, Wk, Wv)
ffn_once = ffn(X)
ffn_sonra = ffn(X_degisik)

print(f"\n0. token DEĞİŞTİRİLDİ, DİĞER token'ların (1-4) çıktısı ne kadar değişti?")
print(f"{'Token':<8} {'Attention farkı':<20} {'FFN farkı':<20}")
for i in range(1, N):
    attn_fark = (attn_once[i] - attn_sonra[i]).abs().max().item()
    ffn_fark = (ffn_once[i] - ffn_sonra[i]).abs().max().item()
    print(f"{i:<8} {attn_fark:<20.4f} {ffn_fark:<20.2e}")
print("\nAttention'da DİĞER token'ların çıktısı da DEĞİŞTİ (0. token'a 'bakıyorlardı').")
print("FFN'de DİĞER token'ların çıktısı HİÇ DEĞİŞMEDİ (fark tam 0) -- FFN, token'lar ARASI")
print("bilgi TAŞIMIYOR; bu iş TAMAMEN attention'a ait. FFN sadece HER token'ı KENDİ İÇİNDE işliyor.")

0. token DEĞİŞTİRİLDİ, DİĞER token'ların (1-4) çıktısı ne kadar değişti?
Token    Attention farkı      FFN farkı           
1        3.0138               0.00e+00            
2        12.3983              0.00e+00            
3        12.4502              0.00e+00            
4        4.4883               0.00e+00            

Attention'da DİĞER token'ların çıktısı da DEĞİŞTİ (0. token'a 'bakıyorlardı').
FFN'de DİĞER token'ların çıktısı HİÇ DEĞİŞMEDİ (fark tam 0) -- FFN, token'lar ARASI
bilgi TAŞIMIYOR; bu iş TAMAMEN attention'a ait. FFN sadece HER token'ı KENDİ İÇİNDE işliyor.

Matematik

Position-wise feed-forward ağ
FFN(x)=GELU(xW1+b1)W2+b2\text{FFN}(x) = \text{GELU}(xW_1 + b_1)W_2 + b_2
SembolAnlamı
xxTEK bir token’ın dmodeld_{model} boyutlu temsili
W1W_1dmodel×dffd_{model} \times d_{ff} boyutunda GENİŞLETEN matris
W2W_2dff×dmodeld_{ff} \times d_{model} boyutunda TEKRAR DARALTAN matris
dffd_{ff}Genelde 4×dmodel4 \times d_{model} (örn. dmodel=512dff=2048d_{model}=512 \Rightarrow d_{ff}=2048)

Bu formül, xx‘e HER SEFERİNDE, HANGİ token olduğuna BAKMAKSIZIN, AYNI W1,W2W_1, W_2 ile uygulanır — Transformer’ın “her token için AYRI bir ağ” değil, “TÜM token’lar için PAYLAŞILAN TEK bir ağ” kullandığı anlamına gelir.

Kod

Gerçek ölçekte bu iki alt-katmanın (attention vs FFN) parametre payını karşılaştıralım:

FFN, parametrelerin büyük kısmını taşır

# Gerçek "Attention is All You Need" makalesindeki boyutlarla parametre sayısı:
D_MODEL, D_FF_GERCEK = 512, 2048
ffn_gercek = nn.Sequential(nn.Linear(D_MODEL, D_FF_GERCEK), nn.GELU(), nn.Linear(D_FF_GERCEK, D_MODEL))
parametre_sayisi = sum(p.numel() for p in ffn_gercek.parameters())
attention_parametre = 4 * D_MODEL * D_MODEL  # Wq + Wk + Wv + Wo (12. ders), hepsi d_model x d_model
print(f"\nGerçek ölçek: d_model={D_MODEL}, d_ff={D_FF_GERCEK} (= 4 x d_model)")
print(f"TEK bir FFN alt-katmanının parametre sayısı: {parametre_sayisi:,}")
print(f"Karşılaştırma: AYNI boyuttaki TÜM multi-head attention alt-katmanının (Wq+Wk+Wv+Wo) parametre sayısı: {attention_parametre:,}")
print(f"FFN/Attention oranı: {parametre_sayisi / attention_parametre:.2f}x")
print("FFN, Transformer'ın parametrelerinin BÜYÜK bir kısmını oluşturur --")
print("'bilginin nerede SAKLANDIĞI' sorusunun cevabının BÜYÜK kısmı burada.")

Gerçek ölçek: d_model=512, d_ff=2048 (= 4 x d_model)
TEK bir FFN alt-katmanının parametre sayısı: 2,099,712
Karşılaştırma: AYNI boyuttaki TÜM multi-head attention alt-katmanının (Wq+Wk+Wv+Wo) parametre sayısı: 1,048,576
FFN/Attention oranı: 2.00x
FFN, Transformer'ın parametrelerinin BÜYÜK bir kısmını oluşturur --
'bilginin nerede SAKLANDIĞI' sorusunun cevabının BÜYÜK kısmı burada.
0. token değiştirildiğinde diğer token'ların attention ve FFN çıktısındaki değişimi gösteren çubuk grafik; attention çubukları büyük, FFN çubukları sıfır.
0. token değiştirilince, attention'da DİĞER token'ların çıktısı da değişiyor (turuncu çubuklar); FFN'de HİÇ değişmiyor (mavi çubuklar, sıfıra yakın).

Nerede işe yarar

Bu ayrım, Transformer’ın TASARIM felsefesinin özeti sayılabilir:

  • Attention = “NEREYE bakayım?” (token’lar arası iletişim); FFN = “gördüğümle NE yapayım?” (her token’ın kendi işlenmesi) — bir Transformer bloğu, bu ikisini SIRAYLA tekrarlayarak derinleşir.
  • FFN’nin genişleme boyutu (dffd_{ff}), modelin “düşünme kapasitesinin” büyük kısmını taşır — araştırmalar, FFN katmanlarının OLGU/BİLGİ depolamada (örn. “Fransa’nın başkenti Paris’tir”) ÖZELLİKLE önemli rol oynadığını gösteriyor.
  • GELU (ya da ReLU), DL Görüntü kategorisinde (8. ders) zaten gördüğün AYNI aktivasyon fonksiyonları — burada YENİ bir matematik YOK, sadece YENİ bir BAĞLAMDA (Transformer bloğu içinde) kullanılıyorlar.

Bu 2 hatayı yaparsın:

  1. FFN’nin token’lar arasında bilgi TAŞIDIĞINI sanmak — HAYIR, bu İŞ tamamen attention’a ait; FFN kesinlikle “position-wise” (konum-bağımsız çalışan, ama konumlar arası KARIŞTIRMAYAN) bir işlemdir.
  2. FFN’yi “attention’ın yanında küçük bir ek” sanmak — gerçekte FFN, parametrelerin YARISINDAN FAZLASINI oluşturur (bu dersteki 2x oranına bak).

Kendini test et

1. 'Position-wise feed-forward ağ' ifadesindeki 'position-wise' NE anlama gelir?
  1. Her konum için FARKLI bir ağırlık matrisi kullanılır
  2. AYNI W1, W2 ağırlıkları HER token'a, diğer token'lardan BAĞIMSIZ olarak uygulanır -- tüm diziyi birden işlemekle her token'ı tek tek işlemek AYNI sonucu verir (doğru cevap)
  3. Sadece cümlenin İLK konumuna uygulanır
  4. Konum bilgisini (13. ders) hesaplar

Neden: konum-bagimsiz-mi bloğunda, tüm diziyi birden işlemek ile döngüyle tek tek işlemek arasındaki fark 5.96e-08 (pratikte sıfır) -- bu, AYNI ağırlıkların her token'a bağımsız uygulandığını kanıtlıyor.

2. 0. token'ı büyük ölçüde değiştirdiğimizde, attention'da diğer token'ların çıktısı DEĞİŞİRKEN, FFN'de HİÇ değişmiyor (fark tam 0). Bu farkın nedeni ne?
  1. FFN bozuktur
  2. Attention, her token'ın çıktısını DİĞER token'ların ağırlıklı bir karışımından hesaplar (10. ders); FFN ise her token'ı SADECE kendi değerine bakarak işler, diğer token'lardan hiçbir girdi almaz (doğru cevap)
  3. Attention daha yavaştır
  4. Bu, sadece küçük modellerde görülen bir durumdur

Neden: attention-ile-fark bloğunda attention farkları 3.0-12.4 arasında (token'lar birbirini GÖRÜYOR) iken, FFN farkları tam olarak 0.00e+00 -- FFN'nin matematiksel tanımı gereği (her token bağımsız işlenir) diğer token'ları hiç ETKİLEMEZ.

3. Notebook'ta gerçek ölçekte (d_model=512, d_ff=2048) FFN'nin parametre sayısı, TÜM multi-head attention alt-katmanının (Wq+Wk+Wv+Wo) 2 katı çıkıyor. Bu NEYİ gösteriyor?
  1. Bir hesaplama hatası olduğunu
  2. FFN'nin genişleme boyutu (d_ff = 4 x d_model) nedeniyle, Transformer'ın parametrelerinin BÜYÜK bir kısmının FFN katmanlarında bulunduğunu -- bu da modelin 'bilgi kapasitesinin' önemli bir kısmının FFN'de saklandığı anlamına gelir (doğru cevap)
  3. Attention'ın gereksiz olduğunu
  4. FFN'nin daha az önemli olduğunu

Neden: gercek-olcek bloğunda FFN parametre sayısı 2,099,712 iken attention 1,048,576 -- oran tam 2.00x, d_ff=4×d_model seçiminin doğrudan bir sonucu.

Özet

Özet

  • FFN, DL Görüntü kategorisinden bildiğin 2 katmanlı bir MLP (Linear → GELU → Linear) -- yeni olan, HER token'a AYNI ağırlıklarla, bağımsız uygulanması.
  • "Position-wise": tüm diziyi birden işlemek, her token'ı döngüyle tek tek işlemekle MATEMATİKSEL olarak özdeştir.
  • Attention token'lar ARASINDA bilgi taşır; FFN taşımaz -- bir token değişince FFN'de diğerlerinin çıktısı HİÇ etkilenmez (fark tam 0).
  • FFN'nin genişleme boyutu (d_ff, genelde 4×d_model) onu Transformer'ın parametre-ağır bileşeni yapar -- gerçek ölçekte attention'ın 2 katı parametre.
  • Attention "nereye bakayım" sorusunu, FFN "gördüğümle ne yapayım" sorusunu cevaplar -- bir Transformer bloğu ikisini SIRAYLA tekrarlar.
Sonraki adım: Encoder-decoder yapısı →