Import’lar ve Temel Hazırlık
Her Python projesi import satırlarıyla başlar. Karpathy burada kasıtlı olarak sıfır dış bağımlılık kullanıyor — PyTorch yok, NumPy yok. Sadece Python’un yerleşik modülleri.
microgpt.py — satır 1–4
import os # os.path.exists → dosya var mı kontrolü
import math # math.log, math.exp → logaritma ve üstel fonksiyon
import random # random.seed, random.choices, random.gauss, random.shuffle
random.seed(42) # Kaosa düzen getir — tekrarlanabilirlik sağla
| Terim | Açıklama |
|---|---|
| import | Python’da dış kütüphaneleri yükleme komutu. “Bu araç kutusunu aç” demek gibi. |
| os | İşletim sistemiyle iletişim modülü. Burada sadece os.path.exists() ile “dosya var mı?” kontrolü için kullanılıyor. |
| math | Matematik fonksiyonları — log (logaritma) ve exp (üstel fonksiyon) gibi hesaplamalar için. |
| random | Rastgele sayı üretici. Yapay zekada “kontrollü rastgelelik” kritik bir kavramdır. |
| random.seed(42) | Seed (Tohum): Rastgeleliğe bir başlangıç noktası verir. 42 ünlü bir sayıdır (Otostopçunun Galaksi Rehberi). Seed sayesinde kodu her çalıştırdığında aynı sonuçları alırsın. Buna reproducibility (tekrarlanabilirlik) denir. |
Karpathy’nin amacı eğitim. PyTorch, TensorFlow gibi kütüphaneler bu kodun yaptığı her şeyi arka planda yapar. Ama ne yaptığını anlamadan kullanırsan “sihir” gibi kalır. Bu kod sihri kaldırıp mekanizmayı gösteriyor.
Veri Seti Yükleme
Her yapay zeka modeli veriden öğrenir. Bu kodda veri seti, ~32.000 İngilizce insan ismi listesidir. Her isim mini bir “doküman” olarak ele alınır.
microgpt.py — satır 6–11
if not os.path.exists('input.txt'):
import urllib.request
names_url = 'https://raw.githubusercontent.com/karpathy/makemore/.../names.txt'
urllib.request.urlretrieve(names_url, 'input.txt')
docs = [l.strip() for l in open('input.txt').read().strip().split('\n') if l.strip()]
random.shuffle(docs)
print(f"num docs: {len(docs)}")
| Terim | Açıklama |
|---|---|
| os.path.exists() | Dosya var mı kontrolü. Yoksa internetten indirecek — gereksiz indirmeyi önler. |
| urllib.request | URL’den dosya indirme modülü. HTTP isteği yapıp dosyayı diske kaydeder. |
| input.txt | İnsan isimleri listesi. Her satırda bir isim: “emma”, “olivia”, “ava” gibi. ~32.000 satır. |
| docs | Doküman listesi. Her isim bir “doküman.” GPT’ler dokümanlar üzerinde eğitilir — burada her isim, mini bir doküman. |
| l.strip() | Satır başı/sonu boşlukları temizler. “\n” ve ” ” gibi görünmez karakterleri kaldırır. |
| random.shuffle() | Listeyi rastgele karıştır. Modelin “önce A’lar, sonra B’ler” diye ezber yapmasını engeller. Buna data shuffling denir. |
Bir deste kağıdı karıştırmak gibi — iskambil oyununda deste karıştırılmazsa aynı sıralama tekrar eder ve oyun öğretilemez. Shuffle, modelin verideki gerçek örüntüleri yakalamasını sağlar.
Tokenizer — Metin → Sayı Dönüşümü
Bilgisayarlar harflerle değil sayılarla çalışır. Tokenizer, metni model için anlaşılır sayılara çevirir. Bu kodda her karakter bir token.
microgpt.py — satır 13–16
uchars = sorted(set(''.join(docs))) # unique karakterler → token ID'leri
BOS = len(uchars) # Beginning of Sequence özel tokeni
vocab_size = len(uchars) + 1 # toplam benzersiz token sayısı
print(f"vocab size: {vocab_size}") # ≈ 27 (26 harf + 1 BOS)
| Terim | Açıklama |
|---|---|
| Token | Metnin en küçük anlamlı parçası. Burada her karakter bir token. ChatGPT gibi büyük modellerde tokenler kelime parçaları olur (“un”, “believ”, “able” gibi). |
| Tokenizer | Metni sayılara çeviren sistem. "a" → 0, "b" → 1, "c" → 2 gibi eşleştirme yapar. |
| uchars | Unique Characters — veri setindeki tüm benzersiz karakterler. Alfabetik sıraya dizilir: [‘a’, ‘b’, ‘c’, …, ‘z’] |
| set() | Tekrarları siler. “aab” → {‘a’, ‘b’}. Her karakter sadece bir kez temsil edilir. |
| BOS | Beginning of Sequence — “Dizi Başlangıcı” özel tokeni. Modele “yeni bir isim başlıyor / bitti” sinyali verir. Bir kitabın bölüm başlığı gibi. |
| vocab_size | Kelime hazinesi boyutu. Tüm unique karakterler + BOS tokeni. ≈ 27 (26 harf + 1 BOS). |
Karakter bazlı (bu kodda): Her harf = 1 token → basit ama yavaş.
Alt-kelime bazlı (GPT-2/3/4): BPE algoritmasıyla kelime parçaları → dengeli.
Kelime bazlı: Her kelime = 1 token → devasa vocab, nadir kelimeler sorun olur.
Autograd — Otomatik Türev Alma (Kodun Kalbi)
Bu bölüm kodun en kritik parçası. Yapay zekanın “öğrenme” mekanizmasının temelidir. Her matematiksel işlem bir hesaplama grafiği olarak kaydedilir. Sonra bu grafik geriye doğru yürüyerek her parametrenin hataya katkısı hesaplanır.
microgpt.py — Value sınıfı
class Value:
__slots__ = ('data', 'grad', '_children', '_local_grads')
def __init__(self, data, children=(), local_grads=()):
self.data = data # skaler değer (ileri geçişte hesaplanır)
self.grad = 0 # gradyan (geri geçişte hesaplanır)
self._children = children # çocuk düğümler
self._local_grads = local_grads # yerel türevler
| Terim | Açıklama |
|---|---|
| Autograd | Automatic Gradient — Otomatik türev hesaplama sistemi. Her işlemin türevini otomatik olarak kaydedip hesaplar. PyTorch’un temeli de bu. |
| Gradient (Gradyan) | Bir fonksiyonun eğimi. “Bu parametre biraz artarsa kayıp ne kadar değişir?” sorusunun cevabı. Öğrenmenin pusula oku. |
| Computation Graph | Hesaplama Grafiği. Her matematiksel işlem bir düğüm, her veri bağlantısı bir kenar. c = a + b → üç düğüm, iki kenar. |
| Chain Rule | Zincir Kuralı. Bileşik fonksiyonların türevini hesaplama: f(g(x))' = f'(g(x)) × g'(x). Autograd bunu otomatik uygular. |
| __slots__ | Python bellek optimizasyonu. Normal class’lar dictionary tutar, __slots__ ile sadece belirtilen alanlar için yer ayrılır → %30-40 bellek tasarrufu. |
| data | Bu düğümün skaler değeri. İleri geçişte hesaplanır. Örneğin 3 + 5 için sonuç 8. |
| grad | Bu düğümün gradyanı. Geri geçişte hesaplanır. “Son kayba ne kadar katkın var?” sorusu. |
| _children | Bu düğümün çocukları — hangi değerlerden hesaplandığı. c = a + b → c’nin children’ı = (a, b). |
| _local_grads | Yerel gradyanlar — bu işlemin her çocuğa göre kısmi türevleri. |
Bir fabrikada hatalı ürün çıktığında, hatanın hangi makineden kaynaklandığını bulmak için üretim hattını geriye doğru takip edersin. Autograd tam olarak bunu yapıyor — kayıptan başlayıp geriye doğru her parametrenin hataya katkısını hesaplıyor.
Matematiksel İşlemler ve Türevleri
İşlem operatörleri
def __add__(self, other): # c = a + b
return Value(self.data + other.data, (self, other), (1, 1))
def __mul__(self, other): # c = a × b
return Value(self.data * other.data, (self, other), (other.data, self.data))
def __pow__(self, other): # c = a ^ n
return Value(self.data**other, (self,), (other * self.data**(other-1),))
def log(self): # c = ln(a)
return Value(math.log(self.data), (self,), (1/self.data,))
def exp(self): # c = e^a
return Value(math.exp(self.data), (self,), (math.exp(self.data),))
def relu(self): # c = max(0, a)
return Value(max(0, self.data), (self,), (float(self.data > 0),))
| İşlem | Matematik | Yerel Gradyan | Açıklama |
|---|---|---|---|
| __add__ | c = a + b | (1, 1) | Toplamada her iki tarafın türevi 1’dir. a biraz artarsa c de o kadar artar. |
| __mul__ | c = a × b | (b, a) | Çarpmada türev çapraz: a‘nın türevi = b, b‘nin türevi = a. |
| __pow__ | c = an | n × an-1 | Üs kuralı. Klasik kalkülüs: türev = üs × taban^(üs-1). |
| log() | c = ln(a) | 1/a | Doğal logaritmanın türevi 1/x. Kayıp fonksiyonunda kullanılır. |
| exp() | c = ea | ea | Üstel fonksiyonun türevi kendisidir! Matematiğin en güzel özellikleri arasında. |
| relu() | c = max(0,a) | 1 (a>0), 0 (a≤0) | Pozitifse geçir, negatifse sıfırla. Bir kapı gibi çalışır. |
Backward — Geri Yayılım (Backpropagation)
backward() metodu
def backward(self):
topo = [] # topolojik sıralama listesi
visited = set()
def build_topo(v):
if v not in visited:
visited.add(v)
for child in v._children:
build_topo(child)
topo.append(v)
build_topo(self)
self.grad = 1 # kayıp kendine göre türev = 1
for v in reversed(topo):
for child, local_grad in zip(v._children, v._local_grads):
child.grad += local_grad * v.grad # zincir kuralı!
| Terim | Açıklama |
|---|---|
| Backward Pass | Geri geçiş. Kayıptan başlayıp parametrelere doğru gradyanları hesaplama süreci. Öğrenmenin “nasıl düzeltmeliyim?” adımı. |
| Topological Sort | Topolojik sıralama. Grafiği bağımlılık sırasına göre dizer. Bir çocuk, ebeveyninden önce gelir. Sonra ters sırada yürüyeceğiz. |
| self.grad = 1 | Başlangıç noktası. “Kaybın kendine göre türevi = 1.” Yani kayıp 1 birim değişirse, kayıp 1 birim değişir (trivial ama gerekli). |
| child.grad += | Zincir kuralının uygulanması: yerel_gradyan × yukarıdan_gelen_gradyan. += çünkü bir düğüm birden fazla yoldan katkı alabilir. |
| Backpropagation | Geri yayılım. 1986’da Rumelhart, Hinton ve Williams tarafından popülerleştirildi. Tüm modern yapay zekanın temel öğrenme algoritması. |
Gradyan = Pusula. Geri yayılım her parametreye bir gradyan verir. Gradyan şunu söyler: “Bu parametreyi şu yönde değiştirirsen kayıp azalır.” Tüm derin öğrenme bu pusulayı takip etmekten ibarettir.
Model Parametreleri ve Ağırlıklar
Parametreler modelin bilgisidir. Eğitim başlamadan önce rastgele sayılarla başlatılır, eğitim boyunca güncellenir. Beyindeki sinaps güçleri gibi düşünülebilir.
Hiperparametreler ve başlatma
n_embd = 16 # embedding boyutu
n_head = 4 # attention head sayısı
n_layer = 1 # transformer katman sayısı
block_size = 16 # maksimum dizi uzunluğu (context window)
head_dim = n_embd // n_head # = 4, her head'in boyutu
# Rastgele matris oluşturucu
matrix = lambda nout, nin, std=0.08: [
[Value(random.gauss(0, std)) for _ in range(nin)]
for _ in range(nout)
]
| Parametre | Değer | Açıklama |
|---|---|---|
| n_embd | 16 | Embedding boyutu. Her tokenin kaç boyutlu vektörle temsil edileceği. GPT-3’te bu 12.288! Burada eğitim amaçlı küçük tutulmuş. |
| n_head | 4 | Attention head sayısı. Modelin aynı anda kaç farklı bakış açısından ilişki araması gerektiği. |
| n_layer | 1 | Katman sayısı. Transformer bloğu kaç kez tekrarlanacak. GPT-3’te bu 96! |
| block_size | 16 | Context window (bağlam penceresi). Model aynı anda en fazla 16 token görebilir. GPT-4’te 128K token! |
| head_dim | 4 | n_embd / n_head = 16/4 = 4. Her attention head’in çalıştığı boyut. |
| Hiperparametre | — | Modelin yapısını belirleyen, eğitim öncesi insanın seçtiği değerler. Model bunları öğrenmez, insan tasarlar. |
| gauss(0, std) | — | Gauss (normal) dağılımından rastgele sayı. Ortalama=0, standart sapma=0.08. Küçük rastgele değerler = dengeli başlangıç. |
state_dict — Tüm Ağırlıklar
| Anahtar | Boyut | Görevi |
|---|---|---|
| wte | vocab × n_embd | Word Token Embedding. Her token ID’sini bir vektöre çevirir. “a” → [0.12, -0.34, …] |
| wpe | block × n_embd | Word Position Embedding. Her pozisyonu bir vektöre çevirir. “1. sıra” → [0.56, 0.11, …] |
| lm_head | vocab × n_embd | Language Model Head. Son katman — embedding’den tekrar token olasılıklarına dönüş. |
| attn_wq | n_embd × n_embd | Query ağırlıkları. “Ne arıyorum?” projeksiyonu. |
| attn_wk | n_embd × n_embd | Key ağırlıkları. “Ben neyim?” projeksiyonu. |
| attn_wv | n_embd × n_embd | Value ağırlıkları. “Bende ne bilgi var?” projeksiyonu. |
| attn_wo | n_embd × n_embd | Output projeksiyonu. Tüm head çıktılarını birleştirip dönüştürür. |
| mlp_fc1 | 4×n_embd × n_embd | MLP genişletme katmanı. 16 → 64 boyut. Modele “düşünme alanı” verir. |
| mlp_fc2 | n_embd × 4×n_embd | MLP daraltma katmanı. 64 → 16 boyut. Bilgiyi yoğunlaştırır. |
Model Mimarisi Fonksiyonları
GPT’nin yapı taşları olan dört temel fonksiyon: linear, softmax, rmsnorm ve relu. Her biri farklı bir görevi yerine getirir.
Linear — Doğrusal Dönüşüm
y = W · x (matris çarpımı)
def linear(x, w):
return [sum(wi * xi for wi, xi in zip(wo, x)) for wo in w]
| Terim | Açıklama |
|---|---|
| Linear Layer | En temel sinir ağı katmanı. y = W·x — matris çarpımı. Her girdi, her çıktıya bağlıdır (fully connected / dense). |
| Dot Product | İç çarpım. İki vektörün eleman eleman çarpımının toplamı. İki vektörün “ne kadar benzer” olduğunu ölçer. |
Bir karışım masası (mixer) gibi — her girdi sinyalini (ses kanalını) farklı oranlarda karıştırıp yeni sinyaller üretir. W matrisindeki ağırlıklar “hangi kanalı ne kadar aç/kapa” kontrolüdür.
Softmax — Olasılık Dağılımına Dönüşüm
Ham skorlar → olasılıklar
def softmax(logits):
max_val = max(val.data for val in logits) # sayısal kararlılık
exps = [(val - max_val).exp() for val in logits] # exp(x - max)
total = sum(exps) # normalize et
return [e / total for e in exps] # toplamları = 1
| Terim | Açıklama |
|---|---|
| Softmax | Herhangi bir sayı dizisini olasılık dağılımına çevirir. Tüm çıktılar 0–1 arası olur ve toplamları 1 eder. |
| Logits | Softmax öncesi ham skorlar. -∞ ile +∞ arası herhangi bir değer alabilir. Modelin “ham tahmini.” |
| max_val çıkarma | Numerical stability (sayısal kararlılık). exp() büyük sayılarda infinity verir. Maks değeri çıkarmak bunu önler ama matematiksel sonucu değiştirmez. |
Sınav sonuçlarını yüzdelik dilime çevirmek gibi. Puanlar 85, 90, 95 → Softmax sonrası ≈ %15, %33, %52 olasılık. En yüksek puan en yüksek olasılığı alır ama diğerleri de sıfırlanmaz.
RMSNorm — Normalizasyon
Root Mean Square Normalization
def rmsnorm(x):
ms = sum(xi * xi for xi in x) / len(x) # karelerin ortalaması
scale = (ms + 1e-5) ** -0.5 # 1 / √(ms + ε)
return [xi * scale for xi in x] # ölçekle
| Terim | Açıklama |
|---|---|
| Normalization | Verileri belirli bir ölçeğe getirme. Değerlerin çok büyük veya küçük olmasını engeller. Eğitimi stabil tutar. |
| RMSNorm | LayerNorm’un sadeleştirilmiş hali. Ortalama çıkarma yok, sadece RMS’e bölme var. LLaMA modellerinde kullanılır. |
| 1e-5 (epsilon) | 0.00001. Sıfıra bölünmeyi önlemek için eklenen çok küçük sayı. Her normalizasyonda bulunur. |
GPT Fonksiyonu — Transformer Mimarisi
Bu fonksiyon, tüm Transformer mimarisini tek bir yerde toplar. Her çağrıda bir token alır, tüm katmanlardan geçirir ve bir sonraki tokenin olasılıklarını döndürür.
gpt() — Embedding + Transformer Block + LM Head
def gpt(token_id, pos_id, keys, values):
# 1) Embedding: token + pozisyon
tok_emb = state_dict['wte'][token_id]
pos_emb = state_dict['wpe'][pos_id]
x = [t + p for t, p in zip(tok_emb, pos_emb)]
x = rmsnorm(x)
for li in range(n_layer):
# 2) Multi-Head Attention
x_residual = x
x = rmsnorm(x)
q = linear(x, state_dict[f'layer{li}.attn_wq']) # Query
k = linear(x, state_dict[f'layer{li}.attn_wk']) # Key
v = linear(x, state_dict[f'layer{li}.attn_wv']) # Value
keys[li].append(k)
values[li].append(v)
# Her head için ayrı attention hesapla
x_attn = []
for h in range(n_head):
hs = h * head_dim
q_h = q[hs:hs+head_dim]
k_h = [ki[hs:hs+head_dim] for ki in keys[li]]
v_h = [vi[hs:hs+head_dim] for vi in values[li]]
# Scaled dot-product attention: Q·K / √d
attn_logits = [sum(q_h[j] * k_h[t][j]
for j in range(head_dim)) / head_dim**0.5
for t in range(len(k_h))]
attn_weights = softmax(attn_logits)
# Weighted sum of values
head_out = [sum(attn_weights[t] * v_h[t][j]
for t in range(len(v_h)))
for j in range(head_dim)]
x_attn.extend(head_out)
x = linear(x_attn, state_dict[f'layer{li}.attn_wo'])
x = [a + b for a, b in zip(x, x_residual)] # residual!
# 3) MLP bloğu
x_residual = x
x = rmsnorm(x)
x = linear(x, state_dict[f'layer{li}.mlp_fc1']) # genişlet
x = [xi.relu() for xi in x] # aktivasyon
x = linear(x, state_dict[f'layer{li}.mlp_fc2']) # daralt
x = [a + b for a, b in zip(x, x_residual)] # residual!
logits = linear(x, state_dict['lm_head']) # final: token olasılıkları
return logits
| Terim | Açıklama |
|---|---|
| Embedding | Bir tamsayıyı (token ID) anlamlı bir vektöre çevirme. “a” → [0.12, -0.34, 0.56, …] gibi 16 boyutlu bir dizi. |
| Token Embedding | Tokenin ne olduğunu kodlar. Farklı karakterler farklı vektörler alır. |
| Position Embedding | Tokenin nerede olduğunu kodlar. 1. pozisyon ile 5. pozisyon farklı vektörler. Attention sıra bilgisi taşımadığından bu zorunludur. |
| Attention | “Bu token diğer hangi tokenlere dikkat etmeli?” mekanizması. Hangi kelimelerin birbiriyle ilişkili olduğunu öğrenir. |
| Query (Q) | “Ne arıyorum?” — mevcut tokenin ihtiyacını temsil eden vektör. |
| Key (K) | “Ben ne sunuyorum?” — her tokenin kimlik/etiket vektörü. |
| Value (V) | “Bende hangi bilgi var?” — her tokenin gerçek bilgi içeriği. |
| Scaled Dot-Product | Q·K / √d — Vaswani et al. 2017’nin “Attention Is All You Need” makalesi. √d‘ye bölme büyük boyutlarda softmax’ı dengeler. |
| Multi-Head | Aynı anda birden fazla bakış açısı. Head 1 → gramer, Head 2 → anlam, Head 3 → pozisyon ilişkileri. |
| KV-Cache | Önceki pozisyonların Key ve Value vektörlerini saklama. Her seferinde baştan hesaplamamak için. Inference hızını katlayarak artırır. |
| Residual Connection | Katmanın girdisini çıktısına eklemek: çıktı = f(girdi) + girdi. Gradyanın rahatça akmasını sağlar, derin ağları eğitilebilir kılar. |
| MLP / FFN | Feed-Forward Network. İki katmanlı sinir ağı: genişlet (16→64) → ReLU → daralt (64→16). Attention çıktısını işleyip zenginleştirir. |
| lm_head | Son katman. Embedding uzayından tekrar token olasılıklarına dönüştürür. “Bir sonraki karakter ne olmalı?” |
Query: Aradığın konu (“yapay zeka tarihi”).
Key: Her kitabın etiketi/başlığı.
Value: Kitabın içeriği.
Attention Score: Etiketin aradığın konuya ne kadar uyduğu.
Multi-Head: Aynı anda hem konuya, hem yazara, hem yıla göre arama yapmak.
Residual Analojisi — Şelale ve Boru
Bir şelalede her basamağın yanında bir bypass borusu var. Su hem basamaklardan hem borudan akıyor. Basamaklar tıkansa bile su borudan geçmeye devam eder. Residual, gradyan akışı için bu borudur.
Adam Optimizer — Öğrenme Stratejisi
Gradyanlar hesaplandıktan sonra parametrelerin nasıl güncelleneceğine optimizer karar verir. Adam, en popüler ve güvenilir optimizer’dır.
Adam optimizer başlatma ve güncelleme
# Başlatma
learning_rate, beta1, beta2, eps_adam = 0.01, 0.85, 0.99, 1e-8
m = [0.0] * len(params) # first moment (momentum)
v = [0.0] * len(params) # second moment (varyans)
# Güncelleme (her adımda)
lr_t = learning_rate * (1 - step / num_steps) # linear LR decay
for i, p in enumerate(params):
m[i] = beta1 * m[i] + (1 - beta1) * p.grad # momentum güncelle
v[i] = beta2 * v[i] + (1 - beta2) * p.grad ** 2 # varyans güncelle
m_hat = m[i] / (1 - beta1 ** (step + 1)) # bias düzeltme
v_hat = v[i] / (1 - beta2 ** (step + 1)) # bias düzeltme
p.data -= lr_t * m_hat / (v_hat ** 0.5 + eps_adam) # parametre güncelle
p.grad = 0 # gradyanı sıfırla
| Terim | Açıklama |
|---|---|
| Adam | Adaptive Moment Estimation. 2014’te Kingma ve Ba tarafından yayınlandı. Momentum + adaptive learning rate birleşimi. |
| Learning Rate | Öğrenme hızı (0.01). Her adımda parametrelerin ne kadar değişeceği. Çok büyük = kararsız, çok küçük = yavaş öğrenir. |
| beta1 (0.85) | Momentum katsayısı. Gradyanın hareketli ortalamasını kontrol eder. “Son zamanlarda hangi yöne gidiyoruz?” |
| beta2 (0.99) | Varyans katsayısı. Gradyan karelerinin hareketli ortalaması. “Ne kadar salınıyoruz?” |
| First Moment (m) | Gradyanların hareketli ortalaması. Yön bilgisi taşır. |
| Second Moment (v) | Gradyan karelerinin hareketli ortalaması. Büyüklük/değişkenlik bilgisi taşır. |
| Bias Correction | İlk adımlarda m ve v sıfırdan başladığı için düşük kalır. /(1-β^t) düzeltmesi bunu telafi eder. |
| Linear LR Decay | lr × (1 - step/total_steps). Eğitim ilerledikçe öğrenme hızını düşür. Başta keşfet, sonda ince ayar yap. |
| p.grad = 0 | Gradyanı sıfırla. Her adım temiz bir sayfayla başlamalı, eski gradyanlar birikmemeli. |
Adam, bir dağda minimum noktayı arayan akıllı bir dağcı gibi.
Momentum: Rüzgar yönünü hatırlar, ani engellere rağmen ilerler.
Adaptive LR: Zor arazide yavaşlar, düz arazide hızlanır.
Bias Correction: İlk birkaç adımda etrafı tanıyıp kendini kalibre eder.
Eğitim Döngüsü (Training Loop)
Tüm parçalar bir araya geliyor. Eğitim döngüsü 1000 kez tekrarlar: ileri geçiş → kayıp hesapla → geri yayılım → parametre güncelle.
Ana eğitim döngüsü
num_steps = 1000
for step in range(num_steps):
# 1) Doküman seç ve tokenize et
doc = docs[step % len(docs)]
tokens = [BOS] + [uchars.index(ch) for ch in doc] + [BOS]
n = min(block_size, len(tokens) - 1)
# 2) İleri geçiş — hesaplama grafiği oluşur
keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)]
losses = []
for pos_id in range(n):
token_id, target_id = tokens[pos_id], tokens[pos_id + 1]
logits = gpt(token_id, pos_id, keys, values)
probs = softmax(logits)
loss_t = -probs[target_id].log() # cross-entropy loss
losses.append(loss_t)
loss = (1 / n) * sum(losses) # ortalama kayıp
# 3) Geri yayılım — gradyanlar hesaplanır
loss.backward()
# 4) Adam güncelleme — parametreler güncellenir
# ... (önceki bölümde gösterildi)
print(f"step {step+1:4d} / {num_steps:4d} | loss {loss.data:.4f}")
| Terim | Açıklama |
|---|---|
| Training Loop | Eğitim döngüsü. Forward → Loss → Backward → Update. Bu döngü 1000 kez tekrarlanır. Tüm derin öğrenme bu ritimdir. |
| step % len(docs) | Modüler aritmetik. Dokümanlar bitince başa dön. Sonsuz döngü etkisi yaratır. |
| [BOS] + tokens + [BOS] | Her ismi BOS tokenleriyle çevrele. Model BOS gördüğünde “yeni isim başlıyor / bitti” anlar. |
| Forward Pass | İleri geçiş. Girdiyi modelden geçirip çıktı alma. Bu sırada hesaplama grafiği oluşur. |
| Target | Hedef. Modelin tahmin etmesi gereken doğru token. “emm” gördükten sonra hedef = “a”. |
| Cross-Entropy Loss | -log(p_doğru). Doğru tokene verilen olasılığın negatif logaritması. Olasılık 1’e yakınsa loss ≈ 0, 0’a yakınsa loss → ∞. |
| loss.backward() | Geri yayılım tetikleme. Tüm hesaplama grafiğinde geriye doğru yürüyerek her parametrenin gradyanını hesaplar. |
Forward: Öğrenci sınava girer, cevapları yazar.
Loss: Öğretmen puanlama yapar, hata sayısını verir.
Backward: Öğrenci hangi soruları neden yanlış yaptığını analiz eder.
Update: Öğrenci zayıf alanlarını çalışıp geliştirir.
Bu döngü 1000 sınav boyunca devam eder. Her sınavda öğrenci biraz daha iyi olur.
Inference — Metin Üretimi
Eğitim bitti, model artık yeni isimler üretebilir. Hiç görmediği, tamamen hayal ürünü isimler oluşturur.
Inference — sampling ile isim üretme
temperature = 0.5 # yaratıcılık düğmesi (0,1] arası
print("\n--- inference (yeni, halüsinasyon isimler) ---")
for sample_idx in range(20):
keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)]
token_id = BOS # her zaman BOS ile başla
sample = []
for pos_id in range(block_size):
logits = gpt(token_id, pos_id, keys, values)
probs = softmax([l / temperature for l in logits]) # temperature uygula
token_id = random.choices(
range(vocab_size),
weights=[p.data for p in probs]
)[0] # olasılığa göre rastgele seç
if token_id == BOS: # BOS gördüyse isim bitti
break
sample.append(uchars[token_id])
print(f"sample {sample_idx+1:2d}: {''.join(sample)}")
| Terim | Açıklama |
|---|---|
| Inference | Eğitilmiş modeli kullanarak yeni içerik üretme. Eğitim bitti, şimdi model konuşsun. |
| Temperature | Yaratıcılık kontrolü (0,1] arası. 0’a yakın = deterministik (en olası seçilir). 1’e yakın = yaratıcı ama tutarsız. ChatGPT’de de aynı mantık! |
| Temperature Matematiği | logits / T. Düşük T → farklar büyür → softmax sivri → en olası baskın. Yüksek T → farklar küçülür → softmax düz → daha rastgele. |
| Sampling | Olasılık dağılımından rastgele seçim. random.choices() ağırlıklı rastgele seçim yapar. %60 olasılıklı token %60 şansla seçilir. |
| Autoregressive | Otoregresif üretim. Her üretilen token bir sonraki için girdi olur: “e” → “m” → “m” → “a” → BOS (dur). ChatGPT de böyle çalışır! |
| BOS = dur sinyali | Model BOS tokeni ürettiğinde “isim bitti” anlaşılır ve döngü kırılır (break). |
T = 0.1: “emma”, “anna”, “olivia” — çok güvenli, bilinen isimler.
T = 0.5: “karina”, “jalen”, “meria” — makul ama yaratıcı.
T = 1.0: “xqzem”, “brfui”, “lwoa” — kaotik, gerçekçi değil.
Tam da ChatGPT’deki temperature ayarıyla aynı mekanizma.
Büyük Resim: Mimari Akış Şeması
Tüm parçaların birbirine nasıl bağlandığını gösteren tam akış şeması:
[Metin: "emma"]
│
▼
┌─────────────┐
│ TOKENIZER │ "e" → 4, "m" → 12, "m" → 12, "a" → 0
└──────┬──────┘
▼
┌──────────────────────────────┐
│ EMBEDDING │
│ Token Emb + Position Emb │
│ [0.12, -0.34, ...] 16-dim │
└──────────────┬───────────────┘
▼
╔══════════════════════════════════╗
║ TRANSFORMER BLOCK (×N) ║
║ ║
║ ┌───────────────────────────┐ ║
║ │ MULTI-HEAD ATTENTION │ ║
║ │ │ ║
║ │ Q·K / √d → Softmax │ ║
║ │ → Weighted Sum V │ ║
║ │ (4 head paralel) │ ║
║ └─────────────┬─────────────┘ ║
║ + (Residual) ║
║ ┌─────────────┴─────────────┐ ║
║ │ MLP BLOCK │ ║
║ │ │ ║
║ │ Linear (16 → 64) │ ║
║ │ ReLU (aktivasyon) │ ║
║ │ Linear (64 → 16) │ ║
║ └─────────────┬─────────────┘ ║
║ + (Residual) ║
╚═════════════════╤════════════════╝
▼
┌──────────────────────────────┐
│ LM HEAD (Linear → Logits) │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ SOFTMAX → Olasılıklar │
│ [a: 0.52, b: 0.03, ...] │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ SAMPLING → Sonraki Token │
│ "a" seçildi (p=0.52) │
└──────────────────────────────┘
microGPT vs Gerçek Modeller
Aradaki fark sadece ölçek. Algoritma birebir aynı. Her kavram microGPT’de de ChatGPT’de de var.
| Özellik | microGPT | GPT-2 Small | GPT-3 | GPT-4 (tahmin) |
|---|---|---|---|---|
| Parametreler | ~5K | 117M | 175B | ~1.8T |
| Katmanlar | 1 | 12 | 96 | ~120 |
| Embedding | 16 | 768 | 12,288 | ~? |
| Head sayısı | 4 | 12 | 96 | ~? |
| Context | 16 | 1,024 | 2,048 | 128K |
| Vocab | 27 | 50,257 | 50,257 | ~100K |
| Eğitim Süresi | ~dakikalar | ~günler | ~aylar | ~aylar |
| Eğitim Maliyeti | $0 | ~$50K | ~$12M | ~$100M+ |
Algoritma aynı. Ölçek farklı. microGPT’deki Autograd = PyTorch Autograd. microGPT’deki Attention = ChatGPT’nin Attention’ı. Aradaki fark GPU, parallelizm, FlashAttention, mixed precision, KV-cache optimizasyonları… hepsi sadece aynı şeyi daha hızlı yapmak için.
Altın İlkeler
Bu kodun öğrettiği temel ilkeler — bunları bilmek, tüm yapay zeka dünyasının kapısını açar.
“Everything else is just efficiency”
Bu koddaki her şey gerçek modellerde birebir var. GPU, parallelizm, FlashAttention, mixed precision… hepsi sadece aynı şeyi daha hızlı yapmak için. Algoritmayı anladıysan, gerisini anlaman çok daha kolay.
Eğitim = Gradyan İnişi Döngüsü
Forward → Loss → Backward → Update. Tüm derin öğrenme bu dört adımdan ibarettir. Her model, her framework, her donanım bu döngüyü çalıştırır.
Attention = Seçici Hafıza
Model, hangi geçmiş bilgiye dikkat edeceğini öğrenir. Q/K/V mekanizması sayesinde “bu token şu tokene benziyor” ilişkilerini keşfeder. Transformer’ın devrimsel yeniliği budur.
Residual = Bilgi Otoyolu
Skip connection’lar, gradyanların onlarca katmandan rahatça akmasını sağlar. Bu basit toplama işlemi olmadan 100+ katmanlı modeller eğitilemezdi.
Temperature = Yaratıcılık Düğmesi
Düşük T = güvenli, tekrarlayan çıktı. Yüksek T = yaratıcı, kaotik çıktı. ChatGPT’de bile aynı parametre var. Dengelenmesi bir sanattır.