EFE KESLER — Yapay Zekâ Mühendisi
trend yapay zekâ
My notes.

Makineler düşünmez. Biz düşünürüz.

Modeller her hafta değişiyor, sorular değişmiyor. Burada haber yok — dikkatle okunmuş kâğıtlar, denenmiş sistemler ve nadiren de olsa net bir fikir var.

4 yazı
2026 arşivi
Türkçe
04 Fine-tuning: modeli ne zaman değiştirmelisin LoRA · düşük rank · katastrofik unutma 17 Tem 2026 → 03 Pruning: ağın nesini kesebilirsin seyreklik · yapısal kesim · gecikme 10 Tem 2026 → 02 Quantization: kaybın nerede birikiyor düşük hassasiyet · kalibrasyon · bellek 10 Tem 2026 → 01 RAG: getirim iyi olduğunda çalışır gömme · vektör arama · yeniden sıralama 10 Tem 2026 →

Sonsuz üretim çağında nadir olan, dikkat.

Her hafta bir konu seçiyorum, kaynağına iniyorum, kendim deniyorum. Çoğu yazı bir iddiayla değil bir şüpheyle başlıyor. Bülten yok, abone çağrısı yok — istersen okursun.

Hakkında

Efe Kesler. Yapay zekâ sistemleriyle çalışıyorum ve çalışırken not tutuyorum. Bu site o notların temize çekilmiş hali.

İlgilendiğim şey modellerin ne yapabildiği değil, insanların onlarla ne yapmaya karar verdiği.

Yazdıklarımda kesinlik yerine gerekçe bulacaksın. Yanıldığım yerleri de bırakıyorum.

Teknik · No. 0110 Temmuz 2026

RAG: getirim iyi olduğunda çalışır.

RAG bir mimari değil, bir ödünleşme. Çoğu ekip modeli suçlarken aslında getirim katmanını hiç ölçmemiş oluyor. Aşağısı, üretimde çalışan bir sistemin nasıl kurulduğu ve nerede kırıldığı üzerine.

Bir dil modeli yalnızca eğitildiği şeyi bilir. Şirketinin dünkü politika değişikliğini, müşterinin sözleşme maddesini, dün akşam kapanan destek talebini bilmez ve bilemez. RAG — Retrieval-Augmented Generation, Türkçesiyle getirimle desteklenmiş üretim — bu boşluğu kapatmanın en yaygın yolu: modeli yeniden eğitmek yerine, soru sorulduğu anda ilgili belgeleri bulup bağlam penceresine koymak ve cevabı onların üzerinden yazdırmak.

Mekanik üç adımda özetlenebilir. Getir: kullanıcının sorgusuyla bilgi tabanını ara, en alakalı parçaları seç. Ekle: bu parçaları isteme (prompt) iliştir. Üret: modelden yalnızca verilen bağlama dayanarak cevaplamasını iste. Kazanç açık — bilgi tabanı güncellendiğinde model yeniden eğitilmez, sadece indeks yenilenir; cevap kaynağa dayandığı için alıntılanabilir ve denetlenebilir.

Fikir 2020'de Lewis ve arkadaşlarının makalesiyle isimlendirildi, ama yeni değildi. Basit de görünüyor. Üretimde basit değil.

Çünkü bir RAG sistemi kurup üretime aldıysan ve model "halüsinasyon görüyor" diyorsan, muhtemelen model halüsinasyon görmüyor. Ona yanlış belge veriliyor ve o da elindekiyle en makul cümleyi kuruyor. Dil modeli, bağlam penceresine ne koyduysan onun üzerinden akıl yürütür. Yanlış paragrafı verip doğru cevap beklemek, yanlış dosyayı açıp derleyiciden farklı bir program çıkmasını beklemeye benziyor. Sistemin kalitesi neredeyse tamamen getirim katmanının kalitesine bağlı ve o katman genellikle hiç ölçülmüyor.

Üretim seviyesinde RAG'de model bir bileşen, getirim ise sistemin kendisi.

01 / ÇerçeveYanlış soruyla başlamak

Çoğu ekip şu soruyla başlıyor: "Hangi vektör veritabanını kullanmalıyım?" Bu, yanlış yerden giriş. Doğru sıra tersine işliyor:

  1. Kullanıcı hangi soruları soruyor? Gerçek sorgu dağılımını topla. Sentetik sorularla tasarlanan sistemler üretimde çöküyor, çünkü insanlar yazım hatası yapar, kısaltma kullanır, bağlamı eksik verir.
  2. Cevap belgede nerede duruyor? Cevap tek bir paragrafta mı, yoksa üç ayrı bölümün sentezi mi? Bu, parçalama stratejini belirler, tersi değil.
  3. Yanlış cevabın maliyeti ne? Bir destek botunun yanlışı ile bir sözleşme analiz aracının yanlışı aynı şey değil. Bu, eşik değerlerini ve "bilmiyorum" davranışını belirler.
  4. Ancak bundan sonra altyapı seçilir.

02 / GetirimKelime, vektör ve ikisinin toplamı

Yaygın yanılgı: gömme (embedding) tabanlı arama, anahtar kelime aramasının modern ve üstün halidir. Değil. İkisi farklı hata modlarına sahip ve hataları birbirini örtüyor.

Seyrek getirim (BM25)

BM25, kelime sıklığı ve belge uzunluğunu tartan klasik bir sıralama fonksiyonu. Nadir tokenlarda çok güçlü: ürün kodları, hata mesajları, kişi adları, mevzuat maddeleri. ORA-01555 aradığında BM25 tam isabet verir, gömme modeli ise bunu "veritabanı hatası" semantik uzayına yerleştirip yakın ama yanlış on belge getirir.

Yoğun getirim (embedding + ANN)

Yoğun getirim eşanlamlıyı ve parafrazı yakalar. "Ödememi nasıl iptal ederim" sorgusu, içinde "iptal" kelimesi hiç geçmeyen "aboneliğinizi sonlandırma" başlıklı belgeye ulaşır. BM25 bunu ıskalar.

Hibrit ve füzyon

Pratikte ikisi paralel çalıştırılıp sonuçlar birleştirilir. En dayanıklı yöntem Reciprocal Rank Fusion: skorları normalize etmeye çalışmaz, sadece sıralamalara bakar. Bu yüzden farklı ölçeklerdeki sistemleri güvenle harmanlar.

# Reciprocal Rank Fusion — skor değil, sıra birleştirir.
# k=60 literatürde standart; sıralamanın kuyruğunu yumuşatır.

def rrf(rankings, k=60):
    scores = defaultdict(float)
    for ranking in rankings:            # [bm25_ids, dense_ids, ...]
        for rank, doc_id in enumerate(ranking):
            scores[doc_id] += 1.0 / (k + rank + 1)
    return sorted(scores, key=scores.get, reverse=True)

bm25  = opensearch.search(query, size=50)      # seyrek
dense = qdrant.search(embed(query), limit=50)   # yoğun
candidates = rrf([bm25, dense])[:30]            # reranker'a gidecek
Saha notu

Bir kurumsal doküman aramasında yalnız yoğun getirimden hibrite geçiş, Recall@20'yi 0.71'den 0.89'a taşıdı. Değişen tek şey BM25'in eklenmesiydi. Model, gömme modeli, parça boyutu — hepsi aynı kaldı.

03 / HazırlıkParçalama, gerçekten önemli

Parçalama (chunking) bir ön işleme detayı gibi görünür, oysa getirimin çözünürlüğünü belirleyen şeydir. İndeksteki parça, aramanın erişebileceği en küçük birimdir: bir cevap iki parçaya bölünmüşse hiçbir sıralama algoritması onu bütün halinde geri getiremez. Sistemin tavanı, belgeyi kestiğin anda çizilmiş olur.

Yine de en yaygın varsayılan, metni 512 token'lık sabit pencerelere bölmek. Bu, belgenin anlamını değil karakter sayısını dikkate alan bir karar. Sonucunda maddenin şartı bir parçada, hükmü diğerinde kalır; tablonun başlığı gövdesinden kopar; "bu durumda" diye başlayan paragraf, hangi duruma işaret ettiğini kaybeder. Getirim doğru parçayı bulur, cevap yine de eksiktir.

Daha iyi yaklaşımlar:

  • Yapıya duyarlı bölme. Markdown başlıkları, HTML bölümleri, PDF'te yazı tipi boyutu hiyerarşisi. Belgenin kendi yapısı zaten bir bölme sinyali.
  • Bağlamsal başlık ekleme. Her parçanın başına ait olduğu belge ve bölüm başlığını yaz. Parça artık kendi başına anlamlı: "Ürün İadeleri > Süre Sınırı — Kargo teslim tarihinden itibaren 14 gün..."
  • Üst-alt parça ayrımı. Küçük parçaları indeksle (isabet keskin olsun), ama modele büyük üst parçayı gönder (bağlam yeterli olsun). Getirim ve okuma için farklı granülerlik kullan.
  • Tabloları metne çevirme. Ham CSV satırları gömme uzayında anlamsızdır. Her satırı cümleye dönüştür veya tabloyu bir LLM'e özetlettir, ikisini birden indeksle.

04 / KesinlikYeniden sıralama katmanı

Getirim geniş ağ atar, yeniden sıralama (reranking) ağı daraltır. Aradaki fark mimari: bi-encoder sorgu ve belgeyi ayrı ayrı kodlar (bu yüzden hızlıdır, önceden indekslenebilir), cross-encoder ikisini birlikte okur (bu yüzden çok daha doğru ama yavaştır).

Doğru kompozisyon: bi-encoder ile 50 aday çek, cross-encoder ile ilk 5'i seç. Cross-encoder'ı tüm korpusa çalıştırmak imkânsız, ama 50 adaya çalıştırmak birkaç yüz milisaniye.

# Aşama 1: geniş, ucuz. Aşama 2: dar, pahalı, doğru.

candidates = hybrid_search(query, k=50)

pairs  = [(query, c.text) for c in candidates]
scores = cross_encoder.predict(pairs)   # bge-reranker, Cohere Rerank...

top = [c for c, s in sorted(zip(candidates, scores),
       key=lambda x: x[1], reverse=True) if s > 0.35][:5]

# Eşiğin altında hiçbir şey yoksa: uydurma. Söyle ki bilmiyorsun.
if not top:
    return ABSTAIN
Sık atlanan

Son üç satır, çoğu sistemde yok. Eşik altı sonuç geldiğinde yine de modele veriliyor ve model kibarca uyduruyor. "Bilmiyorum" bir başarısızlık değil, bir özellik — ve ölçülmesi gereken bir metrik.

05 / BütçeBağlam, bedava değil

Bağlam penceresi bir milyon tokena çıktı diye her şeyi içine atmak cazip. Üç sebeple kötü fikir:

  • Ortadaki kayıp. Uzun bağlamlarda modeller baştaki ve sondaki bilgiyi hatırlar, ortadakini kaçırır. On beşinci belgeye gömülü doğru cevap, pratikte yok sayılır.
  • Gürültü, dikkati seyreltir. Beş alakalı belge yerine yirmi belge verdiğinde, on beş alakasız belge modeli yanlış çıkarıma çeker. Kesinlik (precision), hatırlamadan (recall) daha kıymetlidir — bir noktadan sonra.
  • Maliyet ve gecikme. Token başına ödüyorsun ve kullanıcı bekliyor.
~5Çoğu görev için
ideal parça sayısı
0.35Tipik reranker
kesme eşiği
50 → 5Aday havuzundan
bağlama

06 / ÖlçümÖlçmediğin şeyi düzeltemezsin

En yaygın hata: uçtan uca cevap kalitesine bakıp getirimi hiç ölçmemek. Cevap kötü çıktığında suçlanacak model var, düzeltilecek bir sayı yok. Katmanları ayrı ölç.

MetrikNe ölçerNe zaman düşer
Recall@kDoğru belge ilk k içinde mi?Parçalama ya da gömme kötü. Getirim katmanına bak.
MRR / nDCGDoğru belge kaçıncı sırada?Reranker yok ya da zayıf.
FaithfulnessCevap, verilen bağlamdan mı türedi?Model uyduruyor. Eşik ve çekimserlik davranışına bak.
Answer relevanceCevap, sorulan soruya mı cevap veriyor?İstem (prompt) ya da sorgu anlama katmanı zayıf.
Abstention rateNe sıklıkla "bilmiyorum" diyor?Sıfırsa şüphelen. Sistem asla bilmediğini itiraf etmiyor demektir.

Altın küme (golden set) şart. Elli soru ve elle işaretlenmiş doğru belgeleriyle başla. Elli, bindir. Bu kümeyi her değişiklikte çalıştır — parça boyutunu değiştirdiğinde, gömme modelini yükselttiğinde, istemi düzelttiğinde. Ragas, TruLens ve DeepEval bunu otomatikleştirir, ama araç değil disiplin belirleyici.

07 / KırılmaNerede kırılıyor

Sorgu ile belge aynı dili konuşmuyor

Kullanıcı "faturamı göremiyorum" der, belge "invoice retrieval failure" der. Çözüm: HyDE (varsayımsal cevap üretip onu gömmek), sorgu genişletme, ya da çok dilli gömme modeli. Türkçe için ek bir zorluk: token ekonomisi Türkçe aleyhine, yani aynı anlam daha çok token yiyor ve parça sınırları daha erken geliyor.

Çok atlamalı sorular

"X politikası, Y bölgesindeki çalışanlar için Z tarihinden sonra ne söylüyor?" Cevap tek parçada yok. Naif RAG burada çuvallar. Çözüm ajanlı getirim: model sorguyu alt sorulara böler, sırayla arar, ara sonuçları biriktirir.

Zaman ve yetki

İki sinsi hata. Birincisi, indeks eski belgeyi de yenisini de tutuyor ve model beş yıl önceki politikayı alıntılıyor. İkincisi, kullanıcının görmemesi gereken belge getirime giriyor. Her ikisi de metadata filtreleme ile çözülür ve her ikisi de gömme benzerliğiyle çözülmez. Filtre, aramadan önce uygulanmalı.

# Yetki ve tazelik, benzerlik hesabından önce gelir.
results = qdrant.search(
    vector=embed(query),
    query_filter=Filter(must=[
        FieldCondition(key="acl", match=MatchAny(any=user.groups)),
        FieldCondition(key="valid_until", range=Range(gte=now())),
    ]),
    limit=50,
)

08 / YığınNe kullanılıyor

Kategori kategori, üretimde sık gördüklerim ve seçim kriteri:

KatmanSeçeneklerKritere göre
Vektör deposuQdrant, Weaviate, Milvus, pgvector, VespaZaten Postgres varsa pgvector yeter. Filtreli arama ağırsa Qdrant. Milyar ölçekte Vespa/Milvus.
Seyrek aramaOpenSearch, Elasticsearch, TantivyBM25'i atlama. Çoğu yığında zaten var.
GömmeBGE-M3, E5, Voyage, Cohere Embed, OpenAITürkçe için çok dilli modeller (BGE-M3, multilingual-E5) tek dilli İngilizce modelleri açık ara geçer.
Yeniden sıralamabge-reranker, Cohere Rerank, JinaEn yüksek getiri/maliyet oranlı tek ekleme. Önce bunu yap.
AyrıştırmaUnstructured, Docling, LlamaParsePDF ve tablo işi kirli. Buraya harcanan zaman geri döner.
OrkestrasyonLlamaIndex, Haystack, ya da düz kodPrototipte çerçeve, üretimde çoğu ekip düz koda dönüyor. Soyutlama hata ayıklamayı zorlaştırıyor.
DeğerlendirmeRagas, TruLens, DeepEval, PhoenixHangisi olduğu önemli değil. Olmaması ölümcül.
Bir reranker eklemek, gömme modelini büyütmekten neredeyse her zaman daha çok kazandırır. Ve çok daha ucuzdur.

Son bir şey. RAG'in modası geçmiş olduğu, uzun bağlamın onu gereksiz kıldığı düzenli aralıklarla söyleniyor. Bu yanlış çerçeve. Uzun bağlam, neyi okuyacağına karar verme problemini çözmüyor; sadece erteliyor. Kurumsal bir bilgi tabanı terabaytlarca. Soru hep aynı kalıyor: bu sorgu için hangi beş paragraf?

Cevabı iyi verirsen sistem çalışır. Kötü verirsen, dünyanın en iyi modeli sana kendinden emin bir yanlış yazar.

No. 01 — Teknik 10 Temmuz 2026
Teknik · No. 0210 Temmuz 2026

Quantization: kaybın nerede birikiyor.

Modeli 4 bit'e indirdin, VRAM'e sığdı, hız ikiye katlandı. Peki ne kaybettin? Cevap "hiçbir şey" değil — ve kaybın nerede olduğunu ölçmediysen, bulduğun yerde bulacaksın: üretimde. Aşağısı, kaybın hangi katmanda ve hangi görevde yoğunlaştığı üzerine.

Bir dil modelinin ağırlıkları sayıdır. Yetmiş milyar tane sayı. Her birinin bellekte kaç bit yer kaplayacağı ise bir tasarım kararı — modelin doğasında olan bir şey değil. Eğitim sırasında FP32, BF16, FP8 karışık kullanılabilir; dağıtıma çıkarken çoğu ekip BF16 ya da FP16 seçiyor. Somut olsun diye 16 bit üzerinden hesaplayalım: 70 milyar × 2 bayt = 140 gigabayt.

Bu ağırlıkları bir grafik kartına sığdırmak istiyorsanız — ki istiyorsunuz, çünkü bellekten okuma çıkarımın en yavaş adımıdır — ya çok pahalı bir karta ya da daha küçük sayılara ihtiyacınız var. Quantization (niceleme) ikincisini seçmek demek.

Ne yapıyor

Fikir kaba biçimde şu: bir ağırlığı temsil etmek için ayrılan bit sayısını azalt. Nereden başladığın önemli değil — 16 bit'ten 4'e, 8'den 4'e, ya da FP8'den 2'ye. Bir ağırlık matrisindeki değerlerin çoğu birbirine yakın; bu aralığı alıp eşit dilimlere böl, her ağırlığı en yakın dilimin numarasıyla değiştir. Kaybettiğin şey hassasiyet, kazandığın şey bellek ve bant genişliği.

Neden yapılıyor

Dört somut kazanç var ve hepsi aynı kökten geliyor: model diskte ve bellekte daha az yer kaplıyor. Aşağıdaki sayılar 16 bit'ten 4 bit'e inen 70B bir model için; başka bir başlangıç noktası başka oranlar verir.

  • Sığdırma. 140 GB yerine ~40 GB. Tek bir A100'e sığar. Bu genellikle "çalışıyor" ile "çalışmıyor" arasındaki farktır, hız meselesi değil.
  • Hız. Token üretimi bellek bant genişliğine bağlıdır. Her adımda tüm ağırlıkları okumak gerekir; dörtte birini okumak ciddi hızlanma demek. Pratikte 2–4 kat.
  • Maliyet. Aynı GPU'da daha fazla eşzamanlı istek. Bulut faturası doğrudan düşer.
  • Erişim. Tüketici donanımında, dizüstünde, telefonda çalışan modeller. Kapalı kapı ardında kalacak yeteneklerin yerelde çalışması.

Buraya kadar herkes hemfikir. Anlaşmazlık şurada başlıyor: bu kayıp nerede birikiyor ve ne zaman görünür hale geliyor? Çünkü niceleme, kaybını her yere eşit dağıtan nazik bir işlem değil. Belirli katmanlarda, belirli görevlerde, belirli girdi dağılımlarında yoğunlaşıyor. Ve standart ölçütler bunu göstermiyor.

Quantization bir sıkıştırma değil, bir ödünleşme. Modelin hangi kapasitesini feda edebileceğine dair bir karar.

01 / TemelAslında ne oluyor

Bir ağırlık tensörünü nicelemek için ölçek (scale) ve bit genişliği gerekir; asimetrik şemalarda buna bir de sıfır noktası (zero_point) eklenir — ona birazdan geleceğiz. Değeri tam sayıya haritalar, çarpım sırasında geri açarsın. Aşağısı simetrik hâli.

# Simetrik, kanal başına niceleme — INT8
# W şekli: [çıkış_boyutu, giriş_boyutu]. Her satır bir çıkış nöronu.

def quantize(W, bits=8):
    qmax  = 2 ** (bits - 1) - 1          # 127

    # Her satırın en büyük mutlak değerini bul → satır başına bir ölçek.
    # [çıkış, giriş] --amax(dim=1)--> [çıkış, 1]
    scale = W.abs().amax(dim=1, keepdim=True) / qmax

    # Böl, yuvarla, taşanı kırp. Kayıp yuvarlamada oluşur.
    Wq = torch.round(W / scale).clamp(-qmax, qmax)
    return Wq.to(torch.int8), scale

def dequantize(Wq, scale):
    return Wq.to(torch.float16) * scale   # geri açma; kayıp geri gelmez

Ölçek nasıl seçilir

Bütün mesele scale satırında. Ölçek, gerçek sayıları tam sayı aralığına sıkıştıran bölendir. Onu kaç ağırlık için ortak hesapladığın, kalitenin tamamını belirler.

Küçük bir örnekle bakalım. Diyelim ağırlık matrisimiz 2 satır, 4 sütun:

        sütun:   0      1      2      3
satır 0:       0.10   0.20   0.15   0.05
satır 1:       0.30   90.0   0.25   0.40   ← 90.0 bir aykırı değer

INT8 kullanıyoruz, yani her ağırlığı −127 ile +127 arasında bir tam sayıya çevireceğiz.

Tek ölçek (tensör başına). Bütün matris için tek bir bölen: en büyük mutlak değer 90.0, ölçek = 90.0 / 127 ≈ 0.709. Şimdi her ağırlığı bu ölçeğe bölüp yuvarlayalım:

0.10 / 0.709 = 0.14  → yuvarla → 0
0.20 / 0.709 = 0.28  → yuvarla → 0
0.15 / 0.709 = 0.21  → yuvarla → 0
0.05 / 0.709 = 0.07  → yuvarla → 0
90.0 / 0.709 = 127   → yuvarla → 127   ← tek hayatta kalan

İlk satırın tamamı sıfıra çöktü. Dört farklı ağırlık, artık aynı sayı. Bilgi yok oldu — tek bir aykırı değer yüzünden.

Satır başına ölçek. Her satır için ayrı bölen hesaplayalım. Satır 0'ın maksimumu 0.20, ölçeği 0.20 / 127 ≈ 0.00157. Satır 1'in maksimumu 90.0, ölçeği 0.709:

satır 0 (ölçek 0.00157):
  0.10 → 63     0.20 → 127
  0.15 → 95     0.05 → 32     ← dördü de ayırt edilebilir

satır 1 (ölçek 0.709):
  0.30 → 0      90.0 → 127
  0.25 → 0      0.40 → 1      ← burası hâlâ kötü, ama hasar bu satırla sınırlı

Koddaki amax(dim=1) tam olarak bunu yapıyor: her satırın en büyük mutlak değerini bulup satır sayısı kadar ölçek üretiyor. Buna kanal başına niceleme denir; bir doğrusal katmanda her satır bir çıkış nöronunun katsayılarıdır, o yüzden "kanal".

Grup başına niceleme

Satır başına ölçek hasarı satırla sınırlıyor, ama satırı kurtarmıyor. Yukarıdaki satır 1'de 90.0 yüzünden 0.30 ve 0.25 hâlâ sıfıra çöktü.

Gerçek bir katmanda satır 4 eleman değil, sekiz bin eleman civarı. Öyleyse satırı da böl: her 128 elemana kendi ölçeğini ver. Sekiz bin elemanlık bir satır 64 bloğa ayrılır, her blok kendi bölenine sahip olur. Aykırı değer hangi bloktaysa hasar orada kalır; diğer 63 blok bundan hiç etkilenmez.

Buna grup başına niceleme denir. Grup boyutu 128, pratikte neredeyse standart hâline geldi.

Neden tam olarak 128

Grup küçüldükçe doğruluk artar — daha az ağırlık aynı böleni paylaşır, aykırı değerin ezdiği komşu sayısı azalır. Öyleyse neden grup 8 yapmıyoruz?

Çünkü her ölçek de bellekte yer kaplar. Ölçek bir kayan noktalı sayıdır, tipik olarak 16 bit tutulur. Ne kadar çok grup, o kadar çok ölçek, o kadar çok ek yük. "4 bit niceleme" dediğin şey gerçekte 4 bit'ten fazladır.

Hesap basit. Grup 128, simetrik şema:

128 ağırlık × 4 bit  =  512 bit
1 ölçek     × 16 bit =   16 bit
                        ────────
                         528 bit

ağırlık başına: 528 / 128 = 4.125 bit

Yani ilan edilen 4 bit'in üstüne %3 ek yük. Grup boyutunu değiştirdikçe bu oran şöyle hareket ediyor:

GrupAğırlık/bitEk yükDoğruluk
324.50+%12.5En iyi
644.25+%6.2İyi
1284.13+%3.1Yeterli
2564.06+%1.6Aykırılar yayılmaya başlar

Sıkıştırma kazancı hızla doyuyor. 128'den 256'ya çıkmak ağırlık başına yalnızca 0.06 bit kazandırır — 70B model için 36.1 GB yerine 35.5 GB, yani yarım gigabayt. Buna karşılık her ölçek iki kat fazla ağırlığı yönetmek zorunda kalır ve tek bir aykırı değer 128 yerine 256 komşusunu ezer. Kötü bir takas.

Ters yönde de aynı asimetri var. 128'den 64'e inmek doğruluğu bir miktar artırır, ama ağırlık başına 4.13'ten 4.25 bit'e çıkarsın — ek yük ikiye katlanır. 32'de %12.5'e fırlar; bu noktada "4 bit" demek anlamını yitirmeye başlar. 128, iki eğrinin makul kesiştiği yer.

Sıfır noktası nedir

Yukarıdaki hesap simetrik nicelemeye aitti: değerlerin sıfır etrafında dengeli dağıldığını varsayıp tek bir bölen kullanıyoruz. Aralık −127 ile +127 arası, ortası sıfır.

Ama her tensör böyle davranmaz. Bir ReLU çıktısı asla negatif olmaz; değerler diyelim 0 ile 6 arasında toplanmıştır. Böyle bir dağılıma çarpık denir — kütlesi sıfırın bir yanında, simetrik değil.

simetrik şema, aralık 0–6 için:

  -127 ................ 0 ................ 127
  └─ hiç kullanılmaz ──┘└─── veri burada ────┘

Kullanılabilir 255 basamağın yarısı boşta duruyor.

Asimetrik niceleme bunu düzeltir: ölçeğin yanına bir de kaydırma değeri saklar. Bu değer, gerçek sıfırın tam sayı ekseninde nereye düştüğünü söyler — adı zero_point, sıfır noktası. Sıfırı −128'e kaydırırsan bütün eksen 0–6 aralığına yayılır.

simetrik:    gerçek = ölçek × tamsayı
asimetrik:   gerçek = ölçek × (tamsayı − sıfır_noktası)

Kazanç çözünürlükte — yani iki temsil edilebilir değer arasındaki mesafede:

simetrik   : ölçek = 6 / 127 ≈ 0.047   → basamaklar 0.047 aralıklı
asimetrik  : ölçek = 6 / 255 ≈ 0.024   → basamaklar 0.024 aralıklı

Aynı 8 bitle, aynı bellekle, iki kat ince bir ızgara. Sıfırı eksenin ucuna kaydırmak, bir bit daha kazanmışsın gibi sonuç veriyor.

Bedeli şu: artık grup başına iki sayı saklıyorsun. Ölçek ve sıfır noktası, ikisi de tipik olarak 16 bit. Ek yük ikiye katlanır:

GrupSimetrikAsimetrik
644.25 bit4.50 bit
1284.13 bit4.25 bit
2564.06 bit4.13 bit

Buradan şu tuhaflık çıkıyor ve karışıklık yaratıyor: asimetrik grup 128 ile simetrik grup 64, ikisi de ağırlık başına tam 4.25 bit eder. Aynı bellek, farklı takas.

Asimetrik-128, o ek 16 biti çarpık dağılımları düzgün temsil etmeye harcar. Çarpık dağılım demek, değerlerin sıfırın iki yanına dengeli yayılmadığı dağılım demek — yukarıdaki ReLU örneğinde olduğu gibi, hepsi bir tarafta toplanmış. Simetrik-64 ise aynı biti gruba daha küçük bir çevre vermeye harcar: aykırı bir değer 128 yerine 64 komşusunu ezer.

Hangisinin kazandığı, nicelediğin tensörün şekline bağlı. Ve burada modelin iki farklı türde sayısı olduğunu ayırmak gerekiyor.

Ağırlıklar mı, aktivasyonlar mı

Ağırlıklar, eğitimle öğrenilen ve sonra sabit kalan sayılardır. Matrisler, dosyada duran şey. Eğitim boyunca pozitifler ve negatifler dengelenir; histogramları sıfırda tepe yapan, iki yana kabaca eşit yayılan bir çan gibi görünür. Simetrik şema bu şekle zaten oturur. zero_point'in kazandıracağı bir şey yok, ama ödeteceği 16 bit var.

Aktivasyonlar ise girdi geldikçe anlık üretilen ara değerlerdir. Bir katmanın çıktısı, bir sonrakinin girdisi. Ve onları üreten fonksiyonlar tek yönlüdür:

  • ReLU negatifleri sıfıra kırpar. Çıktı asla negatif olmaz.
  • Softmax daima 0 ile 1 arasında değer verir.
  • GELU ve SiLU küçük bir negatif kuyruk bırakır, ama kütle ezici biçimde pozitif taraftadır.

Yani aktivasyon dağılımları çarpıktır — tam olarak yukarıdaki 0–6 örneği. Simetrik nicelersen tam sayı ekseninin yarısı boş durur, çözünürlüğün yarısını kaybedersin. zero_point burada ödediği biti fazlasıyla geri kazandırır.

Pratik sonuç: ağırlıklarda simetrik, aktivasyonlarda asimetrik. Ağırlık nicelemesi (W4A16) yapan araçların çoğu simetrik şema kullanır ve doğru yaparlar. Aktivasyonlara dokunan şemalar (W8A8, W4A4) sıfır noktasını hesaba katmak zorundadır — ve bu, bir sonraki bölümdeki aykırı değer sorununun neden tam da aktivasyonlarda patladığının ilk ipucu.

02 / KırılmaAykırı değerler sorunu

2022'de fark edilen ve alanı yeniden şekillendiren bulgu şu: 6.7 milyar parametreden büyük modellerde, aktivasyonlarda sistematik aykırı değerler beliriyor. Belirli gizli boyutlarda, diğerlerinden yüz kat büyük değerler. Bunlar gürültü değil — modelin işleyişi için gerekliler; sıfırlarsanız model çöküyor.

Sonuç dramatik: ağırlıkları nicelemek görece kolay, aktivasyonları nicelemek zor. Aykırı bir boyut, o katmanın ölçeğini tek başına belirler ve normal değerler hassasiyetlerini kaybeder.

Üç ana strateji üretildi:

  • Karma hassasiyet. Aykırı boyutları FP16'da bırak, kalanı INT8 yap. LLM.int8()'in yaklaşımı. Doğru ama yavaş — iki ayrı çekirdek çalıştırıyorsun.
  • Zorluğu taşıma. Aktivasyondaki aykırılığı matematiksel olarak ağırlıklara aktar. SmoothQuant bunu yapar: aktivasyonu bölerken ağırlığı çarpar, çarpım değişmez ama zorluk daha kolay nicelenen tarafa geçer.
  • Aykırıları döndürme. Ağırlık matrisini rastgele bir ortogonal matrisle çarparak aykırı enerjiyi tüm boyutlara yay. QuaRot ve SpinQuant'in fikri. Matematiksel olarak zarif; 4 bit aktivasyonu ilk kez uygulanabilir kıldı.
Saha notu

Yalnızca ağırlık niceleme (W4A16) ile ağırlık+aktivasyon niceleme (W4A4) arasındaki fark, mühendislik olarak uçurumdur. Birincisi bir hafta sonu işi. İkincisi, çekirdek yazmayı ve donanım özelliklerini bilmeyi gerektirir. Çoğu ekibin ihtiyacı olan birincisidir.

03 / YöntemEğitim sonrası niceleme

Eğitim sonrası niceleme (PTQ), eğitilmiş bir modeli alıp küçük bir kalibrasyon kümesiyle sıkıştırır. Yeniden eğitim yok, birkaç yüz örnek yeter, işlem dakikalar sürer. Üretimde ezici çoğunluk bunu kullanıyor.

GPTQ

Katman katman ilerler. Her ağırlığı sırayla niceler ve o adımda oluşan hatayı, henüz nicelenmemiş komşu ağırlıklara dağıtarak telafi eder. İkinci dereceden bilgiyi (Hessian) kullanır. 4 bit'te çok iyi, 3 bit'te zorlanır.

AWQ

Farklı bir sezgiden hareket eder: tüm ağırlıklar eşit önemde değil. Aktivasyon büyüklüğüne bakarak "önemli" kanalları tespit eder ve onları nicelemeden önce ölçeklendirerek korur. Kalibrasyon verisine GPTQ'dan daha az duyarlı; bu yüzden alan dışı görevlerde daha sağlam davranıyor.

GGUF ve k-quant'lar

llama.cpp ekosisteminin formatı. Q4_K_M gibi isimler bir karışım tanımlar: kritik katmanlar (dikkat çıkışı, aşağı projeksiyon) daha yüksek bitte, kalanı daha düşükte. Teorik olarak zarif değil, pratikte şaşırtıcı derecede iyi.

YöntemTipik yapıNerede parlar
GPTQW4A16, grup 128GPU çıkarımı, kalibrasyon verisi görev dağılımına yakınsa.
AWQW4A16, grup 128Genel amaçlı model, bilinmeyen görev dağılımı.
GGUF k-quantKarma 2–8 bitCPU ve Apple Silicon, tüketici donanımı.
SmoothQuantW8A8Aktivasyon nicelemesi gerektiğinde, sunucu ölçeğinde.
QuaRot / SpinQuantW4A4Bellek bant genişliğinin gerçekten sınır olduğu yerde.
bitsandbytes NF4W4A16Hızlı prototip, QLoRA ile ince ayar.

04 / AlternatifNicelemeye duyarlı eğitim

PTQ mevcut bir modeli sıkıştırır. Nicelemeye duyarlı eğitim (QAT) ise modeli, nicelenecek olduğunu bilerek eğitir. İleri geçişte ağırlıklar sahte-nicelenir, geri geçişte gradyan düz geçirilir (straight-through estimator). Model, düşük hassasiyete dayanıklı temsiller öğrenir.

Sonuçlar daha iyi — özellikle 2–3 bit gibi agresif rejimlerde PTQ tamamen çökerken QAT ayakta kalabiliyor. Bedeli ise eğitim maliyeti. Yetmiş milyar parametrelik bir modeli yeniden eğitmek çoğu ekip için erişilemez.

Orta yol QLoRA: taban modeli 4 bit'te dondur, üzerine düşük ranklı adaptörler ekle ve yalnızca onları eğit. Tek bir 24 GB kartta 65 milyar parametrelik model ince ayarlanabiliyor. Niceleme burada bir sıkıştırma tekniği değil, bir erişim tekniği.

140 GB70B model, 16 bit'te
(örnek başlangıç)
~40 GBAynı model 4 bit'te
(grup ölçekleri dahil)
2–4×Tipik üretim
hızlanması

05 / DarboğazKV önbelleği: asıl darboğaz

Ağırlıkları nicelediniz, model karta sığdı. Sonra uzun bağlamlı bir istek geldi ve bellek yine doldu. Suçlu ağırlıklar değil — KV önbelleği.

Üretilen her token için, her katmanda anahtar ve değer vektörleri saklanır. Bu, bağlam uzunluğuyla doğrusal, eşzamanlı istek sayısıyla da doğrusal büyür. 128 bin tokenlık bağlamda KV önbelleği, modelin kendisinden büyük olabilir.

Buradaki niceleme farklı bir problem. Ağırlıklar statiktir, bir kez nicelenir. KV önbelleği her adımda yazılır ve okunur; niceleme çekirdeğin sıcak yolunda çalışmalı.

# KV önbelleği 8 bit — anahtar ve değer farklı davranır.
# Anahtarlarda aykırılar belirli kanallarda kümeleniyor: kanal başına
# ölçek, aykırıyı kendi diliminde izole eder. Değerler daha düzgün
# dağıldığı için token başına ölçek yeterli.

cache_config = {
    "key_bits":     8,
    "value_bits":   8,
    "key_axis":     "channel",
    "value_axis":   "token",
    "residual_len": 128,   # en son 128 token FP16 kalsın
}

Son satır önemli: en son üretilen tokenlar dikkat skorlarına en çok katkı yapar. Onları tam hassasiyette tutmak, maliyeti neredeyse değiştirmeden kaliteyi korur.

06 / ÖlçümPerplexity yalan söyler

Niceleme makalelerinin çoğu WikiText perplexity'si raporlar. FP16'da 5.68, 4 bit'te 5.71 — "kayıp ihmal edilebilir" denir. Bu ölçüt, sıradaki tokeni tahmin etme yeteneğini ölçer ve niceleme hasarına karşı şaşırtıcı derecede duyarsızdır.

Hasarın gerçekten göründüğü yerler:

  • Çok adımlı muhakeme. Zincirin her adımında biriken küçük sapmalar, on beşinci adımda yanlış cevaba çıkar. Perplexity bunu görmez, GSM8K görür.
  • Kod üretimi. Sözdizimi hataya sıfır toleranslıdır. Bir noktalama işareti farkı programı bozar.
  • Uzun kuyruk bilgi. Nadir olguları hatırlamak, seyrek aktive olan ağırlıklara bağlıdır — ve niceleme tam olarak bu ağırlıkları ezer. Model genel konularda akıcı kalır, spesifik sorularda uydurmaya başlar.
  • Yapılandırılmış çıktı. JSON şemasına uyma oranı, nicelenmiş modellerde belirgin biçimde düşüyor.
  • Ana dil dışı diller. Türkçe dahil, eğitim verisinde daha az temsil edilen diller nicelemeden orantısız zarar görüyor. Zaten zayıf olan temsiller önce kopuyor.
Perplexity düştü mü diye bakmayı bırak. Görevin bozuldu mu diye bak.

Pratik tavsiye: kendi görevinden yüz örnek al, FP16 ve nicelenmiş modeli yan yana çalıştır, çıktıları karşılaştır. Bu, yayınlanmış her ölçütten daha bilgilendirici.

07 / DonanımBit sayısı ile hız aynı şey değil

Yaygın yanılgı: bit sayısını yarıya indirdim, iki kat hızlanmalı. Gerçekte çıkarımın iki farklı rejimi var ve niceleme yalnızca birinde yardım eder.

Bellek bağımlı aşama — token token üretim. Her adımda tüm ağırlıkları bellekten okumak gerekir. İşlem birimleri boş bekler. Burada niceleme doğrudan kazanç: yarı bellek, yarı okuma süresi.

Hesap bağımlı aşama — istemi işleme (prefill), toplu iş. Matris çarpımları doyurulmuş durumda; işlem birimleri boş beklemiyor. Burada niceleme neden yardım etmiyor, adım adım bakalım.

Ağırlığı 4 bit sakladın, tamam. Ama bilgisayar 4 bit'lik sayılarla çarpma yapamıyor — çarpmayı yapan devreler daha büyük sayılarla çalışıyor. Yani çarpımdan hemen önce, her 4 bit'lik ağırlık tekrar açılıp büyütülüyor (16 bit'e). Çarpma o büyük halde yapılıyor.

Sonuç: ağırlığı küçültmek çarpmayı hızlandırmıyor, çünkü çarpma yine büyük sayılarla oluyor. Üstüne, o açma işleminin kendisi ekstra zaman yiyor. Bu aşamada niceleme cepten harcatıyor.

Tek çıkış yolu, açmayı çok hızlı yapan özel yazılım. Marlin tam bunun için yazılmış: açma maliyetini çarpmanın gölgesine saklayarak teorik hıza yaklaştırıyor. Ama bu bir kaçış, çözüm değil.

Asıl çözüm, sayıları hiç açmadan doğrudan küçük halde çarpabilmek — ki bunun için donanımın o küçük boyutu yerel desteklemesi gerekiyor. Eski kartlar 4 bit çarpmayı desteklemez, hep açmak zorundasın. Yeni Blackwell nesli ise 4 bit'i (FP4) doğrudan destekliyor — ilk kez açma gerekmeden, gerçek hızlanmayla. Yakın gelecekte "hangi bit genişliği" sorusunun cevabını algoritma değil, kartın kendisi belirleyecek.

08 / KararNe zaman hangisi

Kaba bir karar ağacı:

  1. Model zaten sığıyor ve hız yeterli. Niceleme yapma. Ücretsiz kalite kaybı satın alıyorsun.
  2. Bellek sınırında, kalite kritik. 8 bit ağırlık (W8A16). Kayıp neredeyse ölçülemez, kazanç gerçek.
  3. Belleğe sığmıyor. 4 bit ağırlık, grup 128, AWQ ya da GPTQ. Kendi görevinde doğrula.
  4. Uzun bağlam, çok eşzamanlı istek. Önce KV önbelleğini nicele. Ağırlıklardan daha çok kazandırır.
  5. Tüketici donanımı, CPU. GGUF, Q4_K_M ile başla.
  6. 2–3 bit gerekiyor. PTQ yetmez. QAT'e bütçe ayır ya da daha küçük bir modeli tam hassasiyette çalıştırmayı düşün.

Son maddeyi genişletmek gerek, çünkü en çok atlanan karşılaştırma bu. 4 bit'e nicelenmiş 70B model mi, tam hassasiyette çalışan 13B model mi? Bellek kullanımları benzer. Cevap görevine bağlı: geniş bilgi gerektiren sorularda büyük-nicelenmiş kazanıyor, hassas muhakeme ve kod üretiminde küçük-tam sıklıkla öne geçiyor. Kimse senin adına bu testi yapmadı.

Niceleme mühendisliğin en dürüst alanlarından biri, çünkü ödünleşme gizlenemiyor. Bit alıyorsun, kalite veriyorsun. Tek soru, verdiğin şeyin senin için ne kadar değerli olduğu — ve bunu ancak kendi verinle öğrenirsin.

No. 02 — Teknik 10 Temmuz 2026
Teknik · No. 0310 Temmuz 2026

Pruning: ağın nesini kesebilirsin.

Bir sinir ağının ağırlıklarının çoğu, çıktıya neredeyse hiç dokunmuyor. Öyleyse at gitsin. Kulağa basit geliyor — ta ki neyi kestiğinde donanımın gerçekten hızlandığını sorana kadar. Aşağısı, budamanın hangi biçiminin bellek kazandırdığı, hangisinin sadece kâğıt üstünde kaldığı üzerine.

Bir sinir ağını eğitirsin, milyarlarca ağırlık öğrenir. Sonra oturup tek tek bakarsın: bu ağırlıkların çoğu sıfıra çok yakın. O kadar küçük ki, çıkarttığında modelin cevabı neredeyse değişmiyor. Pruning — budama — tam olarak bunu yapmak: katkısı ihmal edilebilir olan bağlantıları kesip atmak ve geriye kalan daha küçük ağla yaşamaya devam etmek.

Sezgi eski. 1989'da LeCun'un "Optimal Brain Damage" makalesi, bir ağırlığı sildiğinde kaybın ne kadar artacağını ikinci türevlerle tahmin edip en zararsızları budamayı önerdi. O günden beri model on binlerce kat büyüdü, sezgi aynı kaldı: her parametre eşit doğmaz, bazıları silinmeyi hak eder.

Basit de görünüyor. Üretimde basit değil. Çünkü "ağırlığı sıfırladım" demek ile "model bellekte küçüldü ve daha hızlı çalışıyor" demek arasında derin bir uçurum var. Bu yazının tamamı o uçurum üzerine.

Bir ağırlığı sıfır yapmak onu silmez. Bellekte hâlâ orada duruyor — sadece değeri sıfır olan bir kayan noktalı sayı.

01 / TemelNeden bu kadar çoğu kesilebiliyor

Modern ağlar aşırı parametreli (over-parameterized) eğitilir. Bu bir kaza değil, bir tercih: geniş bir ağ, kayıp yüzeyinde iyi bir çözüme ulaşmayı kolaylaştırır. Eğitim optimizasyonu, çok sayıda gereksiz yol açık olduğunda daha rahat iniyor. Ama eğitim bittiğinde o bolluğun tamamına ihtiyaç kalmıyor.

Bunu düşündüren gözlem şu: eğitilmiş bir ağın ağırlık dağılımına baktığında, kütlenin büyük bölümü sıfırın çevresinde toplanmıştır. Yani pek çok bağlantı zaten "neredeyse yok". Onları tam olarak yok yapmak, dağılımın kuyruğunu değil, tepesinin hemen yanını temizlemek demek.

Saha notu

Büyük dil modellerinde ağırlıkların %40–%50'sini yapısız biçimde budayıp kaybı neredeyse ölçülemez tutmak mümkün. Ama bu %50, çoğu donanımda tek bir milisaniye bile kazandırmıyor. Nedeni ikinci bölümde.

02 / AyrımNeyi kesiyorsun — asıl soru bu

Bütün mesele tek bir ayrımda düğümleniyor: kestiğin şey ağın içinde nasıl bir desen oluşturuyor? İki uç var, ve pratikteki her şey bu ikisinin arasında.

Yapısız budama (unstructured)

Tek tek ağırlıkları kesersin. Matriste nereye denk gelirse. Sonuçta ortaya seyrek (sparse) bir matris çıkar: içinde delikler olan, ama deliklerin hiçbir düzeni olmayan bir tablo. En yüksek esneklik, en yüksek sıkıştırma oranı buradadır — çünkü hangi ağırlığın gereksiz olduğuna hücre hücre karar verirsin.

Yapılı budama (structured)

Tek ağırlık değil, bütün bir birim kesersin: bir nöron, bir kanal, bir dikkat başlığı, hatta bütün bir katman. Matristen bir satırı ya da sütunu tümüyle çıkarırsın. Esneklik düşük — çünkü içinde işe yarar ağırlıklar olsa bile bütün grubu feda edersin — ama geriye kalan yine dolu, düzenli, küçük bir matristir.

Yapısız budama daha çok kesip aynı hızda kalır. Yapılı budama daha az kesip gerçekten hızlanır. Fark, donanımın seyrekliği kullanabilmesinde.

Bu ayrım, budamanın en çok yanlış anlaşılan yeri. O yüzden ikisini ayrı ayrı, ne kazandırıp ne kaybettikleriyle açalım.

03 / YapısızDelikli matrisin bedeli

Yapısız budama en yüksek teorik oranı verir: bir matrisin ağırlıklarını mutlak değerine göre sırala, en küçük %50'yi sıfırla, kaybı doğrula. Çoğu durumda kalite şaşırtıcı derecede korunur. Kâğıt üstünde model yarıya inmiştir.

Sorun donanımda. Bir katmanın yaptığı iş, özünde çarpmadır: her çıktı, girdilerin ağırlıklarla çarpılıp toplanmasıyla bulunur — ağın içindeki hesap, milyarlarca girdi × ağırlık işleminden ibaret. Budamanın hız umudu da buradan doğar: bir ağırlık sıfırsa girdi × 0 = 0 olacağından, o çarpmayı hiç yapmasan da sonuç değişmez. Atlarsan zaman kazanırsın — teoride.

Pratikte iş karışıyor, çünkü GPU düzenli işi sever: matristeki sayıları bitişik bloklar hâlinde topluca okur ve işlem birimlerini doldurur, böyle akıcı çalışır. Ama ağırlıkları rastgele yerlerden budadığında, sıfırlar matrise gelişigüzel serpilir — ve bu düzensizlik GPU'nun akışını bozar.

Üstelik bir sıfırı atlayabilmen için önce onun nerede olduğunu bir yerde yazılı tutman, sonra her çarpımda "burası sıfır mıydı?" diye kontrol etmen gerekir. O konum listesi bellekte yer kaplar, o kontrol de zaman harcar. Yani kazandığını sandığın şeyi geri ödersin.

Seyrek bir matrisi saklamanın yaygın yolu, bütün tabloyu değil yalnızca sıfır olmayan değerleri, üstüne de her birinin hangi konumda durduğunu tutmaktır. Yani "değer" ile "adres" ayrı listelerde taşınır: biri sayının kendisini, diğeri onun matriste nereye düştüğünü söyler. Sıfırlar hiç yazılmaz — zaten kaydetmediğin şey yer kaplamaz.

Ama bedeli burada saklı: her değeri artık yanında bir adresle birlikte taşıyorsun. Matrisin yarısını sıfırladın ama sakladığın veri yarıya inmedi — çünkü o adresler de yer tutuyor. Üstelik GPU bu dağınık yapıyı, düzenli bir bloğu okuduğu hızda okuyamaz; belleğin içinde oradan oraya zıplar. Sonuç ikisi bir arada: bellek beklediğin kadar düşmez, hız ise çoğu zaman hiç artmaz, hatta bazen düşer.

İşte bu yüzden yapısız budama uzun süre "teoride şık, pratikte işe yaramaz" diye anıldı. Sıfırlar oradaydı ama kimse onlardan bir kazanç çıkaramıyordu.

Yarı yapılı: 2:4 seyreklik

İki uç arasına donanımın sığdığı bir orta yol var. Modern NVIDIA kartları (Ampere ve sonrası) tek bir spesifik deseni doğrudan destekliyor: her dört ardışık ağırlıktan tam ikisi sıfır. Buna 2:4 seyreklik deniyor.

Bu desen bir kısıt getiriyor — nereyi keseceğine tümüyle serbest değilsin, her dörtlü blokta tam iki kurban seçmek zorundasın — ama karşılığında donanım o deseni tanıyor. Sıfır konumlarını rastgele saklamak yerine, her dörtlü için 2 bitlik sabit bir maske yetiyor ve tensör çekirdekleri bu maskeyi okuyup atlanacak çarpımları gerçekten atlıyor.

2:4 seyreklik — her 4'lünün 2'si sıfır

blok:   [0.8, 0.0, 0.0, 0.3]   ✓ 2 sıfır
blok:   [0.0, 0.5, 0.1, 0.0]   ✓ 2 sıfır
blok:   [0.9, 0.2, 0.0, 0.0]   ✓ 2 sıfır
        └── maske 2 bit/eleman, çekirdek doğrudan atlar
Sık atlanan

2:4, "%50 seyreklik" gibi görünse de yapısız %50 ile aynı şey değil. Kısıt yüzünden kalite biraz daha düşer, ama karşılığında gerçek hızlanma gelir — çoğu iş yükünde ~1.5–1.7 kat. Yapısız %50 tipik olarak 1.0 kat verir. Aynı oranda kesiyorlar ama faturayı yalnızca 2:4 düşürüyor — çünkü hızlanmayı getiren kesme oranı değil, donanımın o deseni tanıması.

04 / YapılıBütün bir birimi çıkarmak

Asıl güvenilir hızlanma yapılı budamada. Bir doğrusal katmandaki bir nöronu (yani ağırlık matrisinin bir satırını) tümüyle silersen, matris fiziksel olarak küçülür: 8192×8192 iken 8192×7168 olur. Ortada delik yok, koordinat saklama yok, özel çekirdek yok. Sadece daha küçük bir yoğun matris — ve her donanım küçük yoğun matrisi hızlı çarpar.

Transformer'da yapılı budamanın doğal hedefleri var:

  • Dikkat başlıkları. Çok başlıklı dikkatte başlıkların çoğu, eğitim sonrası bakıldığında ya birbirini tekrar ediyor ya da neredeyse hiç aktive olmuyor. Bütün bir başlığı çıkarmak, o başlığın Q/K/V/O projeksiyonlarındaki ilgili dilimleri birlikte siler.
  • FFN ara nöronları. Besleme-ileri katmanın gizli boyutu genelde model boyutunun dört katıdır ve en çok gevşeklik burada. Ara boyutu %30–%40 kısmak çoğu modelde ucuz.
  • Bütün katmanlar (derinlik budaması). Bazı katmanların girdiyle çıktısı neredeyse aynı — katman kimliğe yakın bir dönüşüm yapıyor. Böyle katmanları tümden atlamak, en agresif ama bazen en etkili yöntem.
Yapısız budama modeli seyrekleştirir. Yapılı budama modeli küçültür. Faturayı düşüren ikincisidir.

Bedeli de açık: bir başlık ya da nöron içinde işe yarar ağırlıklar da vardır, onları da feda edersin. Bu yüzden yapılı budama aynı kalite bütçesinde yapısızdan daha az kesebilir. Takas nettir — daha az kes, ama kestiğin gerçekten kâra geçsin.

05 / ÖlçütHangi ağırlık gereksiz — nasıl bilinir

Neyi keseceğine karar vermek, budamanın kalbi. En basit ölçütten en pahalısına doğru gidelim.

Büyüklük (magnitude)

En yaygın ve en ucuz sezgi: mutlak değeri küçük ağırlık, önemsiz ağırlıktır. Sırala, en küçükleri at. Çoğu durumda şaşırtıcı derecede iyi çalışır, çünkü küçük ağırlık gerçekten çıktıya az katkı yapar. Hesabı bedava — sadece ağırlıklara bakarsın, veri gerekmez.

Ama körü bir ölçüt: küçük bir ağırlık, girdisi sürekli büyükse çıktıya aslında çok katkı yapıyor olabilir. Büyüklük tek başına bu durumu göremez.

Aktivasyona duyarlı önem

Daha iyi soru şu: bu ağırlığı sıfırlarsam çıktı ne kadar değişir? Bu, ağırlığın büyüklüğüyle o ağırlıktan geçen tipik aktivasyonun büyüklüğünü birlikte tartmayı gerektirir. Bunun için modele biraz kalibrasyon verisi geçirip her ağırlığın gördüğü girdi ölçeğini gözlemlersin.

# Önem = |ağırlık| değil, |ağırlık × tipik girdi|.
# Küçük ağırlık büyük aktivasyon görüyorsa aslında önemli.

# X: kalibrasyon aktivasyonları [örnek, giriş_boyutu]
act_scale = X.abs().mean(dim=0)          # kanal başına tipik ölçek

# W: [çıkış, giriş] — her sütun bir giriş kanalına karşılık gelir
importance = W.abs() * act_scale.unsqueeze(0)

# En düşük önemli %p'yi maskele
thresh = torch.quantile(importance, p)
mask   = importance > thresh
W_pruned = W * mask

Bu fikir, niceleme tarafındaki aykırı-değer sezgisiyle akraba: orada da "büyük aktivasyon gören kanal" özel muamele görüyordu. Budamada da aynı kanal, kesilmemesi gereken kanaldır.

İkinci türev (Hessian)

En ilkesel yöntem, 1989'daki asıl fikre döner: bir ağırlığı silmenin kayba maliyetini, kayıp yüzeyinin eğriliğinden (Hessian) tahmin et. Modern büyük modellerde tam Hessian imkânsız, ama yaklaşık hâlleri (ör. OBS türevleri) hâlâ en doğru budama kararlarını veriyor — karşılığında hesap pahalı.

ÖlçütNeye bakarMaliyet
BüyüklükYalnız |ağırlık|Bedava, veri gerekmez
Aktivasyon|ağırlık × girdi|Ucuz, kalibrasyon verisi
HessianKayba gerçek etkiPahalı, en doğru

06 / OnarımKesip bırakmak yetmez

Buraya kadar hep "kes" dedik. Ama bir ağı bir kerede %50 budayıp bıraktığında, kayıp genellikle ihmal edilebilir olmaz — model gözle görülür biçimde bozulur. Kritik adım kesmenin kendisi değil, kesme sonrası onarım.

İki temel yaklaşım var:

  1. Yeniden eğitimle onarım (fine-tuning). Buda, sonra kalan ağırlıkları birkaç adım eğit ki kaybı telafi etsinler. Klasik reçete tek seferde değil kademeli budamaktır: biraz kes, biraz eğit, tekrar kes. Ağın deseni yavaşça seyrekliğe uyum sağlar. Pahalı ama en yüksek kaliteyi verir.
  2. Eğitimsiz onarım. Büyük modellerde yeniden eğitim çoğu zaman lüks. Bunun yerine, kalan ağırlıkları kapalı formda güncelleyip budamanın çıktı üstündeki hatasını en aza indiren yöntemler var — SparseGPT bunu katman katman, bir en-küçük-kareler problemi çözerek yapıyor. Tek GPU'da, tek geçişte, yeniden eğitim olmadan büyük bir modeli budayabiliyorsun.
2:4Donanımın desteklediği
tek seyreklik deseni
1.5×2:4'ün getirdiği
gerçek hızlanma
~50%Yapısız budamada kaliteyi bozmadan
çıkılabilen tipik seyreklik sınırı

07 / KırılmaNerede beklenmedik biçimde bozuluyor

Ortalama kayıp korunuyor diye her şey yolunda sanmak, budamanın en pahalı hatası. Niceleme tarafındaki perplexity yanılgısının kardeşi burada da var: toplam metrik korunurken belirli yetenekler sessizce çöküyor.

  • Uzun kuyruk bilgi. Nadir olguları taşıyan, seyrek aktive olan ağırlıklar tam da büyüklüğü küçük olanlar — yani budamanın ilk kurbanları. Model genel konularda akıcı kalır, spesifik sorularda unutmaya başlar.
  • Çok adımlı muhakeme. Her katmandaki küçük sapmalar zincir boyunca birikir. Tek adımlık görevde görünmez, uzun akıl yürütmede yanlış cevaba çıkar.
  • Ana dil dışı diller. Türkçe dahil, eğitim verisinde az temsil edilen dillerin karşılıkları zaten zayıf ağırlıklarda taşınır. Budama önce onları keser.
  • Kalibrasyon önyargısı. Aktivasyona duyarlı budamada, kalibrasyon verisi neyi temsil ediyorsa model onu korur. Kalibrasyonu İngilizce metinle yaptıysan, kod ve çok dilli yetenek orantısız zarar görür.
Ortalama kaybı değil, görevini ölç. Buda, sonra kendi verinle FP16'yla yan yana koy. Yayınlanmış her seyreklik oranından çok daha bilgilendirici.

08 / KararNe zaman hangisi

Kaba bir karar ağacı:

  1. Amaç bellek değil, gecikme. Yapısız budamayı unut — hız kazandırmaz. Yapılıya ya da 2:4'e git.
  2. Ampere+ GPU, ılımlı sıkıştırma. 2:4 seyreklik. Donanım destekli, ~1.5 kat gerçek hızlanma, kalite kaybı yönetilebilir.
  3. Modeli fiziksel olarak küçültmek gerek. Yapılı budama — başlık, FFN nöronu, katman. Sonra mutlaka onarım eğitimi.
  4. Yeniden eğitim bütçesi yok. SparseGPT tarzı eğitimsiz onarım. Tek geçiş, tek GPU.
  5. Agresif hedef (%70+). Tek yöntem yetmez. Budamayı nicelemeyle birleştir; ikisi büyük ölçüde bağımsız kazanç veriyor.

Son bir karşılaştırma, en çok atlanan. %50 budanmış büyük model mi, baştan küçük eğitilmiş model mi? Genelde budanmış-büyük kazanır, çünkü küçük ağın hiç öğrenemediği temsilleri o bir kez öğrenip sonra seyrekleştirmiştir. Ama bu görevine bağlı ve kimse senin adına ölçmedi.

Budama, nicelemenin akrabası: ikisi de modelden bir şey alıp yerine verim koyuyor. Fark şu — niceleme her ağırlığı biraz kabalaştırır (en yakın dilime yuvarlayarak), budama bazı ağırlıkları tümden siler. Hangi kaybın senin görevine daha ucuz geleceğini, yine yalnızca kendi verinle öğrenirsin.

No. 03 — Teknik 10 Temmuz 2026
Teknik · No. 0417 Temmuz 2026

Fine-tuning: modeli ne zaman değiştirmelisin.

Fine-tuning, ilk akla gelen çözüm olduğunda genellikle yanlış çözümdür. Çoğu ekip istem mühendisliğiyle çözülebilecek bir problemi eğitim problemi sanıyor ve haftalarını GPU faturasına yatırıyor. Aşağısı, ne zaman gerektiği ve gerektiğinde nasıl yapıldığı üzerine.

Bir dil modeli, eğitimi bittiğinde bir ağırlık dosyasıdır. Yetmiş milyar sayı, donmuş. Onu davranışını değiştirmek istediğinde iki kolun var: istemi değiştirmek — model sabit, girdiyi düzenliyorsun — ya da ağırlıkları değiştirmek — modelin kendisini oynatıyorsun.

Fine-tuning ikincisidir. Ve ikincisi, birincisi yetmediğinde yapılır. Sırayı ters çevirmek, alandaki en pahalı alışkanlık.

Mekanik açık. Eğitilmiş bir modeli al, kendi verinle birkaç adım daha eğit, ağırlıklar senin dağılımına doğru kaysın. Kazanç da açık — modelin çıktı biçimi, tonu, alan jargonu senin istediğin hâle gelir; her istemde otuz satır talimat taşımaktan kurtulursun.

Anlaşmazlık şurada başlıyor: fine-tuning modele ne öğretir? Sorunun cazip cevabı "ne istersen" — ve bu cevap, üç haftalık bir eğitim döngüsünün sonunda yanlış olarak ortaya çıkabilir. O noktada öğrendiğin şey pahalıdır: GPU faturası, kaybedilen zaman ve elinde kalan, görevinde iyi ama başka her şeyde bozulmuş bir model.

Doğru cevap daha dar. Fine-tuning modelin neyi bildiğinden ziyade nasıl davrandığını değiştirir. Ağırlıkları senin dağılımına doğru iter — biçim, ton, refleks oynar. Olgu oynamaz.

Buradaki itiraz haklı ve sık gelir: "peki model alanı hiç bilmiyorsa, ona eğitimle öğretemez miyiz?" Cevap ölçekte saklı. Birkaç bin örnek, ön eğitimdeki trilyonlarca tokenın yanında bir fısıltı. O fısıltı var olanı biçimlendirebilir. Model alanı gerçekten hiç bilmiyorsa çözüm fine-tuning değil, continued pretraining — milyarlarca tokenlık alan korpusuyla ön eğitimi sürdürmek. Ayrı bir bütçe kategorisi, ayrı bir problem.

Ve pratikte "hiç bilmiyor" durumu neredeyse hiç olmaz. Model alanı kıyısından biliyordur; fine-tuning onu bir uzman gibi konuşturur. Ama şirketinin dünkü politikası modele eğitimle girse bile politika yarın güncellendiğinde yeniden eğitmen gerekir. Bu ayrımı baştan yapmazsan RAG işini eğitime yıkarsın. Eğitim o işi yapmayı reddetmez; sessizce kötü yapar.

Fine-tuning modele bilgiden ziyade biçim öğretir. Modelin neyi bildiğinden ziyade nasıl davrandığını değiştirir.

01 / ÇerçeveYanlış problem seçimi

Çoğu ekip şu soruyla başlıyor: "Hangi fine-tuning yöntemini kullanmalıyım?" Bu, yanlış yerden giriş. Doğru sıra tersine işliyor:

  1. Problem gerçekten eğitim problemi mi? Model senin alan terminolojini bilmiyorsa bu bir RAG problemi. Çıktıyı yanlış biçimde veriyorsa bu bir istem problemi. Bunlar fine-tuning'e gitmeden çözülür ve çok daha ucuza çözülür.
  2. İstem mühendisliği nerede tıkandı? Birkaç örnekli (few-shot) istemle görev çözülüyor ama örnekler bağlamda çok yer kaplıyorsa, işte bu fine-tuning'e giden makul yol. Hiç denemediysen henüz o yolda değilsin.
  3. Yeterli veri var mı? Elindeki yeterli sayıda etiketli verinin temiz olması gerekir. Beş bin gürültülü örnek, beş yüz temiz örnekten kötü sonuç verir.

Ancak bundan sonra yöntem seçilir.

Saha notu

Bir müşteri destek sınıflandırıcısı için fine-tuning talebi geldi. Önce istem incelendi: sistem isteminde kategori tanımları eksikti, birkaç örnek yoktu. İki saat istem düzeltmesi, doğruluğu %71'den %89'a çıkardı. Fine-tuning hiç yapılmadı. Bu, alandaki en yaygın senaryo.

02 / AyrımNeyi öğretebilirsin, neyi öğretemezsin

Fine-tuning'in gerçekten iyi öğrettikleri

  • Biçim ve yapı. Belirli bir JSON şeması, belirli bir rapor düzeni, belirli bir çıktı uzunluğu. Model bunu birkaç yüz örnekle sağlam biçimde öğrenir.
  • Ton ve üslup. Kurumsal ses, teknik ciddiyet, kısalık. İstemde tarif etmesi zor, örnekle göstermesi kolay şeyler.
  • Görev davranışı. Sınıflandırma sınırları, ne zaman çekimser kalacağı, hangi adımı hangi sırayla yapacağı.
  • Alan jargonunu kullanma. Terimi doğru bağlamda, doğru refleksle kullanması.

Fine-tuning'in kötü öğrettikleri

  • Muhakeme yeteneği. Model zaten yapamadığı bir akıl yürütmeyi, örnek göstererek öğrenmez. Taklit eder, çuvallar.
  • Uzun kuyruk olgular. Nadir bilgiyi eğitimle yerleştirmek, seyrek aktive olan ağırlıkları oynatmayı gerektirir — ve o ağırlıklar bir görevi öğrenirken başka bir şeyi unutur.
Model bir şeyi bilmiyorsa ona söyle. Bir şeyi yanlış biçimde yapıyorsa ona göster. İlki bağlam, ikincisi eğitim.

03 / YöntemLoRA ve düşük ranklı uyarlama

Tam fine-tuning bütün ağırlıkları oynatır ve bunun bedeli, model dosyasının boyutuna bakarak tahmin edilemez. Somut olsun diye baştan sona tek bir örnek üzerinden gidelim: 70 milyar parametreli bir model, BF16 ağırlıkla, Adam optimizatörüyle. Sayılar başka bir kurulumda değişir — nerede değiştiğini yeri geldikçe söyleyeceğim — ama oranlar aynı kalır.

Kaba bir kural: bu kurulumda parametre başına 16 bayt civarı. Sayı kafa karıştırıcı, çünkü ağırlık dosyasında parametre başına yalnızca 2 bayt duruyor. Eğitim sekiz katını istiyor. Nereden geldiğine bakalım.

Sebep şu: eğitim sırasında bir parametre hakkında dört ayrı şey bellekte durmak zorunda.

  • Ağırlığın kendisi — 2 bayt. BF16, ileri geçişte kullanılan hâli. Dosyada duran şey de bu.
  • Gradyanı — 2 bayt. Geri geçişte her parametre için "kaybı azaltmak isteseydim bu sayıyı hangi yöne oynatmalıydım" bilgisi hesaplanır. Parametre başına bir sayı, yani ağırlıklar kadar yer.
  • Optimizatör durumu — 8 bayt. Adam, gradyanı doğrudan kullanmaz. Parametre başına iki şey biriktirir: gradyanların hareketli ortalaması (momentum) ve gradyan karelerinin hareketli ortalaması (ikinci moment). İkisi de FP32'de tutulur, çünkü bunlar zamanla biriken küçük sayılar — BF16'nın hassasiyeti burada yetmez, güncellemeler yuvarlamada kaybolur. 2 × 4 bayt = 8 bayt.
  • Ana ağırlık kopyası (master weights) — 4 bayt. Karışık hassasiyetli eğitimin sessiz maliyeti. İleri geçiş BF16'da yapılır ama güncelleme FP32 kopyada birikir, sonra BF16'ya yuvarlanıp geri yazılır. Neden: tipik bir güncelleme, ağırlığın kendisinden binlerce kat küçüktür. BF16'da o küçük değişikliği doğrudan eklersen yuvarlama onu yutar ve parametre hiç oynamaz. FP32 kopya bu birikimi tutar.
ağırlık (BF16)                  2 bayt
gradyan (BF16)                  2 bayt
Adam momentum (FP32)            4 bayt
Adam ikinci moment (FP32)       4 bayt
ana kopya (FP32)                4 bayt
                               ────────
                               16 bayt / parametre

Örneğimize dönelim. 70 milyar parametre × 16 bayt ≈ 1.1 TB. Aktivasyonlar buna dahil değil — geri geçişte kullanılmak üzere saklanan ara değerler, ki onlar toplu iş boyutu ve dizi uzunluğuyla ayrıca büyür.

Aynı modelin çıkarımda ne istediğine bakalım. Cevap üretirken gradyan hesaplanmıyor, Adam çalışmıyor, güncelleme yok. Tablodan yalnızca ilk satır kalıyor: 70 milyar × 2 bayt = 140 GB. Model aynı model, aynı dosya, aynı 70 milyar sayı. Farkı yaratan ona ne yaptığın.

Bu yüzden "modeli çalıştırabiliyorum, o hâlde eğitebilirim de" yanlış bir çıkarım. Arada sekiz kat var ve tamamı eğitimin ek yüklerinden geliyor.

Sayılar nerede oynar

16 bayt, bu kurulumun sayısı — sabit bir yasa değil. Optimizatörü değiştirirsen düşer: SGD momentum ile parametre başına tek durum tutar, Adafactor ikinci momenti sıkıştırır, 8 bit Adam optimizatör durumunu dörtte birine indirir. Kartlar arasında bölersen (ZeRO, FSDP) toplam değişmez ama kart başına düşen düşer. Checkpointing aktivasyon tarafını ucuzlatır, bu tabloya dokunmaz. Çıkarım tarafındaki 140 GB da hassasiyete bağlı: FP8'de 70 GB, 4 bit'te 40 GB civarı.

Ama hepsi aynı yerde tıkanıyor: kaç parametre eğitiyorsan, o parametre başına maliyeti o kadar kez ödüyorsun. Çarpanı küçültebilirsin. Çarpılan sayıyı küçültmedikçe duvar aynı yerde duruyor.

LoRA eğitilen sayı adedini düşürüyor — çarpılan sayıyı, çarpanı değil.

Fikir şu: fine-tuning modeli baştan yazmıyor, kenarından itiyor. Küçük bir dokunuş. Öyleyse o dokunuşu milyonlarca ayrı sayıyla tarif etmeye gerek yok.

Tek bir katmana bakalım

Örneğimizdeki modelin içinden bir ağırlık matrisi alalım: W.

W bir tablo — 8192 satır, 8192 sütun. Bu 8192, modelin gizli boyutu: model içeride her kelimeyi 8192 sayılık bir vektörle temsil ediyor, katman 8192 sayı alıp 8192 sayı veriyor. O yüzden tablo kare.

Tablodaki her hücrede bir sayı var:

8192 × 8192 = 67.108.864     →  kabaca 67 milyon sayı

Tam fine-tuning'de bu 67 milyonun hepsini eğitirsin — her biri için gradyan, momentum, FP32 kopya.

LoRA ne yapıyor

W'ye hiç dokunmuyor. Yanına iki ince tablo koyuyor: A ve B.

  • A gelen 8192 sayıyı 16 sayıya sıkıştırıyor
  • B o 16 sayıyı tekrar 8192'ye açıyor

Bu iki adım birleşince W boyutunda bir düzeltme çıkıyor ve W'nin üstüne ekleniyor. Model artık farklı davranıyor — W hiç değişmeden.

Şimdi bu iki tablonun büyüklüğüne bakalım:

A:  16 satır × 8192 sütun  =  131.072 sayı
B:  8192 satır × 16 sütun  =  131.072 sayı
                              ─────────
                               262.144 sayı

İkisi de ince: bir kenarı 8192, diğer kenarı sadece 16.

Kazanç

W'yi eğitseydin:   67.108.864 sayı
A + B ile:            262.144 sayı

262.144 / 67.108.864 = %0.4

Aynı işi görüyor, 256 kat az sayıyla. Kazanç doğrudan önceki tablodan geliyor. W bellekte durmak zorunda — ileri geçişte kullanılıyor — ama sadece ilk satırı kadar: 2 bayt. Gradyanı yok, momentumu yok, FP32 kopyası yok. 16 baytlık tam maliyeti artık yalnızca A ve B'nin 262.144 sayısı ödüyor.

Nasıl mümkün

W'nin 67 milyon hücresinin hepsi değişiyor. Düzeltme, boş hücre bırakmıyor.

Ama o 67 milyon düzeltmeyi tek tek seçmiyorsun — 262.144 sayıdan üretiyorsun. Hepsi var, hepsi birbirine bağlı: bilgi 8192 boyuttan 16'ya iniyor, oradan tekrar 8192'ye çıkıyor. Ortadaki o daralma, düzeltmenin ne kadar çeşitlenebileceğini belirliyor.

Bedeli de bu. Tam fine-tuning'de düzeltme matrisi tamamen serbest — 67 milyon hücre, 67 milyon bağımsız karar. LoRA'da hücreler bağımsız değil; hepsi aynı 16 boyutluk ara adımdan türetiliyor. Düzeltme daha az çeşitli. Pratikte bu kısıt çoğu iş için sorun olmuyor, çünkü fine-tuning'in ihtiyaç duyduğu değişim zaten dar bir alanda kalıyor.

O 16 nereden geliyor

Bir yerden gelmiyor — sen seçiyorsun. Adı rank, kısaca r. Dar geçidin genişliği tam olarak bu.

Küçük rank → dar kanal, az öğrenir, az bozar
Büyük rank → geniş kanal, çok öğrenir, çok unutur

16, çoğu işte oturan değer.

04 / AyarRank, alfa, hedef katmanlar

Üç hiperparametre. Üçü de yanlış anlaşılıyor.

Rank

Az önce gördük: A'nın çıktı boyutu, yani adaptörün kapasitesi. Eğitilen sayı adedi rank ile doğrusal artıyor.

RankEğitilen payNerede yeter
4–8~%0.1Ton, biçim, dar sınıflandırma
16~%0.4Çoğu görev. Varsayılan olarak buradan başla.
32–64~%1.5Karmaşık görev davranışı, çok adımlı akış
128+~%3Nadiren gerekli. Tam fine-tuning'i düşünmeye başla.

Rank'i büyütmek düşündüğün kadar kazandırmıyor. 16'dan 64'e çıkmak eğitilen parametreyi dörde katlar, ama kaliteyi çoğu zaman ancak kıl payı artırır — çabaya değmeyecek kadar küçük bir fark. Buna karşılık unutma riskini belirgin yükseltir. Kapasite arttıkça model taban davranışından daha rahat uzaklaşıyor; istediğin şey buysa iyi, değilse zarar.

Alfa

Formüldeki çarpan: alfa / r. Tek işi var — adaptörün ürettiği düzeltme W'ye eklenirken ne kadar güçlü eklensin, onu ayarlamak. Büyük alfa → düzeltme daha baskın. Küçük alfa → daha yumuşak.

Yaygın gelenek alfa = 2r. r=16 ise alfa 32, çarpan da 2 olur. Bunun kutsal bir kural olduğu sanılıyor, değil — sadece pratikte iyi çalışan bir başlangıç.

Faydası şurada. Rank'i değiştirdiğinde alfayı da orantılı büyütürsen çarpan sabit kalır:

r=16,  alfa=32   →  çarpan 2
r=64,  alfa=128  →  çarpan 2

İkisi aynı şiddette düzeltme veriyor. Böylece farklı rank'ler denerken tek bir şeyi değiştirmiş oluyorsun — sadece kapasiteyi. Alfayı sabit bırakıp rank'i oynatırsan hem kapasite hem şiddet birden değişir, sonucun hangisinden geldiğini ayıramazsın.

Kısaca: rank'i oynat, alfayı ona oranla büyüt.

Hedef katmanlar

Bir transformer modelinin içinde çok sayıda ağırlık tablosu var. Hatırla: LoRA bir ağırlık tablosunun (W) yanına iki ince tablo (A ve B) ekliyordu. "LoRA'yı bir katmana uygulamak" tam olarak bu demek — o katmanın W'sinin yanına kendi A ve B'sini koymak.

Ama modelde tek bir W yok. Her katmanın içinde bir avuç ayrı W var, model de onlarca katmandan oluşuyor. Örneğimizdeki 70B model 80 katmanlı ve her katmanda 7 ağırlık tablosu bulunuyor — toplam 560 ayrı W. Soru şu: bunların hangilerine uygulayacaksın? Hepsine mecbur değilsin, ve bu seçim rank'ten bile daha çok fark yaratıyor.

Peki bu 560 tablo ne? Her katmanda ikiye ayrılıyorlar: dikkat tarafı ve FFN tarafı.

Dikkat tarafında dört tablo var — işte o sürekli geçen Q, K, V, O bunlar. Modelin bir kelimeyi işlerken hangi diğer kelimelere bakacağına karar verdiği yer:

  • Q (query / sorgu) — "ben ne arıyorum?"
  • K (key / anahtar) — "bende ne var?"
  • V (value / değer) — "bulunca ne alınacak?"
  • O (output / çıkış) — sonucu toparlayıp bir sonraki adıma veren tablo

Q ile K eşleşmeyi kuruyor, V içeriği taşıyor, O çıkışı topluyor. Dördü birlikte bir dikkat bloğu — ve dördü de birer W.

FFN tarafında ise dikkatten sonra gelen, modelin asıl "düşünme" ağırlıklarının çoğunu taşıyan büyük tablolar var.

Şimdi seçimler, ucuzdan pahalıya. Her seçim, LoRA'yı bu W'lerden hangilerine uygulayacağını söylüyor:

  • Yalnız Q ve V. Her katmanda dörtlünün ikisine uygula. Orijinal LoRA makalesinin önerisi. En ucuzu, çoğu görevde yeter.
  • Bütün dikkat (Q, K, V, O). Dörtlünün hepsine uygula. Biraz daha pahalı, gözle görülür daha iyi.
  • Dikkat + FFN. Büyük FFN tablolarına da uygula. En güçlü sonuç, ama unutma riski de en yüksek — çünkü modelin ana bilgisi orada.
Pratik reçete

560 tabloya da uygula, rank 16 ile başla. Bu tablolara teknik adıyla "doğrusal katman" da deniyor — Q, K, V, O ve FFN'in hepsi birer doğrusal katman, çünkü hepsi aynı işi yapıyor: gelen sayıları ağırlıkla çarpıp topluyor. Modern kütüphaneler bunu tek satırla yapıyor; ek maliyet, hangisini seçeceğini düşünmekle geçen zamanın yanında önemsiz.

Sık atlanan

Bu 560 tablonun dışında, modelin iki ucunda iki tablo daha var ve genelde listeye alınmıyor: en baştaki gömme katmanı (kelimeleri sayıya çeviren) ve en sondaki lm_head (sayıları tekrar kelimeye çeviren). Modele yeni bir çıktı biçimi ya da yeni kelimeler öğretiyorsan bu ikisi kritik. Uygulamazsan model tam o noktada eski alışkanlığına geri döner.

05 / VeriAz ve temiz, çok ve kirli değil

Fine-tuning'de veri, hiperparametrelerden önce gelir. Ve buradaki asıl eksen, çoğu ekibin sandığının aksine, hacim değil: kalite.

Yanlış anlaşılmasın — temiz kaldığı sürece daha çok veri çoğu zaman daha iyidir. 5.000 temiz örnek, 500 temiz örneği neredeyse her zaman geçer. Sorun şu ki hacim büyüdükçe temiz kalmak zorlaşıyor ve kirlenen veri eklediğinden fazlasını götürüyor.

Sebebi şu. Fine-tuning modele bir dağılım gösteriyor ve "böyle davran" diyor. Gösterdiğin örneklerden biri kötüyse, model kötü olanı da öğreniyor — üstelik kötü örnekler iyi örneklerden daha güçlü sinyal veriyor, çünkü model onları zaten kendiliğinden üretmiyordu; yeni ve yanlış olanı daha hevesle kapıyor.

Bu yüzden pratikte tavan, okuyup denetleyebildiğin veri miktarıdır. 500 örneği bir kişi iki günde tek tek okur. 50.000 örnekte bu çok zor — araya giren gürültüyü göremezsen o gürültü, hacmin kazandırdığından çok götürebilir. Önemli olan temiz veriler kullanmaktır. Az ve denetlenmiş veri, çok ve denetlenmemiş veriyi çok yüksek ihtimalle yener. İkisi eşit derecede temizse, çok olanın kazanma olasılığı çok daha yüksektir.

Veri kümesiTipik sonuç
50 mükemmel örnekBiçim ve ton oturur. Şaşırtıcı derecede iyi bir başlangıç.
500 temiz örnekÇoğu görev için sağlam nokta. Hepsi elle okunabilir.
5.000 temiz örnekDaha iyi — kalite korunduğu sürece. Denetlemesi ciddi emek.
50.000 denetlenmemişGenellikle 500 temiz örnekten kötü. Gürültü hacmi yutuyor.

Somut kurallar:

  • Her örneği gözden geçir. Beş yüz örnek, bir kişinin iki gününde okunur. Okumadıysan ne öğrettiğini bilmiyorsun.
  • Çeşitlilik, hacimden önemli. Aynı kalıbın beş yüz varyasyonu, beş yüz farklı durumdan kötü öğretir.
  • Negatif örnekleri unutma. Modelin yapmaması gerekeni de göster — çekimser kalması gereken durumları, reddetmesi gereken istekleri.
  • Değerlendirme kümesini önce ayır. Eğitim verisinden değil, gerçek dağılımdan. Ve ona hiç bakmadan eğit.

06 / HizalamaSFT'den sonrası

Denetimli ince ayar (SFT) modele "şuna böyle cevap ver" der. Yeterli olduğu yer çok, ama bir sınırı var: SFT yalnızca doğru cevabı gösterir, o cevabın alternatiflerinden neden daha iyi olduğunu göstermez.

DPO (Direct Preference Optimization) bunu değiştirir. Her örnekte iki cevap verirsin — biri tercih edilen, biri edilmeyen — ve model ikisinin arasındaki farkı öğrenir. Ödül modeli eğitmek gerekmez, RLHF'in karmaşık döngüsü burada yoktur; doğrudan bir kayıp fonksiyonu mevcuttur.

DPO için örnek girdi ve çıktılar:

# DPO veri biçimi — tek doğru değil, bir karşılaştırma.
{
  "prompt":   "Fatura iptali nasıl yapılır?",
  "chosen":   "Fatura iptali için... [kaynak: Politika 4.2]",
  "rejected": "Fatura iptali için müşteri hizmetlerini arayın."
}

Ne zaman DPO'ya geçilir: SFT'den sonra, model doğru şeyi söylüyor ama tarzı hâlâ tam oturmamışsa. Ya da iki makul cevap arasında sistematik olarak yanlışını seçiyorsa. SFT yerine değil, SFT'nin üstüne.

Tarz hâlâ oturmamışsa neden DPO?

Çünkü SFT ile DPO modele iki farklı şey öğretiyor ve "tarz" tam da DPO'nun güçlü olduğu yere düşüyor.

SFT tek bir doğru cevap gösterir: "şu soruya şöyle cevap ver." Model o cevabı taklit eder. Ama tarz — üslup, uzunluk, ton, ne kadar resmi olacağı — tek bir örnekle keskin öğretilemez. Çünkü tarz bir "doğru/yanlış" meselesi değil, bir tercih meselesi. İki cevap da olgusal olarak doğru olabilir; biri sadece daha iyi oturur.

SFT bunu ifade edemiyor. "Bu cevap doğru" diyebiliyor ama "bu doğru cevap, şu doğru cevaptan daha iyi" diyemiyor — elinde tek örnek var, karşılaştırma yok.

DPO tam da karşılaştırma veriyor: iki cevap, biri tercih edilen biri edilmeyen. İkisi de geçerli olabilir; model aradaki farkı öğreniyor. "Şu ton bunun yerine tercih ediliyor." Tarz dediğin şey birikimli olarak bu farklardan oluşuyor.

DPO'nun bedeli: tercih verisi toplamak, SFT verisi toplamaktan pahalı. Her örnek için iki cevap ve bir karar gerekiyor.

500Çoğu görev için
tatlı nokta örnek sayısı
16Varsayılan
LoRA rank
~%0.4Bu iki değerden gelen
eğitilen parametre oranı

07 / KırılmaKatastrofik unutma

Fine-tuning'in en sinsi hatası: model senin görevinde mükemmelleşirken başka her şeyde bozuluyor ve sen bunu ölçmüyorsun.

Mekanizma basit. Ağırlıkları senin dağılımına doğru itiyorsun. O ağırlıklar başka yetenekleri de taşıyordu. İtiş yeterince güçlüyse, taşıdıkları şey düşüyor.

Nerede görünüyor:

  • Genel talimat takibi. Dar bir görevde eğitilmiş model, alakasız bir istek geldiğinde eğitim görevine benzer bir şey yapmaya çalışıyor. Sınıflandırıcı olarak eğittiğin model, sohbet isteğine kategori etiketiyle cevap veriyor.
  • Çok dillilik. İngilizce veriyle eğittiysen Türkçe yetenek zarar görür. Zaten zayıf olan temsiller önce kopuyor — niceleme ve budamadaki aynı asimetri.
  • Güvenlik davranışı. Yalnızca yararlı örneklerle eğitmek, modelin reddetme refleksini zayıflatır.
  • Muhakeme. Kısa cevaplı örneklerle eğitirsen model kısa cevap vermeyi öğrenir — düşünmesi gereken yerde de.

Karşı tedbirler:

  • Düşük öğrenme oranı. Öğrenme oranı, modelin her adımda ağırlıklarını ne kadar sert oynatacağını belirler — büyük değer büyük adım demek. LoRA için 0.0001–0.0002 (yani 1e-4 – 2e-4) iyi çalışır. Tam fine-tuning yapıyorsan bunun onda birini kullan, 0.00001 civarı; çünkü orada bütün ağırlıklar oynuyor, büyük adım modeli hızla bozar. Genel kural: yüksek oran hızlı öğretir ama eskiyi de hızlı unutturur.
  • Az epoch. 1–3. Daha fazlası ezberleme ve unutma.
  • Karışık veri. Eğitim kümesine görev dışı genel örnekler serpiştir. %10–20 oranında yeter, unutmayı belirgin azaltır.
  • Düşük rank. Rank, adaptörün kapasitesi — modeli ne kadar oynatabileceği. Rank küçükse model taban davranışından fazla uzaklaşamaz, dolayısıyla eskiyi de fazla bozamaz. Unutma zaten "eskiyi bozmak" olduğu için, düşük rank onu kendiliğinden sınırlar. Bu, LoRA'nın söylenmeyen bir avantajı: kapasiteyi kıstığın anda unutmaya karşı da korunmuş olursun.
  • Geniş değerlendirme. Yalnız görevini değil, modelin eskiden yaptığı şeyleri de ölç. Eğitim öncesi ölçümünü al, sonra karşılaştır.
Görevinde %95'e çıkıp genel yetenekte %30 kaybettiysen, kazanmadın. Ve ölçmediysen, kaybettiğini bilmiyorsun bile.

08 / KararNe zaman hangisi

Kaba bir karar ağacı:

  1. Problem bilgi eksikliği. Fine-tuning yapma. RAG kur.
  2. Problem çıktı biçimi ve istemde çözülüyor. Fine-tuning yapmadan istemi, birkaç örnek ekleyerek düzeltebilirsin.
  3. İstem çalışıyor ama çok uzun / pahalı. LoRA, rank 16, bütün doğrusal katmanlar. Buradan başlayabilirsin.
  4. Bellek sınırında. QLoRA. 4 bit taban, 16 bit adaptör.
  5. SFT sonrası tarz hâlâ oturmadı. DPO ekle. SFT'nin üstüne, yerine değil.
  6. Onlarca farklı müşteri / görev. Tek taban model, çok adaptör. LoRA'nın en güçlü olduğu senaryo.
  7. Gerçekten tam fine-tuning gerekiyor. Nadiren. Ve gerekiyorsa, önce rank 128 LoRA dene — çoğu zaman farkı kapatıyor.

Son bir karşılaştırma, en çok atlanan. Fine-tuning mi, daha büyük model mi? Görevin dar ve iyi tanımlıysa, fine-tuned küçük model büyük genel modeli sıklıkla geçiyor — hem daha ucuz hem daha hızlı. Görev açık uçlu ve muhakeme ağırlıklıysa, büyük genel model neredeyse her zaman kazanıyor. Kimse senin adına bu testi yapmadı.

Fine-tuning, nicelemenin ve budamanın tersi bir işlem: onlar modelden bir şey alıp yerine verim koyuyor, bu modele bir şey ekleyip yerine genellik alıyor. Üçünde de aynı soru: aldığın şeyin karşılığında verdiğin, senin görevinde ne kadar değerli? Cevabı yine yalnızca kendi verinle bulursun.

No. 04 — Teknik 17 Temmuz 2026