- Metnin tokenlere ve gömme vektörlerine nasıl dönüştüğünü açıklamak
- Öz-dikkati formülle ve kodla hesaplamak, maskenin ve √dₖ'nın rolünü bilmek
- LLM'lerin nasıl eğitildiğini (sonraki token, ince ayar) ve perpleksitenin ne olduğunu açıklamak
- Önceden eğitilmiş modelleri kullanmak ve sorumlu yapay zekânın ele aldığı riskleri tanımak
Sohbet asistanları, makine çevirisi, kod yazmaya yardım eden araçlar; hepsinin kalbinde transformer mimarisi vardır. 2017'de “Attention Is All You Need” makalesinde (Vaswani ve arkadaşları) tanıtıldı. Büyük dil modeli (LLM) ise aslında tek bir basit görevle eğitilmiş çok büyük bir transformerdır: bir metinde sonraki tokeni tahmin etmek. Bu derste bu fikrin içine bakacak ve dikkat mekanizmasını kendi ellerimizle hesaplayacağız.
Tokenler ve gömmeler
Bir sinir ağı harflerle değil sayılarla çalışır. Bu yüzden metin önce tokenlere (sözcükler, sözcük parçaları ya da karakterler) bölünür ve her tokene bir sözlükte bir numara verilir. Modern modeller alt sözcük tokenleştirmesi (örneğin BPE) kullanır: sık görülen sözcükler tek bir token olur, nadir sözcükler parçalara bölünür. Sözlükler genellikle on binlerce token içerir; örneğin GPT-2'de 50.257 token vardır.
text = 'the cat sat on the mat'
words = text.split()
vocab = sorted(set(words))
stoi = {w: i for i, w in enumerate(vocab)}
ids = [stoi[w] for w in words]
print(vocab)
print(ids)▸ Beklenen çıktı
['cat', 'mat', 'on', 'sat', 'the'] [4, 0, 3, 2, 4, 1]
Bir token numarası kendi başına anlam taşımaz; bu yüzden her numara öğrenilen bir gömme (embedding) vektörüne dönüştürülür. Bu, V × d boyutunda bir tablodur: i. satır i. tokenin vektörüdür. Eğitim sırasında anlamca yakın tokenlerin vektörleri birbirine yaklaşır.
import torch
from torch import nn
torch.manual_seed(42)
emb = nn.Embedding(num_embeddings=5, embedding_dim=4)
ids = torch.tensor([4, 0, 3, 2, 4, 1])
vectors = emb(ids)
print(vectors.shape, emb.weight.shape)
print(torch.equal(vectors[0], vectors[4]))torch.Size([6, 4]) torch.Size([5, 4]) True
Öz-dikkat (self-attention)
İngilizce “bank” sözcüğü nehir kıyısı ya da bir finans kuruluşu anlamına gelebilir; hangisi olduğuna bağlam karar verir. Öz-dikkatte her token diğer tokenlere “bakar” ve onların bilgilerinin ağırlıklı bir karışımını alır. Bunun için her token üç vektör üretir: sorgu (query, “ne arıyorum?”), anahtar (key, “bende ne var?”) ve değer (value, “ne aktarıyorum?”). Bir sorgu ile bir anahtarın iç çarpımı ne kadar büyükse o tokenin değeri sonuca o kadar çok katılır.
- X(T, d) şeklinde token vektörleri
- WQ, WK, WVöğrenilen (d, dₖ) matrisleri
- Q · Kᵀ(T, T) puan matrisi: her sorgunun her anahtarla benzerliği
- √dₖölçek çarpanı; dₖ anahtar boyutudur
- softmaxsatır satır uygulanır: dikkat ağırlıkları pozitiftir ve toplamı 1'dir
- Vdeğerler; çıktı onların ağırlıklı ortalamasıdır
Ölçekli iç çarpım dikkati (scaled dot-product attention).
Neden √dₖ'ya bölüyoruz? q ve k'nın bileşenleri ortalaması 0, varyansı 1 olan bağımsız sayılarsa q · k = ∑ qᵢkᵢ toplamının varyansı dₖ olur. dₖ = 64 iken puanlar ±8 civarına yayılır, softmax neredeyse “one-hot” olur ve gradyanlar kaybolur. √dₖ'ya bölmek varyansı yeniden 1'e getirir.
dₖ = 4. Sorgu q = (1, 0, 1, 0); anahtarlar k₁ = (1, 0, 1, 0), k₂ = (0, 1, 0, 1); değerler v₁ = (1, 0), v₂ = (0, 1). Dikkatin çıktısını bul.
Çözümü gösterÇözümü gizle
√dₖ = 2'ye bölüyoruz: (1; 0).
softmax: e / (e + 1) ≈ 0,731 ve 1 / (e + 1) ≈ 0,269.
Çıktı: 0,731 · v₁ + 0,269 · v₂ = (0,731; 0,269); sorguya daha çok benzeyen birinci tokenden daha fazla bilgi alındı.
GPT gibi metin üreten modellerde bir token geleceğe bakamaz; yoksa tahmin etmesi gereken cevabı “görürdü”. Bu yüzden köşegenin üstündeki puanlar −∞ yapılır (nedensel maske, causal mask); softmax'tan sonra ağırlıkları 0 olur. Aşağıdaki kod 4 token için öz-dikkati NumPy ile baştan sona hesaplar:
import numpy as np
def softmax(z):
e = np.exp(z - z.max(axis=-1, keepdims=True))
return e / e.sum(axis=-1, keepdims=True)
rng = np.random.default_rng(4)
T, d = 4, 8
X = rng.normal(size=(T, d))
Wq, Wk, Wv = (rng.normal(size=(d, d)) / np.sqrt(d) for _ in range(3))
Q, K, V = X @ Wq, X @ Wk, X @ Wv
scores = Q @ K.T / np.sqrt(d)
mask = np.triu(np.ones((T, T), dtype=bool), k=1)
scores[mask] = -np.inf
A = softmax(scores)
print(np.round(A, 2))
print(A.sum(axis=1))
print((A @ V).shape)▸ Beklenen çıktı
[[1. 0. 0. 0. ] [0.82 0.18 0. 0. ] [0.14 0.47 0.39 0. ] [0.23 0.66 0.03 0.08]] [1. 1. 1. 1.] (4, 8)
Çok başlı dikkat, konum kodlaması ve transformer bloğu
- hbaş sayısı; her başın boyutu d / h'dir
- WObirleştirilmiş başları karıştıran (d, d) matris
Her baş farklı bir ilişkiye dikkat etmeyi öğrenebilir: biri dil bilgisel bağlara, diğeri bir zamirin neyi gösterdiğine. Parametreler: WQ, WK, WV, WO için 4 · d² ağırlık ve 4 · d sapma.
import torch
from torch import nn
torch.manual_seed(42)
mha = nn.MultiheadAttention(embed_dim=64, num_heads=8, batch_first=True)
x = torch.randn(2, 10, 64)
out, weights = mha(x, x, x)
print(out.shape, weights.shape)
print(sum(p.numel() for p in mha.parameters()))torch.Size([2, 10, 64]) torch.Size([2, 10, 10]) 16640
Dikkat kendi başına tokenlerin sırasını bilmez: “köpek kediyi kovaladı” ve “kedi köpeği kovaladı” cümlelerinde aynı tokenler vardır. Bu yüzden gömmelere bir konum kodlaması eklenir. Orijinal transformerda farklı frekanslarda sinüs ve kosinüsler kullanıldı; GPT-2 gibi modeller konum vektörlerini öğrenir, günümüzün birçok LLM'i ise dönel kodlama (RoPE) kullanır.
- postokenin konumu: 0, 1, 2, …
- ibileşen çiftinin numarası; küçük i hızlı, büyük i yavaş salınır
- dgömme boyutu
import numpy as np
def positional_encoding(T, d):
pos = np.arange(T)[:, None]
i = np.arange(0, d, 2)[None, :]
angles = pos / 10000 ** (i / d)
pe = np.zeros((T, d))
pe[:, 0::2] = np.sin(angles)
pe[:, 1::2] = np.cos(angles)
return pe
print(np.round(positional_encoding(T=5, d=4), 3))▸ Beklenen çıktı
[[ 0. 1. 0. 1. ] [ 0.841 0.54 0.01 1. ] [ 0.909 -0.416 0.02 1. ] [ 0.141 -0.99 0.03 1. ] [-0.757 -0.654 0.04 0.999]]
Bir transformer bloğu şöyle kurulur: x → LayerNorm → çok başlı dikkat → artık bağlantı (x + …) → LayerNorm → iki katmanlı bir MLP (genellikle 4d gizli nöron ve GELU) → yine bir artık bağlantı. Artık bağlantılar, gradyanın onlarca bloktan kaybolmadan geçmesine yardım eder. Bir model bu bloklardan N tanesinin art arda dizilmesidir. Üç ana tür vardır:
| Mimari | Dikkat | Örnekler | Tipik görevler |
|---|---|---|---|
| Yalnızca kodlayıcı | çift yönlü | BERT | metin sınıflandırma, arama, adlandırılmış varlık tanıma |
| Yalnızca kod çözücü | nedensel (maskeli) | GPT | metin üretme, sohbet, kod |
| Kodlayıcı–kod çözücü | çift yönlü + nedensel + çapraz dikkat | T5 | çeviri, özetleme |
LLM'ler nasıl eğitilir
Ön eğitim (pretraining) aşamasında model, devasa bir metin derleminin her konumunda sonraki tokeni tahmin eder. Bu öz-denetimli öğrenmedir: etiketleri kimse yazmaz, onlar metnin kendisindeki sonraki tokenlerdir. Kayıp, tüm konumlar üzerinden ortalaması alınmış çapraz entropidir; ondan perpleksite hesaplanır: modelin her adımda ortalama kaç seçenek arasında “kararsız kaldığı”.
- xₜmetindeki t. token
- p(xₜ₊₁ | x₁, …, xₜ)önceki tokenler verildiğinde modelin doğru sonraki tokene verdiği olasılık
- PPLperpleksite; ne kadar düşükse model o kadar iyidir
import torch
import torch.nn.functional as F
torch.manual_seed(42)
tokens = torch.tensor([4, 0, 3, 2, 4, 1])
inputs, targets = tokens[:-1], tokens[1:]
logits = torch.randn(len(inputs), 5)
loss = F.cross_entropy(logits, targets)
print(inputs.tolist(), targets.tolist())
print(round(loss.item(), 4), round(torch.exp(loss).item(), 2))
print(round(torch.log(torch.tensor(5.0)).item(), 4))[4, 0, 3, 2, 4] [0, 3, 2, 4, 1] 1.6522 5.22 1.6094
Sözlükte 50.000 token var. a) Körü körüne tahmin eden bir modelin kaybı ve perpleksitesi nedir? b) Eğitilmiş bir modelin ortalama kaybı 2,0'dır. Perpleksitesi nedir ve bu ne anlama gelir?
Çözümü gösterÇözümü gizle
b) PPL = e² ≈ 7,4: model her adımda sanki yaklaşık 7 eşit olasılıklı seçenek arasından seçiyor; 50.000'e göre muazzam bir ilerleme.
Ön eğitimden sonra model metni sürdürmeyi bilir ama henüz iyi bir asistan değildir. Ardından ince ayar (fine-tuning) gelir: soru–cevap örnekleri üzerinde denetimli eğitim, sonra da insanların tercih ettiği cevaplara dayanan yöntemler (örneğin insan geri bildirimiyle pekiştirmeli öğrenme, RLHF). Bir modeli kendi görevine uyarlarken milyarlarca parametresinin hepsini eğitmen gerekmez: LoRA gibi yöntemler yalnızca küçük ek matrisleri eğitir. Metin üretilirken model sonraki tokenin dağılımını verir, bir token seçilir ve süreç tekrarlanır.
- τsıcaklık: τ < 1 daha emin ve tekrarlı, τ > 1 daha çeşitli ve riskli metin verir
Sıcaklıklı softmax ile sonraki tokenin seçilmesi.
import numpy as np
z = np.array([2.0, 1.0, 0.0])
for T in [0.5, 1.0, 2.0]:
p = np.exp(z / T) / np.exp(z / T).sum()
print(T, np.round(p, 3))▸ Beklenen çıktı
0.5 [0.867 0.117 0.016] 1.0 [0.665 0.245 0.09 ] 2.0 [0.506 0.307 0.186]
Hazır modeller ve sorumlu yapay zekâ
Uygulamada modelleri sıfırdan eğitmek yerine hazır modeller kullanılır. Hugging Face Hub binlerce açık modeli barındırır; transformers kütüphanesi (pip install transformers) ise onları birkaç satırla yükler. Bu kod tarayıcıda çalışmaz: ilk çalıştırmada modelin ağırlıkları (yüzlerce megabayt) indirilir.
from transformers import pipeline
classifier = pipeline('sentiment-analysis', model='distilbert/distilbert-base-uncased-finetuned-sst-2-english')
print(classifier('I love learning with Educora!'))
generator = pipeline('text-generation', model='openai-community/gpt2')
result = generator('Deep learning is', max_new_tokens=20)
print(result[0]['generated_text'])- Yanlılık: modeller eğitim metinlerindeki kalıp yargıları tekrarlayabilir; işe alım ya da kredi gibi kararlarda özellikle tehlikelidir.
- Halüsinasyonlar: model kulağa inandırıcı gelen ama yanlış olgular, alıntılar ve kaynaklar uydurabilir.
- Gizlilik: kişisel verileri, parolaları ve gizli belgeleri çevrim içi yapay zekâ hizmetlerine yazma; eğitim verisindeki kişisel veriler de korunmalıdır.
- Telif hakları ve lisanslar: her modelin ve veri kümesinin kullanım koşulları vardır; onları oku.
- Enerji ve kaynaklar: büyük modelleri eğitmek ve çalıştırmak çok fazla elektrik ve hesaplama gücü gerektirir.
Önemli noktalar
- Metin tokenlere bölünür, her token öğrenilen bir gömme vektörüne dönüşür ve ona konum bilgisi eklenir.
- Attention(Q, K, V) = softmax(QKᵀ/√dₖ)·V: her token diğerlerinin değerlerinin ağırlıklı ortalamasını alır; √dₖ softmax'ın doymasını önler.
- Nedensel maske kod çözücüde gelecekteki tokenleri gizler; çok başlı dikkat farklı ilişkileri paralel öğrenir.
- Bir LLM sonraki tokeni tahmin edecek şekilde eğitilir: L = −(1/T)∑ ln p(xₜ₊₁ | x≤ₜ), PPL = eᴸ; ardından ince ayar yapılır.
- Hazır modelleri kullanırken yanlılığı, halüsinasyonları, gizliliği ve lisansları aklında tut.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.