Belirttiğiniz yönergeler doğrultusunda, paylaştığınız dokümanın her bir satırını ve konusunu süre bilgilerinden tamamen arındırarak, bol örnekli, uygulamalı ve derinlemesine bir rehber hâline getirdim. Kursun içeriğinde yer alan tüm teorik kavramlar ve pratik aşamalar aşağıda en detaylı şekilde açıklanmıştır.


📚 "Sıfırdan LLM Geliştirme: Kendi Dil Modelini Oluştur" Ders İçeriği Analiz ve Uygulama Rehberi

🎯 "Öğrenecekleriniz" Bölümünün Detaylı Açıklaması

Bu bölüm, kursu tamamladığınızda kazanacağınız temel mühendislik becerilerini ve yetkinlikleri özetler. Yapay zeka dünyasında sadece tüketici (hazır modelleri kullanan biri) olmaktan çıkıp, üretici (mimariyi kuran, eğiten ve optimize eden) konumuna gelmenizi hedefler. Bileşenlerin açıklamaları şu şekildedir:


🏗️ Derslerin Satır Satır Ele Alınması ve Derinlemesine Açıklamaları

📹 Sıfırdan LLM Geliştirme Tanıtım Videosu

Kursun yol haritası, neden sıfırdan model geliştirilmesi gerektiği ve eğitim sonunda elde edilecek çıktılar bu bölümde tanıtılır. Hazır API'lara bağımlı kalmadan yerel imkanlarla model geliştirmenin önemi vurgulanır.

📚 LLM ile İlgili Temel Terminoloji, Önemli Makaleler ve Siteler

Yapay zeka literatürüne giriş adımıdır. Sektörde konuşulan ortak dili anlamak için teorik bir zemin hazırlanır.

📝 Quiz 1

Temel terminoloji, yapay zeka tarihindeki dönüm noktaları ve LLM mimarilerinin genel işleyiş mantığı üzerine bilginizi test eden ilk değerlendirme aşamasıdır.

🛠️ LLM Geliştirme için Gerekli Kurulum ve Araçlar

Kodlama ortamının hazırlanması adımıdır. Büyük modeller yüksek işlem gücü gerektirdiğinden, doğru kütüphanelerin kurulması kritiktir.

·        import torch

·        print("PyTorch Sürümü:", torch.__version__)

·        print("GPU Kullanılabilir mi?:", torch.cuda.is_available())

📝 Quiz 2

Geliştirme ortamı ayarları, sanal ortam (virtual environment) yönetimi ve PyTorch temel tensör operasyonları hakkındaki bilgileri ölçer.

✂️ Sıfırdan Python ile Tokenizer Kodlama

Modeller metinleri doğrudan okuyamaz; onları sayılara bölmek gerekir. Tokenizer, metni bilgisayarın anlayacağı "token" adı verilen parçalara ayıran yapıdır.

·        text = "yapay zeka gelecektir zeka gelecektir"

·        # Benzersiz kelimeleri bulup sözlük (vocab) oluşturma

·        words = sorted(list(set(text.split())))

·        vocab = {word: i for i, word in enumerate(words)}

·        print("Sözlük (Vocab):", vocab)

·         

·        # Metni sayısal ID listesine dönüştürme (Encode)

·        sample = "zeka gelecektir"

·        encoded = [vocab[w] for w in sample.split()]

·        print("Sayısal Karşılığı (Encoded):", encoded)

📝 Quiz 3

Kelimeleri ve karakterleri haritalandırma, sözlük boyutu (vocabulary size) yönetimi ve bilinmeyen kelimeler (UNK token) ile başa çıkma stratejilerini test eder.

🌐 Açık Kaynak Tokenizer’ları Kullanma

Sıfırdan mantığı anladıktan sonra, endüstride dev şirketlerin (OpenAI, Meta) kullandığı gelişmiş ve optimize edilmiş hazır sistemleri entegre etmeyi öğrenirsiniz.

📝 Quiz 4

Hazır kütüphanelerin verimliliği, özel karakterlerin (BOS, EOS gibi özel belirteçler) yönetimi ve tokenizasyon hızlarının karşılaştırılması üzerine sorular içerir.

🧠 Sıfırdan Subword Tokenizer Kodlama

Kelime tabanlı tokenizer'lar yeni kelimelerle karşılaştığında hata verir (Out of Vocabulary). Karakter tabanlılar ise çok yavaştır. İkisinin ortası olan "Subword" (Alt kelime) mantığı bu sorunu çözer.

📝 Quiz 5

Subword algoritmalarının çalışma mantığı, nadir kelimelerin parçalanma biçimleri ve sözlük verimliliği analiz edilir.

🛠️ SentencePiece ile BPE Tokenizer Oluşturma ve Hugging Face’e Yükleme

Google tarafından geliştirilen SentencePiece ve Byte Pair Encoding (BPE) algoritmalarını kullanarak profesyonel düzeyde tokenizer üretimi yapılır.

·        # Gerçek uygulamada Hugging Face Hub kütüphanesi kullanılır

·        from transformers import PreTrainedTokenizerFast

·        # Eğitilen tokenizer kuralları kaydedilir ve paylaşılır

·        print("Tokenizer Hugging Face Hub'a yüklenmeye hazır.")

📏 Context Length ve Veri Seti Hazırlama

Modelin bir seferde okuyabileceği maksimum metin uzunluğuna (Context Length / Bağlam Penceresi) karar verilmesi ve verilerin buna göre dilimlenmesi adımıdır.

📝 Quiz 7

Bağlam uzunluğunun bellek (RAM/VRAM) üzerindeki etkileri, veri sızıntılarını önleme ve kayan pencere (sliding window) veri hazırlama tekniklerini ölçer.

🗂️ PyTorch ile DataLoader Oluşturma

Eğitim sırasında verilerin modele tek tek değil, gruplar halinde (Batch) hızlıca pompalanması gerekir. DataLoader bu akışı yönetir.

·        import torch

·        from torch.utils.data import Dataset, DataLoader

·         

·        class MetinVeriSeti(Dataset):

·            def __init__(self):

·                # Temsili token dizisi

·                self.data = torch.randint(0, 1000, (100, 8)) # 100 örnek, her biri 8 token

·            def __len__(self): return len(self.data)

·            def __getitem__(self, idx): return self.data[idx]

·         

·        dataset = MetinVeriSeti()

·        dataloader = DataLoader(dataset, batch_size=4, shuffle=True)

·        ilk_grup = next(iter(dataloader))

·        print("İlk Batch Şekli (Batch Size, Context Length):", ilk_grup.shape)

📝 Quiz 8

Batch boyutu seçimi, karıştırma (shuffle) mekanizmasının önemi ve DataLoader performans optimizasyonları sorgulanır.

📐 Embedding Katmanları ve Anlam Temsili

Kelimelerin sayısal ID'lerinin, aralarındaki anlamsal ilişkiyi koruyacak şekilde çok boyutlu vektörlere dönüştürüldüğü katmandır.

📝 Quiz 9

Matris çarpımı olarak embedding mantığı, ağırlıkların güncellenmesi ve boyut sayısı (dimension) seçim kriterlerini değerlendirir.

🔄 Sözlük ile Embedding Arasındaki Bağ

Sayısal bir token ID'sinin embedding matrisindeki ilgili satıra nasıl denk geldiği ve bu geri alma (lookup) işleminin matematiksel arka planı işlenir.

📝 Quiz 10

Embedding Lookup operasyonunun hesaplama maliyeti ve ağırlık matrisinin ilk değer ataması (initialization) konularını test eder.

📍 Basit Positional Embedding Uygulaması

Transformer modelleri, metindeki kelimeleri sırayla değil hepsini aynı anda okur (paralel işlem). Bu yüzden kelimelerin cümledeki sıra bilgisini (konumunu) modele eklemek zorundayız.

📝 Quiz 11

Öğrenilebilir (learnable) pozisyon embedding yapısının avantajları, dezavantajları ve uzun metinlerde karşılaşılan sınırlandırmalar ele alınır.

🌊 Sinusoidal Positional Encoding Uygulaması

Öğrenilebilir pozisyon vektörleri yerine, sabit matematiksel formüller (Sinüs ve Kosinüs dalgaları) kullanarak konum bilgisi üretme yöntemidir.

📝 Quiz 12

Farklı frekanslardaki sinüs/kosinüs dalgalarının matris izdüşümleri ve geometrik uzaklık ilişkileri test edilir.

🔄 Rotary Position Encoding (RoPE) Uygulaması

Günümüzdeki modern LLM'lerin (LLaMA, Mistral) kullandığı, kelimelerin birbirine göreceli uzaklıklarını çok daha iyi koruyan gelişmiş bir konumlama tekniğidir.

📝 Quiz 13

Dönme matrisleri, karmaşık sayılarla konum kodlama ve RoPE mimarisinin geleneksel yöntemlerden farkları ölçülür.

🧱 Modelin Temelini Oluşturmak

Oluşturulan tüm bu ön hazırlık bileşenlerinin (Tokenizer, Embedding ve Context Length kısıtlamaları) tek bir çatı altında birleştirilmesidir.

📝 Quiz 14

nn.Module yapısı, girdi-çıktı tensör boyutlarının kontrolü ve mimari iskeletin kurulması üzerine sorular içerir.

🧠 Basit Self-Attention ile Bağlamı Anlamak

Bir kelimenin cümle içerisindeki diğer kelimelerle olan ilişkisini (hangi kelimeye ne kadar dikkat etmesi gerektiğini) hesaplayan, Transformer'ın en önemli mekanizmasıdır.

📝 Quiz 15

Attention matrisinin mantığı, kelimelerin birbirine olan ağırlık payları ve hesaplama karmaşıklığı incelenir.

📐 Manhattan Mesafesiyle Anlamsal Yakınlığı Hesaplamak

İki kelime vektörünün birbirine ne kadar benzediğini ölçmek için kullanılan geometrik bir yöntemdir.

📐 Kosinüs Benzerliğiyle Anlamsal Yakınlığı Hesaplamak

Vektörlerin uzunluklarına bakmaksızın, aralarındaki açıya odaklanarak yapılan anlamsal benzerlik ölçümüdür.

🧮 Attention Skoru Hesaplamak: QKV ve Softmax

Self-Attention mekanizmasının matematiksel motorudur: Query (Soru), Key (Anahtar) ve Value (Değer) matrisleri oluşturulur.

🛠️ Sıfırdan Self-Attention Katmanı Kodlama

Yukarıda anlatılan Q, K, V matris çarpımlarını ve Softmax operasyonlarını hazır hiçbir şey kullanmadan PyTorch doğrusal katmanları (nn.Linear) ile kodlama aşamasıdır.

🔒 Causal Self-Attention ve Dropout Uygulaması

Dil modelleri metin üretirken gelecekteki kelimeleri görmemelidir, sadece geçmişe bakmalıdır. Causal (Nedensel) mekanizma bunu sağlar. Dropout ise ezberlemeyi (overfitting) önler.

🛡️ Masking, Truncation ve Yapısal Hataları Önlemek

Eğitim esnasında verinin yapısından kaynaklanan hataların (örneğin padding tokenlarının model tarafından gerçek kelime gibi algılanması) önüne geçmek için uygulanan maskeleme ve kesme teknikleridir.

📝 Quiz 21

Maskeleme matrislerinin (alt üçgen matris / lower triangular matrix) yapısı ve geleceği görme sızıntılarının nasıl engellendiği sorgulanır.

👥 PyTorch ile Multi-Head Attention Kodlama

Tek bir attention mekanizması yerine, cümlenin farklı yerlerine aynı anda odaklanabilen birden fazla "baş" (Head) yapısının kurulmasıdır.

📝 Quiz 22

Çok başlı dikkat yapısının boyut bölüşümleri, tensörlerin parçalanması (splitting) ve yeniden birleştirilmesi (concatenation) işlemleri test edilir.

⚖️ Layer Normalization Mantığı ve PyTorch ile Uygulaması

Eğitim sırasında sayıların çok büyümesini veya küçülmesini önleyerek eğitimin stabil kalmasını sağlayan istatistiksel düzeltme katmanıdır.

📝 Quiz 23

Batch Normalization ile Layer Normalization arasındaki farklar ve LLM'lerde neden Layer Normalization tercih edildiği sorulur.

⚡ Transformer’da Multi-Layer Perceptron (MLP) ve GeLU Aktivasyonu

Attention katmanından çıkan verilerin, daha derin kalıpları öğrenebilmesi için doğrusal olmayan bir yapay sinir ağı katmanından (MLP) geçirilmesidir.

📝 Quiz 24

GeLU fonksiyonunun matematiksel türevi, gradyan akışına etkisi ve MLP katmanının genişleme katsayıları (expansion factor) analiz edilir.

🧱 MLP ve Residual Bağlantılarla Decoder Bloğu Kurma

Attention katmanı, Layer Norm ve MLP katmanını üst üste koyarak tam bir "Transformer Decoder" hücresi (bloğu) inşa etme adımıdır.

📝 Quiz 25

Artık bağlantıların (residual connections) gradyan patlaması/sönümlenmesini nasıl engellediği ve blokların üst üste eklenme limitleri test edilir.

🔮 LM Head ile Kelime Tahmini Yapmak

Modelin en son katmanıdır. İçerideki karmaşık sayısal vektörleri tekrar bizim sözlüğümüzdeki kelime olasılıklarına dönüştürür.

📝 Quiz 26

Dil modeli kafasının (Language Model Head) ağırlık paylaşımı (weight tying) konsepti ve çıktı boyutu hesaplamaları işlenir.

📊 Logits ve Loss Fonksiyonunu Anlamak

Modelin ürettiği ham tahmin skorlarına "Logits" denir. Loss (Kayıp) fonksiyonu ise modelin ne kadar yanlış tahmin yaptığını ölçer.

📝 Quiz 27

Logit'lerin ham olasılıklara dönüştürülme süreçleri ve Cross-Entropy fonksiyonunun matematiksel tabanı test edilir.

📉 Loss, Optimizer ve Backpropagation’u Anlamak

Modelin yaptığı hatadan ders çıkararak kendi ağırlıklarını (parametrelerini) güncelleme mekanizmasıdır.

📝 Quiz 28

Türev alma zincir kuralı (chain rule), AdamW gibi optimizasyon algoritmalarının çalışma mekanizması sorgulanır.

🔁 Dataset, Tokenizer ve Eğitim Döngüsü Kurmak

Artık tüm parçalar hazırdır. Kendi metin veri setimiz, kendi eğittiğimiz tokenizer ve inşa ettiğimiz Transformer modeli gerçek bir eğitim döngüsüne (for epoch in range...) sokulur.

📝 Quiz 29

Eğitim adımı (step) ile devir (epoch) arasındaki farklar, öğrenme oranı (learning rate) zamanlaması (scheduling) konuları ele alınır.

💾 PyTorch ile Model Kaydetme ve Yükleme (torch.save & load_state_dict)

Saatlerce veya günlerce eğitilen modelin bilgisayara dosya olarak kaydedilmesi ve gerektiğinde kaldığı yerden geri yüklenmesi işlemidir.

·        # Temsili kaydetme adımı

·        model_ornek = torch.nn.Linear(10, 2)

·        torch.save(model_ornek.state_dict(), "model_ağırlıkları.pth")

·        print("Model başarıyla diske kaydedildi.")

·         

·        # Temsili geri yükleme adımı

·        yeni_model = torch.nn.Linear(10, 2)

·        yeni_model.load_state_dict(torch.load("model_ağırlıkları.pth"))

·        print("Model ağırlıkları dosyadan geri yüklendi.")

📝 Quiz 30

Sadece ağırlıkları kaydetmek ile tüm modeli kaydetmek arasındaki farklar ve checkpoint yönetimi test edilir.

📓 Notebook’u Birleştirip Yayına Hazırlamak

Parça parça kodlanan tüm hücrelerin tek bir temiz kod dosyasına (Notebook) toplanması ve baştan sona hatasız çalışacak ilk sürümün (v1 LLM from scratch) oluşturulmasıdır.

📝 Quiz 31

Kod modülaritesi, kod blokları arası veri tipi uyumluluğu ve temiz kod yazım prensipleri ölçülür.

✍️ LLM için Generate Fonksiyonu Yazmak

Eğitilen modelin kullanıcıdan gelen bir kelimeye bakarak kendi kendine yeni cümleler üretmesini (Metin üretimi) sağlayan döngüsel fonksiyondur.

📝 Quiz 32

Ototekrarlı (autoregressive) üretim mantığı ve nesil üretim döngüsündeki bellek verimliliği incelenir.

🖥️ Gradio ile Chatbot Arayüzü Geliştirmek (Bölüm 1 & 2)

Yazdığınız siyah ekran kodunu, herkesin tarayıcıdan girip mesajlaşabileceği modern bir sohbet robotu arayüzüne dönüştürme adımıdır.

📝 Quiz 33 ve Quiz 34

Web arayüz entegrasyonu, eşzamansız (async) istek yönetimi ve kullanıcı oturum senaryoları test edilir.

🚀 CPU'dan GPU'ya Geçiş ve Batch Processing

Modelin bilgisayar işlemcisinden (CPU) alınıp, yapay zekayı yüzlerce kat hızlı çalıştırabilen ekran kartına (GPU) taşınması ve çoklu veri işleme süreçleridir.

📝 Sınav 29

Batch Processing ve Padding: Aynı anda birden fazla soruya cevap verirken kısa kalan cümlelerin sonuna eklenen dolgu (Padding) tokenlarının attention mekanizması tarafından nasıl göz ardı edileceği üzerine pratik sınavdır.

📝 Sınav 30

Batch Processing ve MPS ile Hızlandırmak: Apple silicon işlemcili Mac bilgisayarlarda GPU hızlandırması sağlayan MPS (Metal Performance Shaders) altyapısının PyTorch ile konfigüre edilmesini ölçen sınavdır.

📝 Sınav 35

Temperature, Top-P ve Top-K Nedir?: Modelin ürettiği metinlerin yaratıcılığını ve doğruluğunu kontrol eden hiperparametre teorisidir.

📝 Sınav 31

Temperature, Top-P ve Top-K Kodlama: Softmax işleminden hemen sonra gelen logit değerlerini formüllerle filtreleyen ve en yüksek olasılıklı kelime gruplarını seçen matematiksel filtreleme kodunun PyTorch ile yazılması sınavıdır.

📝 Sınav 32

Top-P (Nucleus) Sampling Nedir?: Kelimeleri en yüksek olasılıktan başlayarak kümülatif (toplam) olasılık değerine göre filtreleyen tekniktir.

📝 Sınav 33

Arayüzü Geliştirip Parametre Kontrolü Eklemek: Gradio arayüzüne kaydırma çubukları (Slider) ekleyerek, kullanıcının sohbet ederken Temperature, Top-K ve Top-P değerlerini canlı olarak değiştirebilmesini sağlayan kodlama sınavıdır.

🎓 Sınav 34

LLM Fine-Tuning ve Dağıtım Eğitimi: Modelin genel yeteneklerini kazandıktan sonra özel bir alanda uzmanlaşması (Fine-Tuning) ve sunucuya kurulması aşamasıdır.


📝 "Açıklama" Paragraflarının Detaylı Çözümlemesi

Paylaştığınız belgenin alt kısımlarında yer alan "Açıklama" paragrafları, kursun genel felsefesini, hedef kitlesini ve nihai vizyonunu ortaya koymaktadır:


 

Müfredatta yer alan tüm ana başlıkları, mantığını en şeffaf şekilde görebilmeniz için hazır kütüphane (Hugging Face vb.) kullanmadan, saf Python ve PyTorch ile çalıştırılabilir kod demoları haline getirdim.

Bu demoları sırasıyla kopyalayıp bir Jupyter Notebook veya Google Colab hücresinde doğrudan çalıştırabilirsiniz.


1. Sıfırdan Python ile Tokenizer Kodlama (Kelimeden ID'ye)

Amaç: Ham metni kelimelerine ayırmak, benzersiz bir sözlük (vocab) kurmak ve metni sayısal verilere (encode) dönüştürüp tekrar geri çözmek (decode).

class BasitTokenizer:

    def __init__(self):

        self.word2id = {}

        self.id2word = {}

        self.unk_token = "<UNK>"

        self.pad_token = "<PAD>"

       

    def sozluk_olustur(self, metinler):

        # Özel belirteçleri ekle

        benzersiz_kelimeler = [self.pad_token, self.unk_token]

       

        # Metindeki tüm kelimeleri temizleyip topla

        for metin in metinler:

            temiz_metin = metin.lower().replace(".", " .").replace(",", " ,")

            for kelime in temiz_metin.split():

                if kelime not in benzersiz_kelimeler:

                    benzersiz_kelimeler.append(kelime)

                   

        # Çift yönlü sözlük haritalama

        self.word2id = {kelime: i for i, kelime in enumerate(benzersiz_kelimeler)}

        self.id2word = {i: kelime for i, kelime in enumerate(benzersiz_kelimeler)}

        print(f"✓ Sözlük başarıyla kuruldu. Toplam Kelime Sayısı: {len(self.word2id)}")

 

    def encode(self, metin):

        temiz_metin = metin.lower().replace(".", " .").replace(",", " ,")

        token_ids = []

        for kelime in temiz_metin.split():

            # Kelime sözlükte yoksa <UNK> ID'sini ver

            token_ids.append(self.word2id.get(kelime, self.word2id[self.unk_token]))

        return token_ids

 

    def decode(self, ids):

        return " ".join([self.id2word.get(i, self.unk_token) for i in ids])

 

# --- UYGULAMA VE TEST ---

egitim_verisi = ["Yapay zeka gelecektir.", "Kendi dil modelini sıfırdan kur."]

tokenizer = BasitTokenizer()

tokenizer.sozluk_olustur(egitim_verisi)

 

# Test Etme

ornek_metin = "Yapay zeka modelini kur."

encoded_ids = tokenizer.encode(ornek_metin)

decoded_metin = tokenizer.decode(encoded_ids)

 

print(f"\nGirdi Metin: '{ornek_metin}'")

print(f"Sayısal ID Karşılığı (Modelin Okuduğu): {encoded_ids}")

print(f"Geri Çözülen Metin (Decode): '{decoded_metin}'")


2. PyTorch ile Dataset ve DataLoader Oluşturma

Amaç: Metin tabanlı sayısal verileri, yapay zekanın eğitim esnasında tüketeceği "Girdi (X)" ve "Hedef/Etiket (Y)" (Next-Token Prediction) çiftleri halinde gruplara (Batch) ayırmak.

import torch

from torch.utils.data import Dataset, DataLoader

 

class YapayZekaVeriSeti(Dataset):

    def __init__(self, token_ids, baglam_uzunlugu):

        self.token_ids = torch.tensor(token_ids, dtype=torch.long)

        self.baglam_uzunlugu = baglam_uzunlugu

 

    def __len__(self):

        # Toplam kaç tane kayan pencere örneği çıkarabileceğimizi hesapla

        return len(self.token_ids) - self.baglam_uzunlugu

 

    def __getitem__(self, idx):

        # X: Mevcut kelimeler, Y: Bir sonraki kelime (X'in bir adım kaymış hali)

        x = self.token_ids[idx : idx + self.baglam_uzunlugu]

        y = self.token_ids[idx + 1 : idx + self.baglam_uzunlugu + 1]

        return x, y

 

# --- UYGULAMA VE TEST ---

# Temsili olarak tokenizer'dan geçmiş 20 adet kelime ID'si düşünelim

yapay_tokenler = [3, 7, 2, 9, 11, 5, 8, 4, 14, 1, 9, 2, 5, 12, 6, 8, 3, 15, 7, 10]

BAGLAM_PENCERESI = 4 # Model tek seferde 4 kelimeye bakarak sonraki kelimeyi tahmin edecek

BATCH_BOYUTU = 2     # Her adımda 2 adet örnek eğitilecek

 

veri_seti = YapayZekaVeriSeti(yapay_tokenler, baglam_uzunlugu=BAGLAM_PENCERESI)

veri_yukleyici = DataLoader(veri_seti, batch_size=BATCH_BOYUTU, shuffle=True)

 

# İlk veri grubunu inceleyelim

ilk_x, ilk_y = next(iter(veri_yukleyici))

print("Girdi Paketi (Batch X):\n", ilk_x)

print("Hedef Paketi (Batch Y - Bir sonraki kelimeler):\n", ilk_y)

print(f"\nTensör Boyutları -> X: {ilk_x.shape}, Y: {ilk_y.shape}")


3. Embedding Katmanı ve Anlam Temsili

Amaç: Kelime ID'lerini rastgele sayılar olmaktan çıkarıp, çok boyutlu uzayda yönü ve büyüklüğü olan anlam vektörlerine dönüştürmek.

import torch

import torch.nn as nn

 

# Varsayalım ki sözlüğümüzde (vocab) toplam 10 kelime var.

SOZLUK_BOYUTU = 10

# Her kelimeyi ifade etmek için 4 boyutlu bir uzay seçtik.

EMBEDDING_BOYUTU = 4

 

# PyTorch Embedding Katmanı Oluşturma

embedding_katmani = nn.Embedding(num_embeddings=SOZLUK_BOYUTU, embedding_dim=EMBEDDING_BOYUTU)

 

# Girdi olarak az önceki DataLoader'dan gelen ilk_x paketini (2 örnek, 4'er kelime) verelim

girdi_tokenleri = torch.tensor([[2, 5, 1, 8],

                                [4, 9, 3, 2]], dtype=torch.long)

 

# Kelimeleri Vektör Uzayına Taşıyalım

vektor_karsiliklari = embedding_katmani(girdi_tokenleri)

 

print("Girdi Boyutu (Batch, Context Length):", girdi_tokenleri.shape)

print("Çıktı Boyutu (Batch, Context Length, Embedding Dim):", vektor_karsiliklari.shape)

print("\nİlk Cümlenin İlk Kelimesinin 4 Boyutlu Anlam Vektörü:\n", vektor_karsiliklari[0, 0])


4. Sinusoidal Positional Encoding (Konum Bilgisi Enjeksiyonu)

Amaç: Modele kelimelerin cümledeki sırasını (0. kelime, 1. kelime vb.) anlatmak için sabit matematiksel dalgalar kullanarak konum matrisi üretmek ve bunu kelime vektörleriyle toplamak.

import torch

import math

 

def konumsal_kodlama_uret(baglam_uzunlugu, embedding_boyutu):

    # Boş bir konum matrisi oluştur

    pe = torch.zeros(baglam_uzunlugu, embedding_boyutu)

   

    # Pozisyon indeksleri (0, 1, 2...)

    pozisyon = torch.arange(0, baglam_uzunlugu, dtype=torch.float).unsqueeze(1)

   

    # Frekans bölenlerini hesapla

    div_term = torch.exp(torch.arange(0, embedding_boyutu, 2).float() * (-math.log(10000.0) / embedding_boyutu))

   

    # Çift indekslere Sinüs, tek indekslere Kosinüs dalgası yerleştir

    pe[:, 0::2] = torch.sin(pozisyon * div_term)

    pe[:, 1::2] = torch.cos(pozisyon * div_term)

   

    return pe

 

# --- UYGULAMA VE TEST ---

KONUM_MATRISI = konumsal_kodlama_uret(baglam_uzunlugu=4, embedding_boyutu=4)

print("Üretilen Sabit Konum Matrisi (Her satır bir pozisyonu temsil eder):\n", KONUM_MATRISI)

 

# Bir önceki adımdaki kelime vektörlerine konum bilgisini ekleyelim (Matris Toplaması)

# Kelime anlamları + Kelime konumları = Tam Temsil

nihai_girdi = vektor_karsiliklari + KONUM_MATRISI.unsqueeze(0) # Batch boyutuna uyumlu hale getirdik

print("\nHem Anlam Hem Konum İçeren Yeni Vektör Boyutu:", nihai_girdi.shape)


5. Sıfırdan Causal Self-Attention Katmanı Kodlama

Amaç: Kelimelerin birbirleriyle olan bağlarını hesaplamak ve metin üretirken gelecekteki kelimeleri görmesini engellemek (Masking).

import torch

import torch.nn as nn

import torch.nn.functional as F

 

class NedenselDikkatKatmani(nn.Module):

    def __init__(self, d_model):

        super().__init__()

        # Query, Key ve Value matris dönüşümleri için doğrusal katmanlar

        self.query = nn.Linear(d_model, d_model)

        self.key = nn.Linear(d_model, d_model)

        self.value = nn.Linear(d_model, d_model)

 

    def forward(self, x):

        B, T, C = x.shape # Batch, Time (Context), Channels (Embedding Dim)

       

        # Q, K, V matrislerini üretelim

        q = self.query(x)

        k = self.key(x)

        v = self.value(x)

       

        # Kelimelerin birbiriyle eşleşme skorlarını bul (Enerji Matrisi)

        # Sorumuz (Q) ile Anahtarları (K) çarpıyoruz

        skorlar = torch.bmm(q, k.transpose(1, 2)) / (C ** 0.5) # Ölçeklendirilmiş çarpım

       

        # CAUSAL MASKING (Geleceği Gizleme): Üst üçgeni eksi sonsuz yap

        maske = torch.tril(torch.ones(T, T)).view(1, T, T)

        skorlar = skorlar.masked_fill(maske == 0, float('-inf'))

       

        # Olasılıklara dönüştür (Satır toplamları 1 olacak şekilde)

        dikkat_haritasi = F.softmax(skorlar, dim=-1)

       

        # Ağırlıklarla değerleri (V) çarpıp bağlamsal çıktı üret

        cikti = torch.bmm(dikkat_haritasi, v)

        return cikti, dikkat_haritasi

 

# --- UYGULAMA VE TEST ---

dikkat_motoru = NedenselDikkatKatmani(d_model=4)

katman_cikti, harita = dikkat_motoru(nihai_girdi)

 

print("Maskelenmiş Dikkat Ağırlık Matrisi (İlk Örnek):\n", harita[0])

print("\nDikkat Sonrası Yeni Vektör Boyutu (Giriş ile Aynı Kalmalı):", katman_cikti.shape)

# Dikkat ederseniz matrisin sağ üst köşesi tamamen 0.0 oldu.

# Yani 1. kelime üretilirken 2, 3 ve 4. kelimelere bakması tamamen engellendi!


6. MLP (Feed Forward) ve GeLU Aktivasyon Fonksiyonu

Amaç: Attention katmanından gelen verileri doğrusal olmayan (GeLU) bir süzgeçten geçirerek daha üst düzey semantic (anlamsal) çıkarımlar yapmasını sağlamak.

class TransformerMLP(nn.Module):

    def __init__(self, d_model):

        super().__init__()

        # Genişleme katmanı (Genelde mimari boyutun 4 katına genişletilir)

        self.fc1 = nn.Linear(d_model, d_model * 4)

        # Daraltma katmanı (Eski orijinal boyuta geri getirir)

        self.fc2 = nn.Linear(d_model * 4, d_model)

       

    def forward(self, x):

        # Genişlet -> GeLU Aktivasyonundan Geçir -> Tekrar Daralt

        x = self.fc1(x)

        x = F.gelu(x)

        x = self.fc2(x)

        return x

 

# --- UYGULAMA VE TEST ---

mlp_katmani = TransformerMLP(d_model=4)

mlp_cikti = mlp_katmani(katman_cikti)

print("MLP İşleminden Geçen Tensörün Son Hali:", mlp_cikti.shape)


7. Model Kaydetme ve Yükleme Mantığı (state_dict)

Amaç: Tasarlanan sinir ağının eğitildikten sonra disk üzerine kaydedilmesi ve ardından sıfır bir nesneye enjekte edilerek canlandırılması.

# Temsili bir katman oluşturalım ve içindeki eğitilebilir rastgele ağırlıklara bakalım

orijinal_katman = nn.Linear(2, 2)

print("Orijinal Katmanın Ağırlık Matrisi:\n", orijinal_katman.weight.data)

 

# Ağırlıkları Bilgisayara Bir Dosya Olarak Kaydedelim

torch.save(orijinal_katman.state_dict(), "gecici_model.pth")

print("\n✓ Ağırlıklar 'gecici_model.pth' adıyla diske yazıldı.")

 

# Şimdi tamamen sıfır ve içi farklı sayılarla dolu yeni bir katman oluşturalım

yeni_katman = nn.Linear(2, 2)

print("\nYükleme Yapılmadan Önce Yeni Katmanın Rastgele Ağırlığı:\n", yeni_katman.weight.data)

 

# Diskteki dosyayı okuyup yeni katmanın içine enjekte edelim

yeni_katman.load_state_dict(torch.load("gecici_model.pth"))

print("\nYükleme Yapıldıktan Sonra Yeni Katmanın Ağırlığı (Orijinal ile Aynı Oldu!):\n", yeni_katman.weight.data)


8. Metin Üretim Algoritması (Temperature Süzgeci ve Multinomial Örnekleme)

Amaç: Modelin ürettiği kelime skorlarını (Logits) çeşitlendirmek. Temperature parametresi ile modelin yaratıcılığını artırıp azaltmak ve rastgele kelime seçimi yapmak.

def sonraki_tokeni_sec(logits, temperature=1.0):

    # Logit değerlerini sıcaklık parametresine bölüyoruz

    # Sıcaklık 0'a yaklaştıkça en yüksek puanlı kelime kesinleşir (Daha az yaratıcı)

    # Sıcaklık büyüdükçe olasılıklar birbirine yaklaşır (Daha çılgın/yaratıcı)

    logits = logits / temperature

   

    # Skorları Softmax ile %0 ile %100 arasında ihtimallere dönüştür

    olasiliklar = F.softmax(logits, dim=-1)

   

    # Multinomial (Çoklu terimli) örnekleme yaparak torbadan bilye çeker gibi kelime ID'si seç

    secilen_id = torch.multinomial(olasiliklar, num_samples=1)

    return secilen_id, olasiliklar

 

# --- UYGULAMA VE TEST ---

# Sözlüğümüzde 5 kelime olduğunu ve modelin bu kelimeler için ürettiği tahmin skorlarını düşünelim

ornek_logits = torch.tensor([2.0, 4.5, 1.0, -0.5, 3.0])

 

print("--- YÜKSEK SICAKLIK (Temperature = 1.5) | Daha Riskli/Çeşitli ---")

secim, ihtimaller = sonraki_tokeni_sec(ornek_logits, temperature=1.5)

print("Kelimelerin Seçilme İhtimalleri (%):", (ihtimaller * 100).tolist())

print("Seçilen Kelime ID'si:", secim.item())

 

print("\n--- DÜŞÜK SICAKLIK (Temperature = 0.2) | Daha Güvenli/Deterministik ---")

secim, ihtimaller = sonraki_tokeni_sec(ornek_logits, temperature=0.2)

print("Kelimelerin Seçilme İhtimalleri (%):", (ihtimaller * 100).tolist())

print("Seçilen Kelime ID'si:", secim.item())

# Dikkat ederseniz sıcaklık düştüğünde 2. indeksteki kelimenin şansı neredeyse %99'a fırladı!



İşte yukarıda parça parça kodladığımız tüm yapı taşlarını (Tokenizer, Embedding, Positional Encoding, Causal Self-Attention, MLP ve Üretim Algoritması) tek bir çatı altında toplayan, saf PyTorch ile yazılmış, gerçekten eğitebileceğiniz ve cümle tamamlatabileceğiniz mini bir GPT modeli.

Bu kod bloğunun tamamını kopyalayıp tek bir hücrede çalıştırabilirsiniz. Kodun içinde küçük bir metin veri seti oluşturulmuş ve modelin bu veriyi nasıl ezberleyip yeni cümleler ürettiği adım adım simüle edilmiştir.

import torch

import torch.nn as nn

import torch.nn.functional as F

import math

 

# ==========================================

# 1. HAZIRLIK: VERİ SETİ VE BASİT TOKENIZER

# ==========================================

 

# Modelin eğitileceği küçük metin kümesi

ham_veri = """

yapay zeka gelecektir. kendi dil modelini sıfırdan kur.

yapay zeka insanlığa yardım eder. kendi modelini eğit ve çalıştır.

sıfırdan gpt mimarisi kurmak çok eğlencelidir.

"""

 

class KarakterTokenizer:

    """Karakter tabanlı basit bir tokenizer (Eğitim kolaylığı için)"""

    def __init__(self, metin):

        self.chars = sorted(list(set(metin)))

        self.vocab_size = len(self.chars)

        self.char2id = {ch: i for i, ch in enumerate(self.chars)}

        self.id2char = {i: ch for i, ch in enumerate(self.chars)}

       

    def encode(self, s): return [self.char2id[c] for c in s]

    def decode(self, l): return ''.join([self.id2char[i] for i in l])

 

tokenizer = KarakterTokenizer(ham_veri)

veri_sayisal = tokenizer.encode(ham_veri)

 

# ==========================================

# 2. MODEL BİLEŞENLERİ (TRANSFORMER MOTORU)

# ==========================================

 

class NedenselDikkat(nn.Module):

    """Causal Self-Attention Katmanı"""

    def __init__(self, d_model):

        super().__init__()

        self.query = nn.Linear(d_model, d_model)

        self.key = nn.Linear(d_model, d_model)

        self.value = nn.Linear(d_model, d_model)

        self.d_model = d_model

 

    def forward(self, x):

        B, T, C = x.shape

        q = self.query(x)

        k = self.key(x)

        v = self.value(x)

       

        # Dikkat skorlarını hesapla

        skorlar = torch.bmm(q, k.transpose(1, 2)) / (C ** 0.5)

       

        # Maskeleme (Geleceği gizleme)

        maske = torch.tril(torch.ones(T, T, device=x.device)).view(1, T, T)

        skorlar = skorlar.masked_fill(maske == 0, float('-inf'))

       

        dikkat_haritasi = F.softmax(skorlar, dim=-1)

        return torch.bmm(dikkat_haritasi, v)

 

class BasitMLP(nn.Module):

    """Feed Forward Network ve GeLU Aktivasyonu"""

    def __init__(self, d_model):

        super().__init__()

        self.fc1 = nn.Linear(d_model, d_model * 4)

        self.fc2 = nn.Linear(d_model * 4, d_model)

       

    def forward(self, x):

        return self.fc2(F.gelu(self.fc1(x)))

 

class TransformerBloku(nn.Module):

    """Geleneksel bir GPT Bloğu (Attention + MLP + Residual + LayerNorm)"""

    def __init__(self, d_model):

        super().__init__()

        self.ln1 = nn.LayerNorm(d_model)

        self.ln2 = nn.LayerNorm(d_model)

        self.attention = NedenselDikkat(d_model)

        self.mlp = BasitMLP(d_model)

 

    def forward(self, x):

        # Önce Normalizasyon -> Sonra Attention -> Başlangıç girdisi ile topla (Residual)

        x = x + self.attention(self.ln1(x))

        # Önce Normalizasyon -> Sonra MLP -> Tekrar topla

        x = x + self.mlp(self.ln2(x))

        return x

 

# ==========================================

# 3. ANA MODEL: MİNİ GPT MİMARİSİ

# ==========================================

 

class MiniGPT(nn.Module):

    def __init__(self, vocab_size, d_model, context_length):

        super().__init__()

        self.context_length = context_length

        # Kelime (Karakter) anlam haritası

        self.token_embedding = nn.Embedding(vocab_size, d_model)

        # Pozisyon (Konum) anlam haritası (Öğrenilebilir pozisyon seçtik)

        self.position_embedding = nn.Embedding(context_length, d_model)

       

        # Üst üste binen 3 adet güçlü deşifre edici blok

        self.bloklar = nn.Sequential(

            TransformerBloku(d_model),

            TransformerBloku(d_model),

            TransformerBloku(d_model)

        )

       

        self.ln_final = nn.LayerNorm(d_model)

        self.lm_head = nn.Linear(d_model, vocab_size) # Vektörleri tekrar harflere dönüştüren kafa

 

    def forward(self, idx, targets=None):

        B, T = idx.shape

       

        # Girişleri hazırla

        tok_emb = self.token_embedding(idx)

        pos_emb = self.position_embedding(torch.arange(T, device=idx.device))

        x = tok_emb + pos_emb # Anlam ve konum toplandı

       

        # Transformer katmanlarından geçir

        x = self.bloklar(x)

        x = self.ln_final(x)

        logits = self.lm_head(x) # Tahmin skorları (Logits)

       

        # Eğer eğitim yapılıyorsa Loss (Hata) hesapla

        loss = None

        if targets is not None:

            B, T, C = logits.shape

            logits_duz = logits.view(B*T, C)

            targets_duz = targets.view(B*T)

            loss = F.cross_entropy(logits_duz, targets_duz)

           

        return logits, loss

 

    def generate(self, idx, max_new_tokens, temperature=1.0):

        """Modelin ototegrarlı olarak metin üretmesini sağlayan fonksiyon"""

        for _ in range(max_new_tokens):

            # Bağlam penceresinden uzun girdileri kırp

            idx_cond = idx[:, -self.context_length:]

            logits, _ = self(idx_cond)

            # Sadece cümlenin en son üretilen harfinin tahminlerine odaklan

            logits = logits[:, -1, :] / temperature

            probs = F.softmax(logits, dim=-1)

            # Sonraki karakteri seç ve mevcut metne ekle

            idx_next = torch.multinomial(probs, num_samples=1)

            idx = torch.cat((idx, idx_next), dim=1)

        return idx

 

# ==========================================

# 4. HİPERPARAMETRELER VE EĞİTİM DÖNGÜSÜ

# ==========================================

 

# Cihaz seçimi (GPU varsa kullanılır, yoksa CPU)

cihaz = "cuda" if torch.cuda.is_available() else "cpu"

 

CONTEXT_LENGTH = 16 # Model tek seferde geriye dönük en fazla 16 karaktere bakabilir

D_MODEL = 64        # Her bir karakterin ifade edildiği vektör boyutu

 

model = MiniGPT(vocab_size=tokenizer.vocab_size, d_model=D_MODEL, context_length=CONTEXT_LENGTH).to(cihaz)

optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)

 

print("🚀 Mini GPT Modeli Eğitiliyor (Lütfen Bekleyin)...")

model.train()

 

# 1000 adımlık hızlı bir eğitim döngüsü

for adim in range(1000):

    # Rastgele bir kayan pencere seçerek Batch oluşturma

    idx = torch.randint(0, len(veri_sayisal) - CONTEXT_LENGTH, (32,))

    x = torch.stack([torch.tensor(veri_sayisal[i:i+CONTEXT_LENGTH]) for i in idx]).to(cihaz)

    y = torch.stack([torch.tensor(veri_sayisal[i+1:i+CONTEXT_LENGTH+1]) for i in idx]).to(cihaz)

   

    # İleri Besleme ve Hata Hesaplama

    logits, loss = model(x, y)

   

    # Geriye Yayılım (Backpropagation) ve Güncelleme

    optimizer.zero_grad()

    loss.backward()

    optimizer.step()

   

    if adim % 200 == 0:

        print(f"Adım {adim:4d} | Güncel Hata (Loss): {loss.item():.4f}")

 

print("✓ Eğitim tamamlandı. Hata başarıyla düşürüldü.\n")

 

# ==========================================

# 5. TEST VE METİN ÜRETİMİ (GENERATE)

# ==========================================

 

model.eval()

baslangic_metni = "yapay zeka "

print(f"🤖 Model Başlangıç İpucunu Alıyor: '{baslangic_metni}'")

 

# Metni sayısal verilere dönüştür ve Batch boyutunu (1) ekle

girdi_tensör = torch.tensor([tokenizer.encode(baslangic_metni)], dtype=torch.long, device=cihaz)

 

# Modelden 60 karakterlik bir devam metni üretmesini isteyelim

uretilen_id_listesi = model.generate(girdi_tensör, max_new_tokens=60, temperature=0.7)

nihai_metin = tokenizer.decode(uretilen_id_listesi[0].tolist())

 

print(f"\n✨ Modelin Tamamladığı Cümle:\n{nihai_metin}")

💡 Kod Çalıştığında Ne Oluyor?

  1. Veriyi Öğreniyor: Model, verdiğimiz ham metindeki harflerin peş peşe gelme sıralarını ve nedensel ilişkilerini Attention katmanları sayesinde hafızasına kazıyor.
  2. Hata Oranı Düşüyor: Başlangıçta yüksek olan Loss değeri, adımlar ilerledikçe (0'dan 1000'e doğru) hızla azalıyor. Bu, modelin artık rastgele sallamadığını, kalıpları ezberlemeye başladığını gösterir.
  3. Yeni Metin Doğuruyor: Eğitim bittiğinde verdiğimiz "yapay zeka " ipucunu alarak, veri setindeki mantığa uygun şekilde kelimeleri kendi kendine yan yana dizip anlamlı bir şekilde cümleyi tamamlıyor.

 

Sağladığınız belgeyi satır satır ve bölüm bölüm ele alarak, hiçbir konuyu atlamadan, özetlemeden, süre bilgilerini tamamen kaldırarak ve her kavramı günlük hayattan benzetmelerle detaylandırarak açıklıyoruz. Bu uzun ve teknik eğitim içeriğini 4. sınıf düzeyinde, herkesin anlayabileceği çok basit bir dille maddeler halinde işleyeceğiz.


BÖLÜM 1: Giriş ve "Öğrenecekleriniz" Paragrafının Detaylı Açıklaması

Bu kursta büyük dil modellerinin (yani bilgisayarların bizim gibi konuşmasını sağlayan sistemlerin) içini açıp her bir parçanın nasıl çalıştığını öğreneceksiniz. Kursun "Öğrenecekleriniz" kısmında yer alan tüm terimlerin ne anlama geldiği aşağıda detaylıca açıklanmıştır:


BÖLÜM 2: Kurs Müfredatının Satır Satır Detaylı İncelenmesi

Müfredatta yer alan tüm ders başlıklarını ve uygulamaları sırasıyla ele alıyoruz:

Başlangıç ve Ön Gereksinimler

Kelimeleri Sayılara Dönüştürme (Tokenization ve Embeddings)

Kelime Anlam Haritaları (Word Embeddings)

Büyük Dil Modellerini İnşa Etme Dönemi

Yapay Zekayı Eğitme ve Optimizasyon

İnce Ayar (Fine-Tuning) ve Özelleştirme

Komut Eğitimi (Instruction Tuning) ve Chatbot Yapımı

Yapay Zeka Modellerini Sınava Sokmak (Değerlendirme - Evaluation)

Yapay Zekanın İçini Açıp İncelemek (Mechanistic Interpretability)

Müdahale Ederek Yapay Zekayı Değiştirme (Causal Mech Interp)

Matematik ve Python Temelleri (Kursun Sonundaki Destek Bölümleri)

Kursun en sonunda, yukarıdaki ağır konuları yapabilmeniz için gereken tüm temel dersler sıfırdan anlatılmaktadır:


BÖLÜM 3: "Açıklama:" Paragraflarının Detaylı İncelemesi

Belgenin alt kısmındaki tanıtım ve açıklama yazılarının içerdiği mesajlar ve detaylar şunlardır:


 

 

Büyük Dil Modelleri (LLM) mimarisinin, eğitim optimizasyonunun ve Mekanik Anlaşılabilirlik (Mechanistic Interpretability) dünyasının kalbinde yer alan en kritik matematiksel formülleri ve bunların sıfırdan Python / PyTorch kodlarını içeren devasa bir teknik rehberi aşağıda bulabilirsiniz.

Her konu; Matematiksel Mantık, Temiz ve Çalıştırılabilir PyTorch Kodu ve 4. Sınıf Seviyesinde Basit Benzetme adımlarıyla ele alınmıştır.


1. KISIM: LLM MİMARİSİ VE ÇEKİRDEK MATEMATİK

1.1. Öz-Dikkat (Self-Attention) Mekanizması

Matematiksel Formül

Giriş matrisi dizisi X olduğunda; Sorgu (Q), Anahtar (K) ve Değer (V) matrisleri doğrusal projeksiyonlarla elde edilir. Dikkat katsayıları, Q ve K'nın nokta çarpımı alınıp, anahtar boyutunun kareköküne ($\sqrt{d_k}$) bölünerek ölçeklenir. Ardından satır bazında Softmax uygulanarak ağırlıklar bulunur:

$$Q = XW_Q, \quad K = XW_K, \quad V = XW_V$$

$$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$

PyTorch Kodu

import torch

import torch.nn as nn

import torch.nn.functional as F

 

class SingleHeadAttention(nn.Module):

    def __init__(self, d_model, d_k):

        super().__init__()

        self.d_k = d_k

        # Doğrusal dönüşüm vidaları (Ağırlık matrisleri)

        self.W_q = nn.Linear(d_model, d_k, bias=False)

        self.W_k = nn.Linear(d_model, d_k, bias=False)

        self.W_v = nn.Linear(d_model, d_k, bias=False)

       

    def forward(self, x):

        # x: [Batch Size, Sequence Length, d_model]

        Q = self.W_q(x) # [B, S, d_k]

        K = self.W_k(x) # [B, S, d_k]

        V = self.W_v(x) # [B, S, d_k]

       

        # Kolay anlaşılması için adım adım çarpım: Q * K^T

        # scores boyutu: [B, S, S] olur. Her kelimenin diğer her kelimeyle bağı.

        scores = torch.bmm(Q, K.transpose(1, 2)) / (self.d_k ** 0.5)

       

        # Olasılık dağılımına çevir (Satır toplamları 1 olur)

        attention_weights = F.softmax(scores, dim=-1)

       

        # Değer matrisi (V) ile ağırlıkları çarparak yeni anlamı üret

        output = torch.bmm(attention_weights, V) # [B, S, d_k]

        return output, attention_weights

 

# Deneme Uygulaması:

x_deneme = torch.randn(1, 4, 16) # 1 cümle, 4 kelime, her kelime 16 sayılık vektör

dikkat_katmani = SingleHeadAttention(d_model=16, d_k=8)

cikti, agirliklar = dikkat_katmani(x_deneme)

print("Dikkat Çıktı Boyutu:", cikti.shape)

Basit Benzetme

Kütüphane Örneği: Masanızda 4 farklı ders kitabı var (X). Aradığınız bir bilgiye (Q) en uygun başlığı (K) bulmak için kitapların kapaklarına bakarsınız. En yüksek puanı alan kitaptan (V) bilgiyi okuyup kafanıza yazarsınız.


1.2. Nedensel Maskeleme (Causal Masking)

Matematiksel Formül

Üretken modeller (GPT gibi) gelecekteki kelimeleri göremez. Bu yüzden dikkat matrisinde geleceğe denk gelen sağ üst üçgen bölgedeki değerler Softmax öncesinde eksi sonsuza (-∞) yuvarlanır. Böylece softmax(-∞) = 0 olur ve gelecek kelimelerin etkisi sıfırlanır.

$$M_{ij} = \begin{cases} 0 & \text{eğer } i \ge j \\ -\infty & \text{eğer } i < j \end{cases}$$

$$\text{MaskedAttention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + M\right)V$$

PyTorch Kodu

def causal_masking_demo(Q, K):

    # Q ve K matrislerinin boyutu: [1, 4, 8] olsun (4 kelime)

    scores = torch.matmul(Q, K.transpose(-2, -1)) # [1, 4, 4]

   

    seq_len = scores.size(-1)

    # Üst üçgeni 1, alt üçgen ve köşegeni 0 yapan maske matrisi

    mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()

   

    # Maskelenen yerleri çok küçük bir sayı (-inf) ile doldur

    scores = scores.masked_fill(mask, float('-inf'))

   

    # Softmax uygulandığında -inf olan yerler tam 0 olacaktır

    attention_weights = F.softmax(scores, dim=-1)

    return attention_weights

 

# Deneme:

q_test = torch.randn(1, 4, 8)

k_test = torch.randn(1, 4, 8)

print("Maskelenmiş Dikkat Matrisi:\n", causal_masking_demo(q_test, k_test))

Basit Benzetme

Kitap Okuma Örneği: Bir kitabı okurken sağ sayfanın üzerine elinizi koyup kapatmak gibidir. Gözünüz sadece o an okuduğunuz kelimeye ve arkasında kalan geçmiş kelimelere bakabilir.


1.3. Katman Normalizasyonu (Layer Normalization)

Matematiksel Formül

Verilen bir x girdisinin ortalaması (μ) ve varyansı (σ²) her katman için bağımsızca hesaplanır. Sayılar normalize edildikten sonra, modelin öğrenilebilir parametreleri olan γ (ölçekleme) ve β (kaydırma) ile yeniden şekillendirilir. ε sayısı ise sıfıra bölünme hatasını engeller.

$$\mu = \frac{1}{d} \sum_{i=1}^{d} x_i, \quad \sigma^2 = \frac{1}{d} \sum_{i=1}^{d} (x_i - \mu)^2$$

$$\hat{x}_i = \frac{x_i - \mu}{\sqrt{\sigma^2 + \epsilon}}$$

$$y_i = \gamma \hat{x}_i + \beta$$

PyTorch Kodu

class CustomLayerNorm(nn.Module):

    def __init__(self, features, eps=1e-5):

        super().__init__()

        # Öğrenilebilir terazi parametreleri

        self.gamma = nn.Parameter(torch.ones(features))

        self.beta = nn.Parameter(torch.zeros(features))

        self.eps = eps

 

    def forward(self, x):

        # x boyutu: [Batch, Seq_Len, Features]

        # Son boyut (Features) boyunca ortalama al

        mean = x.mean(-1, keepdim=True)

        # Son boyut boyunca varyans al

        var = x.var(-1, keepdim=True, unbiased=False)

       

        # Matematiksel standartlaştırma

        x_hat = (x - mean) / torch.sqrt(var + self.eps)

       

        # Ölçekle ve kaydır

        return self.gamma * x_hat + self.beta

 

# Deneme:

ln_katmani = CustomLayerNorm(features=16)

x_gurultulu = torch.randn(1, 2, 16) * 10 + 5 # Büyük sayılardan oluşan girdi

print("Normalizasyon Sonrası Çıktı Kontrolü (Ortalama ~0 olmalı):\n", ln_katmani(x_gurultulu).mean().item())

Basit Benzetme

Sınıf Notları Örneği: Bir öğretmen sınav yapıyor. Sınıfın ortalaması çok yüksek veya çok düşük çıktığında, tüm notları ortak bir standarda getirip (çan eğrisi gibi) adil bir şekilde dağıtmak gibidir.


1.4. Yumuşak Maksimum ve Sıcaklık Ayarı (Softmax & Temperature)

Matematiksel Formül

Modelin ürettiği ham puanları ($z_i$ - logits) kelime seçme olasılıklarına dönüştürür. Formüle eklenen T (Sıcaklık) parametresi 1'den küçükse en yüksek olasılıklı kelimeyi aşırı öne çıkarır (model ciddi ve robotik olur), 1'den büyükse tüm kelimelerin şansını birbirine yaklaştırır (model yaratıcı veya saçmalayan bir yapıya bürünür).

$$P(x_i) = \frac{\exp(z_i / T)}{\sum_{j} \exp(z_j / T)}$$

PyTorch Kodu

def softmax_with_temperature(logits, temperature=1.0):

    # Sıfıra bölünme hatasını engellemek için kontrol

    if temperature == 0:

        temperature = 1e-7

    # Logit değerlerini sıcaklığa böl

    scaled_logits = logits / temperature

    # Olasılıkları hesapla

    probs = F.softmax(scaled_logits, dim=-1)

    return probs

 

# Deneme:

ham_puanlar = torch.tensor([2.0, 1.0, 0.5])

print("Düşük Sıcaklık (T=0.2) - Net/Ciddi:", softmax_with_temperature(ham_puanlar, temperature=0.2))

print("Yüksek Sıcaklık (T=2.0) - Dağınık/Yaratıcı:", softmax_with_temperature(ham_puanlar, temperature=2.0))

Basit Benzetme

Dondurma Seçimi Örneği: Önünüzde Çikolatalı, Çilekli ve Limonlu dondurmalar var. Sıcaklık çok düşükse (T → 0) her zaman kesinlikle en sevdiğiniz çikolatayı seçersiniz. Sıcaklık çok yüksekse (T → 2) gözünüzü kapatıp hiç denemediğiniz limonluyu seçme şansınız artar.


2. KISIM: EĞİTİM, KAYIP FONKSİYONLARI VE OPTİMİZASYON

2.1. Çapraz Entropi Kayıp Fonksiyonu (Cross-Entropy Loss)

Matematiksel Formül

Yapay zekanın tahmin ettiği olasılık dağılımı (P) ile olması gereken gerçek hedef (One-hot vektör Y) arasındaki farkı ölçer. Yapay zeka doğru kelimeye ne kadar düşük olasılık verdiyse, yiyeceği ceza (kayıp puanı) logaritmik olarak o kadar büyür.

$$\mathcal{L}_{CE} = - \sum_{i} Y_i \log(P_i)$$

PyTorch Kodu

class CustomCrossEntropy(nn.Module):

    def __init__(self):

        super().__init__()

 

    def forward(self, logits, targets):

        # logits: [Batch, Classes], targets: [Batch] (Doğru sınıfların indeksleri)

        # Adım 1: Log-Softmax hesapla (Sayısal kararlılık için)

        max_logits = torch.max(logits, dim=-1, keepdim=True)[0]

        stabilized_logits = logits - max_logits

        log_sum_exp = torch.log(torch.sum(torch.exp(stabilized_logits), dim=-1, keepdim=True))

        log_probs = stabilized_logits - log_sum_exp

       

        # Adım 2: Sadece doğru olan hedef sınıfların ceza puanlarını topla

        batch_indices = torch.arange(logits.size(0))

        loss = -log_probs[batch_indices, targets]

       

        # Ortalama kaybı dön

        return loss.mean()

 

# Deneme:

ceza_olcer = CustomCrossEntropy()

tahmin_logits = torch.tensor([[1.5, 4.0, 0.1]]) # Model 2. sıradaki kelimeye (indeks 1) güveniyor

gercek_hedef = torch.tensor([1]) # Gerçekten de doğru cevap indeks 1'miş.

print("Hesaplanan Kayıp Puanı (Düşük çıkmalı):", ceza_olcer(tahmin_logits, gercek_hedef).item())

Basit Benzetme

Okul Sınavı Örneği: Öğrenci test sınavında doğru şıkka "%90 eminim" derse az ceza alır, ama doğru şıkka "%5 şans" verip yanılırsa öğretmeninden büyük bir hata puanı alır.


2.2. AdamW İyileştiricisi (Weight Decay Özellikli Adam)

Matematiksel Formül

Gradiyenlerin birinci momentini ($m_t$ - momentum/hız) ve ikinci momentini ($v_t$ - dalgalanma gücü) hesaplar. AdamW'nin normal Adam'dan farkı, ağırlık azaltma (L₂ regülasyonu) işlemini doğrudan ağırlık güncelleme aşamasında uygulamasıdır.

$$m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t, \quad v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2$$

$$\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}$$

$$\theta_t = \theta_{t-1} - \eta \left( \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} + \lambda \theta_{t-1} \right)$$

PyTorch Kodu

def adamw_step(param, grad, m, v, t, lr=0.001, beta1=0.9, beta2=0.999, weight_decay=0.01, eps=1e-8):

    # Birinci moment (Hız birikmesi)

    m = beta1 * m + (1 - beta1) * grad

    # İkinci moment (Değişkenlik ölçümü)

    v = beta2 * v + (1 - beta2) * (grad ** 2)

   

    # Zaman düzeltme katsayıları

    m_hat = m / (1 - beta1 ** t)

    v_hat = v / (1 - beta2 ** t)

   

    # Güncelleme adımı + Ağırlıkların aşırı büyümesini engelleyen Weight Decay (\lambda * \theta)

    param_updated = param - lr * (m_hat / (torch.sqrt(v_hat) + eps) + weight_decay * param)

   

    return param_updated, m, v

 

# Deneme Parametreleri:

w = torch.tensor([1.0])

g = torch.tensor([0.1])

m_t, v_t = torch.tensor([0.0]), torch.tensor([0.0])

w, m_t, v_t = adamw_step(w, g, m_t, v_t, t=1)

print("Güncellenmiş Ağırlık Değeri:", w.item())

Basit Benzetme

Bisiklet Sürme Örneği: Yokuş aşağı bisiklet sürerken hem eski hızınızı korursunuz ($m_t$), hem de yolun taşlı olup olmadığına bakıp freni ayarlarsınız ($v_t$). Ayrıca çantanızdaki gereksiz ağırlıkları yolda düşürerek hafiflersiniz (λ).


3. KISIM: MEKANİK ANLAŞILABİLİRLİK (MECHANISTIC INTERPRETABILITY) VE PROBING

3.1. Kosinüs Benzerliği (Cosine Similarity)

Matematiksel Formül

İki kelime vektörünün yönsel olarak birbirine ne kadar paralel olduğunu ölçer. Değer 1 çıkarsa kelimeler aynı doğrultudadır, 0 çıkarsa tamamen bağımsızdır, -1 çıkarsa zıt kutuplardadır.

$$\text{Cosine Similarity}(A, B) = \frac{A \cdot B}{\Vert{}A\Vert{} \Vert{}B\Vert{}} = \frac{\sum_{i} A_i B_i}{\sqrt{\sum_{i} A_i^2} \sqrt{\sum_{i} B_i^2}}$$

PyTorch Kodu

def custom_cosine_similarity(A, B):

    # A ve B: [Vector Dimension] şeklinde iki tekil kelime vektörü

    dot_product = torch.dot(A, B)

    norm_A = torch.sqrt(torch.sum(A ** 2))

    norm_B = torch.sqrt(torch.sum(B ** 2))

   

    # Sıfıra bölünme kontrolü

    if norm_A == 0 or norm_B == 0:

        return torch.tensor(0.0)

       

    return dot_product / (norm_A * norm_B)

 

# Deneme Uygulaması:

kral_vektor = torch.tensor([0.9, 0.1, 0.0])

kralice_vektor = torch.tensor([0.8, 0.2, 0.1])

araba_vektor = torch.tensor([0.0, 0.0, 0.9])

 

print("Kral - Kraliçe Benzerliği (Yüksek olmalı):", custom_cosine_similarity(kral_vektor, kralice_vektor).item())

print("Kral - Araba Benzerliği (Düşük olmalı):", custom_cosine_similarity(kral_vektor, araba_vektor).item())

Basit Benzetme

Ok İşareti Örneği: İki kişinin ellerindeki okları aynı gökyüzü hedefine doğru tutup tutmadığına bakmak gibidir. Okların boyu önemli değildir, önemli olan baktıkları açıdır.


3.2. Aktivasyon Kancaları (Activation Hooks) ile İç Hücre İzleme

Matematiksel Mantık

Model çalışırken (Forward Pass esnasında), katmanların ürettiği gizli durum (Hidden State) matrislerini dışarı sızdırmak veya üzerlerinde değişiklik yapmak için kullanılan kesinti mekanizmalarıdır.

PyTorch Kodu

# İzlemek için çok basit tek katmanlı bir yapay sinir ağı oluşturalım

class MiniModel(nn.Module):

    def __init__(self):

        super().__init__()

        self.fc = nn.Linear(4, 4)

    def forward(self, x):

        return self.fc(x)

 

# Kanca tetiklendiğinde içine veriyi kaydedeceğimiz boş bir liste

akil_okuyucu_kutusu = []

 

# Kanca Fonksiyonu: Model buraya uğradığında içerideki sayıyı yakalar

def gizli_katman_kancasi(module, input, output):

    akil_okuyucu_kutusu.append(output.detach())

 

# Çalıştırma Simülasyonu:

model = MiniModel()

# Modele kancayı takıyoruz (fc katmanının çıktısını dinle)

handle = model.fc.register_forward_hook(gizli_katman_kancasi)

 

girdi_verisi = torch.randn(1, 4)

cikti_verisi = model(girdi_verisi)

 

print("Kanca Tarafından Gizlice Yakalanan Hücre Değerleri:\n", akil_okuyucu_kutusu[0])

handle.remove() # İşimizi bitince dinleme cihazını söküyoruz

Basit Benzetme

Hırsız Dinleme Cihazı Örneği: Bir binanın havalandırma borusuna gizli bir mikrofon takıp, içerideki ajanların gizli planları konuşurken seslerini kaydetmek gibidir.


3.3. Logit Lens (Çıkış Merceği) Tekniği

Matematiksel Formül

Modelin 12 katmandan oluştuğunu varsayalım. Logit Lens, modelin en son katmana kadar gitmesini beklemez. Örneğin 5. katmandaki ara gizli çıktıyı ($h^{(5)}$) alır ve doğrudan en sondaki Unembedding ($W_U$) matrisi ile çarparak, modelin yolun ortasındayken aklından hangi kelimenin geçtiğini sorgular.

$$\text{Logits}_{\text{early}} = h^{(l)} W_U$$

PyTorch Kodu

class ToyTransformerWithLogitLens(nn.Module):

    def __init__(self, vocab_size, d_model):

        super().__init__()

        # Katman 1 ve Katman 2 (Gizli katmanlar)

        self.layer1 = nn.Linear(d_model, d_model)

        self.layer2 = nn.Linear(d_model, d_model)

        # Kelime Çevirici Matris (Unembedding Matrix)

        self.W_u = nn.Linear(d_model, vocab_size, bias=False)

 

    def forward_with_lens(self, x):

        # Yolculuk Başlıyor

        h1 = self.layer1(x)

       

        # LOGIT LENS ADIMI: Katman 2'ye geçmeden hemen tahmin alalım!

        lens_logits = self.W_u(h1)

       

        # Yolculuk normal seyrinde devam ediyor

        h2 = self.layer2(h1)

        final_logits = self.W_u(h2)

       

        return final_logits, lens_logits

 

# Deneme:

lens_model = ToyTransformerWithLogitLens(vocab_size=1000, d_model=16)

test_girdisi = torch.randn(1, 16)

final, erken_tahmin = lens_model.forward_with_lens(test_girdisi)

print("Logit Lens Erken Tahmin Boyutu:", erken_tahmin.shape)

Basit Benzetme

Düşünce Okuma Örneği: Bir çocuk resmi çizip bitirmeden önce, resmin ortasındayken yanına gidip "Hımm, galiba bir kedi çiziyorsun değil mi?" diyerek aklını erkenden tahmin etmek gibidir.


3.4. Seyrek Otonom Kodlayıcılar (Sparse Autoencoders - SAE)

Matematiksel Formül

Modelin gizli katmanlarındaki yoğun verileri (h), çok daha yüksek boyutlu ama neredeyse tamamı sıfırlardan oluşan seyrek özelliklere (f) dönüştürür. L₁ cezası sayesinde nöronların sadece küçük bir kısmı aktif kalır (ReLU).

$$f = \text{ReLU}(hW_{\text{enc}} + b_{\text{enc}})$$

$$\hat{h} = fW_{\text{dec}} + b_{\text{dec}}$$

$$\mathcal{L}_{\text{SAE}} = \Vert{}h - \hat{h}\Vert{}^2 + \alpha \sum_{i} \vert{}f_i\vert{}$$

PyTorch Kodu

class SparseAutoencoder(nn.Module):

    def __init__(self, d_model, d_hidden_sae, alpha=0.01):

        super().__init__()

        self.alpha = alpha

        # Yoğun katmandan çok geniş/seyrek katmana geçiş

        self.encoder = nn.Linear(d_model, d_hidden_sae)

        # Geri toplama katmanı

        self.decoder = nn.Linear(d_hidden_sae, d_model)

 

    def forward(self, h):

        # f: Seyrek özellik aktivasyonları

        f = F.relu(self.encoder(h))

        # h_hat: Yeniden kurgulanan girdi

        h_hat = self.decoder(f)

       

        # Kayıp hesaplama: Yeniden kurma hatası + L1 Seyreklik Cezası

        reconstruction_loss = F.mse_loss(h_hat, h)

        l1_loss = torch.sum(torch.abs(f))

       

        total_sae_loss = reconstruction_loss + self.alpha * l1_loss

        return h_hat, total_sae_loss, f

 

# Deneme:

sae_katmani = SparseAutoencoder(d_model=16, d_hidden_sae=64, alpha=0.05)

hidden_states_ornek = torch.randn(1, 16)

_, kayip_puani, seyreklik_aktivasyonlari = sae_katmani(hidden_states_ornek)

print("Sıfır olan nöronların sayısı (Yüksek olmalı):", torch.sum(seyreklik_aktivasyonlari == 0).item(), "/ 64")

Basit Benzetme

Kavram Sözlüğü Örneği: Bilgisayarın karmaşık beynindeki milylarca sayıyı basitleştirerek; "Burası sadece kedilerden bahsederken yanan nörondur", "Şurası sadece uzayla ilgili kelimelerde yanan nörondur" diye tek tek insan diline tercüme etmek gibidir.


4. KISIM: MÜDAHALE VE DENEYSEL NEDENSELLİK (CAUSAL INTERVENTION)

4.1. Aktivasyon Düzenleme ve Yama (Activation Editing / Patching)

Matematiksel Mantık

Modelin temiz çalışan bir işlem akışındaki aktivasyon değerlerinin bir kısmını söküp, onun yerine kasti olarak bozucu bir gürültü veya başka bir cümleye ait özellikleri yamama (A ← B) operasyonudur. Çıktının nasıl değiştiği gözlemlenerek o katmanın görevi kesin olarak ispatlanır.

PyTorch Kodu

def activation_patching_simulation():

    # Temiz Duygu Aktivasyonu (Model mutlu bir şey düşünüyor)

    temiz_aktivasyon = torch.tensor([[5.0, 4.5, 0.1]])

   

    # Kötü niyetli/Gürültülü müdahale vektörü (Araya girip fikri değiştiriyoruz)

    sabotaj_aktivasyonu = torch.tensor([[-10.0, 0.0, 0.0]])

   

    # Yamama Operasyonu: 0. indeksteki değeri bozuyoruz

    manipüle_edilmis_aktivasyon = temiz_aktivasyon.clone()

    manipüle_edilmis_aktivasyon[0, 0] = sabotaj_aktivasyonu[0, 0]

   

    return manipüle_edilmis_aktivasyon

 

print("Müdahale Sonrası Yeni Hücre Durumu:", activation_patching_simulation())

Basit Benzetme

Çorba Örneği: Bir aşçı çorba yaparken tam tencereyi karıştıracağı sırada gizlice içine bir kaşık tuz atmak gibidir. Çorbanın tadının bozulup bozulmadığına bakarak o tuzun çorbayı ne kadar etkilediğini anlarsınız.


4.2. Dikkat Kafası Susturma (Head Ablation)

Matematiksel Formül

Belirli bir dikkat kafasının (h) çıktıya katkısını sıfıra indirmek için, o kafadan gelen projeksiyon matrisinin sonucu bir maske katsayısı olan 0 ile çarpılır.

$$\text{Output} = \sum_{h=1}^{H} \text{Mask}_h \times \text{Attention}_h(Q, K, V)W_O^h$$

$$\text{Susturma Durumunda: } \text{Mask}_h = 0$$

PyTorch Kodu

class MultiHeadAblationDemo(nn.Module):

    def __init__(self, num_heads, d_model):

        super().__init__()

        self.num_heads = num_heads

        self.d_model = d_model

 

    def forward(self, head_outputs, ablate_head_idx=None):

        # head_outputs: [Batch, Num_Heads, Seq_Len, Dim]

        # Bütün kafalara başlangıçta 1 (açık) değerini ver

        mask = torch.ones(self.num_heads)

       

        # Eğer kapatmak istediğimiz bir kafa indeksi varsa onu 0 (sustur) yap

        if ablate_head_idx is not None:

            mask[ablate_head_idx] = 0.0

            print(f"DIKKAT: {ablate_head_idx}. kafanın fişi çekildi!")

           

        # Maskeyi boyutlara uydur ve kafaları çarpıp sustur

        scaled_outputs = []

        for i in range(self.num_heads):

            scaled_outputs.append(head_outputs[:, i] * mask[i])

           

        return torch.cat(scaled_outputs, dim=-1)

 

# Deneme:

susturucu = MultiHeadAblationDemo(num_heads=3, d_model=12)

kafa_verileri = torch.ones(1, 3, 2, 4) # 3 kafa da 1'lerden oluşan çıktılar veriyor

yeni_cikti = susturucu(kafa_verileri, ablate_head_idx=1)

print("Susturma Sonrası Çıktı Kontrolü (Ortadaki kafanın alanı sıfırlandı):\n", yeni_cikti)

Basit Benzetme

Sigorta Kutusu Örneği: Evdeki elektrik sigortalarını tek tek indirip "Mutfaktaki lambalar söndü mü?" diye bakmak gibidir. Hangi sigorta inince mutfak sönüyorsa, o sigortanın mutfağa ait olduğunu anlarsınız.