8 Ön Eğitim ve Model Manzarası
Öğrenme hedefleri. Bu bölümün sonunda şunları yapabileceksiniz:
- rastgele ilklenmiş bir transformer’ı önce bir temel modele, sonra talimatlara uyarlanmış bir asistana çeviren aşamaları (ön eğitim, denetimli ince ayar, tercih ayarı) çizmek ve her aşamanın hangi veriyi, hangi amacı kullandığını söylemek;
- bir token’ı web taramasından eğitim batch’ine kadar izlemek, her filtreleme adımının neyi attığını ve neye karşı koruduğunu adlandırmak;
- açık bir veri kümesinde en agresif tekilleştirmenin (deduplication) veriyi neden kötüleştirdiğini ve bunun genel olarak kalite filtreleri hakkında ne söylediğini açıklamak;
- bir ön eğitim koşusunun hesabını parametre ve token sayısından kabaca kestirmek; varsayılan bir GPU verimiyle geçen süreyi ve kiralama maliyetini ayrıca hesaplamak ve bu kestirimin nerede geçerliliğini yitirdiğini belirtmek;
- model FLOP kullanımını (MFU) bir donanım broşürü ile bir veri merkezi arasındaki fark olarak okumak ve bu farkı doğru sebebe bağlamak;
- byte-pair encoding’in (BPE) çalışma ilkesini açıklamak ve verilen başlangıç birimleri ile birleştirme kurallarını kullanarak yeni bir kelimenin nasıl token’lara ayrılacağını belirlemek;
- bir tokenizer’ın bir dile neye mal olduğunu ölçmek ve bu bedeli bağlam penceresi, gecikme ve para cinsinden fiyatlandırmak;
- bir model sürümünü gerçekte neyi açık olarak paylaştığına göre sınıflandırmak — ağırlıklar, veri, kod, lisans — ve belirli bir görev ile bütçe için birini seçmek.
8.1 Hesap yapabilen ve hiçbir şey bilmeyen bir model
Bölüm 7’nin sonunda elimizde doğru şekle sahip ama içi boş bir makine vardı. İçindeki her matris — \(W^Q\), \(W^K\), \(W^V\), \(W_1\), \(W_2\) ve embedding tablosu — küçük rastgele sayılarla dolu. Mimari bitti. Model hiçbir şey bilmiyor. Yeni ilklenmiş, Llama şeklindeki bir ağdan kedi sütü ifadesini devam ettirmesini isteyin. Standart küçük ilklemeyle skorlar birbirine yakın olduğu için size 128.000 seçenek arasından kabaca eşit olasılıklarla seçilmiş, dil açısından anlamsız bir token verecektir.
Modelin bir gün bileceği her şey, birkaç milyon kez tekrarlanan tek bir işlemle geliyor:
ona bir metin parçası göster, sonraki token’ı tahmin etmesini iste, ne kadar yanıldığını ölç ve her parametreyi doğru token’ı daha olası kılacak yönde birazcık it.
Ön eğitimin mekanizması bu; ikincisi yok. Dilbilgisi, Fransa’nın başkenti, bir Python parantezinin nasıl kapatılacağı, Bölüm 7’deki robot ve kahve cümlesinde it’in neyi gösterdiği (hazır olan kahvedir, talimat alan robot) — hepsi, yeterince metin üzerinde tek bir tahminde iyileşmenin yan etkisi olarak geliyor; ne kadarının geldiğini veri, mimari ve optimizasyon kararları belirliyor.
Sonraki token tahmini, bu bölümün izlediği aile olan GPT ve Llama gibi yalnızca decoder’lı modellerin amacıdır. Bölüm 7.5’teki encoder modelleri aynı fikrin çeşitlemelerini kullanır. BERT (ve aşağıdaki tokenizer tablosunda karşımıza çıkacak BERTurk) token’ların yaklaşık %15’ini gizler ve onları iki yandaki bağlamdan tahmin eder: maskeli dil modellemesi. T5 ise metnin bütün parçalarını gizleyip onları üretir: span bozma (span corruption). Tarif aynıdır: metnin bir kısmını gizle, tahmin et, hatayı ölç.
Bu bölüm, o döngüyü endüstriyel ölçekte çalıştırdığınızda ne olduğuyla ilgili. Metnin nereden geldiği, kullanılabilir hâle gelmeden önce neyin atılması gerektiği, koşunun donanım, saat ve para cinsinden neye mal olduğu, Türkçe bir cümlenin İngilizce çevirisinden neden daha pahalıya gelebildiği ve model sürümlerini, duyurularına değil neyi paylaştıklarına ve model kartlarının neyi gösterdiğine bakarak nasıl ayırt edeceğiniz: hepsi bu bölümün konusu.
8.1.1 Üç aşama: veri faturasına ilki hâkim
Dağıtılabilir bir asistan tek bir eğitim koşusunun çıktısı değildir. Kısa bir pipeline’ın çıktısıdır ve aşamalar yalnızca ne kadar veri tükettikleriyle değil, ne işe yaradıklarıyla birbirinden ayrılır.
Üç aşama ve her birinin çalıştığı ölçek
Her aşamada önemli olan iki şey var: verinin ne olduğu ve ne kadar olduğu. Bu ikisi ters yönde ilerliyor: en çok veri en az özenle derlenmiş aşamada, en özenle derlenmiş aşamada ise neredeyse hiç veri yok.
Bu uçurumu yayımlanmış sayılarla somutlaştıralım. GPT-3, 300 milyar token üzerinde ön eğitildi (Brown vd. 2020). GPT-3 sınıfı bir temel modeli konuşabileceğiniz bir şeye çeviren InstructGPT çalışması ise yaklaşık 13.000 denetimli prompt kullandı: eğitim bölmesinde 12.725 tane, her biri ortalama 408 token, yani kabaca beş milyon token’lık prompt metni. Bunlara ek olarak ödül modeli için 33.000, pekiştirmeli öğrenme aşaması için de 31.000 prompt kullanıldı (Ouyang vd. 2022).
Ön eğitimin gördüğü token sayısı, denetimli fine-tuning’in (denetimli ince ayar; supervised fine-tuning, SFT) gördüğü prompt token sayısının kabaca 58.000 katı. Paydayı dikkatle okuyun: o beş milyon token yalnızca prompt’lardan ibaret; bir SFT örneği ise prompt artı cevaptır ve kayıp genellikle cevap üzerinden hesaplanır. Eğitim metninin tamamına göre oran daha küçük çıkar; iki makale de bu oranı bildirmiyor. Yine de bu büyüklük mertebesi, pipeline hakkındaki en yararlı tek bilgidir, çünkü aksi hâlde şaşırtıcı bulacağınız bir örüntüyü açıklar: bir fine-tuning, bir modelin nasıl cevap verdiğini çoğu zaman güçlü biçimde değiştirir, ne bildiğini ise genellikle daha sınırlı etkiler (ne kadar etkilediği veriye, yönteme ve değerlendirmeye bağlı). Olgular sonradan da öğretilebilir; Bölüm 9 bu iki etkiyi de ölçüyor. Mesele şu: üç yüz milyara karşı birkaç milyon token, bir dünya görüşü yüklemenin yeri değildir; olguları güncel tutmanın daha kolay yolu da genellikle erişimdir (retrieval, Bölüm 19). Bilginin büyük kısmı 1. aşamada yüklendi. 2. ve 3. aşamalar, bir benzetmeyle, bir kat boyaya yakın — başkasının on milyonlarca dolar harcayarak inşa ettiği bir binaya usta ellerin sürdüğü, önemli bir kat boya.
Ön eğitim adı tarihin bir cilvesidir. Aşamanın gerçekten hazırlık niteliği taşıdığı zamanlarda konmuştu: etiketsiz metin üzerinde ön eğitim yapar, asıl eğitimi ise etiketli göreviniz üzerinde yapardınız. Bugün çoğu zaman en çok veri ve hesabı bu ilk aşama tüketiyor; isim ise buna hiç ayak uyduramadı.
Bu bölüm 1. aşamayla ilgili. Bölüm 9 2. ve 3. aşamaları ayrıntılı olarak ele alıyor; LoRA, DPO ve “hizalama”nın gerçekte ne kazandırdığı dâhil.
8.1.2 Sıra neden değiştirilemez
2. aşamaya neden doğrudan atlayamayacağınızı açıkça söylemekte fayda var, çünkü verisine gerçekten gücünüzün yettiği aşama 2. aşama.
Talimat verisi bir dili öğretmek için fazlasıyla küçük. Beş milyon token kabaca kırk romana denk. Sıfırdan başlatılmış bir modelin kırk romandan bir asistanın İngilizce sözdizimine hâkimiyetine — Python semantiğini ve Anadolu coğrafyasını bir yana bırakın — ulaşmasını beklemeyiz. Bir model bu büyüklükte bir derlemden elbette bir şeyler öğrenir; ama oradan geniş ve genel bir yetkinlik edinmesi beklenmez. Üstelik milyarlarca parametreli bir modelin bu veriyi büyük ölçüde ezberleme riski yüksek.
Özenle yazılmış beş milyon token’ın yapabildiği şey bir biçim öğretmektir: bir sorunun ardından başka bir soru değil bir cevap geldiğini, liste istendiğinde liste üretildiğini, “bilmiyorum”un izin verilen bir çıktı olduğunu. Biçimi öğrenmek tam da şu yüzden ucuzdur: temel modelde (base model) bütün malzeme zaten vardır; eksik olan tek şey, bir diziliş biçimini ötekine tercih etmesi için bir sebepti.
base model (temel model) — ön eğitimin tek başına ürettiği şey: metni makul biçimde devam ettiren, ama bir soruya başka bir soru sormak yerine cevap vermesi için özel bir sebebi olmayan bir model. ↩︎
Akılda tutulması gereken neden-sonuç ilişkisi bu; aşağıdaki tablo onu özetliyor. Tablonun son satırı, üç aşamalı resme sonradan eklenen dördüncü aşama; ona tablodan hemen sonra dönüyoruz.
| aşama | ne sağlar | neye mal olur | tekrarlanabilir mi? |
|---|---|---|---|
| ön eğitim | bilgi, dilbilgisi, dünya modeli | büyük modelde haftalar ila aylar, binlerce GPU | çoğu ekip için pratikte hayır; büyük bütçeyle seyrek |
| fine-tuning | biçim, görev şekli, alan üslubu | veri ve modele göre saatler ya da günler, çoğu zaman tek düğüm | sık sık |
| tercih ayarı | üslup, ret, cevapların sıralaması | günler, artı etiketleme ve aday üretimi | genellikle sürüm başına |
| doğrulanabilir ödüllerle pekiştirmeli öğrenme (RL) | akıl yürütme izleri, araç kullanımı | günler ila haftalar, gerçek bir GPU kümesi | altyapı ve bütçeye bağlı |
O resim çizildikten sonra dördüncü bir aşama geldi. 2024 sonundan beri akıl yürütme için eğitilen modellere, doğrulanabilir ödüllerle büyük ölçekli bir pekiştirmeli öğrenme aşaması ekleniyor: cevabı kontrol edilebilen matematik, testi geçen kod. Bu aşama “üstüne bir kat boya” tarifine uymuyor. Token sayıları küçük kalıyor ama hesabı küçük kalmıyor: rollout’lar (modelin denemek için ürettiği cevaplar) birer üretimdir ve üretim, RL’nin pahalı yarısıdır. Yukarıdaki 58.000 katlık oran veri hakkında bir olgu, para hakkında değil; paranın gittiği yer Bölüm 10.
Son sütun, hiç model eğitmeseniz bile bu bölümün neden önemli olduğunu söylüyor. Ön eğitim kararları, devraldığınız ve geri almanın pahalı olduğu kararlardır. Tokenizer Türkçeyi kötü bölüyorsa o modeli kullanan her kullanıcı bunun bedelini öder; tokenizer’ı değiştirmek ise modeli yeniden uyarlamak demektir. Veri kesim tarihi Aralık 2023 ise sonraki eğitim, modele 2025’teki bir seçimi kimin kazandığını öğretebilir. Ama o zaman kapsamın, güvenilirliğin ve interference’ın (yeni eğitimin mevcut bilgi ve yetenekleri bozması) sorumluluğu da size kalır. Sürekli değişen olgularda erişimin genellikle üstün gelmesinin sebebi bu. Derlemde az Türkçe varsa bir adaptörün üzerine bina edeceği az şey vardır; bunun sonucu ne kadar sınırladığını hedef görevde ölçmek gerekir.
Neye bakacağız. Ön eğitimin ne ürettiği ve — daha yararlısı — neyi üretmediği. Sonra herhangi bir mimari sorusu gelmeden bütçeyi tüketen üç karar: metnin nereden geldiği, token’lara nasıl bölündüğü ve koşunun gerçekte neye mal olduğu. Seçebileceğiniz modellerin manzarasıyla ve bunlardan biri hakkındaki bir iddianın nasıl okunacağıyla bitiriyoruz.
8.2 Veri nereden geliyor
“Büyük bir dil modeli ne üzerinde eğitiliyor?” sorusunun kısa cevabı şu: web, artı laboratuvarın elde edebildiği başka her şey, eksi metin çıkarma, dil seçimi, kalite süzme ve tekilleştirme sırasında atılan devasa bir miktar. İlginç olan, eksi kısmı: her adımın neyi çıkardığı ve neden.
8.2.1 Ham madde
Açık ön eğitim derlemlerinin çoğu Common Crawl ile başlar. Common Crawl, 2008’den beri web’i tarayıp sonuçları yayımlayan, kâr amacı gütmeyen bir kuruluştur. Bir iki ayda bir anlık görüntü yayımlıyor; FineWeb ekibi bunlardan 96’sıyla çalıştı (Penedo vd. 2024). Bir anlık görüntü, döneme ve indirilen dosya türüne göre değişmekle birlikte, yüzlerce terabaytlık ham HTTP cevabı mertebesinde.
Common Crawl — 2008’den beri açık web’i tarayan ve her taramayı ücretsiz yayımlayan bir kâr amacı gütmeyen kuruluş. Açık ön eğitim derlemlerinin çoğu buradan başlar. ↩︎
İki dosya biçimi önemli ve aralarında seçim yapmak ilk gerçek karar. WARC dosyaları taranan sayfanın ham cevabını — HTML’in tamamını ve istek üstverisini — tutar. WET dosyaları ise Common Crawl’ın HTML’den kendi çıkardığı düz metni tutar; onu kullanmak ayrı bir metin çıkarma adımını ve bunun hesabını kurtarır. FineWeb, WARC’ı kullanıp metni kendisi trafilatura ile çıkardı ve sebebini açıkça söylüyor: WET dosyaları “fazla miktarda kalıp metin ve menü metni barındırıyordu” (Penedo vd. 2024). Gezinti çubukları, çerez uyarıları ve alt bilgi bağlantıları da metindir ve sonraki token amacı bunları tahmin etmeyi seve seve öğrenir.
Burada, pipeline’ın tamamı boyunca tekrarlanan bir örüntüyle ilk kez karşılaşıyoruz: modelin size verisinin kötü olduğunu söyleyecek bir yolu yoktur. Model, kendisine verilen kaybı küçültür; sonraki token kaybı çerez bildirimini aradığınız bilgiden ayırt etmez. Derlemde çerez bildirimleri çok yer tutuyorsa eğitim bütçesinin bir kısmı onları modellemeye gider — diyelim ki ulaşılabilir kayıp düşüşünün onda biri oradaysa, model çerez bildirimlerinde iyileşir. Bu payın gerçekte ne olduğunu veride ölçmek gerekir.
8.2.2 Huni
Sağ kalan şey aşağıda; her aşamada FineWeb’in yayımladığı token sayılarıyla. Yandaki küresel tekilleştirme kolu, ana işlem hattının bir sonraki adımı değil, karşılaştırma için denenmiş alternatif bir yol.
96 tarama anlık görüntüsünden kullanılabilir bir derleme
Token sayıları FineWeb’in kendi yaklaşık sayıları; GPT-2 tokenizer’ıyla ölçüldü (Penedo vd. 2024). Yandaki 4T kolu ana hattın sonraki adımı değil, küresel tekilleştirme için denenmiş alternatif bir yol; aşağıda tartışılan sonuç: daha fazla tekilleştirme her zaman daha iyi demek değil. FineWeb-Edu ise yayımlanan FineWeb’den seçilmiş bir alt küme; 6.000 H100-saat, sınıflandırıcıyı 15 trilyon token’a uygulamanın maliyeti.
8.2.3 Her filtre gerçekte neye karşı koruyor
Bir filtre listesi sıkıcıdır. Her birinin var olma sebebi değil.
| filtre | neyi atar | azaltmayı hedeflediği risk |
|---|---|---|
| URL kara listesi | yetişkin içerik listesindeki sayfalar | savunamayacağınız ve sonradan çıkaramayacağınız materyal üzerinde eğitim (liste dışındakileri yakalamaz) |
trafilatura ile metin çıkarma |
gezinti, reklam, alt bilgi | “Tüm çerezleri kabul et” konusunda akıcı bir model (yararlı içerik de kaybolabilir) |
| fastText dil tespiti, skor \(\ge 0{,}65\) | İngilizce olduğuna yeterli güvenle karar verilemeyen sayfalar | etiketlendiği dilde olmayan metinlerle dolu bir derlem |
| tekrar filtreleri | tek satırı 400 kez tekrarlayan sayfalar | üretim anında yozlaşmış döngüler (onları tek başına önlemez) |
| kalite sezgisel kuralları | cümle sonu noktalaması yok, saçma sembol oranları | hiçbir insanın okumadığı, anahtar kelime tıkıştırılmış spam |
| MinHash tekilleştirme | neredeyse birebir aynı belgeler | ezberleme ve tek bir metne iki kez harcanan hesap (ezberlemeyi bütünüyle önlemez) |
| PII (kişisel bilgi) yeniden biçimlendirme | e-posta adresleri, herkese açık IP adresleri | prompt’la gerçek bir kişinin bilgilerini sızdırmaya ikna edilebilen bir model (eksik tespit ve dolaylı sızıntı riski sürer) |
Bu satırların ikisi bir tablo hücresinden fazlasını hak ediyor.
Tekilleştirme yerini deneylerle hak ediyor. Tekilleştirilmiş veri üzerinde eğitilen modeller eğitim kümelerini kayda değer ölçüde daha az ezberliyor ve hedef görevlerde de daha kötü değiller (Lee vd. 2022). Ezberleme varsayımsal bir şey değil: doğru prompt verildiğinde büyük bir model, kişisel bilgiler dâhil, eğitim verisinden uzun pasajları kelimesi kelimesine dökebiliyor (Carlini vd. 2021). Kopyalar bunu mekanik bir sebeple kötüleştiriyor — yüz kez geçen bir pasaj, gradyanın modeli yeniden üretmesi için yüz kez ödüllendirdiği bir pasajdır. Tablodaki MinHash, belgelerin n-gram kümelerinden kısa “imzalar” çıkarıp yakın kopyaları her çifti tek tek karşılaştırmadan bulan yöntemdir; mekanizması Bölüm 11.3’te.
Dil filtresi bir ölçüm değil, bir politikadır. İngilizce bir sınıflandırıcıda 0,65 eşiği yalnızca dili tespit etmez, derlemi tanımlar. Diller arası geçiş yapan metin, Türkçeye özgü harfleri ASCII karşılıklarıyla yazılmış Türkçe (cok guzel), ağır lehçe özellikleri taşıyan İngilizce: hepsi daha düşük puan almaya yatkın ve bir kısmı eşiğin altında kalıp elenir. Hangi oranda elendiklerini bir örneklem üzerinde ölçmek gerekir. Bir model sonradan dilin bir çeşidinde zayıf çıktığında, sorun genellikle tam burada başlamıştır — sessizce, daha kimse bir şey eğitmeden aylar önce.
8.2.4 Tekilleştirme sürprizi
Şimdi veri pipeline’ları hakkında akla ilk geleni sınayan bir sonuç.
Tekilleştirmenin (deduplication) apaçık bir ayar düğmesi var: kopyaları ne kadar geniş bir alanda arıyorsunuz? Tek bir anlık görüntünün içinde mi, yoksa 96’sının tamamı arasında mı? Hepsinin arasında aramak daha kapsamlıdır; akla ilk gelen beklenti, daha iyi olması.
deduplication (tekilleştirme) — zaten tutulanlarla birebir ya da neredeyse birebir aynı olan belgeleri atmak; böylece model aynı metne tekrar tekrar hesap harcamaz ve onu ezberlemez. ↩︎
FineWeb bunu denedi. Bu iki strateji, aynı başlangıç noktasından ayrılan alternatif yollardır. Temel filtrelenmiş metnin ~36 trilyon token’ı üzerinde çalıştırıldığında anlık görüntü içi tekilleştirme geriye 20 trilyon, küresel tekilleştirme ise 4 trilyon token bırakıyor — beşte biri kadar ve girenin kabaca dokuzda biri. Küresel tekilleştirme en çok da en eski anlık görüntüleri etkiledi; onlardan “özgün temel filtrelenmiş verinin %90’ı kadarını” kaldırdı, çünkü bu görüntüler sonraki 95 taramanın hepsiyle karşılaştırılarak tekilleştirildi (Penedo vd. 2024).
Sonra kontrol ettiler; çoğu pipeline’ın atladığı kısım da bu. 2013-48 anlık görüntüsünü tek başına alıp iki havuz kurdular: küresel tekilleştirmenin tuttuğu ~31 milyar token ve attığı ~460 milyardan yeniden tekilleştirilmiş 171 milyar token. Sonra her havuzdan alınan birer örneklem üzerinde, aynı model boyutu ve aynı token bütçesiyle birer ablasyon modeli (yalnızca tek bir etkeni değiştiren kontrollü eğitim koşusu; bkz. Bölüm 4) eğittiler; böylece tek değişken, token’ların hangi havuzdan geldiğiydi. Tutulan havuz kaybetti.
Sonucu anlamlı kılan şey o eşit bütçe ayrıntısı. Modellerden biri diğerinden daha çok token görseydi, karşılaştırma veri kalitesini değil veri miktarını ölçmüş olurdu — ki asıl iddia kalite hakkında.
Belgeleri elle okuduktan sonra yaptıkları açıklama ezberlemeye değer: agresif küresel tekilleştirmeden sağ çıkan veri “başlangıçta atılan veriye kıyasla daha çok reklam, tutarsız anahtar kelime listeleri ve genel olarak kötü biçimlendirilmiş metin içeriyor” (Penedo vd. 2024).
FineWeb’in tekilleştirmeyi her anlık görüntünün içinde yapıp orada durmasının sebebi bu. Bu aynı zamanda kitap boyunca tekrarlanan bir argümanın da habercisi: bir veri kararı apaçık doğru göründüğünde, onu küçük bir eğitim koşusuyla kontrol etmenin maliyeti çoğu zaman büyük ölçekte yanılmanın maliyetinden düşüktür; deneyin maliyetini kararın maliyetiyle birlikte tartın.
8.2.5 Miktar, ağırlık demek değildir
Veriyi topladıktan sonra, modelin her türden ne kadarını gerçekten göreceğine karar vermeniz gerekir. Elinizdeki miktar ile modelin gördüğü miktar farklı sayılardır. İkisini birbirine karıştırmak, bir model raporunu yanlış okumanın klasik bir örneğidir.
GPT-3’ün tablosu ayrımı alışılmadık ölçüde net gösteriyor (Brown vd. 2020):
| veri kümesi | mevcut token | eğitim karışımındaki payı | 300B token içinde kaç kez görüldü |
|---|---|---|---|
| Common Crawl (filtrelenmiş) | 410B | %60 | 0,44 |
| WebText2 | 19B | %22 | 2,9 |
| Books1 | 12B | %8 | 1,9 |
| Books2 | 55B | %8 | 0,43 |
| Wikipedia | 3B | %3 | 3,4 |
Son iki sütunu birlikte okuyun. Wikipedia, mevcut token’ların %0,6’sı ve eğitim karışımının %3’ü; yani model, filtrelenmiş web taramasının yarısından azını okurken Wikipedia’nın tamamını 3,4 kez baştan sona geçti. Yazarlar sebebini tek cümlede söylüyor: ağırlıklar kasten boyutla orantılı değil ve “daha yüksek kaliteli eğitim verisi karşılığında az miktarda aşırı öğrenmeyi” kabul ediyorlar (Brown vd. 2020).
Bu tabloyu yeniden kullanmadan önce rakamlara dair iki not. Karışım sütunu makalenin kendi yuvarlanmış rakamlarından oluşur ve toplamı %100 değil, %101 eder. Son sütun ise makalenin bildirdiği epoch sayısıdır; diğer iki sütundan yeniden hesaplayabileceğiniz bir şey değildir. Pay × 300B ÷ mevcut token hesabı WebText2 için 3,5 verir, oysa tabloda 2,9 yazıyor; Wikipedia için 3,0 verir, tabloda 3,4 yazıyor. Bunlar özgün tablonun bildirdiği rakamlar; birbirleriyle tam uyuşmuyorlar; yuvarlanmış paylar ya da farklı sayım tabanları olası sebepler, ama kaynak bunu açıklamıyor ve kesin yeniden hesap için eğitim örnekleme yordamı gerekir. İki sütunu yaklaşık örnekleme ağırlıkları olarak okuyun. Tabloyu, birbirini tutan bir sayı kümesi olarak değil, argümanın biçimini görmek için okuyun: miktar, ağırlık değildir.
Dört yıl sonra Llama 3, karışımını kaynağa göre değil konuya göre raporluyor; bu tercih bile alanın neyi önemsemeyi öğrendiğini gösteriyor: kabaca %50 genel bilgi, %25 matematik ve akıl yürütme token’ı, %17 kod ve %8 çok dilli (Grattafiori vd. 2024). Son rakama dikkat edin. Açıkça çok dilli diye pazarlanan bir modelde, İngilizce dışındaki bütün diller bu yüzde sekizi paylaşıyor. Bu toplam, Türkçenin kendi payını da modelin Türkçede ne kadar iyi olduğunu da söylemiyor; onlar için dil dağılımı ve hedef görevde ölçüm gerekir. Bu sayıyı aklınızda tutun; Türkçenin maliyetini hesaplarken karşımıza yeniden çıkacak.
8.2.6 Son kırk milyon token
Llama 3’ün ön eğitimi kendi içinde üç aşamalı ve oranlar şaşırtıcı (Grattafiori vd. 2024):
- İlk ön eğitim. AdamW, tepe öğrenme oranı \(8\times10^{-5}\). Oran bu değere 8.000 adımlık bir ısınmayla (warmup: öğrenme oranını sıfırdan tepe değere yavaş yavaş çıkarma) çıkıyor, ardından 1,2 milyon adım boyunca kosinüs programıyla (cosine schedule) \(8\times10^{-7}\)’ye düşürülüyor. Batch boyu büyüyor: 4.096 dizi uzunluğunda 4M token’la başlıyor; 252M token sonra 8.192 uzunlukta 8M token’a, 2,87 trilyon token sonra da 16M’ye çıkıyor, yani her seferinde ikiye katlanıyor. Baştaki küçük batch’ler kararlılık, sonraki büyük batch’ler verimlilik sağlıyor.
- Uzun bağlam ön eğitimi. Bağlam penceresi altı aşamada 8K’dan 128K’ya çıkarılıyor; kabaca 800 milyar token kullanılıyor — koşunun yaklaşık %5’i yalnızca daha uzun bir pencereyi kullanmayı öğrenmeye harcanıyor.
- Tavlama. Son 40 milyon token boyunca öğrenme oranı doğrusal olarak sıfıra indiriliyor ve bu sırada veri karışımı da çok yüksek kaliteli kaynakları yukarı örnekleyecek biçimde değişiyor. Yayımlanan ağırlıklar ise bu aşamada kaydedilen checkpoint’lerin (ara ağırlık kayıtlarının) ortalaması, yani bir Polyak ortalaması.
Kırk milyon token, 15,6 trilyonun \(\%0{,}00026\)’sı. Bu kadar az veri bir fark yaratabilir mi? Makale bunu son 40 milyon token’lık aşamanın kendisinde değil, ayrı bir deneyde sınadı. Ön eğitimli 8B’lik bir modeli, yüksek kaliteli kod ve matematiğin ağırlığı artırılmış bir karışım üzerinde (GSM8k ve MATH’in eğitim kümeleri de dâhil) bir tavlama (annealing) aşamasından geçirmek, doğrulama kümelerinde GSM8k başarısını %24,0, MATH başarısını %6,4 iyileştirdi (makale bunların göreli artış mı, yüzde puan mı olduğunu söylemiyor). 405B modelde aynı işlemin etkisi ihmal edilebilir düzeyde kaldı; yazarlar bunu, daha büyük modelde bu yeteneğin zaten bulunduğu ve hatırlatmaya ihtiyaç olmadığı şeklinde yorumluyor.
annealing (tavlama) — bir koşunun sonunda öğrenme oranını sıfıra indirmek; genelde veri karışımını eldeki en iyi malzemeye doğru kaydırarak. Yavaş soğutmanın bir yapıyı oturttuğu metalurjiden ödünç alınmış bir ad. ↩︎
Bir token’ın programın neresinde durduğu, ne öğrettiğini değiştirir. 400.000. adımda, büyük bir öğrenme oranı altında görülen bir token, geriye kalan 800.000 güncellemenin kısmen üzerine yazacağı geniş bir yeteneğe katkıda bulunur. Koşunun son %0,00026’sında, öğrenme oranı sıfıra giderken görülen bir token ise ardından çok az güncellemeyle karşılaşır; bu yüzden son aşamadaki veri karışımı modelin çıktısını etkileyebilir (tek bir token’ın kalıcı katkısını bu takvimden doğrudan çıkaramayız). Aksi hâlde gizemli görünecek bir endüstri alışkanlığının arkasındaki akla yatkın mekanizma bu: en iyi veriyi sona saklayın.
8.2.7 Bir token’ı kaç kez yeniden kullanabilirsiniz?
Er ya da geç her ciddi ön eğitim projesinin istediği dildeki verisi tükenir. Bu Türkçe için şimdiden geçerli; İngilizce için de ham token sayılarının düşündürdüğünden daha erken geçerli olacak. Akla ilk gelen hamle, elinizdekinin üzerinden daha fazla epoch (eğitim verisi üzerinden bir tam geçiş) geçmektir.
Ölçülmüş cevap, alandaki yaygın kanının beklediğinden daha cömert (Muennighoff vd. 2023). Tekrarlanan veri üzerinde dört epoch’a kadar eğitim “benzersiz veriye kıyasla kayıpta ihmal edilebilir değişiklikler üretiyor”. Bunun ötesinde her ek epoch’un değeri giderek azalıyor. Sonunda hesap eklemenin değeri de sıfıra iniyor, çünkü modelin zaten tükettiği veri üzerinden fazladan geçişlerin bir faydası olamaz.
Tavsiyenin pratikteki hâli:
| durumunuz | kanıtın desteklediği şey |
|---|---|
| hesabınızın kullanabileceğinden fazla benzersiz token var | tekrar etmeden önce benzersiz veriyi kullanın |
| veri kısıtlı, hesap fazlası ölçülü | birkaç epoch tekrar deneyin; makaledeki “dörde kadar neredeyse maliyetsiz” bulgusunu kendi doğrulama kaybınızla sınayın |
| veri kısıtlı, hesap fazlası büyük | fazlayı parametreler ve epoch’lar arasında bölün, epoch’lara meylederek |
| iki sınırın da çok ötesinde | ek epoch’un marjinal yararını yeni veri ve hesap maliyetiyle karşılaştırın; makalede getiri sıfıra yaklaşıyor |
İnsanları şaşırtan satır üçüncüsü; o yüzden sözü doğrudan yazarlara bırakalım: veri kısıtlı rejimde, yeni hesabı hem daha fazla parametreye hem de epoch’a ayırmak “gerekiyor ve … epoch’lar biraz daha hızlı ölçeklenmeli” (Muennighoff vd. 2023). Makaledeki şekil bunu daha da keskin söylüyor: veriler, “Chinchilla ölçekleme yasalarının tekrarlanmış veride de geçerli olduğu varsayılsaydı öngörülecek olanın aksine, daha küçük modelleri daha çok epoch boyunca eğitmeyi” öneriyor. Veriniz azken Chinchilla’nın oranına (Bölüm 7.8) başvurursanız, bu oran size parametre sayısını artırmanızı söyler ve yanılır.
Türkçe bir proje için bu umut verici. 30 milyar Türkçe token’lık bir derlem sizi 30 milyar token’lık eğitimle sınırlamak zorunda değil: dört geçişte 120 milyar işlenmiş token eder ve genel bulgu doğruysa getiri o noktaya kadar belirgin biçimde azalmaz. Bunun sizin derleminizde tutup tutmadığını — çeşitliliğine ve tekrar biçimine bağlı — doğrulama kaybıyla ölçün; tutarsa hangi model boyutunun savunulabilir olduğunu değiştirir.
Verisi tükenen projelerin başvurduğu ikinci yol sentetik veridir: güçlü bir modelin ürettiği ya da mevcut metni yeniden yazdığı (rephrasing) token’lar, yeni ön eğitim derlemlerinde giderek daha çok yer alıyor. Bu yolun da bir sınırı var: modelin çıktısı nesilden nesile, özgün gerçek veri korunmadan yeniden eğitim verisine döndüğünde dağılımın nadir kuyruklarının adım adım silindiği ve modelin giderek daralan bir dünyayı öğrendiği gösterildi. Buna model çöküşü (model collapse) deniyor (Shumailov vd. 2024). Riskin büyüklüğü sentetik verinin payına, nasıl üretilip seçildiğine ve karışımda ne kadar gerçek veri kaldığına bağlı.
8.3 Alt kelime tokenleştirmesi: model metni nasıl görür
Bölüm 2 metni kelimelere bölüp saymıştı; kelime torbası ve TF-IDF için bu yetiyordu. Ön eğitimli bir dil modeli ise metni kelimeler olarak değil, kendi tokenizer’ının ürettiği birimler olarak görür ve bu birimler çoğu zaman kelimeden küçüktür. Bölüm 7 boyunca “token” dediğimiz şey buydu; orada token’ın nereden geldiğini sormamıştık.
Bu kısım o soruyu cevaplıyor. Önce BPE’yi küçük bir derlemde adım adım kuracağız. Sonra başlangıç alfabesinin karakter mi bayt mı olduğunun neyi değiştirdiğine ve aynı tokenizer’ın Türkçe bir metni İngilizce karşılığından neden daha fazla token’a böldüğüne bakacağız. BERT’in kullandığı WordPiece ile T5’in kullandığı Unigram LM aynı fikrin iki akrabası; onları kısmın sonundaki “Derinleşme” kutularında çalıştırıyor, modellerle birlikte ise Bölüm 8.4.5 içinde karşılaştırıyoruz. Bir sonraki kısım (Bölüm 8.4) aynı kararı ön eğitim ölçeğinde bir bütçe kalemi olarak fiyatlandırıyor.
8.3.1 Alt kelimeler: kazanan uzlaşma
byte-pair encoding (BPE) — alt kelime sözlüğünü eğitim verisinden öğrenmenin bir yolu: seçilen başlangıç birimlerinden (uygulamaya göre karakterler ya da baytlar) başlayın ve en sık yan yana gelen birim çiftlerini sırayla birleştirin; birleştirme listesi, yeni metne aynı sırayla uygulanır. ↩︎
Kelime düzeyinde tokenleştirmede, sabit bir sözlük (vocabulary: tokenizer’ın çıktı olarak üretebildiği token kimliklerinin sonlu kümesi) yeni metinlerde karşılaşılan bütün kelime biçimlerini kapsamayabilir. Karakter düzeyinde tokenleştirme ise aynı metni genellikle daha uzun dizilerle temsil eder; modelin kelime parçalarını ve kelimeleri bu küçük birimlerden öğrenmesi gerekir. Byte-pair encoding (BPE), birimlerini veriden öğrenerek bu iki yaklaşım arasında bir seçenek sunar (Sennrich vd. 2016). Böyle bir sözlükte bir kelimenin bütün hâlinin bulunması gerekmez; tokenizer onu sözlükteki daha küçük parçalarla yazabilir.
Üç seçeneği tek bir kelimede görelim. evlerden kelimesinin, tokenizer’ın eğitim metninde hiç geçmediğini düşünün. Karşılaştırmada kelime düzeyindeki tokenizer’ın sözlüğünün sabit olduğunu ve bilinmeyen kelimeleri <UNK> (unknown) ile gösterdiğini varsayıyoruz. Karakter düzeyindeki tokenizer’ın alfabesi ise kelimedeki bütün karakterleri içeriyor.
| Birim | evlerden nasıl görünür |
Sonuç |
|---|---|---|
| Kelime | <UNK> |
Kelimenin tamamı sözlükte bulunmadığı için yazımı korunmaz; yerine bilinmeyen kelime işareti gelir. |
| Karakter | e v l e r d e n |
Kelimenin yazımı sekiz birimle korunur. Model, kelime içindeki örüntüleri bu birimlerin dizilişinden öğrenir. |
| Alt kelime | ev ler den |
Kelime üç birimle temsil edilir. Bu parçalar başka kelimelerde de bulunur: evde, gözler, sizden. |
Son satırdaki bölünme uydurma değil: OpenAI’ın cl100k_base tokenizer’ı bu kelimeyi tam olarak böyle bölüyor. Geriye şu soru kalıyor: ev, ler ve den parçalarını kim seçti? Tek tek kimse seçmedi. Tokenizer’ı tasarlayanlar başlangıç birimlerini, ön tokenleştirmeyi ve sözlük bütçesini seçer; birleştirme kuralları ise eğitim verisinden sayılarak bulunur. Aşağıdaki dört kelimelik örnek bu sayma işlemini gösteriyor; cl100k_base’in parçaları ise çok daha büyük kendi eğitim verisinden öğrenildi.
Bu örnekte BPE eğitimine, kelimeleri karakterlerine ayırarak başlıyoruz. Her kelimenin sonuna, kelime sonunu gösteren </w> sembolünü ekliyoruz. Yan yana gelen sembol çiftlerini, kelimelerin derlemdeki sıklıklarını dikkate alarak sayıyor ve en sık çifti yeni bir sembolde birleştiriyoruz. Ardından sayımları yenileyip işlemi tekrarlıyoruz. Aşağıdaki kod on birleştirme yapıyor. Eşit sıklıktaki çiftlerden hangisinin önce seçileceği kullanılan uygulamaya bağlıdır; buradaki kod ilk karşılaştığı çifti seçer.
from collections import Counter
corpus = {"low": 5, "lower": 2, "newest": 6, "widest": 3}
words = {tuple(w) + ("</w>",): n for w, n in corpus.items()}
def pair_counts(words):
pairs = Counter()
for symbols, freq in words.items():
for a, b in zip(symbols, symbols[1:]):
pairs[(a, b)] += freq
return pairs
def merge(words, pair):
a, b = pair
out = {}
for symbols, freq in words.items():
new, i = [], 0
while i < len(symbols):
if i < len(symbols) - 1 and symbols[i] == a and symbols[i + 1] == b:
new.append(a + b)
i += 2
else:
new.append(symbols[i])
i += 1
out[tuple(new)] = freq
return out
merges = []
for step in range(1, 11):
best, count = pair_counts(words).most_common(1)[0]
merges.append(best)
words = merge(words, best)
print(f"merge {step:>2}: {best[0]!r} + {best[1]!r} -> "
f"{best[0] + best[1]!r} (seen {count} times)")merge 1: 'e' + 's' -> 'es' (seen 9 times)
merge 2: 'es' + 't' -> 'est' (seen 9 times)
merge 3: 'est' + '</w>' -> 'est</w>' (seen 9 times)
merge 4: 'l' + 'o' -> 'lo' (seen 7 times)
merge 5: 'lo' + 'w' -> 'low' (seen 7 times)
merge 6: 'n' + 'e' -> 'ne' (seen 6 times)
merge 7: 'ne' + 'w' -> 'new' (seen 6 times)
merge 8: 'new' + 'est</w>' -> 'newest</w>' (seen 6 times)
merge 9: 'low' + '</w>' -> 'low</w>' (seen 5 times)
merge 10: 'w' + 'i' -> 'wi' (seen 3 times)
İlk iki birleştirme, bu kelimelerde İngilizcenin en üstünlük ekiyle örtüşen est dizisini oluşturuyor. Üçüncü birleştirme, bu diziyi kelime sonu işaretiyle birleştiriyor: est</w>. Sonraki adımlarda low ve new dizileri de oluşuyor. Algoritma bu parçaları gövde veya ek olarak tanımıyor; her adımda en sık komşu sembol çiftini seçiyor. Bu küçük derlemde bazı parçalar biçimbirimlerle (morpheme: anlam taşıyan en küçük birim) örtüşüyor; BPE böyle bir örtüşmeyi garanti etmez ve bu örnek, örtüşmenin bir modele ne kazandırdığını göstermez.
BPE, tokenizer’ın eğitim derleminde bulunmayan kelimeleri de öğrenilmiş parçalara ayırabilir. Bu örnekte yeni bir kelimeyi token’lara ayırmak için birleştirme kurallarını öğrenildikleri sırayla uyguluyoruz:
def apply_merges(word, merges):
symbols = tuple(word) + ("</w>",)
for pair in merges:
symbols = tuple(merge({symbols: 1}, pair).keys())[0]
return symbols
for w in ["lowest", "newer", "slow", "widest"]:
print(f"{w:<8} -> {' '.join(apply_merges(w, merges))}")lowest -> low est</w>
newer -> new e r </w>
slow -> s low</w>
widest -> wi d est</w>
lowest, tokenizer’ın eğitim derleminde bulunmadığı hâlde sözlükteki iki birimle temsil edildi: low ve est</w>. Alt kelimelerin yaygınlaşmasının başlıca nedeni budur: bu BPE düzeninde başlangıç alfabesindeki karakterler kullanılabilir kaldığı sürece, hiç görülmemiş bir kelime de bu karakterlerden ve öğrenilmiş birleşimlerinden oluşturulabilir. slow örneğindeki s gibi bazı parçalar tek karakter olarak kalabilir. Daha küçük parçalar kullanılması token sayısını artırabilir; bunun bir dil modelinin başarısını nasıl etkileyeceği ise ayrıca değerlendirilmelidir.
Buradaki koşula dikkat edin: yeni kelimenin her karakteri, birleştirmelerin öğrenildiği alfabede bulunmalı. Bizim alfabemiz yalnızca dört İngilizce kelimenin harflerinden oluşuyor. ç gibi, o alfabede olmayan bir harf gelirse ne olur? Şeklin ardından Bölüm 8.3.2 bunu ele alıyor.
Byte-pair encoding ne öğreniyor ve onu nasıl kullanıyor
Eğitimde (üstte), sembol çiftlerinin sıklıkları sayılarak sıralı bir birleştirme listesi oluşturulur. Bu küçük derlemde ilk üç birleştirme, kelime sonu işaretini de içeren est</w> birimini oluşturuyor. Bu birim, örnekteki kelimelerin en üstünlük ekiyle örtüşüyor; ancak seçim dilbilgisel çözümlemeye değil, çiftlerin sıklığına dayanıyor. Çıkarımda (altta), öğrenilmiş liste yeni kelimeye uygulanıyor. Eğitim derleminde bulunmayan lowest, sözlükteki low ve est</w> birimlerine ayrılıyor (Sennrich vd. 2016).
8.3.2 Karakter mi bayt mı: BPE neyle başlar
Yukarıdaki örnek karakterlerle başladı. GPT-2’nin tokenizer’ı ve cl100k_base gibi bayt düzeyinde BPE kullanan tokenizer’lar ise baytlardan başlar. Aradaki farkı anlamak için karakter, kod noktası, karakter kodlaması ve bayt kavramlarını ASCII, Unicode ve UTF-8 üzerinden açıklayalım.
Karakter, metni oluşturan soyut bir birimdir; harfler, rakamlar, noktalama işaretleri ve boşluklar buna örnektir. ç, a, y, 7, ? ve 😀 görünür örneklerdir. Ancak ekranda tek bir işaret olarak algıladığımız birim, Unicode’da bir veya birden fazla kod noktasıyla temsil edilebilir.
Bilgisayarlar metni bit dizileri olarak saklar. Karakter kodlamaları, metindeki birimlerin bu dizilerle nasıl temsil edileceğini belirler. ASCII, ilk sürümü 1963’te yayımlanan 7 bitlik bir karakter kodlamasıdır. 128 kod değeri; İngilizce harfleri, rakamları, noktalama işaretlerini, boşluğu ve kontrol karakterlerini kapsar. a harfinin kod değeri 97’dir. ASCII’de ç, ş ya da ğ yoktur; Arap ve Çin yazısı da, emoji de yoktur.
Unicode, farklı yazı sistemlerindeki karakterleri ortak bir sistemde temsil etmeyi amaçlayan standarttır. Unicode kod alanındaki sayısal konumlara kod noktası (code point) denir; kodlanmış karakterlere bu konumlar atanır. Kod noktası çoğu zaman U+ ve ardından onaltılık (hexadecimal) bir sayı olarak yazılır: ç harfinin kod noktası 231’dir, yani U+00E7. ASCII’deki 128 karakter Unicode’da aynı numaralarını korur; a yine 97’dir.
Bayt (byte), bilgisayarın veriyi sakladığı temel birimdir. Sekiz bitten oluşur ve 0 ile 255 arasında bir sayı tutar; yani yalnızca 256 farklı değer alabilir. Unicode’un numaraları 255’i çok aştığı için her kod noktası tek bayta sığmaz. Bir kod noktasının hangi baytlarla saklanacağına bir kodlama (encoding) karar verir. Web’de yaygın olarak kullanılan UTF-8, kodlanabilir her Unicode kod noktasını bir ile dört bayt arasında temsil eder. ASCII aralığındaki kod noktaları tek baytla, daha büyük değerler ise UTF-8’in belirlediği bit kalıpları kullanılarak iki, üç veya dört baytla kodlanır.
Bu kavramları çay kelimesi üzerinde yan yana görelim:
ç |
a |
y |
|
|---|---|---|---|
| Unicode kod noktası | 231 (U+00E7) | 97 (U+0061) | 121 (U+0079) |
| ASCII tablosunda var mı | hayır | evet | evet |
| UTF-8 baytları | 195, 167 | 97 | 121 |
Buradaki gösterimde çay üç harften ve üç kod noktasından oluşur; UTF-8 ile kodlandığında dört bayt tutar. Python’da len("çay") 3, len("çay".encode("utf-8")) ise 4 verir. Aynı görünen metin farklı kod noktası dizileriyle de yazılabilir: ç yerine c (U+0063) ve ardından birleştirici çengel işareti (U+0327, COMBINING CEDILLA) yazılırsa görünüş aynı kalır, ama kelime dört kod noktası ve beş bayt olur. Bu sayılar, kullanılan Unicode gösterimine ve kodlamaya bağlıdır; token sayısı da tokenizer’ın Unicode normalleştirmesi yapıp yapmadığına göre değişebilir.
Bu ayrım tokenizer için neden önemli? Çünkü BPE’nin birleştirmeye başlayacağı semboller ya karakterler olur ya da baytlar; ikisinin sayısı ise çok farklı:
- Karakter alfabesi büyük olabilir. Unicode’un kod alanı sonludur, ancak çok sayıda karakter içerir ve yeni sürümlerde yeni karakterler tanımlanır. Tokenizer’ın başlangıç alfabesi eğitim verisinden seçilebilir; buna ayrıca karakterler eklenebilir veya kapsamı sınırlanabilir. Bu alfabede bulunmayan bir karakter için bilinmeyen token ya da baytlara dönme gibi ek bir mekanizma gerekir.
- Bayt alfabesi 256 değerle tamamlanabilir. Başlangıç alfabesi bütün bayt değerlerini içeriyorsa, UTF-8 ile kodlanmış metnin her baytı temsil edilebilir. Böylece yeni bir karakterin baytları için ayrıca yeni bir başlangıç sembolü gerekmez.
Bu alt bölümün geri kalanı bu iki seçeneği ve bedellerini açıyor.
Önce kısa bir tarih notu. Yukarıdaki döngü — yan yana çiftleri say, en sık olanı birleştir, tekrarla — BPE’nin kendisidir. Adı, NLP’deki kullanımından eskidir: 1994’te yayımlanmış bir veri sıkıştırma algoritmasından gelir. O algoritma, bir dosyada yan yana en sık geçen iki baytı, dosyada hiç kullanılmayan tek bir bayt değeriyle değiştirmeyi tekrarlıyordu (Gage 1994). Sennrich ve arkadaşları döngüyü korudu, amacını değiştirdi: birleştirmeler bir dosyayı küçültmek yerine bir sözlük kuruyor ve birleştirme listesi, yeni metne tekrar uygulanabilsin diye saklanıyor (Sennrich vd. 2016).
Geriye döngünün sizin yerinize vermediği bir karar kalıyor: başlangıç sembolleri ne olacak? Bunu algoritma seçimiyle karıştırmayın; ikisi ayrı kararlardır. BPE, alt kelime sözlüğü öğrenmenin tek yolu değil. İleride iki akrabasıyla da karşılaşacaksınız: BERT’in kullandığı WordPiece ve T5’in kullandığı Unigram. Üç yöntem de alt kelime sözlükleri oluşturmak için kullanılır; ancak sözlüğü öğrenme ve yeni metni parçalara ayırma işlemleri farklıdır. Buradaki ana örneğimiz BPE’dir. WordPiece ve Unigram’a bu bölümdeki bir “Derinleşme” kutusunda değiniyor (Bölüm 8.3.4), yöntemleri BERT’in tokenizer’ını incelerken daha ayrıntılı karşılaştırıyoruz (Bölüm 8.4.5). Şimdilik bilmeniz gereken şu: algoritma, birimlerin nasıl öğrenileceğine karar verir. Karakter ya da bayt seçimi ise birimlerin neyden kurulacağına karar verir ve üç algoritma için de ortak bir sorudur.
Karakterlerden başlamak. Yukarıdaki örnek bunu yaptı. Birleştirme tablosu yalnızca gördüğü sembolleri birleştirebilir; bu tablonun gördüğü alfabe de dört İngilizce kelimeden geliyordu. apply_merges("çay", merges) çağrısı ('ç', 'a', 'y', '</w>') döndürür. Ancak ç, a ve y bu küçük derlemden oluşturulan başlangıç alfabesinde yoktur. İşlev yalnızca birleştirme kurallarını uyguladığı, sözlükte bulunmayan sembolleri denetlemediği için bunları çıktıda bırakır. Kullanılabilir bir tokenizer’ın bu durumu ayrıca ele alması gerekir: karakterleri başlangıç alfabesine ekleyebilir, bilinmeyen token (<UNK>) kullanabilir veya baytlara dönebilir. Bir karakterin nadir olması, mutlaka bilinmeyen token’a dönüşeceği anlamına gelmez.
Baytlardan başlamak. Diğer seçenek, karakterlerin kendisi yerine onların UTF-8 baytlarından başlamaktır. UTF-8, kodlanabilir her Unicode kod noktasını bir ile dört bayt arasında temsil eder. ASCII harfleri bir bayt tutar. Aşağıdaki gösterimlerde Türkçedeki ç, ş, ğ, ı, ö, ü ve İ harflerinin her biri iki bayttır. 世 üç, 😀 ise dört bayttır. Birden fazla kod noktasından oluşan emoji ve diğer birleşik gösterimler toplamda dört bayttan uzun olabilir:
for ch in ["a", "ç", "ş", "İ", "世", "😀"]:
b = ch.encode("utf-8")
print(f"{ch} U+{ord(ch):04X} {len(b)} byte(s): {' '.join(f'{x:02X}' for x in b)}")a U+0061 1 byte(s): 61
ç U+00E7 2 byte(s): C3 A7
ş U+015F 2 byte(s): C5 9F
İ U+0130 2 byte(s): C4 B0
世 U+4E16 3 byte(s): E4 B8 96
😀 U+1F600 4 byte(s): F0 9F 98 80
Bir baytın yalnızca 256 olası değeri vardır; dolayısıyla 256 baytlık bir alfabe kapalıdır: UTF-8 ile kodlanmış her metin, hangi dilde olursa olsun, bu değerlerin bir dizisidir. Bayt düzeyinde BPE, aynı birleştirme döngüsünü karakterler yerine bayt dizileri üzerinde çalıştırır (Radford vd. 2019). Döngü, her adımda en sık komşu sembol çiftini birleştirir. Böylece bazı karakterler ve kelime parçaları tek token olarak temsil edilebilir. Örneğin ç harfinin iki baytı da tek token hâline gelebilir; bunun gerçekleşip gerçekleşmeyeceği ve birleştirme sırası, eğitim verisindeki sıklıklara ve yapılan birleştirmelerin sayısına bağlıdır. Ama birleştirmeler Unicode karakter sınırlarına bağlı değildir: algoritma karakterin nerede bittiğini bilmez, yalnızca hangi bayt çiftinin sık olduğunu bilir. Bu yüzden bir token tam bir karakteri de, birkaç karakteri de, bir UTF-8 karakterinin yalnızca bir parçasını da temsil edebilir. Bir sonraki çıktıda bunun üçünü de göreceksiniz.
Aşağıda bayt düzeyinde bir tokenizer, OpenAI’ın cl100k_base kodlaması, her token’ın arkasındaki baytları gösteriyor. enc.encode, token kimliklerini (id) tamsayılardan oluşan bir liste olarak döndürür. Metin, modele bu kimlikler üzerinden aktarılır. decode_single_token_bytes ise her kimliğin temsil ettiği bayt dizisini gösterir:
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
for text in ["çay", "şişe", "ŞİŞE", "😀"]:
pieces = [enc.decode_single_token_bytes(t) for t in enc.encode(text)]
print(f"{text:<5} {len(pieces)} tokens {pieces}")çay 2 tokens [b'\xc3\xa7', b'ay']
şişe 3 tokens [b'\xc5\x9fi', b'\xc5\x9f', b'e']
ŞİŞE 6 tokens [b'\xc5', b'\x9e', b'\xc4\xb0', b'\xc5', b'\x9e', b'E']
😀 2 tokens [b'\xf0\x9f\x98', b'\x80']
Bu çıktıda ç harfinin iki baytı tek token’da yer alıyor. ŞİŞE altı, şişe ise üç token üretiyor. Büyük Ş harfinin iki baytı ayrı token’lara bölünürken İ ve E bütün olarak kalıyor. Yalnızca bu çıktıya bakarak Ş harfinin eğitim verisinde ne kadar sık geçtiğini belirleyemeyiz. b'\xc5' tek başına geçerli bir UTF-8 dizisi değildir; karakterin okunabilmesi için sonraki baytla birleştirilmesi gerekir. 😀 de iki token’a ayrılıyor: ilk token üç baytı, ikincisi son baytı taşıyor. Bu örneklerin hiçbirinde bilinmeyen token gerekmiyor; ancak aynı sayıda görünen karakter farklı sayıda token üretebiliyor.
Aşağıdaki tabloda “karakter” ile Unicode kod noktasını kastediyoruz. Bayt düzeyindeki sütunda başlangıç alfabesinin 256 bayt değerinin tamamını içerdiğini varsayıyoruz.
| Karakterlerden başlayan BPE | Baytlardan başlayan BPE | |
|---|---|---|
| Başlangıç alfabesi | Seçilmiş kod noktaları; eğitim verisinden alınabilir veya ayrıca eklenebilir. | 256 bayt değeri. |
| Başlangıç alfabesinde bulunmayan bir karakter | Bilinmeyen token veya aşağıdaki byte fallback gibi ek bir mekanizma gerekir. | UTF-8 baytlarıyla temsil edilir. |
| Bir token neyi temsil eder? | Bir veya birden fazla tam kod noktası. | Bir bayt dizisi; bazen bir kod noktasının UTF-8 gösteriminin yalnızca bir bölümü. |
| Daha büyük bir parçayla birleşmeyen bir kod noktasının maliyeti | Alfabedeyse bir token. | UTF-8 gösterimine ve öğrenilmiş birleşimlere göre bir ile dört token. |
| Kapsama | Seçilen alfabe ve varsa geri dönüş mekanizmasıyla sınırlıdır. | UTF-8 ile kodlanmış metnin bütün baytlarını kapsar. |
İki seçeneği birleştiren üçüncü bir tasarım da var: byte fallback, yani bilinmeyen bir karakteri baytlarıyla yazmak. Sözlük yine karakterlerden ve onların birleşimlerinden kurulur; ama içine 256 bayt değerinin her biri için birer token da eklenir. Tokenizer tanıdığı karakterleri her zamanki gibi işler. Tanımadığı bir karakterle karşılaşınca <UNK> yazmak yerine o karakterin UTF-8 baytlarını tek tek, bu bayt token’larıyla yazar. SentencePiece kütüphanesi bunu bir seçenek olarak sunar (byte_fallback=True).
Küçük bir deneyle görelim. Aşağıda SentencePiece’i, içinde ç harfi hiç geçmeyen sekiz Türkçe kelimeyle iki kez eğitiyoruz: bir kez bu seçenek kapalı, bir kez açık. Sonra ikisine de çay kelimesini veriyoruz:
import sentencepiece as spm
words = ["ev", "evde", "evden", "evler", "yol", "yolda", "yoldan", "yollar"]
with open("mini.txt", "w", encoding="utf-8") as f:
f.write("\n".join(words * 5) + "\n") # bu metinde hiç 'ç' yok
for fallback in [False, True]:
spm.SentencePieceTrainer.train(
input="mini.txt", model_prefix="mini", model_type="bpe",
vocab_size=20 + (256 if fallback else 0), byte_fallback=fallback,
character_coverage=1.0, hard_vocab_limit=False, minloglevel=2,
bos_id=-1, eos_id=-1, pad_id=-1)
sp = spm.SentencePieceProcessor(model_file="mini.model")
ids = sp.encode("çay")
print(f"byte_fallback={fallback!s:<5} vocabulary {sp.get_piece_size():>3} "
f"{sp.encode('çay', out_type=str)} -> {sp.decode(ids)!r}")byte_fallback=False vocabulary 20 ['▁', 'ç', 'a', 'y'] -> ' ⁇ ay'
byte_fallback=True vocabulary 276 ['▁', '<0xC3>', '<0xA7>', 'a', 'y'] -> 'çay'
İlk satırda ç sözlükte bulunmuyor ve bilinmeyen token kimliğiyle kodlanıyor. Parça listesinde yine de ç görülüyor; çünkü bu liste bilinmeyen parçanın metindeki yazımını gösterir. Bu, ç için ayrı bir sözlük girdisi bulunduğu anlamına gelmez. Kimliklerden metne dönüldüğünde bu harfin yerini ⁇ işareti alıyor.
İkinci satırda sözlük 20’den 276’ya çıkıyor: bu deneyde byte fallback açıkken hedef sözlük büyüklüğünü 256 artırdık ve 256 bayt parçası bu yere oturdu (başka eğitim ayarlarında gerçek sözlük boyutunu ayrıca denetleyin). ç, <0xC3> ve <0xA7> olarak temsil ediliyor. Bunlar yukarıdaki tabloda gördüğünüz iki bayt: onaltılık C3 = 195, A7 = 167. Kimliklerden metne dönüldüğünde çay eksiksiz elde ediliyor. Baştaki ▁, SentencePiece’in boşluğu görünür kılmak için kullandığı işarettir. Bu örnekte, varsayılan ayarın metnin başına eklediği boşluğu temsil ediyor; bir sonraki alt bölümde bu gösterime döneceğiz.
Bugün hangisi kullanılıyor. Pratik kural en başta: modelin eğitildiği tokenizer’ı kullanın ve token’ları onunla sayın; aynı algoritma adı, iki modelde aynı sözlük anlamına gelmez. GPT tipi birçok model bayt düzeyinde BPE’yi veya onun bir varyantını kullanır. Başka model ailelerinde WordPiece ve Unigram da kullanılır. SentencePiece ise hem BPE hem de Unigram ile tokenizer eğitebilen bir kütüphanedir. GPT-2, bayt düzeyinde BPE’yi 50.257 token’lık bir sözlükle tanıttı (Radford vd. 2019). OpenAI’ın bir sonraki alt bölümde ölçülen cl100k_base ve o200k_base kodlamaları bayt düzeyindedir. Llama 3, 128 bin token’lık bir sözlüğe geçti: OpenAI’ın tiktoken’ından alınan 100 bin token’a İngilizce dışındaki diller için 28 bin token eklendi (Grattafiori vd. 2024). BERT ile DistilBERT ve ELECTRA gibi yakın akrabaları hâlâ karakterler üzerinde WordPiece kullanıyor (Devlin vd. 2019) (RoBERTa ise BERT üzerine kurulu olsa da GPT-2’nin bayt düzeyindeki BPE’sine geçti); hangi algoritmanın hangi modelde kullanıldığını ilerideki bir tablo (Bölüm 8.4.5) gösteriyor.
Burada kapsama ile token sayısını ayırmak gerekiyor. Başlangıç alfabesi bütün 256 bayt değerini içeriyorsa, UTF-8 ile kodlanan bir Türkçe kelimenin baytlarını temsil etmek için bilinmeyen token gerekmez. Ancak bu özellik, tokenleştirme öncesindeki normalleştirmenin özgün metni koruduğu anlamına gelmez; değiştirilen harfler veya silinen boşluklar bayt kapsamı sayesinde geri getirilemez.
Bir metnin kaç token üreteceği ise eğitim verisine, öğrenilen birleştirmelere, sözlüğün büyüklüğüne ve içeriğine bağlıdır. Diller için ayrıca bir sözlük kotası belirlenmiş olması gerekmez. Bir sonraki alt bölüm, token sayısındaki bu farkı Türkçe örneklerle ölçüyor.
Bu alt bölümün özeti. Karakterlerden başlayan BPE’nin kapsamı, seçilen başlangıç alfabesine ve varsa byte fallback gibi ek mekanizmalara bağlıdır. Bütün 256 bayt değerinden başlayan BPE ise UTF-8 ile kodlanmış metnin baytlarını temsil edebilir. Bunun karşılığında bazı kod noktaları birden fazla token’a bölünebilir. Her iki yaklaşımda da oluşan token sayısı, öğrenilen sözlüğe ve metnin içeriğine bağlıdır.
8.3.3 Türkçe için faturayı kim ödüyor
Bir tokenizer, aynı içeriğin farklı dillerdeki karşılıkları için farklı sayıda token üretebilir. Bu fark; eğitim derleminin dil dağılımına ve içeriğine, sözlük büyüklüğüne, tokenleştirme algoritmasına ve ön işleme kurallarına bağlıdır. Türkçe ve İngilizce arasındaki farkı somut bir örnekle inceleyelim. Aşağıda İnsan Hakları Evrensel Bildirgesi’nin 1. maddesi, resmî İngilizce ve Türkçe metinleriyle OpenAI’ın tokenizer’larından geçiriliyor:
import tiktoken
en = ("All human beings are born free and equal in dignity and rights. "
"They are endowed with reason and conscience and should act towards "
"one another in a spirit of brotherhood.")
tr = ("Bütün insanlar hür, haysiyet ve haklar bakımından eşit doğarlar. "
"Akıl ve vicdana sahiptirler ve birbirlerine karşı kardeşlik "
"zihniyeti ile hareket etmelidirler.")
for name in ["cl100k_base", "o200k_base"]:
enc = tiktoken.get_encoding(name)
a, b = len(enc.encode(en)), len(enc.encode(tr))
print(f"{name}:")
print(f" english : {len(en):>4} code points -> {a:>3} tokens "
f"({len(en) / a:4.2f} code points/token)")
print(f" turkish : {len(tr):>4} code points -> {b:>3} tokens "
f"({len(tr) / b:4.2f} code points/token)")
print(f" Turkish/English token count ratio: {b / a:4.2f}")cl100k_base:
english : 170 code points -> 33 tokens (5.15 code points/token)
turkish : 160 code points -> 60 tokens (2.67 code points/token)
Turkish/English token count ratio: 1.82
o200k_base:
english : 170 code points -> 33 tokens (5.15 code points/token)
turkish : 160 code points -> 46 tokens (3.48 code points/token)
Turkish/English token count ratio: 1.39
Kod çıktılarında ondalık ayırıcı nokta, binlik ayırıcı virgüldür; düzyazıda Türkçe biçim kullanıyoruz.
Bildirgenin aynı maddesini aktaran bu iki cümlelik metinlerde, Türkçe token sayısı İngilizcenin cl100k_base ile yaklaşık 1,82 katı, o200k_base ile 1,39 katıdır. Bu örnekte ikinci kodlama farkı azaltıyor.
Token başına aynı girdi ücretinin uygulandığı bir karşılaştırmada, daha fazla token daha yüksek girdi maliyeti demektir. Sabit bir token sınırı da bu tür metinlerde farklı miktarda içeriğe karşılık gelebilir. Ancak toplam maliyet; seçilen modele, girdi ve çıktı uzunluklarına ve ücretlendirme koşullarına bağlıdır.
Diller arasında benzer farklılıklar daha geniş çalışmalarda da gösterilmiştir (Petrov vd. 2023). Buradaki iki metin ise Türkçe için evrensel bir oran vermez. Farkı yalnızca bazı Türkçe harflerin UTF-8’de iki bayt tutmasıyla açıklamak da yeterli değildir; öğrenilmiş sözlük ve tokenleştirme kuralları birlikte etkilidir.
Bu fark nereden geliyor? Türkçe, İngilizceye kıyasla dilbilgisel bilgiyi tek bir kelimenin içinde eklerle kodlamaya çok daha fazla başvurur (Oflazer 1994); bu yüzden aynı kökün çok sayıda yüzey biçimi oluşur. İngilizce, aynı dilbilgisel bilgiyi bazı yapılarda ayrı kelimelerle ifade eder. Bu kelimeler eğitim derleminde sık geçiyorsa kısa token dizileriyle temsil edilebilir. Türkçede ise çok sayıdaki çekimli biçimin nasıl parçalanacağı, tokenizer’ın hangi ortak dizileri öğrendiğine bağlıdır.
Aşağıda ev köküne ekler eklendikçe cl100k_base çıktısının nasıl değiştiğini görüyorsunuz. Her kelimeyi, önünde tek bir boşluk bulunacak biçimde ayrı ayrı kodladık:
ev 1 tokens [' ev']
evler 2 tokens [' ev', 'ler']
evlerimiz 4 tokens [' ev', 'ler', 'im', 'iz']
evlerimizden 5 tokens [' ev', 'ler', 'im', 'iz', 'den']
Bir Türkçe kelimede biçimbirimler ve BPE parçaları
Vurgu renkli kutu ev kökünü gösteriyor. Diğer kutular ekleri veya eklerin parçalarını içeriyor: -imiz, im ve iz olarak iki token’a ayrılmış. BPE bu birimleri dilbilgisi kurallarından değil, eğitim verisindeki birleştirme istatistiklerinden öğrenir. Son satırdaki Türkçe biçim beş token, İngilizce karşılığı üç token olarak gösteriliyor. Aynı token başı ücret uygulanırsa bu fark, ilgili metin parçalarının işlenme ücretine de yansır. ␣, gerçek bir boşluğu görünür kılmak için kullanılan simgedir.
Bu karşılaştırma, daha az kelime kullanmanın daha az token üretmek anlamına gelmediğini gösteriyor. Token sınırlarının biçimbirimlerle ne ölçüde örtüştüğü ise ayrı bir değerlendirme konusu.
ev|ler|im|iz|den bölünmesindeki dört iç sınırın üçü, burada kullandığımız ev|ler|imiz|den biçimbirim çözümlemesiyle örtüşüyor (ekleri farklı ayıran çözümlemeler de mümkün). Fazladan sınır, birinci çoğul kişi iyelik eki -imizin içinde bulunuyor. Dolayısıyla bu örnek, BPE parçalarının biçimbirimlerle kısmen örtüşebildiğini, ancak onları birebir temsil etmediğini gösteriyor. Yalnızca çıktıdan hareketle im ve iz parçalarının eğitim verisindeki sıklığını belirleyemeyiz.
o200k_base ise aynı kelimede -imiz ekini bölmüyor ve kelimeyi dört token’a ayırıyor: ev|ler|imiz|den. Bu fark, aynı kelimenin farklı tokenizer’larda farklı biçimde temsil edilebildiğini gösterir; tek başına bütün Türkçe kelimeler için bir başarı karşılaştırması değildir.
Bostrom ve Durrett (2020), eşit sözlük büyüklüğüyle yürüttükleri İngilizce ve Japonca deneylerinde, BPE’nin bir akrabası olan Unigram LM’in (Bölüm 8.4.5) sınırlarının morfolojik referanslarla BPE’den daha iyi örtüştüğünü bulmuştur. Bu sonuç Türkçe için ayrıca sınanmalıdır.
Yukarıdaki çıktıda gözden kaçabilecek bir ayrıntı var: ilk token 'ev' değil ' ev', yani başında bir boşluk taşıyor. Nedenini anlamak için tokenizer’ın bir cümleyi nasıl ele aldığına bakmak gerekiyor.
Önce ön parçalara, sonra token’lara. GPT-2’nin BPE tokenizer’ı ve BERT’in WordPiece tokenizer’ı, alt kelime işlemlerinden önce metni daha küçük parçalara ayırır. Bu aşamaya ön tokenleştirme (pre-tokenization) denir. GPT-2; harf, sayı, noktalama ve boşluk dizilerini bir düzenli ifadeyle (regex) ayırır. BERT’in temel tokenleştirme işlemleri ise boşlukları, noktalama işaretlerini ve bazı yazı sistemlerine özgü sınırları dikkate alır. Ardından BPE veya WordPiece bu parçaları işler. Oluşan token’lar ön tokenleştirmenin koyduğu sınırları aşamaz; ancak bu sınırlar her dilde kelime sınırı anlamına gelmez.
Boşluklar nasıl temsil edilir? Parçaları yeniden birleştirirken aralarındaki sınırların nasıl tutulduğunu bilmek gerekir. Yalnızca ev, ler, geld, ik dizilerini görmek, boşlukların yerini belirlemeye yetmez: evler geldik mi, ev ler geld ik mi? Tokenizer’lar bu bilgiyi farklı biçimlerde ele alır: bazıları boşlukları token’ların içinde korur, bazıları boşluğu görünür bir simgeyle gösterir, bazıları ise kelime içindeki devam parçalarını işaretler. Bu yöntemlerin özgün metni geri oluşturma özellikleri aynı değildir. Aynı iki kelime, evlerimizden geldik, üç tokenizer ailesinde şöyle görünüyor:
| Aile (çalıştırılan tokenizer) | Token’lar | Sınır bilgisinin gösterimi |
|---|---|---|
GPT (cl100k_base) |
ev ler im iz den ␣geld ik |
Bu örnekte boşluk, geld dizisiyle aynı token’da bulunur; ␣, gerçek boşluğu görünür kılmak için kullanılmıştır. |
| SentencePiece (XLM-R) | ▁ev lerimiz den ▁geldi k |
▁, boşluğun görünür gösterimidir; metnin başında tokenizer’ın eklediği başlangıç boşluğunu da temsil edebilir. |
| WordPiece (çok dilli BERT) | ev ##leri ##mi ##zde ##n geldi ##k |
##, parçanın aynı ön tokenleştirme biriminin devamı olduğunu gösterir; özgün boşluk sayısını saklamaz. |
Bu gösterimler, parçaların nasıl birleştirileceğine ilişkin farklı bilgiler taşır. cl100k_base çıktısındaki ' ev', gerçek bir boşlukla başlayan token’dır. WordPiece’in ## işareti ise devam parçasını belirtir; özgün boşlukların sayısını veya türünü göstermez. Şekilde gerçek boşluğu görünür kılmak için ␣ simgesini kullandık: ␣ev.
SentencePiece (Kudo ve Richardson 2018), eğitim metninin önceden kelimelere ayrılmasını gerektirmez; ham metinden çalışabilir. Boşlukları ▁ ile temsil eder. Bununla birlikte, oluşturabileceği parçalar ayarlarla sınırlandırılır; örneğin varsayılan split_by_whitespace=True ayarı, boşluğun iki yanındaki kelimeleri tek parçada birleştirmeyi sınırlar. Önceden kelime bölümleme gerektirmemesi, Japonca ve Çince gibi boşlukla ayrılmayan metinlerde kullanımını kolaylaştırır.
Tokenleştirme sürecini dört aşamada izlemek. Hugging Face tokenizers kütüphanesinde süreci normalleştirme, ön tokenleştirme, alt kelime kodlaması ve son işleme olarak inceleyebiliriz. Her tokenizer bu aşamaların hepsini kullanmak zorunda değildir. Aşağıda Türkçe bir cümleyi çok dilli BERT’in tokenizer’ında adım adım izliyoruz (tokenizers 0.22 ile):
from tokenizers import Tokenizer
tok = Tokenizer.from_pretrained("google-bert/bert-base-multilingual-uncased")
text = "Çay içtik, sonra evlerimizden çıktık."
norm = tok.normalizer.normalize_str(text)
print("1 normalize :", norm)
print("2 pre-tokenize :", [w for w, _ in tok.pre_tokenizer.pre_tokenize_str(norm)])
print("3 subwords :", tok.encode(text, add_special_tokens=False).tokens)
print("4 special :", tok.encode(text).tokens)
print(" ids :", tok.encode(text).ids)1 normalize : cay ictik, sonra evlerimizden cıktık.
2 pre-tokenize : ['cay', 'ictik', ',', 'sonra', 'evlerimizden', 'cıktık', '.']
3 subwords : ['cay', 'ic', '##tik', ',', 'sonra', 'ev', '##leri', '##mi', '##zde', '##n', 'cıktı', '##k', '.']
4 special : ['[CLS]', 'cay', 'ic', '##tik', ',', 'sonra', 'ev', '##leri', '##mi', '##zde', '##n', 'cıktı', '##k', '.', '[SEP]']
ids : [101, 21373, 11797, 13537, 117, 12624, 18110, 12737, 10555, 55567, 10115, 59161, 10167, 119, 102]
İlk dört satır işlem aşamalarını, son satır ise oluşan token kimliklerini gösteriyor:
- Normalleştirme — Bu BERT tokenizer’ı metni küçük harfe dönüştürür ve Unicode ayrıştırmasının ardından birleştirici işaretleri temizler. Böylece
Çay→cay,içtik→ictikolur. Bu aşamada silinen bilgi geri gelmez; model artıkçayilecayarasındaki farkı göremez.ıise biriile bir işarete ayrışmadığı için korunur. Bu, bu normalleştiricinin davranışıdır, Türkçenin küçük harf kuralı değil: aynı normalleştiriciISPARTA’yıisparta,Iğdır’ıigdıryapıyor (yeniden koşu); TürkçedeIküçülünceıolur. Bu çıktıyı başka bir tokenizer’a genellemeyin. - Ön tokenleştirme — Metin, boşluk ve noktalama sınırlarından ön parçalara ayrılır. Virgül ve nokta da ayrı parçalardır.
- Alt kelime kodlaması — WordPiece bu ön parçaları sözlüğündeki birimlerle temsil eder. Örnekte
evlerimizdenbeş parçadır;sonrabütündür. - Son işleme — Bu tek metinlik BERT girdisinin başına
[CLS], sonuna[SEP]eklenir.
Son satırdaki tamsayılar token kimlikleridir. Model, bunların yanında dikkat maskesi (attention mask) gibi yardımcı girdiler de kullanabilir.
bert-base-multilingual-cased, büyük/küçük harf ayrımını korur; ancak normalleştirme aşaması bütünüyle boş değildir. Metin temizleme (örneğin denetim karakterlerini atma) ve Çince karakterlerin çevresine boşluk ekleme işlemleri etkindir. Burada kullanılan cl100k_base ve o200k_base kodlamalarında BERT’teki gibi küçük harfe dönüştürme ve aksan temizleme aşamaları bulunmaz. SentencePiece ise dışarıdan kelime bölümleme gerektirmeden çalışabilir; kendi normalleştirme ve parça oluşturma ayarları vardır.
Son aşama çıktıda hemen göze çarpıyor, o yüzden özel token’ların adlarını şimdiden verelim:
| token | işlevi |
|---|---|
[UNK] |
Kullanılan kodlama düzeninin temsil edemediği parçanın yerine geçer. Tam bayt kapsamına sahip bir tokenizer, geçerli metnin baytlarını temsil etmek için bu işarete ihtiyaç duymaz. |
[PAD] |
Birlikte işlenen (aynı batch’teki) dizileri hedef uzunluğa tamamlar. Dolgu konumları uygun dikkat maskesiyle dışlanır. |
[CLS] |
BERT girdisinin başındaki özel token’dır. Bu konumun bağlamsal temsili, dizi sınıflandırma gibi görevlerde kullanılabilir. |
[SEP] |
BERT’te metin sonunu ve iki metin (ör. soru ve pasaj) arasındaki sınırı işaretler. |
| BOS / EOS | Modelin kullandığı dizi başı ve dizi sonu işaretleridir. Üretim sırasında EOS, bitiş işareti olarak kullanılabilir. |
Özel token’ların adları ve görevleri modele göre değişir. <s>, </s> ve <|endoftext|> gibi işaretler birbirinin yerine kullanılamaz; modelin beklediği token kimlikleri ve yerleşim kuralları izlenmelidir. Kendi token’larınızı saymaya başladığınızda bunların da bağlam penceresinden pay aldığını unutmayın.
Türkçe metinle çalışırken akılda tutulacak son bir pratik ayrıntı var. ö gibi işaretli bir harf bilgisayarda iki farklı biçimde saklanabilir: tek bir kod noktası olarak ya da o harfi ile ayrı bir “iki nokta” işareti olarak. Bu iki gösterim aynı görünebilir, ancak farklı kod noktası dizileridir. Tokenizer’ın normalleştirme kurallarına bağlı olarak aynı veya farklı token dizileri üretebilirler. Önceden eğitilmiş bir model kullanırken onun tokenizer’ının beklediği işlem düzenini izleyin. Kendi veri işleme düzeninizde NFC adı verilen standart biçimi kullanmaya karar verirseniz, bunu eğitim ve kullanım sırasında tutarlı biçimde uygulayın:
import unicodedata
text = unicodedata.normalize("NFC", text)Token sayısı karşılaştırmalarında, girdilere hangi Unicode normalleştirmesinin uygulandığı ölçüm koşullarının parçası olarak belirtilmelidir.
Türkçe metinle çalışırken üç pratik sonuç.
Birincisi: maliyeti tamamlanan iş başına ölçün. Türkçe ve İngilizce örneklerde girdi ve çıktı token sayılarını, kullanılan modelin ücretleriyle birlikte karşılaştırın. Tek bir metinden sabit bir maliyet oranı çıkarmayın.
İkincisi: bağlam sınırını kullandığınız modelin tokenizer’ıyla denetleyin. Aynı token bütçesine sığan içerik miktarı dile ve belgeye göre değişebilir. Parça (chunk) boyutlarını (Bölüm 20) belirlerken prompt’a, özel token’lara ve üretilecek yanıta da yer ayırın.
Üçüncüsü: kendi modelinizi eğitiyor veya mevcut bir modeli yeni bir sözlüğe uyarlıyorsanız sentencepiece (Kudo ve Richardson 2018) ile Türkçeye uygun bir tokenizer eğitebilirsiniz. Ancak yeni tokenizer, hazır modelin mevcut token kimlikleri ve öğrenilmiş temsilleriyle kendiliğinden uyumlu olmaz. Önce mevcut model–tokenizer seçeneklerini kendi Türkçe verinizde ölçün; özel tokenizer’ın sağlayacağı kazancı model uyarlama maliyetiyle birlikte değerlendirin.
İpucuSezgi kontrolü: neden bütün bunları bırakıp doğrudan karakter kullanmıyoruz?
Sınırlı bir karakter kümesiyle çalışmak küçük bir sözlük sağlayabilir; ancak gerçek metinlerde karşılaşılacak karakterler yalnızca dilin alfabesinden oluşmaz. Bayt düzeyinde ise bütün değerler 256 birimle kapsanabilir. Sabit bir karakter veya bayt sözlüğü kullanıldığında, metni bu birimlere ayırmak için BPE’deki gibi birleştirme kuralları öğrenmek gerekmez. Dil modelinin eğitimi ise yine gerekir. Karakter ve bayt düzeyinde modeller de bulunduğuna göre (Xue vd. 2022), alt kelimelerin hangi avantajları sağladığına bakalım.
Bildirgenin yukarıdaki Türkçe metninde üç farklı birimi sayıyoruz: Python’ın ayırdığı Unicode kod noktaları, cl100k_base token’ları ve boşluklardan ayrılan metin parçaları. Son grupta noktalama işaretleri kelimeye bitişik kalır. Token’ların metin gösterimini yalnızca çıktıyı okumayı kolaylaştırmak için kullanıyoruz; tek bir bayt token’ını ayrı çözmek her zaman geçerli bir Unicode parçası vermez.
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
units = {
"code points": list(tr),
"subword tokens": [enc.decode([t]) for t in enc.encode(tr)],
"words": tr.split(),
}
for name, seq in units.items():
n = len(seq)
print(f"{name:<15} {n:>3} units {n * n:>6,} pairs first six: {seq[:6]}")code points 160 units 25,600 pairs first six: ['B', 'ü', 't', 'ü', 'n', ' ']
subword tokens 60 units 3,600 pairs first six: ['B', 'üt', 'ün', ' insan', 'lar', ' h']
words 21 units 441 pairs first six: ['Bütün', 'insanlar', 'hür,', 'haysiyet', 've', 'haklar']
İlk sebep dizi uzunluğu. Tam self-attention’da (full self-attention), her head için \(n \times n\) boyutunda konum ilişkileri ele alınır (Bölüm 7). Çıktıdaki pairs sütunu bu teorik konum çifti sayısını gösteriyor. Verilen örnekte 160 kod noktası 25.600, 60 alt kelime token’ı ise 3.600 konum çiftine karşılık gelir. Dizi yaklaşık 2,7 kat kısalırken bu sayı yaklaşık 7,1 kat azalır. Bu çift sayısı tek başına GPU süresi ya da API ücreti değildir.
Sabit model genişliğinde tam dikkatin hesaplama yükü dizi uzunluğuyla karesel, katmandaki konum başına işlemler ise doğrusal büyür (Vaswani vd. 2017). Bu basitleştirilmiş modelde diziyi beş kat uzatmak, bu iki bileşenin toplamını beş ile yirmi beş kat arasında artırır. Bu oran doğrudan çalışma süresi veya ücret tahmini değildir; yerel ya da seyrek dikkat kullanan mimarilerde büyüme ilişkisi de değişebilir.
İkinci sebep, birimin büyüklüğü. Her satırın ilk altı birimini okuyun. ü ve t gibi kod noktaları kelimenin yazımına katkıda bulunur; ancak insan gibi daha büyük bir örüntü tek bir girdi birimi olarak sunulmaz. Karakter düzeyindeki modelin bu tür örüntüleri karakter dizilerinden öğrenmesi gerekir. Alt kelime satırında ise insan ve lar doğrudan ayrı birimlerdir. Bunun öğrenmeyi ve görev başarısını nasıl etkilediği, model ve veri üzerinde değerlendirilmelidir.
Boşluktan bölünen parçalar daha da kısa bir dizi verir, ama başka sorunlar getirir. Bu örnekte boşluktan bölme 21 birim üretiyor. Ancak tr.split() noktalama işaretlerini ayırmadığı için hür,, hür’den farklı bir parça olarak kalıyor. Bu sorun daha ayrıntılı bir kelime tokenizer’ıyla giderilebilir. Çekimli biçimlerin sabit sözlükte ayrı girdiler olarak tutulması ise sürer; sözlükte bulunmayan yeni biçimler için ayrıca bir çözüm gerekir. Bir sonraki örnek bunu gösteriyor.
Alt kelime tokenleştirmesinde sözlük büyüklüğü ile dizi uzunluğu arasında bir denge (trade-off) vardır. Daha büyük parçaları sözlüğe almak dizileri kısaltabilir; buna karşılık daha fazla sözlük girdisi gerekir. Hedef sözlük büyüklüğünü ve başlangıç birimlerini tasarımcı belirler; BPE, bu koşullar altında hangi parçaların oluşturulacağını eğitim verisindeki çift sıklıklarından öğrenir. Bu yaklaşım bir sıkıştırma problemine benzer; BPE’nin 1994’te bir veri sıkıştırma algoritması olarak ortaya çıkmış olması da (Gage 1994) bununla uyumludur. Ancak burada amaç doğrudan dosya boyutunu küçültmek değil, modelin kullanacağı birimleri seçmektir.
8.3.4 Karakter, alt kelime, bütün kelime: tek bir örnek
Aşağıdaki tablo üç seçeneği kâğıt üzerinde karşılaştırıyor. Önce üçünü de küçük bir örnekte izleyin; böylece tablonun her satırı, gözünüzle gördüğünüz bir şeye karşılık gelsin.
Derlem, on iki kökün yalın hâllerinden ve dört ek dizisiyle (-ler, -de, -den, -lerde) oluşturulan biçimlerinden oluşuyor: toplam 60 farklı kelime biçimi. Ekler ünlü uyumuna göre yazılmıştır (-ler/-lar, -de/-da). Kodda her biçime verilen sıklıklar dikkate alındığında derlem toplam 216 kelime geçişini temsil eder.
İki test kelimesi, evlerden ve okullardan, derlemde bulunmuyor; ancak bunları oluşturacak karakterler ve ilgili ek dizileri başka biçimlerde geçiyor. Kelime ve karakter yöntemleri derlemdeki birimleri listelerken BPE, sıklıklardan birleştirme kuralları öğreniyor. Ardından üç yöntem de aynı iki test kelimesine uygulanıyor. BPE satırı Bölüm 8.3.1’deki pair_counts, merge ve apply_merges fonksiyonlarını yeniden kullanıyor:
stems = {"ev": "e", "el": "e", "göl": "e", "köy": "e", "gün": "e", "yüz": "e",
"okul": "a", "yol": "a", "kol": "a", "yıl": "a", "kız": "a", "masa": "a"}
corpus = {}
for stem, v in stems.items(): # v: eklerin alacağı ünlü
for suffix, n in [("", 4), (f"l{v}r", 2), (f"d{v}", 4),
(f"d{v}n", 4), (f"l{v}rd{v}", 4)]:
corpus[stem + suffix] = n # ev, evler, evde, evden, evlerde, ...
test = ["evlerden", "okullardan"] # iki kelime de derlemde yok
chars = sorted({c for word in corpus for c in word})
words = {tuple(w) + ("</w>",): n for w, n in corpus.items()}
merges = []
while len(chars) + 1 + len(merges) < 60: # sözlük 60 sembole ulaşınca dur
best, _ = pair_counts(words).most_common(1)[0]
merges.append(best)
words = merge(words, best)
tokenizers = {
"whole words": (len(corpus), lambda w: [w if w in corpus else "<UNK>"]),
"characters": (len(chars), lambda w: list(w)),
"subwords (BPE)": (len(chars) + 1 + len(merges),
lambda w: list(apply_merges(w, merges))),
}
for name, (size, split) in tokenizers.items():
pieces = [p for w in test for p in split(w)]
print(f"{name:<15} vocabulary {size:>2} {len(pieces):>2} units: {' '.join(pieces)}")whole words vocabulary 60 2 units: <UNK> <UNK>
characters vocabulary 18 18 units: e v l e r d e n o k u l l a r d a n
subwords (BPE) vocabulary 60 6 units: ev ler den</w> okul lar dan</w>
Şimdi bu çıktıyı aşağıdaki tablonun satırlarıyla karşılaştırın:
- Sözlük büyüklüğü. Kelime düzeyindeki yöntemde 60 farklı kelime biçimi bulunuyor. Çıktıdaki bu sayı, ayrıca kullanılan
<UNK>işaretini kapsamıyor. Karakter yöntemi 18 farklı karakteri listeliyor. BPE için gösterilen 60 ise 18 karakteri,</w>sembolünü ve 41 birleştirmeyle eklenen birimleri kapsıyor. Bu nedenle sayılar, özel ve yapısal sembolleri bütünüyle aynı kuralla sayan bir karşılaştırma olarak okunmamalı. Gerçek Türkçe veride dört ek dizisinin ötesinde çok sayıda çekimli biçimle karşılaşılır. - Sözlük dışı kelimeler. Kelime düzeyindeki yöntem, iki test kelimesini de aynı
<UNK>işaretiyle temsil ediyor. Böylece kelimelerin yazımları ve birbirlerinden farklı oldukları bilgisi kayboluyor. Karakter ve BPE yöntemleri bu iki girdiyi mevcut birimlerle temsil edebiliyor; çünkü gereken bütün karakterler başlangıç alfabelerinde bulunuyor. Bu küçük örnekte kullanılan işlevler, alfabe dışındaki karakterleri ayrıca denetlemiyor. - Dizi uzunluğu. Üç yöntem aynı bilgiyi korumuyor; bu yüzden aşağıdaki sayılar bir verimlilik sıralaması değil. Ayrı ayrı işlenen iki test kelimesi, gösterilen çıktıda toplam 18 karakter birimi, 6 BPE birimi veya 2
<UNK>birimi üretiyor. Sonuncusu en kısa olsa da kelimelerin yazımını kaybediyor. Ayrıca karakter sayımında kelimeler arası ayırıcı bulunmazken BPE çıktısında kelime sonu işareti kullanılıyor. - Birimlerin dilbilgisel karşılığı.
e,vvelkelimenin yazımını oluşturan karakterlerdir; bu örnekte tek başlarına bir kök veya ek temsil etmezler. BPE çıktısındakiev,lervedenise sırasıyla kök, çoğul eki ve ayrılma hâli ekiyle örtüşüyor.</w>kelime sonunu gösteren yapısal işarettir. - Biçimbilimsel (morphological) açıdan zengin diller. Bu küçük derlemde öğrenilen BPE birimleri, iki test kelimesinde kök ve ek sınırlarıyla örtüşüyor. Algoritma bu parçaları kök veya ek olarak etiketlemiyor; başka kelimelerde ya da başka bir eğitim derleminde aynı örtüşme sağlanmayabilir.
- Tokenizer eğitimi. Yalnızca BPE satırı bir öğrenme döngüsü çalıştırdı. Diğer ikisi derlemde gördükleri birimleri listeledi.
Kısacası bu örnekte kelime düzeyi kısa dizi üretiyor ama görülmemiş biçimlerin yazımını kaybediyor; karakter ve bayt düzeyi kapsam sağlıyor ama diziyi uzatıyor; alt kelimeler ikisi arasında bir denge arıyor. Aşağıdaki tablo bu ayrımı kapsama, uzunluk ve biçimbilim açısından karşılaştırıyor. Normalleştirme, sınırların korunması, dil kapsamı ve modelle uyum gibi kararlar da sonucu etkiler.
| Ölçüt | Karakter veya bayt | Alt kelime | Bütün kelime |
|---|---|---|---|
| Sözlük büyüklüğü | Karakterde seçilen alfabeye bağlıdır; tam bayt alfabesi 256 değerdir. | Eğitimde belirlenen hedefe ve uygulamaya bağlıdır. | Seçilen kelime biçimlerinin sayısına bağlıdır; kullanılan sözlük sonludur. |
| Sözlük dışı girdiler | Karakter alfabesi yetersiz kalabilir. Tam bayt alfabesi bütün bayt dizilerini temsil edebilir. | Alfabe kapsamı, bilinmeyen token kuralları ve varsa byte fallback belirleyicidir. | Sabit sözlükte bulunmayan kelimeler için ek bir yöntem gerekir. |
| Dizi uzunluğu | Genellikle daha uzundur; oran metne ve karşılaştırılan tokenizer’a bağlıdır. | Genellikle karakter ve kelime düzeyleri arasında kalır. | Bilinen kelimeler tek birimle temsil edilebilir. |
| Birimlerin dilbilgisel karşılığı | Yazımı küçük birimlerle temsil eder. | Parçalar bazen biçimbirimlerle örtüşür; bu garanti değildir. | Kelime biçimini korur; kelimenin anlamını bağlamdan bağımsız belirlemez. |
| Zengin biçimbilim | Çok sayıdaki kelime biçimini, alfabe kapsadığı sürece temsil edebilir. | Ortak parçaları farklı çekimli biçimlerde yeniden kullanabilir. | Çok sayıda çekimli biçim, sözlük kapsamını zorlaştırabilir. |
| Tokenizer eğitimi | Sabit alfabe için birleştirme öğrenmek gerekmez. | Parçalar veya parça olasılıkları genellikle derlemden öğrenilir. | Kelime sözlüğü seçilir ya da derlemden çıkarılır; alt kelime birleştirmesi öğrenilmez. |
Alt kelimeler, ortak parçaları farklı kelimelerde yeniden kullanırken karakter düzeyine göre daha kısa diziler üretebilir. Bu denge, birçok dil modelinde tercih edilmelerini sağlar. Karakter, bayt ve kelime düzeyindeki yaklaşımlar da kullanılabilir (Xue vd. 2022); uygun seçim görev, veri, model mimarisi ve hesaplama bütçesine bağlıdır.
NotDerinleşme: aynı tür birimi öğrenmenin üç yolu — BPE, WordPiece, Unigram LM
Bu kutuyu ilk okumada atlayabilirsiniz; bölümün geri kalanı ona dayanmıyor.
Bu kutuda alt kelime tokenleştirmesinde kullanılan üç yöntemi karşılaştırıyoruz: BPE, BERT’in kullandığı WordPiece ve T5’in kullandığı Unigram LM. Yöntemlerin ne olduğunu ve hangi modelde kullanıldığını, BERT’in tokenizer’ını incelediğimiz yerde anlatıyoruz (Bölüm 8.4.5). Bu kutu, merak edenler için o anlatımın deneyini yapıyor: üç yöntemi yukarıdaki derlemde yan yana çalıştırıyor. Temel fikirleri tek satıra iniyor:
| Yöntem | Temel fikir |
|---|---|
| BPE | en sık komşu çifti birleştir |
| WordPiece | birleşmenin göreli faydasını puanla (aşağıdaki oran öğretici bir yaklaşıklık; özgün BERT eğiticisinin tam tarifi değil) |
| Unigram LM | büyük bir parça kümesinden başla, olasılıksal olarak buda |
Bu yöntemler hem sözlüğün nasıl oluşturulduğu hem de yeni metnin hangi parçalara ayrıldığı bakımından farklılaşır. SentencePiece (Kudo ve Richardson 2018) ise dördüncü bir algoritma değil, BPE ya da Unigram LM’i çalıştırabilen bir kütüphanedir.
Aynı derlem, üç yöntem. Aynı iki test kelimesini, her uygulamada 60 sözlük girdisi hedefleyerek karşılaştıralım. Ancak başlangıç gösterimleri aynı değil: BPE kelime sonu işareti kullanıyor, WordPiece başlangıç ve devam parçalarını ayırıyor, küçük Unigram uygulaması ise bu işaretleri kullanmıyor. Bu deney yöntemlerin davranışlarını gösterir; aralarındaki bütün farkları denetleyen bir başarı karşılaştırması değildir. Kod, WordPiece ve Unigram LM’in küçük birer öğretici sürümü.
NotDerinleşme: en küçük WordPiece ve Unigram LM
Aşağıdaki
\[ \mathrm{score}(a,b)=\frac{\mathrm{freq}(ab)}{\mathrm{freq}(a)\,\mathrm{freq}(b)} \]
puanı, WordPiece eğitimini açıklamak için kullanılan öğretici bir yaklaşımdır. BERT’in özgün WordPiece eğiticisinin birebir yeniden üretimi olarak görülmemelidir. Bu kutudaki sonuçlar, özellikle bu puanlama kuralına ve verilen uygulamaya aittir.
train_unigram da Unigram yaklaşımından esinlenen küçük bir öğretici uygulamadır. Her kelimenin bütün olası bölünmelerini hesaba katmak yerine yalnızca en yüksek puanlı bölünmesini kullanır. Parça çıkarma maliyetini hesaplarken diğer parça puanlarını sabit tutar; budamadan sonra seçilen bölünmelerden yeni sayımlar oluşturur. Sözlükte kalan her parçaya verilen 0.001 başlangıç sayımı da sıfır olasılığı önler. Bu nedenle aşağıdaki loss, tam Unigram modelinin marjinal olabilirliğiyle aynı amaç fonksiyonu değildir (Kudo 2018).
import math
def train_wordpiece(corpus, size):
words = {tuple([w[0]] + ["##" + c for c in w[1:]]): n for w, n in corpus.items()}
vocab = {s for symbols in words for s in symbols}
first = None
while len(vocab) < size:
pairs, single = Counter(), Counter()
for symbols, n in words.items():
for s in symbols:
single[s] += n
for a, b in zip(symbols, symbols[1:]):
pairs[(a, b)] += n
score = {p: c / (single[p[0]] * single[p[1]]) for p, c in pairs.items()}
best = max(score, key=lambda p: (score[p], p))
first = first or (pairs, score)
glued = best[0] + best[1].removeprefix("##")
new = {}
for symbols, n in words.items():
out, i = [], 0
while i < len(symbols):
if symbols[i:i + 2] == best:
out.append(glued)
i += 2
else:
out.append(symbols[i])
i += 1
new[tuple(out)] = n
words, vocab = new, vocab | {glued}
return vocab, first
def wordpiece_split(word, vocab): # açgözlü: önce bilinen en uzun parça
pieces, start = [], 0
while start < len(word):
for end in range(len(word), start, -1):
piece = word[start:end] if start == 0 else "##" + word[start:end]
if piece in vocab:
break
else:
return ["[UNK]"]
pieces.append(piece)
start = end
return pieces
def best_split(word, logp): # Viterbi: en olası bölünme
best = [(0.0, [])] + [(-math.inf, None)] * len(word)
for end in range(1, len(word) + 1):
for start in range(end):
piece = word[start:end]
if piece in logp and best[start][1] is not None:
score = best[start][0] + logp[piece]
if score > best[end][0]:
best[end] = (score, best[start][1] + [piece])
return best[-1]
def train_unigram(corpus, size):
counts = Counter() # büyük başla: her alt dizi (substring)
for w, n in corpus.items():
for i in range(len(w)):
for j in range(i + 1, len(w) + 1):
counts[w[i:j]] += n
start_size = len(counts)
logprobs = lambda c: {p: math.log(k / sum(c.values())) for p, k in c.items()}
loss = lambda lp: -sum(n * best_split(w, lp)[0] for w, n in corpus.items())
while len(counts) > size:
lp = logprobs(counts)
base = loss(lp)
cost = {p: loss({q: v for q, v in lp.items() if q != p}) - base
for p in counts if len(p) > 1} # tek harfler her zaman kalır
k = max(1, min(len(counts) - size, len(cost) // 5))
for p in sorted(cost, key=lambda p: (cost[p], p))[:k]:
del counts[p] # en ucuza mal olan parçaları buda
lp = logprobs(counts) # en iyi bölünmelerden yeniden kestir
counts = Counter({p: 0.001 for p in counts})
for w, n in corpus.items():
for piece in best_split(w, lp)[1]:
counts[piece] += n
return logprobs(counts), start_sizewp_vocab, (pairs, score) = train_wordpiece(corpus, 60)
uni_logp, start_size = train_unigram(corpus, 60)
print("first step, WordPiece initial pairs:")
print(" highest raw pair counts: ",
[(a + b.removeprefix("##"), c) for (a, b), c in pairs.most_common(3)])
print(" highest score (WordPiece):",
[(a + b.removeprefix("##"), round(s, 3))
for (a, b), s in sorted(score.items(), key=lambda x: -x[1])[:3]])
print(f" Unigram LM starts from {start_size} substrings and prunes to {len(uni_logp)}")
print()
for w in test:
print(f"{w:<11} BPE : {' | '.join(apply_merges(w, merges))}")
print(f"{'':<11} WordPiece : {' | '.join(wordpiece_split(w, wp_vocab))}")
print(f"{'':<11} Unigram LM: {' | '.join(best_split(w, uni_logp)[1])}")first step, WordPiece initial pairs:
highest raw pair counts: [('##de', 72), ('##da', 72), ('##rd', 48)]
highest score (WordPiece): [('ok', 0.056), ('##ku', 0.056), ('ev', 0.028)]
Unigram LM starts from 322 substrings and prunes to 60
evlerden BPE : ev | ler | den</w>
WordPiece : ev | ##l | ##e | ##r | ##d | ##e | ##n
Unigram LM: evlerde | n
okullardan BPE : okul | lar | dan</w>
WordPiece : okullar | ##d | ##a | ##n
Unigram LM: okullarda | n
İlk iki çıktı satırı, WordPiece’in başlangıç gösterimindeki çiftleri iki ölçüte göre sıralıyor: ham sıklık ve oran puanı. Bu, ölçütlerin farkını gösterir. BPE örneğinin başlangıç alfabesi ve kelime sonu işareti farklı olduğundan, ilk satır onun birleştirme günlüğü olarak okunmamalıdır.
BPE, her adımda en sık komşu sembol çiftini birleştirir. Bu derlemde tekrarlanan kök ve ek dizileri, farklı kelimelerde yeniden kullanılabilen parçaların oluşmasını sağlıyor. Gösterilen sonuçta iki test kelimesi de kök ve ek sınırlarından ayrılmıştır: ev|ler|den ve okul|lar|dan. Bu örtüşme, kullanılan derlem ve sözlük bütçesi için gözlenen sonuçtur; bütün yeni kelimeler için garanti değildir.
WordPiece. Bu öğretici uygulama, çift sıklığını iki parçanın ayrı sıklıklarının çarpımına böler: \(\frac{c(ab)}{c(a)\,c(b)}\). Başlangıçta o + ##k ve ##k + ##u çiftleri aynı yüksek puanı alıyor (0,056). Kod, eşit puanlarda sembol çiftlerinin sıralamasını kullanarak o + ##k çiftini seçiyor. Bu parçalar küçük derlemde okul ve onun çekimli biçimlerinde birlikte görülüyor. ##, parçanın bir kelimenin devamı olduğunu işaretler.
Verilen sözlük bütçesiyle oluşan sonuç, okullar gibi uzun başlangıç parçalarını içeriyor; okullardan kelimesinin geri kalanı ise gösterilen çıktıda tek harflere ayrılıyor. Bu davranış bütün WordPiece tokenizer’larına genellenemez. Yeni kelimeleri işlerken WordPiece birleştirme listesini tekrar uygulamaz; bulunduğu konumdan başlayan en uzun sözlük parçasını seçerek ilerler.
Unigram LM. Küçük Unigram uygulaması, kelimelerdeki bütün kesintisiz alt dizileri (substring) aday olarak topluyor; yayımlanan çıktıda başlangıçta 322 aday var. Ardından kendi yaklaşık kayıp ölçütüne göre düşük katkılı parçaları budayarak 60 parçaya iniyor. Gerçek Unigram uygulamaları aday oluşturma, olasılık kestirimi ve budamada farklı yöntemler kullanabilir.
Burada öğrenilen puanlar, evlerden için evlerde|n bölünmesini öne çıkarıyor. Bu, kullanılan küçük derlemin ve yaklaşık eğitim yordamının sonucudur; en iyi morfolojik çözümleme veya bütün olası sözlükler arasında en iyi çözüm olduğu anlamına gelmez. Unigram, aynı kelimenin alternatif bölünmelerine de puan verir. evlerden için bu sözlükle mümkün olan bütün bölünmeleri listeleyelim:
def every_split(word, logp, prefix=()):
if not word:
yield sum(logp[p] for p in prefix), list(prefix)
for end in range(1, len(word) + 1):
if word[:end] in logp:
yield from every_split(word[end:], logp, prefix + (word[:end],))
splits = sorted(every_split("evlerden", uni_logp), reverse=True)
print(f"{len(splits)} ways to split 'evlerden' with this vocabulary:")
for logp, pieces in splits:
print(f" score = {math.exp(logp):.1e} {' | '.join(pieces)}")4 ways to split 'evlerden' with this vocabulary:
score = 2.1e-03 evlerde | n
score = 1.2e-14 evler | d | e | n
score = 1.3e-22 ev | l | e | r | d | e | n
score = 1.1e-31 e | v | l | e | r | d | e | n
Burada basılan değer, bölünmedeki parça olasılıklarının çarpımıdır. Aynı kelimenin bölünmelerini sıralamak için bu değerler yeterlidir. Bu alternatifler üzerinden bir olasılık dağılımı oluşturmak istediğimizde ise her değeri, kelimenin bütün geçerli bölünmeleri için hesaplanan değerlerin toplamına böleriz.
Daha az parça kullanmak tek başına daha yüksek puanı garanti etmez; karşılaştırılan parçaların olasılıkları da değişir. Bu çıktıda iki parçalı çözüm, en yakın rakibinden yaklaşık 11, sekiz tek karakterlik bölünmeden yaklaşık 28 büyüklük mertebesi önde (yuvarlanmış çıktıdan). Bu fark, bu küçük derlemin ve öğretici uygulamanın parça olasılıklarına ait; gerçek Unigram eğiticilerinin genel davranışı olarak okunmamalı.
Alternatif bölünmelere puan atanabilmesi, bunlar arasından olasılıksal örnekleme yapmayı mümkün kılar. Yukarıdaki kod yalnızca alternatifleri listeliyor; henüz bir bölünme örneklemiyor.
NotDerinleşme: en küçük Unigram LM’i SentencePiece ile karşılaştırmak
Yukarıdaki küçük sürüm, SentencePiece kütüphanesinin kendisi değil. Aşağıdaki kod, aynı kelime biçimlerini ve sıklıklarını kullanarak sentencepiece 0.2.2 ile bir Unigram tokenizer eğitiyor. Hedef sözlük büyüklüğü 60’tır; ancak hard_vocab_limit=False nedeniyle gerçek sözlük daha küçük olabilir. Bu bütçe bilinmeyen token’ı da kapsar: bu koşuda eğitilen modelin 60 girdisinden biri <unk>. SentencePiece’in boşluk gösterimi ve diğer varsayılanları da küçük uygulamadan farklı olduğundan karşılaştırma birebir aynı koşullarda yapılmıyor.
import sentencepiece as spm
lines = [w for w, n in corpus.items() for _ in range(n)]
with open("corpus.txt", "w", encoding="utf-8") as f:
f.write("\n".join(lines) + "\n")
spm.SentencePieceTrainer.train(
input="corpus.txt", model_prefix="uni", model_type="unigram", vocab_size=60,
character_coverage=1.0, hard_vocab_limit=False, minloglevel=2,
bos_id=-1, eos_id=-1, pad_id=-1)
uni = spm.SentencePieceProcessor(model_file="uni.model")
for w in test:
print(f"{w:<11} {' | '.join(uni.encode(w, out_type=str))}")evlerden ▁evlerde | n
okullardan ▁okul | l | a | r | d | a | n
evlerden için gösterilen bölünme yine evlerde|n biçimindedir. Baştaki ▁, SentencePiece’in varsayılan ayarla eklediği başlangıç boşluğunu temsil eder. okullardan için ise ▁okul|l|a|r|d|a|n seçilmiş. Bu çıktı tek başına, okullarda parçasının sözlükte bulunmadığını göstermez; yalnızca seçilen bölünmede kullanılmadığını gösterir. Unigram’da bir parça sözlükte bulunduğu hâlde, başka bir bölünme daha yüksek puan aldığı için seçilmeyebilir. Sözlüğün kendisine baktığımızda, bu koşuda ▁okul ve ▁evlerde parçalarının bulunduğunu, ▁okullarda parçasının ise bulunmadığını görüyoruz.
SentencePiece’in Unigram eğitimi, küçük uygulamadan farklı bir olasılık kestirimi ve budama süreci kullanır. Normalleştirme, başlangıç adayları ve eğitim ayarları da sonucu etkileyebilir; başka sürüm veya ayarlarda farklı bölünmeler görülebilir.
Altmış farklı kelime biçimi içeren bu yapay derlem, eğitim kurallarının etkisini görünür kılmak için seçildi. Buradaki WordPiece ve Unigram uygulamaları öğretici sadeleştirmeler içeriyor; sonuçları gerçek tokenizer’ların genel başarı sıralaması olarak okumamak gerekir. Kutunun sonunda anılan çalışma, daha büyük derlemlerde BPE ile Unigram LM’i karşılaştırıyor; WordPiece hakkında aynı deneyden sonuç çıkarılamaz.
Bu örnekte iki ayrımı korumak önemli. İlk olarak, öğretici WordPiece puanı yalnızca çiftin sıklığını değil, bileşenlerinin sıklıklarını da kullanır. Çift sayımı aynı kaldığında, bileşenlerin daha sık olması puanı düşürür. Ancak bu kural genel olarak köklerin eklerden önce öğrenileceğini garanti etmez.
İkinci olarak, Unigram bölünmeleri olasılıksal puanlarla değerlendirebilir. Kullanım sırasında en yüksek puanlı bölünme seçilebilir veya alternatiflerden örnekleme yapılabilir. Alt kelime düzenlileştirmesinde (subword regularization) amaç, modelin aynı metni farklı bölünmelerle görmesini sağlayarak tek bir bölünmeye bağımlılığını azaltmaktır (Kudo 2018). Örnekleme, eğitim sırasında girdiler yeniden işlendiğinde yapılabilir; her tam geçiş (epoch) için tek bir seçimle sınırlı değildir. Sağladığı yarar deneyle ölçülmelidir. Benzer biçimde farklı bölünmeler üretmek BPE-Dropout ile de mümkündür (Provilkov vd. 2020).
SentencePiece (Kudo ve Richardson 2018), BPE ve Unigram gibi yöntemleri ham metinden eğitmek ve uygulamak için kullanılan bir kütüphanedir. ▁, boşlukların görünür gösterimidir; kullanılan ayarlar özgün boşlukları normalleştirebilir veya metnin başına bir boşluk ekleyebilir.
Bostrom ve Durrett (2020), İngilizce ve Japonca deneylerinde eşit sözlük büyüklüğü kullanarak Unigram LM ile BPE’yi karşılaştırdı. Unigram LM’in sınırları, kullanılan morfolojik referanslarla daha iyi örtüştü. Bu tokenleştirmeyle ön eğitilen modeller de değerlendirilen sonraki görevlerde BPE karşılıklarına denk veya daha iyi sonuçlar verdi. Bulgular, Unigram’ın bu deney koşullarındaki avantajını gösterir; bütün diller ve modeller için değişmez bir üstünlük sıralaması oluşturmaz.
8.4 Tokenizer bir bütçe kararıdır
Bir ön eğitim kararı genellikle ilk gradyan adımından önce verilir ve modelin kullanıldığı sürece, aynı içeriğin kaç token’a mal olacağını ve modelin hangi embedding tablosunu öğreneceğini belirler. O karar tokenizer’dır. Eğitilmiş bir modelde tokenizer’ı değiştirmek mümkün, ama ek uyarlama ve yeniden değerlendirme ister.
Önceki kısım alt kelime tokenleştirmesini sınırsız bir sözlükten kaçınmanın bir yolu olarak tanıttı. Bu çerçeve doğru ama eksik. Ön eğitim ölçeğinde tokenizer bir ön işleme kolaylığı değildir — hesap bütçesinin diller arasında nasıl bölüştürüldüğüdür ve bu bölüşüm pratikte kalıcıdır. Sıradan bir fine-tuning tokenleştirmeyi olduğu yerde bırakır; onu değiştirmek, kendi maliyeti olan ayrı bir projedir ve Bölüm 8.9 bunu anlatıyor.
Llama 3’ün tokenizer’ı, bu kararın açıkça verilmesinin iyi bir örneği. 128.000 token’lık sözlüğü, OpenAI’ın tiktoken’ından alınan 100.000 token artı İngilizce dışındaki dilleri desteklemek için özellikle eklenen 28.000 token (Grattafiori vd. 2024). Rapor, bu 28K’nın diğer diller için sıkıştırmayı ve gerçek görev başarımını “İngilizce tokenizasyonuna hiçbir etkisi olmadan” iyileştirdiğini belirtiyor. Bu, bir kez verilen ve bedeli olan bir tasarım tercihidir.
8.4.1 Fertility ve akla ilk gelen metriğin neden yanılttığı
Standart metrik fertility: kelime başına token. Aynı dilde iki tokenizer’ı karşılaştırırken düşük olanı genellikle tercih edilir; diller arası maliyeti ise tek başına belirlemez.
fertility (kelime başına token sayısı) — bir tokenizer’ın girdideki her kelime için kaç token ürettiği. Tek bir dilde iki tokenizer’ı karşılaştırırken anlamlıdır; bir sonraki paragrafın gösterdiği gibi, iki dili karşılaştırırken yanıltıcıdır. ↩︎
Türkçeyi İngilizceyle karşılaştırırken fertility yanıltıcıdır ve sizi tam tersi bir sonuca götürebilir. Türkçe eklemeli bir dildir: bir gövdenin üzerine ekler yığar, dolayısıyla tek bir Türkçe kelime İngilizcenin birkaç kelimeyle söylediği şeyi sıklıkla taşır. Evlerinizden tek kelimedir ve “from your houses” demektir. Kelime başına token’ı iki dil arasında karşılaştırmak, farklı büyüklükteki birimleri karşılaştırmaktır.
Diller arası karşılaştırma için daha uygun ölçü aynı içerik için token sayısıdır: bir cümleyi ve onun profesyonel çevirisini alın, ikisini de tokenize edin ve bölün. Bu oran, aynı içeriğin yaklaşık token bedelini verir — bağlam penceresinde, gecikmede ve API faturasında. Kendi ürününüzün maliyeti için ise gerçek isteklerin girdi ve çıktı dağılımını modelin kendi tokenizer’ıyla ayrıca ölçün; eşleşmiş çeviri çiftleri bütün istekleri temsil etmez.
8.4.2 Ölçüm
İki metriği de elle seçilmiş bir paragraf yerine gerçek bir paralel derlem üzerinde çalıştırdık, çünkü tek bir pasaj tesadüf olabilir. Kaynak, OPUS-100’ün en-tr kısmı. Buradan 3.000 cümle çifti indirdik ve süzgeçten geçirerek 1.157 kullanılabilir çifte düşürdük. Süzgecin iki koşulu var: iki tarafta da en az dört kelime olmalı ve karakter uzunluğu oranı 0,4 ile 2,5 arasında kalmalı. Bu koşullar, makineyle kurulmuş paralel derlemlerde sık görülen cümle eşleme hatalarının bir kısmını eliyor; çeviri doğruluğunu garanti etmiyor ve örneklemi de değiştiriyor (örneğin kısa cümleleri dışarıda bırakıyor). Geriye eşleşen içerikte boşlukla ayrılmış 8.058 Türkçe birime karşı 10.862 İngilizce birim kalıyor. Bu eşitsizliğe dikkat edin: ham sayımlarda eklemeliliğin izi görünüyor, ama farkın tamamını ona bağlamak için ek çözümleme gerekir.
Aşağıdaki her sayı, modelle birlikte gerçekten dağıtılan tokenizer çalıştırılarak elde edildi — openai-community/gpt2, google-bert/bert-base-multilingual-cased, NousResearch/Meta-Llama-3-8B, Qwen/Qwen2.5-7B, dbmdz/bert-base-turkish-cased ve ytu-ce-cosmos/turkish-gpt2.
| tokenizer | sözlük | TR/kelime | EN/kelime | aynı içerik | ortanca |
|---|---|---|---|---|---|
| GPT-2 (2019) | 50.257 | 3,42 | 1,28 | 1,98× | 1,92 |
| BERT çok dilli (2018) | 119.547 | 2,38 | 1,43 | 1,23× | 1,21 |
| Llama 3 (2024) | 128.000 | 2,12 | 1,28 | 1,23× | 1,22 |
| Qwen 2.5 (2024) | 151.643 | 2,43 | 1,29 | 1,40× | 1,39 |
| BERTurk (Türkçe öncelikli) | 32.000 | 1,59 | 2,03 | 0,58× | 0,58 |
| Cosmos GPT-2 (Türkçe öncelikli) | 50.257 | 1,56 | 1,79 | 0,64× | 0,64 |
“Aynı içerik” sütunu derlemin tamamı üzerindeki toplu oran (cümleler boşlukla birleştirilip tek seferde tokenize edildi; kelime başına sütunlar da bu sayımdan); “ortanca” ise ilk 800 çiftte, her cümle ayrı tokenize edilerek bulunan oranların ortancası — ana rakamı tek bir uzun aykırı değer sürüklemesin diye ayrıca hesaplandı. Bölümün kodunu yeniden yazıp çalıştırdık (yeniden koşu, Ekim 2026): aynı 1.157 çift seçiliyor ve tablodaki bütün değerler birebir çıkıyor. Ortancayı 1.157 çiftin tamamında hesaplayınca değerler en fazla 0,01 değişiyor (GPT-2 1,93; BERT çok dilli 1,22; Llama 3 1,22; Qwen 2.5 1,38; BERTurk 0,58; Cosmos 0,64). Altı tokenizer’ın beşinde iki özet en fazla 0,02 farkla uyuşuyor. Bu, toplu değerin tek bir uzun cümleye dayanmadığını gösteren yararlı bir gözlem; örneklemin bütün Türkçe metinleri temsil ettiğini göstermez. İstisna, 1,92’ye karşı 1,98 ile GPT-2; bu küçük farkın nedenini aşağıdaki açılır kutuda tartışıyoruz. Sözlük sütunu her tokenizer’ın kendi bildirdiği sözlük boyutunu (vocab_size) veriyor; Llama 3’te buna 256 ayrılmış özel token eklenince embedding tablosu 128.256 satıra çıkıyor — \(6ND\) kenar notunda kullanacağımız sayı bu.
NotGPT-2’deki 1,92 ile 1,98 farkı
Bu farkı bir uzunluk etkisine yormaktan kaçının. Toplu değer, cümle başına oranların uzunlukla ağırlıklandırılmış ortalamasıdır (her cümle, İngilizce token sayısıyla ağırlıklandırılır). Ağırlıklı bir ortalama ise uzunlukla hiçbir ilişkisi olmadan da ortancanın üstünde durabilir: oranları 1, 1 ve 2 olan eşit uzunlukta üç cümlenin ortancası 1, toplu değeri ise 1,33’tür. Fark örneklemden de gelmiyor: ortanca 1.157 çiftin tamamında 1,93 (yeniden koşu). GPT-2’nin Türkçe cezasının cümle uzunluğuyla büyüyüp büyümediğini sınamak, cümle başına oranı ortak tek bir çift kümesi üzerinde uzunluğa karşı çizmeyi gerektirir; bu tablo bunu yapmıyor.
İki görünüm arasında geçiş yapın ve Türkçe öncelikli iki tokenizer’ı izleyin. Kelime başına token’da Türkçede açık ara kazanan gibi görünüyorlar ve neyi kaybettikleri belli olmuyor. Aynı içerik oranında ise ödünleşim (trade-off) ortaya çıkıyor: Türkçede 1,0’ın altındalar, çünkü İngilizce tarafta daha çok token üretiyorlar — orada Llama 3’ün 1,28’ine karşı kelime başına 1,8 ila 2,0 token. Bu bir tokenleştirme ödünleşimi; model kalitesi ve toplam ürün maliyeti ayrıca ölçülmeli.
8.4.3 Tablonun söylediği üç şey
1. Uçurum büyük ölçüde daraldı ve bu bir tasarım sonucu. GPT-2 Türkçeden %98 ek ücret alıyordu — aynı içerik neredeyse iki katı token’a mal oluyordu. Llama 3 %23 alıyor. 2019 ile 2024 arasında Türkçe değişmedi; tokenizer’lar değişti. Llama 3 raporu, İngilizce dışı diller için eklenen 28 bin token’ın bazı dillerde sıkıştırmayı iyileştirdiğini söylüyor. Ama farkın tamamını eğitim verisinin dil dağılımına bağlayamayız: sözlük 50 binden 128 bine çıktı, ön tokenleştirme kuralları ve başka tasarım ayrıntıları da değişti.
2. Sözlük boyutu tek başına asıl belirleyici değil. İnsanları şaşırtan bulgu bu ve doğrudan tablodan çıkıyor. Qwen 2.5’in sözlüğü Llama 3’ünkinden daha büyük — 128.000’e karşı 151.643 — ve Türkçede daha kötü: 1,23×’e karşı 1,40×. Başka dillere harcanmış daha büyük bir sözlük sizinkine pek az şey katabilir. Sözlükteki yuva sayısı tek başına açıklamıyor; sözlüğün hangi metinlerle ve hangi ön işleme kurallarıyla öğrenildiği de önemli.
3. 32K’lık Türkçe öncelikli bir sözlük, aynı Türkçe metni 128K’lık çok dilli bir sözlükten daha az token’la yazıyor. Aynı Türkçe metinde BERTurk kelime başına 1,59, Llama 3 2,12 token üretiyor: dörtte bir büyüklükte bir sözlükle yaklaşık %25 daha az token. İngilizceye göre oranı da 0,58× (Llama 3’te 1,23×). Bu, modellerin görev başarısını karşılaştırmıyor. Buna karşılık İngilizce kelime başına 2,03 token’a ihtiyaç duyuyor; bu da kabaca GPT-2’nin Türkçe performansının tersi. Burada bedava öğle yemeği yok ve soyut anlamda “daha iyi tokenizer” diye bir şey de yok: bir sözlük sabit bir bütçedir ve Türkçe biçimbilimine verilen her yuva, İngilizceye, koda ya da Çinceye verilmemiş bir yuvadır.
8.4.4 Bir kelimenin gerçekte başına ne geldiğine bakın
Oranlar mekanizmayı gizler. İşte uzun ama gayet sıradan bir Türkçe kelime — bilgisayarlaştırabildiklerimizden — üç farklı biçimde kesilmiş hâliyle.
Bir Türkçe kelime, üç farklı biçimde tokenleştirilmiş
Bölütlemeler elle değil, her tokenizer çalıştırılarak üretildi. Llama 3’ün dokuz parçası, Türkçe öncelikli tokenizer’ın dört parçasının 2,25 katına mal oluyor — bu kelime her işlendiğinde. Bunun toplam istek maliyetine ve model başarısına etkisi tek kelimeden değil, görev örneklerinden ölçülür.
Llama 3’ün nereden kestiğine bakın. Gündelik, sıradan bir isim olan bilgisayar’ı bil | gis | ayar diye üç parçaya bölüyor. Kelimenin kendi parçaları bilgi ve sayar’dır; kesimler bu sınırı hiç gözetmiyor: gis Türkçede hiçbir birime karşılık gelmiyor, ayar ise alakasız, gerçek bir kelime. Bu bölünmenin modelin kelimeyi ne kadar iyi işlediğini nasıl etkilediği ise tek kelimeden değil, görev örneklerinden ölçülmeli.
8.4.5 BERT’in tokenizer’ı: WordPiece ve akrabaları
Ölçüm tablosunda altı tokenizer var; üst düzeyde iki algoritma ailesine ayrılıyorlar. Aynı aile içinde başlangıç birimi, ön tokenleştirme ve sözlük farklı olabildiği için aynı kelime aynı parçalara ayrılmayabilir. GPT-2, Llama 3, Qwen 2.5 ve Cosmos GPT-2, bu bölümde adım adım kurduğumuz BPE’yi (Bölüm 8.3.1) kullanıyor. İki BERT modeli ise WordPiece kullanıyor. Tabloda olmayan üçüncü bir algoritma, Unigram LM, T5 ve XLM-R gibi modellerde karşınıza çıkacak.
Üçü de aynı işi yapar: sözlüğe hangi alt kelime parçalarının gireceğini bir derlemden öğrenir. Ayrıldıkları yer, bir parçayı neye göre “iyi” saydıklarıdır. Bir modelin hangisini kullandığını bilmek işe yarar, çünkü çıktısını okumanın ve bir kelimeyi nasıl böleceğini öngörmenin yolu budur.
Önce çıktıya bakalım. Aynı kelimeyi, evlerinizden, iki BERT tokenizer’ından ve Unigram LM kullanan XLM-R’dan geçirelim:
from transformers import AutoTokenizer
word = "evlerinizden"
for name in ["google-bert/bert-base-multilingual-cased",
"dbmdz/bert-base-turkish-cased",
"FacebookAI/xlm-roberta-base"]:
tok = AutoTokenizer.from_pretrained(name)
pieces = tok.convert_ids_to_tokens(tok.encode(word))
print(f"{name.split('/')[-1]:<30} {' '.join(pieces)}")bert-base-multilingual-cased [CLS] ev ##lerini ##zde ##n [SEP]
bert-base-turkish-cased [CLS] evlerini ##z ##den [SEP]
xlm-roberta-base <s> ▁ev leriniz den </s>
BERT’in çıktısında, GPT ailesinde görmediğiniz iki şey var.
Baştaki ve sondaki özel token’lar. BERT her girdinin başına [CLS], sonuna [SEP] koyar. [CLS] konumunun bağlamsal temsili, cümle sınıflandırma gibi görevlerde kullanılır (Bölüm 12). [SEP] ise bir metnin bittiği yeri gösterir; girdi bir soru ile bir pasaj gibi iki metinden oluşuyorsa aralarına da konur. XLM-R benzer roller için <s> ve </s> kullanıyor; bu işaretler modeller arasında birbirinin yerine kullanılamaz.
## işareti. WordPiece, bir kelimenin devamı olan her parçanın başına ## koyar. Başında ## olmayan parça yeni bir ön tokenleştirme parçası başlatır. GPT’nin token içinde tuttuğu boşluk ve XLM-R çıktısındaki ▁ işareti de parçaların nasıl birleştirileceğini gösterir; ancak üç gösterim aynı bilgiyi taşımaz (Bölüm 8.3.3): ##, özgün boşlukların sayısını saklamaz. Bunun bir sonucu, ev ile ##ev parçalarının sözlükte iki ayrı girdi olmasıdır; model kelime başındaki ve kelime içindeki ev için iki ayrı vektör öğrenir. Çok dilli BERT’in 119.547 girdilik sözlüğünün 43.606’sı, BERTurk’ün 32.000 girdisinin 7.246’sı ## ile başlıyor.
WordPiece bir kelimeyi nasıl böler. BPE yeni bir kelimeyi bölerken öğrendiği birleştirmeleri sırayla yeniden uygular. WordPiece bunu yapmaz; kuralı daha basittir ve açgözlüdür:
- Kelimenin başından başla. Sözlükte bulunan en uzun parçayı al.
- Kalan kısım için aynısını yap; bu kez parçaların başında
##ara. - Kelime bitene kadar sürdür.
BERTurk’ün evlerinizden kelimesini nasıl böldüğünü izleyin. Sözlükte ev, evler, evleri ve evlerini var; evleriniz yok. En uzun eşleşme evlerini. Geriye zden kalıyor: ##zden ve ##zde sözlükte yok, ##z var. Geriye den kalıyor: ##den var. Sonuç: evlerini ##z ##den.
Açgözlü kuralın bir bedeli de burada görünüyor. Aynı sözlükte ##lerinizden parçası da var; yani ev ##lerinizden diye iki parçalı bir bölünme mümkündü. Kural ilk adımda en uzun parçayı aldığı için bu bölünmeyi hiç denemiyor ve üç parça üretiyor.
WordPiece [UNK] üretebilir. Bir noktada sözlükte eşleşen hiçbir parça bulunamazsa, WordPiece yalnızca o harfi değil kelimenin tamamını [UNK] yapar. Çok dilli BERT’in sözlüğünde 😀 yok:
çay 😀 ça ##y [UNK]
çay😀 [UNK]
İkinci satırda emoji kelimeye bitişik yazıldı ve çay da onunla birlikte kayboldu. Bayt düzeyinde çalışan bir BPE tokenizer’ında bu olmaz (Bölüm 8.3.2): cl100k_base aynı emojiyi baytlarıyla, iki token olarak yazar. Bu davranış bu tokenizer’ın ön tokenleştirmesine ve WordPiece ayarlarına bağlı; bütün WordPiece modelleri için zorunlu değil. Bu yüzden böyle bir modelle çalışırken girdinizde [UNK] sayısına bakmak, ucuz ve faydalı bir kontroldür (yeniden koşuda Çay😀 içtik de [UNK] iç ##tik oluyor).
Üç algoritma sözlüğü nasıl öğreniyor. Buraya kadar hazır bir sözlüğün nasıl kullanıldığını gördünüz. Sözlüğün nasıl öğrenildiği ise üç algoritmada şöyle ayrılıyor:
| Neyi optimize eder | Yön | Nerede kullanılır | |
|---|---|---|---|
| BPE (Sennrich vd. 2016) | en sık komşu çifti birleştir | aşağıdan yukarı, sözlük büyür | GPT-2/3/4, RoBERTa, Llama, Gemma |
| WordPiece (Schuster ve Nakajima 2012) | yaygın açıklamaya göre derlem olabilirliğini en çok artıran çifti birleştir, kabaca \(\frac{c(ab)}{c(a)\,c(b)}\)’yi büyüt (BERT’in özgün yordamı tam yayımlanmadı) | aşağıdan yukarı | BERT, DistilBERT, ELECTRA |
| Unigram LM (Kudo 2018) | büyük bir aday kümeden başla ve kaldırılması en az olabilirliğe mal olan parçaları buda; parça olasılıklarını EM (beklenti–maksimizasyon) ile yeniden kestir | yukarıdan aşağı, sözlük küçülür | T5, ALBERT, XLNet, XLM-R |
Tabloyu satır satır, sezgisiyle birlikte okuyalım.
BPE en sık yan yana gelen çifti birleştirir. Sıklığı ödüllendirdiği için sözlüğü, birçok kelimenin paylaştığı parçalarla dolar: ler, den, lar.
WordPiece çiftin kaç kez geçtiğine bakmakla yetinmez; bu sayıyı iki parçanın ayrı ayrı kaç kez geçtiğine böler. Böylece tek başlarına zaten çok sık olan iki parçanın birleşmesi cezalandırılır; neredeyse yalnızca birlikte görülen parçalar öne geçer. Tablodaki oran için bir çekince: BERT’in özgün eğitim yordamının bütün ayrıntıları yayımlanmış değil. Bu oran, eğitim mantığını açıklamak için yaygın kullanılan yaklaşık bir yeniden kurmadır.
Unigram LM ters yönden gelir. Çok büyük bir aday parça kümesiyle başlar ve her turda, atılması derlemin olasılığını en az düşüren parçaları atar. Bir kelimenin alternatif bölünmelerini olasılıksal puanlarla değerlendirebilir. Kullanım sırasında en yüksek puanlı bölünme seçilebilir ya da alternatiflerden örnekleme yapılabilir. Eğitimde aynı metni farklı bölünmelerle göstermeye alt kelime düzenlileştirmesi (subword regularization) denir; amaç, modelin tek bir bölünmeye bağımlılığını azaltmaktır (Kudo 2018). Sağladığı yarar deneyle ölçülmelidir. Benzer biçimde farklı bölünmeler BPE-Dropout ile de üretilebilir (Provilkov vd. 2020).
Sık yapılan bir karışıklığı da burada giderelim: SentencePiece (Kudo ve Richardson 2018) dördüncü bir algoritma değil, BPE ya da Unigram LM’i çalıştırabilen bir kütüphanedir. Llama 2 ve Gemma onu BPE kipinde, T5 ve ALBERT ise Unigram kipinde kullanır.
Bostrom ve Durrett (2020), İngilizce ve Japonca deneylerinde eşit sözlük büyüklüğü kullanarak Unigram LM ile BPE’yi karşılaştırdı. Unigram LM’in sınırları, kullanılan morfolojik referanslarla daha iyi örtüştü; bu tokenleştirmeyle ön eğitilen modeller de değerlendirilen sonraki görevlerde BPE karşılıklarına denk veya daha iyi sonuçlar verdi. Bulgular bu deney koşulları için geçerlidir; bütün diller ve modeller için değişmez bir sıralama oluşturmaz.
Bu kısmı bölümün asıl sorusuna bağlayalım. Algoritma, ölçüm tablosundaki farkların küçük bir kısmını açıklıyor. Çok dilli BERT ile BERTurk aynı algoritmayı kullanıyor; biri Türkçeden 1,23×, öbürü 0,58× alıyor. Aradaki farkı algoritma değil, büyük ölçüde sözlüğün hangi derlemle eğitildiği yaratıyor — BERTurk’ün sözlüğü daha küçük olduğu hâlde.
8.4.6 Ek ücret gerçekte neye mal oluyor
Llama 3 için ölçülmüş derlem rakamını alalım: Türkçe, birebir aynı içerik için İngilizcenin 1,23× token’ına mal oluyor. Bu tek sayı dört ayrı faturaya yayılıyor. Aşağıdaki satırlar aynı modeli, aynı birim fiyatı ve bu derleme benzeyen metinleri varsayıyor; toplam istek ücreti ve gecikme, çıktı uzunluğuna, önbelleğe ve sunum koşullarına da bağlı.
| nereye düşüyor | 1,23×’te etkisi |
|---|---|
| bağlam penceresi | 128.000 token’lık bir pencere yaklaşık 104.000 İngilizce eşdeğeri token’lık Türkçe alır |
| API maliyeti (girdi) | bir milyon İngilizce eşdeğeri token, 1,23 milyonun fiyatına gelir |
| gecikme | üretim token başına olduğu için, saniyedeki token sayısı aynıyken Türkçe bir cevap yaklaşık %23 daha uzun sürer |
| ön eğitim hesabı | sabit FLOP’la Türkçe bir derlemde İngilizceye göre yaklaşık %19 daha az içerik işlenir |
Son sayının yönüne dikkat edin, çünkü bir oranla yapılabilecek en kolay hata budur. Türkçe 1,23× daha fazla token’a mal oluyor, ama sabit bir token bütçesi içeriğin \(1/1{,}23 = 0{,}813\)’ünü karşılıyor — %23 değil, %18,7 daha az. Bu ikisi aynı rakam değil. Tabloda yalnızca API maliyeti ve gecikme satırları 1,23 ile çarpılıyor; bağlam penceresi ve hesap satırları ise 1,23’e bölünüyor. 128.000 token’ın 98.560 değil de yaklaşık 104.000 İngilizce eşdeğeri token alması bu yüzden.
Bileşik etki yaratan satır hesap satırı. Ölçekleme yasalarında (Bölüm 7.8) gördüğümüz gibi hesap, token sayısıyla ölçekleniyor. Dolayısıyla Türkçeye harcanan sabit bir bütçe, aynı bütçenin İngilizceye harcanmasına kıyasla kabaca beşte bir daha az malzeme görüyor: aynı paraya yaklaşık %18,7 daha az eşleşmiş içerik. Bunun öğrenilen olgu ya da örüntü sayısını aynı oranda azalttığını bu ölçüm göstermez; o etki eğitim karışımı ve görev başarısıyla ölçülür. Tokenizer vergisi yalnızca çıkarım anında alınmıyor; ön eğitim sırasında da işliyor.
1,23× oranında pragmatik cevap genelde “yine de çok dilli modeli kullan” oluyor — %23 gerçek bir maliyet ama bir kararı tersine çevirmiyor. GPT-2’nin 1,98 katlık oranında ise çeviriyor. Varsaymak yerine ölçmenizin sebebi bu. Türkçe öncelikli bir modelin açık ara kazandığı durumlar dâhil, kararın tamamı Türkçe NLP’ye ayrılmış bölümün (Bölüm 16) konusu.
8.5 Bir koşu neye mal olur
Yoğun (dense) bir transformer ön eğitim koşusunun hesabını — kaç FLOP tükettiğini — iki sayıdan, parametre sayısı \(N\) ve token sayısı \(D\)’den yaklaşık olarak kestirebilirsiniz. Kestirim, tipik bir koşunun maliyetine hâkim olan ağırlık matrisi çarpımlarını sayar. Dışarıda bıraktığı asıl terim attention’dır (dikkat mekanizması): ön eğitimin büyük kısmında kullanılan kısa bağlamlarda bu, maliyete yüzde birkaç ile yüzde on beş civarında bir ekleme yapar; daha çok önem kazandığı durumlara bu kısımda ileride döneceğiz. İki sayıdan bu kadar iyi bir kestirim, sistem işlerinde alışılmadıktır ve ciddiye almaya değer. Bir basın bültenindeki sayıları kabaca kontrol etmenizi sağlayan araç da budur.
Önce bir çekince, çünkü \(N\)’e hangi sayıyı koyacağınıza o karar veriyor. \(6ND\) kuralı, kullanılan parametre başına işlem sayıyor ve bir uzman karışımı (MoE) modelinde (Bölüm 7.7) bir token yalnızca yönlendiricisinin seçtiği uzmanlara dokunuyor (Jiang vd. 2024). Yani istediğiniz rakam toplam değil, aktif parametre:
\[C \approx 6\,N_{\text{aktif}}\,D\]
DeepSeek-V3 farkı somutlaştırıyor: 671B toplam parametre, token başına yaklaşık 37B aktif, 14,8T eğitim token’ı. Aktif sayıyı kullanmak \(6 \times 37{\times}10^{9} \times 14{,}8{\times}10^{12} \approx 3{,}3\times10^{24}\) FLOP veriyor; toplamı kullansaydık \(6ND\) terimini 18 kat fazla bulurduk. Bu, iki \(6ND\) terimi arasındaki oran; gerçek eğitim FLOP’u ya da GPU-saati arasındaki fark değil, çünkü attention, yönlendirici ve uzmanlar arası iletişimin de maliyeti var. Bir model duyurusu iki parametre sayısı birden veriyorsa, bu ilk yaklaşık aritmetiğin istediği küçük olanıdır.
FLOP — bir kayan noktalı işlem: kayan noktalı (tam sayı olmayan) biçimde saklanan sayılar üzerinde tek bir çarpma ya da tek bir toplama. Eğitim hesabı FLOP cinsinden sayılır; yongalar ise saniyedeki işlem sayısı olan FLOP/s ile derecelendirilir. İkisini karıştırmak kolaydır; aralarındaki çarpan, koşunun ne kadar sürdüğüdür. ↩︎
8.5.1 6 nereden geliyor
\[ C \;\approx\; 6\,N\,D \quad \text{FLOP} \]
Buradaki 6, baskın matris çarpımlarındaki üç tane 2’den oluşuyor ve her 2’nin ayrı bir sebebi var.
Parametre başına, token başına altı kayan noktalı işlem
İleri geçiş için iki, geri geçiş için dört; parametre başına, token başına. \(N\) parametre ve \(D\) token ile çarpın, koşunun tamamı elinizde.
İleri geçişteki iki, kolay olanı. Yoğun bir doğrusal katmanın matris çarpımındaki her ağırlık token başına tam bir kez kullanılır: bir çarpma ve akümülatöre (accumulator: ara toplamları tutan yazmaç) bir toplama. Ağırlık başına, token başına iki işlem.
Geri geçişteki dört ise insanların kafasının karıştığı yer; o yüzden iki işi ayrı ayrı adlandıralım. Geri yayılım, bir katmandan geçerken iki farklı gradyan üretmek zorunda. Bir yandan \(\partial L/\partial x\)’e ihtiyacı var — kaybın katmanın girdisine göre nasıl değiştiği — yoksa hata bir alttaki katmana yayılamaz. Bir yandan da \(\partial L/\partial W\)’ye ihtiyacı var — kaybın her bir ağırlığa göre nasıl değiştiği — yoksa optimizer’ın güncelleyecek bir şeyi olmaz. Bunların her biri aynı şekle sahip bir başka matris çarpımıdır, dolayısıyla her biri parametre başına token başına 2 işlem daha götürür. İki iş, her biri iki, toplam dört. Bu sayım yoğun matris çarpımları içindir; embedding tablosundan okumayı, bir MoE’de seçilmeyen uzmanları ve attention gibi diğer işlemleri kapsamaz.
8.5.2 Laboratuvarların yayımladığıyla uyuşuyor mu?
| koşu | \(N\) | \(D\) | \(6ND\) | makalede bildirilen hesap | iki yaklaşık sayı arasındaki fark |
|---|---|---|---|---|---|
| GPT-3 | 175B | 300B | \(3{,}150\times10^{23}\) | \(3{,}14\times10^{23}\) | +%0,32 |
| Llama 3 405B | 405B | 15,6T | \(3{,}791\times10^{25}\) | \(3{,}80\times10^{25}\) | −%0,24 |
Hesapta 120 katlık bir fark ve dört yıllık mimari değişime rağmen sapma yüzde yarımın altında. Buna kuralın doğrulanması demek cazip geliyor. Ama bu bir doğrulama değil ve bu ayrım, uyuşmanın kendisinden daha önemli.
Yayımlanan o rakamlar da zaten \(6ND\) ile hesaplanmış. GPT-3’ün Ek D’si aritmetiği sütunlar hâlinde veriyor — “Fwd-pass flops per active param per token: 2” (aktif parametre başına, token başına ileri geçiş FLOP’u), “Mult for bwd pass: 3” (geri geçiş için çarpan), “Flops per param per token: 6” (parametre başına, token başına FLOP) — ve varsayımını açıkça yazıyor: “attention işlemini yok sayıyoruz, çünkü analiz ettiğimiz modellerde tipik olarak toplam hesabın %10’undan azını kullanıyor” (Brown vd. 2020). Llama 3’ün \(3{,}8\times10^{25}\)’i de aynı şekilde bir bütçe: Meta’nın önceden sabitlediği ve sonra ona sığacak bir model boyutu seçtiği sayı (Grattafiori vd. 2024).
Yani tablo, bizim hesap yöntemimizin onlarınkiyle örtüştüğünü gösteriyor; bunu doğrulamak değerli, ama hepsi bu. \(6ND\)’ye güvenmenin sebebi yukarıdaki şekildeki türetme, bu tablo değil. Tablonun size kazandırdığı şey pratik: laboratuvarlar bu şekilde saydığına göre, parametre ve token sayısı veren herhangi bir duyuruyu okuyup onların açıklayacağı sayıyı yeniden hesaplayabilirsiniz — ve bir sonraki kısmın gösterdiği gibi, o sayının neyi dışarıda bıraktığını da bilirsiniz.
8.5.3 Nerede doğru olmaktan çıkıyor
\(6ND\), maliyeti parametre sayısıyla orantılı olan matris çarpımlarını sayar. Attention’ın skor matrisi bunlardan biri değil: o, ne \(N\)’de ne de \(D\)’de görünen dizi uzunluğuna bağlıdır.
Bölüm 7.6, attention’ın bir dizinin tamamı için ileri geçiş maliyetini katman başına \(4n^2d\) olarak veriyor. Bunu üç adımda token başına bir rakama çevirebiliriz. Token başına \(4nd\) elde etmek için \(n\)’e bölün. Sonucu yarıya indirin, çünkü nedensel maskelemede ortalama bir konum dizinin yalnızca yarısına bakar (maskelenmiş çiftleri gerçekten atlayan bir uygulamada; maskeyi uygulayıp tam kareyi yine de hesaplayan kernel’lerde bu yarıya indirme geçerli değildir). Son olarak 3 ile çarpın, çünkü geri geçiş ileri geçişin iki katına mal olur. Sonuçta \(L\) katman, \(n\) dizi uzunluğu ve \(d\) genişlik için token başına yaklaşık \(6\,L\,n\,d\) elde edilir.
Bunu yok saymak ne kadar önemli? Bağlamınız ne kadar uzunsa o kadar.
| model ve bağlam | token başına \(6N\) | token başına yaklaşık attention | attention’ın \(6N\) içindeki payı | \((6N + \text{attention}) \div 6N\) |
|---|---|---|---|---|
| Llama 3 8B, 8K bağlamda | \(4{,}82\times10^{10}\) | \(6{,}44\times10^{9}\) | %13 | 1,13× |
| Llama 3 8B, 128K bağlamda | \(4{,}82\times10^{10}\) | \(1{,}03\times10^{11}\) | %214 | 3,14× |
| Llama 3 405B, 8K bağlamda | \(2{,}43\times10^{12}\) | \(1{,}02\times10^{11}\) | %4 | 1,04× |
Son sütunu, bu nedensel attention sayımını \(6ND\) kestirimine ekleyince çıkan yaklaşık çarpan olarak okuyun; ölçülmüş GPU-saat ya da gerçek toplam işlem sayısı değil.
Ters yöne iten daha küçük bir hata daha var. Girdi embedding’i bir matris çarpımı değil, bir tablodan okuma (lookup); yani neredeyse hiç FLOP harcamıyor — buna karşın parametreleri \(N\)’in içinde sayılıyor. Llama 3 8B’nin çıktı katmanıyla ağırlık paylaşmayan (untied) embedding’i \(128{.}256 \times 4096 = 525\)M parametre, yani \(N\)’inin %6,5’i. Daha geniş modellerde embedding’in payı küçülür: 70B’de yalnızca %1,5, 405B’de %0,5. Paylaşılmayan çıktı katmanı ise gerçek bir matris çarpımı; onun parametreleri \(6ND\)’de doğru sayılıyor. Yani girdi embedding’i açısından \(6ND\), attention’ı eksik sayarken aynı anda küçük modelleri biraz fazla sayıyor. 8B’nin 8K’daki hâlinde ikisi kısmen birbirini götürüyor.
Buradan iki ders çıkıyor, ikisi de pratik. Birincisi, \(6ND\) kısa bağlamlı yoğun ön eğitim için bir yaklaşık hesap kuralıdır: ön eğitim büyük ölçüde kısa bağlamda koştuğu için isabetlidir. En isabetli olduğu yer de 405B’dir, çünkü geniş bir modelde attention terimi görece küçük kalır. İkincisi, 128K bağlamda 8B modelin attention terimi, bu sayım varsayımıyla toplamı \(6ND\) kestiriminin üç katının üzerine çıkarır; çarpan her model ve uygulamada aynı değildir. Uzun bağlam eğitiminin koşunun tamamı boyunca değil, token’ların küçük bir kısmı üzerinde kısa ve ayrı bir aşama olarak yapılmasının sebebi tam olarak budur.
8.5.4 Baştan sona tek bir koşu
Llama 3.1 405B’yi alın ve parametrelerden faturaya kadar takip edin. Her girdi yayımlanmış durumda: makale \(N\) ve \(D\)’yi, Meta’nın model kartı da GPU-saatlerini veriyor (Grattafiori vd. 2024).
| büyüklük | değer | nereden geliyor |
|---|---|---|
| parametre | 405B | makale |
| eğitim token’ı | 15,6T | makale |
| hesap | \(3{,}79\times10^{25}\) FLOP | \(6ND\) |
| H100-saat | 30,84M | Meta’nın model kartı |
| 8.000 H100 üzerinde | 160,6 gün | 30,84M ÷ 8.000 ÷ 24; eşit tahsis varsayımı |
| 16.000 H100 üzerinde | 80,3 gün | makaledeki en büyük filo; aynı varsayım, gerçek koşu takvimi değil |
| 24.000 H100 üzerinde | 53,5 gün | aynı varsayım |
| $2,00/GPU-saatten kiralanırsa | ≈ $62M | varsayımsal kiralama fiyatı; tarihe ve sağlayıcıya göre değişir |
| $3,00/GPU-saatten kiralanırsa | ≈ $93M | aynı hesap, başka birim fiyat; gerçek fatura değil |
Meta’nın kartı Llama 3.1 ailesinin tamamını 39,3M H100-saat olarak veriyor: 8B için 1,46M, 70B için 7,0M ve 405B için 30,84M. Tek başına 405B, ailenin hesabının %78’i. Aynı kart bu saatleri karbon olarak da veriyor: konum bazlı hesapla 405B’nin eğitimi 8.930, ailenin tamamı 11.390 ton CO2eq; pazar bazlı hesapla ise 0 ton, çünkü Meta elektrik tüketimini yenilenebilir enerjiyle eşlediğini söylüyor. Bunlar kartın elektrik ve tesis varsayımlarına dayanan bir emisyon muhasebesi; yaşam döngüsü ya da donanım etkisi değil. Enerji ve karbon, dolardan ayrı bir karar ekseni; bu rakamın nasıl okunacağına Bölüm 8.6.2’de döneceğiz.
16.000 H100’ü saatlik kiralamak her koşulda mümkün olmayabilir. Tablodaki dolar rakamları yalnızca varsayımsal bir dış kiralama bedeli; Meta’nın gerçek harcaması ya da fırsat maliyeti bu çarpımdan çıkarılamaz. Kendi projeniz için sağlayıcı teklifi, kapasite ve hizmet koşullarıyla yeniden hesaplayın; kiralama, satın alma ve ortaklık seçeneklerinden yalnızca biri.
8.5.5 Broşür ile veri merkezi
Şimdi sıra, bir GPU kümesi (cluster) işletmiş olanları bunun hakkında yalnızca okumuş olanlardan ayıran sayıda.
Bir H100 SXM, yoğun (dense) BF16 (bfloat16: derin öğrenmede yaygın 16 bitlik kayan nokta biçimi) için 989 TFLOP/s olarak derecelendirilmiştir. (1.979 rakamını da göreceksiniz; o, 2:4 yapılandırılmış seyreklik (structured sparsity) ile çalışan aynı yonga — ön eğitimin kullanmadığı, farklı bir işlem. PCIe kartı ise SXM’den yaklaşık dörtte bir daha yavaş: yoğun BF16’da 756 TFLOP/s. Herhangi bir karşılaştırma yapmadan önce size hangi sayının verildiğini kontrol edin.) Bir koşunun ihtiyaç duyduğu FLOP’u, GPU’larının tahsis edildikleri saatler boyunca üretebilecekleri FLOP’a bölün; karşınıza model FLOP kullanımı (model FLOPs utilization, MFU) çıkar: teorik tepe değerin gerçekten eğitime dönüşen kısmı.
model FLOPs utilization (model FLOP kullanımı) — birim sürede modelin ileri ve geri geçişi için sayılan yararlı FLOP’un, donanımın belirtilen tepe FLOP/s değerine oranı; genelde MFU diye yazılır. Yeniden hesaplanan aktivasyonlar gibi ek işler paya girmez; bu yüzden toplam donanım kullanımıyla (HFU) aynı şey değildir. Karşılaştırırken hassasiyet türünü, seyrekliği ve sürenin nasıl tanımlandığını belirtin. Büyük koşularda %50’nin üstü bugüne dek nadir; aradaki farkı iletişim, bellek bant genişliği ve duruşlar doldurur. ↩︎
Llama 3 makalesi anlık BF16 MFU’sunu 8.000 GPU’da %43, 16.000’de %41 ve 128K bağlam aşamasında %38 olarak bildiriyor (Grattafiori vd. 2024). Yayımlanan GPU-saatlerden çıkan tablo şu:
| model | GPU-saat | \(6ND\) | etkin MFU |
|---|---|---|---|
| Llama 3.1 8B | 1,46M | \(7{,}23\times10^{23}\) | %13,9 |
| Llama 3.1 70B | 7,00M | \(6{,}35\times10^{24}\) | %25,5 |
| Llama 3.1 405B | 30,84M | \(3{,}79\times10^{25}\) | %34,5 |
8B ve 70B’nin token sayıları kartın düz metninden geliyor: “~15 trilyon token” — aynı koşular için teknik tablosu “15T+” diyor. Yalnızca 405B’nin 15,6T’si kesin olarak belirtilmiş, o da sadece makalede. \(D\)’deki birkaç yüzdelik oynaklık resmi değiştirmiyor.
405B satırını makalenin kendi %41’iyle karşılaştırın. Koşuda gerçekleşen değer %34,5. Eksik 6,5 puan nereye gitti? Büyük olasılıkla iki yere; bunları ayırmakta fayda var, çünkü biri veri merkezleriyle ilgili bir olgu, diğeri ise kendi aritmetiğimizle ilgili. Ama aşağıdaki paylaştırma bir okuma, kesin bir ayrım değil.
Büyük kısmı muhtemelen duruşlardan geliyor. Makale bunu, göz gezdirirken kolayca atlanan bir cümlede söylüyor. Ön eğitimin 54 günlük bir kesitinde 466 iş kesintisi yaşanmış — 47’si planlı, 419’u beklenmedik — ve koşu “>%90 etkin eğitim süresi”ni korumuş (Grattafiori vd. 2024). O sınırı tam 0,90 alıp tek bir aşamanın %41’ini koşunun tamamına uygularsanız:
\[ \%41 \times 0{,}90 = \%36{,}9 \]
Bu iki adım da birer tercih; dolayısıyla %36,9, makalenin bildirdiği bir sayı değil, açıklayıcı bir rakam. Bu okumayla duruşlar, 6,5 puanın 4,1’ini açıklamış olur. Kötü kernel’ler (GPU üzerinde çalışan tek tek hesap rutinleri) değil, zayıf bir framework değil, beceriksizlik değil. Donanım bozulur, bir düğüm devre dışı kalır, iş son checkpoint’ten yeniden başlar ve yapılmış işin bir kısmını tekrarlar. Haftalarca çalışan 16.000 GPU’da her üç saatte bir şeyin bozulması kriz değildir — işin doğasıdır.
Kalanı kümeden değil, kendi hesap yöntemimizden kaynaklanıyor gibi görünüyor. Oranın payını (numerator: gerçekten yapılan yararlı iş; payda ise tepe FLOP/s × süre) \(6ND\) ile kestirdik ve \(6ND\) attention’ı dışarıda bırakıyor. Standart MFU hesabı, modelin attention matris çarpımlarını yararlı iş olarak sayar (yalnızca bellek kazanmak için aktivasyonları yeniden hesaplamak gibi fazladan işleri dışarıda bırakır); makalenin MFU’su da büyük olasılıkla bu geleneği izliyor. Bizim payımız ise attention’ı hiç içermiyor. İki farklı ölçümü karşılaştırıp aradaki farka israf diyoruz. Attention’ı geri ekleyelim: yukarıda türettiğimiz token başına \(6Lnd\) düzeltmesini ve makalenin kendi takvimini kullanarak — koşunun büyük kısmında 8K bağlam, ardından altı aşamada 128K’ya tırmanan “yaklaşık 800B eğitim token’ı” (Grattafiori vd. 2024):
| model | yalnızca \(6ND\) | attention düzeltmeli | %41 \(\times\,0{,}90\), açıklayıcı |
|---|---|---|---|
| Llama 3.1 8B | %13,9 | %15,8–17,2 | yayımlanmadı |
| Llama 3.1 70B | %25,5 | %27,4–29,0 | yayımlanmadı |
| Llama 3.1 405B | %34,5 | %36,0–37,1 | %36,9 |
Aralıklar uzun bağlam kuyruğunu kapsıyor: alt uç bu kuyruğun tamamının 8K’da, üst uç ise tam 128K’da koştuğunu varsayıyor; gerçek ise ikisinin arasında bir yerde, çünkü bağlam aşamalar hâlinde büyüdü. Karşılaştırılacak yayımlanmış bir MFU’ya sahip tek model 405B — makalenin Tablo 4’ü “Llama 3 405B ön eğitiminin her aşamasını” kapsıyor ve daha küçük koşular hakkında hiçbir şey söylemiyor. O tek model için düzeltilmiş aralık, makalenin kendi sayılarından öngörülen değeri içine alıyor: öngörülen %36,9’un etrafında %36,0–37,1’lik bir aralık; bu tür bir yeniden hesaplamanın ulaşabileceği en yakın nokta budur. Elmayla armudu karşılaştırmayı bıraktığınız anda broşür, makale ve fatura birbiriyle uyumlu görünüyor; ama bu uyum, farkın hangi oranda duruşlardan, hangi oranda FLOP sayımından doğduğunu kanıtlamaz. Zinciri, ölçülenle varsayılanı ayırarak bir kez daha yazalım: makalenin ölçtüğü anlık MFU %41 → %90 etkin süre varsayımıyla %36,9 (açıklayıcı) → yayımlanan GPU-saatlerden bizim hesapladığımız \(6ND\) değeri %34,5 → attention eklenince %36,0–37,1.
Aynı Tablo 4, %43’lük aşamada GPU başına 430 TFLOP/s bildiriyor. \(430/989 = \%43{,}5\) — bu da makalenin oranı seyreklik sayısına göre değil, yoğun 989 tepe değerine göre hesapladığını doğruluyor. Kontrol etmeye her zaman değer.
İki ders var ve sizi kurtaracak olan ikincisi: kesintiler, hiçbir kernel ayarının ortadan kaldıramayacağı gerçek ve büyük bir bedeldir ve bir MFU rakamı, siz payına neyin girdiğini öğrenene kadar hiçbir şey ifade etmez. Bir satıcı size bir kullanım oranı söylediğinde, payında ne olduğunu sorun.
8.5.6 Kendi koşunuzu tahmin edin
Yukarıdaki her şey dört çarpmadan ibaret. Girdileri değiştirin ve hangisinin baskın çıktığını izleyin.
Girmeye değer üç ayar.
8B parametre, 15.000B token, %14 MFU Llama 3.1 8B’yi yeniden üretiyor. Tablo, Meta’nın yayımladığı 1,46M’ye karşılık 1,44M GPU-saat gösteriyor — kalan %1,4’lük fark, kaydırıcının yarım puanlık adımından (%13,9 ile sonuç tam tutardı) ve gerçek modelin 8,00B değil 8,03B parametreye sahip olmasından geliyor. Araca güvenebileceğiniz kadar yakın.
%35’te 405B ve 15.600B amiral gemisini yeniden üretiyor: yayımlanan 30,84M’ye karşılık 30,42M GPU-saat. MFU kaydırıcısını bir adım aşağı, bu bölümde daha önce hesapladığımız etkin değer olan %34,5’e çekin; tablo 30,86M gösteriyor, yani yayımlanan sayının kendisi. Bu bir iç tutarlılık kontrolü: %34,5’i zaten bu GPU-saatlerden türetmiştik. Bir koşunun MFU’sunu bildiğiniz anda dört çarpma onun GPU-saatini yeniden üretir; gelecekteki bir koşunun MFU’sunu önceden bilmek ise ayrı bir iş.
%35’te 10B ve 200B ciddi bir akademik koşu — parametre başına 20,0 token, Chinchilla çalışmasındaki yaklaşık orana bir örnek (belirli bir derlem için kanıtlanmış bir optimum değil); saati $2,50’den yaklaşık 9.600 GPU-saat ve $24.000. Şimdi filoyu 512’den, iyi fonlanmış bir üniversite laboratuvarının gerçekte sahip olduğuna daha yakın olan 64’e düşürün ve wall-clock süresinin bir günün altından 6,3 güne çıkışını izleyin. Sonra token sayısını, süre kabul edilebilir olmaktan çıkana kadar artırın. Asıl ders bu son adımda: bu ölçekte bağlayıcı kısıt çoğu zaman FLOP değil, takvim olur; gerçek bir planda kesintileri ve kaynağa erişimi de hesaba katın.
8.5.7 Chinchilla’ya kim uydu peki?
Bölüm 7.8 hesap-optimal oranı vermişti: parametre başına yaklaşık 20 token (Hoffmann vd. 2022). Aşağıdaki tabloda Chinchilla’nın kendisi dışında hiçbir model buna uymuyor. Ama bu oran, Chinchilla’nın deney koşulları için bir referans, evrensel bir optimum değil: Meta’nın kendi veri karışımı üzerinde kurduğu ölçekleme yasası, \(3{,}8\times10^{25}\) FLOP için 16,55T token üzerinde 402B parametre öneriyor — parametre başına yaklaşık 41 token. Meta, 405B’yi bu yüzden kendi bütçesi için “yaklaşık hesap-optimal” sayıyor (Grattafiori vd. 2024).
| model | parametre başına token |
|---|---|
| GPT-3 175B | 1,7 |
| Chinchilla 70B | 20,0 |
| Llama 3.1 405B | 38,5 |
| Llama 3.1 70B | 212,5 |
| Llama 3.1 8B | 1.868,0 |
GPT-3 çizginin bir büyüklük mertebesi altında duruyor; Chinchilla’nın yayımlanma sebebi zaten bu bulguydu — model fena hâlde az eğitilmişti. Her Llama Chinchilla çizgisinin üstünde, küçük modeller ise çok üstünde: 8B, parametre başına neredeyse 1.900 token gördü; bu, Chinchilla referansının doksan üç katı. Meta bunu bilerek yaptığını söylüyor: küçük modelleri hesap-optimal noktanın çok ötesinde eğitmişler, çünkü böyle eğitilen modeller aynı çıkarım bütçesinde hesap-optimal modellerden daha iyi sonuç veriyor (Grattafiori vd. 2024).
Bu bir hata değil, moda da değil; farklı bir hedefe yönelik farklı bir optimizasyon.
8.5.8 Bir kez eğit, sonsuza kadar sun
Chinchilla tipi seçim, belirli bir eğitim hesabıyla ulaşılan kaybı en aza indirmeyi amaçlıyor (eşdeğer olarak: belirli bir kayba en az eğitim hesabıyla ulaşmayı). Modeli çok sayıda istekte sunacaksanız bu hedef eksik kalır, çünkü eğitim bir kez ödenir; çıkarım ise model emekliye ayrılana kadar her istekte yeniden ödenir.
Aritmetik kısa. Bir token üretmek yaklaşık \(2N\) FLOP’a mal olur — yalnızca ileri geçiş, geri geçiş yok. Yani Llama 3.1 8B için:
\[ \underbrace{7{,}23\times10^{23}}_{\text{eğitim}} \;\Big/\; \underbrace{1{,}61\times10^{10}}_{\text{üretilen token başına}} \;=\; 4{,}5\times10^{13} \]
Kırk beş trilyon token üretildiğinde, bu \(2N\) yaklaşımıyla yalnızca üretim FLOP’ları eğitim FLOP’larına eşitlenir. Günde 100 milyar token üreten varsayımsal bir servis bu noktayı 450 günde geçer. Her ürün bu trafiğe ulaşmaz.
Bu noktanın ne olduğunu ve ne olmadığını söyleyelim. Tek bir model için FLOP denkliğidir: ömür boyu çıkarımının, eğitimi kadar aritmetiğe mal olduğu an. Daha fazla ön eğitimin kendini amorti ettiği nokta değildir, çünkü aynı modeli daha çok token üzerinde eğitmek onun token başına çıkarım maliyetini düşürmez; onu parametre sayısı belirler. “Daha uzun eğitseydik daha mı iyiydi” sorusunu cevaplayan başa baş noktası, eşit kalitedeki iki model arasındadır: \(A\), daha küçük ve daha uzun eğitilmiş model; \(B\) ise hesap-optimal noktaya kadar eğitilmiş daha büyük model. Servis token başına maliyet olmak üzere, başa baş noktası \(T_{\text{başa baş}} = (\text{Eğitim}_A - \text{Eğitim}_B)/(\text{Servis}_B - \text{Servis}_A)\) üretilen token’dır. Formül yalnızca \(A\)’nın eğitimi daha pahalı, token başına servisi daha ucuz olduğunda pozitif bir eşik verir; maliyetler aynı birimde tutulmalı, girdi işleme, boş kapasite ve işletme giderleri ayrıca eklenmelidir. Küçük ve uzun eğitilmiş bir modelin fazladan eğitim koşusuna değmesini sağlayan hesap budur. “Kendin yap ya da satın al” sorusu ise üçüncü bir şeydir; eğitim artı dağıtım artı işletmeyi bir API faturasıyla karşılaştırır.
Üstelik 45 trilyon, elde edebileceğiniz en iyimser sayı. FLOP’u FLOP’la karşılaştırıyor; bu da üretilen bir token ile eğitimde işlenen bir token’ın aynı maliyete çıktığını sessizce varsayıyor. Oysa aynı maliyete çıkmıyorlar ve bunun, ikisi de aynı yöne iten iki sebebi var:
- Decode hesap değil, bellek sınırlıdır. Decode, Bölüm 7.6’da tanımlanan token token üretim adımıdır. Her seferinde tek bir token üretmek, tek bir küçük matris-vektör çarpımı yapabilmek için ağırlık matrisinin tamamını bellekten okumak demektir. Eğitim ise aynı ağırlıkları bir kez okur ve bir batch’teki binlerce token üzerine amorti eder. Ön eğitim %35–40 MFU’yu sürdürürken decode tipik olarak yüzde birkaçta koşar — yonga hesap yapmıyor, belleği bekliyordur.
- Prefill bu formülde maliyetsiz, gerçekte değil. Her girdi token’ı da \(2N\)’e mal olur ve gerçek iş yüklerinin çoğu, geri aldığından çok daha fazla girdi gönderir. Uzun bir sistem prompt’u, erişimle getirilmiş bir belge, bir sohbet geçmişi: hepsi ödenir, hiçbiri yukarıda sayılmaz.
Karşılaştırmayı FLOP yerine, fiilen kiraladığınız şey olan GPU-saat cinsinden, 8B’nin yayımlanmış 1,46M H100-saatine karşı tekrarlayın:
| decode verimliliği | başa baş noktası | günde 100B token’da |
|---|---|---|
| %13,9 MFU | 45,0T token | 15 ay |
| %10 MFU (büyük batch’ler, iyi ayarlanmış) | 32,4T token | 11 ay |
| %5 MFU | 16,2T token | 5 ay |
| %2 MFU (tipik etkileşimli servis) | 6,5T token | 2 ay |
İlk satıra, sonra da yukarıdaki tabloda 8B’nin etkin MFU’suna bakın. İkisi de aynı %13,9 ve bu tesadüf değil: FLOP’u FLOP’a bölmek, decode sunucunuzun Meta’nın eğitimde kullandığı GPU kümesi kadar verimli olduğunu sessizce varsayar. Böyle yazınca varsayımın savunulamaz olduğu apaçık ortaya çıkıyor — decode’un bütün meselesi, eğitimin batch yapabildiği gibi batch yapamamasıdır.
Yani 45 trilyon, bu tablodaki iyimser uç; GPU-saat cinsinden kesişim, decode verimliliğine göre ciddi trafiğin yaklaşık iki ayı ile bir yılı biraz aşan bir süre arasında bir yerde. Bu kesişim, aşırı eğitimin kendini ne zaman amorti ettiğini tek başına söylemez — onu yukarıdaki iki modelli başa baş formülü, eşit kaliteli iki modelin eğitim, sunum ve işletme giderleriyle söyler. Söylediği şu: ciddi trafikte çıkarımın maliyeti, eğitiminkini temiz FLOP hesabının önerdiğinden daha erken yakalayabilir; token başına çıkarım maliyetini küçültmek bu yüzden önemli.
8B’lik bir modeli 15 trilyon token üzerinde eğitmenin gerekçesi bu. Peşinen, Chinchilla referansının 93 katı token harcarsınız. Karşılığında, aynı kaliteye daha az eğitim hesabıyla ulaşacak daha büyük bir modelden token başına daha ucuza çalışan bir model alırsınız. Eşit kaliteli daha büyük modeli eğitmek daha ucuz olabilirdi, ama onu çalıştırmak her token’da daha pahalı olurdu.
8.6 Model manzarası
Buraya kadar anlatılan her şey, 1. aşamayı en ileri (frontier) ölçekte yapan kuruluşların dünyada neden belki bir düzineyi geçmediğini, geri kalanımızın da neden onların çıktıları arasından seçim yaptığını açıklıyor. Peki bu çıktıları birbirinden nasıl ayırt edersiniz?
“Açık” kelimesine bakarak değil. Bir yayım açık ya da kapalı değildir; en az dört başlıkta ayrı ayrı okunur: ağırlıklar, eğitim verisi, eğitim kodu ve lisans. Bunlar aynı ölçüde açık olmak zorunda değildir ve her biri kademeli ya da koşullu olabilir; satıcılar da bu kararları serbestçe harmanlar.
Bir yayımın açabileceği dört şey, ayrı ayrı kararlaştırılır
Sütunlar ayrı ayrı kararlaştırılır. Bir yayım ağırlıkları yayımlayıp veriyi saklayabilir; kimsenin yeniden üretemeyeceği bir modele izin verici bir lisans koyabilir. Tek başına “açık” kelimesi bunlardan hangisi olduğu hakkında hiçbir şey söylemez.
8.6.1 Her sütun size ne kazandırıyor
Ağırlıklar size dağıtımı kazandırır. Elinizdeyse — bir modeli açık ağırlıklı model (open-weights model) yapan şey budur — modeli lisansın izin verdiği ölçüde kendi donanımınızda, kendi ülkenizde çalıştırabilirsiniz. İsteklerin gerçekten kurum dışına çıkmaması için servis mimarisini, kayıtları, telemetriyi ve bağlı araçları da denetlemeniz gerekir. Kişisel veriyi yurt dışına aktarma koşullarını KVKK’ya göre değerlendiren bir kurum için bu önemli bir gerekçe olabilir; KVKK’ya tabi olmak ise tek başına yerel barındırma zorunluluğu değildir. Ayrıca fine-tune edebilir, nicemleyebilir (quantization) ve aktivasyonları inceleyebilirsiniz.
open-weights model (açık ağırlıklı model) — eğitilmiş parametrelerini indirip kendiniz çalıştırabildiğiniz model. Eğitim verisinin, eğitim kodunun ya da izin verici bir lisansın da onlarla birlikte gelip gelmediği hakkında hiçbir şey söylemez; bunlar birbirinden ayrı üç sorudur. ↩︎
Eğitim verisi size denetimi kazandırır. Veriye ve işleme kayıtlarına erişim, değerlendirme kümenizin eğitime sızıp sızmadığını doğrudan araştırmanızı sağlar; veri yayımlanmadığında bu zorlaşır ve geriye dolaylı testler kalır (Oren vd. 2024; Magar ve Schwartz 2022). Verinin açık olması da tek başına temiz bir değerlendirmenin garantisi değildir. Bu soruna benchmark bulaşması (benchmark contamination) denir: bir benchmark’ın (kıyaslama kümesinin) test örnekleri eğitim verisinde yer aldıysa, yüksek bir skor yetenekten çok ezberi ölçüyor olabilir. Veri olmadan ayrıca dilinizin temsil edilip edilmediğini söyleyemez, metnin nereden geldiğini soran bir hukukçuya cevap veremez (Longpre vd. 2024) ve üretimde karşınıza çıkan ezberlenmiş bir pasajı araştıramazsınız.
Eğitim kodu size yordamı inceleme ve, daha da işe yarayanı, değiştirme olanağını kazandırır — bir makaleden yola çıkmak yerine tarifi kendi derleminiz üzerinde koşturabilmeyi. Tam yeniden üretim için veri, ortam ve hesap bütçesi de gerekir.
Lisans ise erişebildiğiniz bileşenleri bir üründe hangi koşullarla kullanıp dağıtabileceğinizi belirler; yayımlanmamış bir şeye erişim sağlamaz. İnsanları en sık şaşırtan sütun bu, çünkü “açık ağırlık” (open weights) ile “açık kaynak” (open source) rutin olarak eş anlamlı sanılıyor, oysa değiller.
Ayrıca bir satırın içinde değişen sütun da bu; şemanın bir sembol seçmek yerine “değişir” demesinin sebebi budur. Orta satırda adı geçen üç modelin üçü de ağırlıkları yayımlıyor, veriyi ve kodu saklıyor — ama Mistral 7B ve Qwen 2.5 boyutlarının çoğu, tamamen açık modellerin kullandığı lisansın aynısı olan düz Apache 2.0 ile yayımlanıyor; Llama 3.1 ise özel şartlar taşıyor. İki yayım üç sütunda birebir aynı olup dördüncüde tamamen ayrışabilir, dolayısıyla burada kestirme yol yok: modele tek tek bakmanız gerekir. Bazen modelin belirli boyutuna bile bakmanız gerekir: Qwen 2.5’in 3B ve 72B modelleri Apache 2.0 ile değil, Qwen’in kendi lisanslarıyla yayımlanıyor.
Izgaradaki isimler çabuk eskir; ızgaranın kendisi eskimez. Yukarıdaki örnekler 2024 yayımları. O günden bu yana (Ekim 2026 itibarıyla) açık ağırlıklar satırı, farklı lisanslarla gelen büyük uzman karışımı modelleriyle doldu — MIT lisanslı DeepSeek-R1, Apache 2.0 lisanslı Qwen3, yine özel bir topluluk lisansıyla gelen Llama 4. Yalnızca API ile çalışan laboratuvarların en bilineni OpenAI bile kendi açık ağırlıklı modellerini yayımladı (gpt-oss, Ağustos 2025, Apache 2.0). Demek ki bir satır bir şirketi değil, bir yayımı tarif ediyor: aynı laboratuvar aynı anda iki satırda birden durabilir. Her yayımı dört sütunun dördünde de, seçtiğiniz gün yeniden kontrol edin.
Tamamen açık satır, bir üniversite için bir girişimden daha çok önem taşıyan bir sebeple var: kontrollü tekrarlama ve ablasyon deneylerinin kolayca yapılabildiği satır budur. “Türkçe veriyi %5 oranında eklemek İngilizceye yarar mı, zarar mı?” diye sormak istiyorsanız yalnızca ağırlıklara değil, veriye ve koda da ihtiyacınız var. The Pile (Gao vd. 2020), RefinedWeb (Penedo vd. 2023), Dolma (Soldaini vd. 2024) ve FineWeb (Penedo vd. 2024), bu soru hiç değilse sorulabilsin diye var.
8.6.2 Bir model kartını eleştirel okumak
Model kartı (model card), bir modelin ne olduğunu, neyle eğitildiğini ve nerede kullanılmaması gerektiğini anlatan kısa ve yapılandırılmış bir belgedir (Mitchell vd. 2019); aynı fikrin veri kümelerine uygulanmış hâline datasheet (veri sayfası) denir (Gebru vd. 2021). Yaygınlaştılar; bu da yalnızca belge değil, aynı zamanda birer pazarlama aracı da olabildikleri anlamına geliyor. Ayrıntı düzeyleri ve bağımsız doğrulanma dereceleri karttan karta değişir; önemli iddiaları ayrıca kontrol edin. Onları bir ilaç prospektüsü okur gibi okuyun: işe yarar bilgi somut olandır, ilginç bilgi ise dışarıda bırakılandır.
model card (model kartı) — bir laboratuvarın modelle birlikte yayımladığı, amaçlanan kullanımı, eğitim verisini, değerlendirme sonuçlarını ve sınırlılıkları belirten belge. Çoğu zaman gönüllü ve bağımsız olarak doğrulanmamış; buna rağmen bir model hakkında okuyacağınız en yararlı sayfalardan biri. ↩︎
Çoğu karttan daha iyi olan Llama 3.1 kartını baştan sona okuyun; okuma yöntemi kendiliğinden netleşecek.
| kartta yazan | nasıl okunur |
|---|---|
| tabloda “15T+ token”, düz metinde “~15 trilyon” | tek sayfada bir alt sınır ve bir yaklaşık değer. Gerçek olanı makalenin 15,6T’si |
| “Aralık 2023 kesim tarihi” | kesin, kontrol edilebilir ve karttaki tek başına en yararlı satır |
| desteklenen diller: İngilizce, Almanca, Fransızca, İtalyanca, Portekizce, Hintçe, İspanyolca, Tayca | Türkçe listede yok |
| “desteklenen 8 dilden daha geniş bir dil koleksiyonuyla eğitildi” | yani liste bir destek sınırı, bir yetenek ölçümü değil |
| konum bazlı (location-based) hesapla “11.390 ton CO2eq”, piyasa bazlı (market-based, enerji tedarik sözleşmelerine dayalı) hesapla “0 ton” | aynı eğitim hesabı (üç modelin toplamı), iki farklı Scope 2 muhasebe yöntemi. Piyasa bazlı sıfır, elektriğin fiziksel olarak emisyonsuz üretildiğini göstermez; enerji sözleşmeleri ve hesap sınırı ayrıca incelenmeli |
| benchmark tabloları | eğitim, ayar ve örnek seçimiyle ilişkisini kontrol edin; skorlar iyimser olabilir ve sizin görev dağılımınızı ölçmez |
Üzerinde durulması gereken satır, dil satırı. Kart, “açıkça anılanların dışındaki dillerde” kullanımı kapsam dışı ilan ediyor — buna karşın iki kısım önce yaptığımız kendi ölçümümüz, Llama 3’ün tokenizer’ının Türkçeyi İngilizcenin 1,23 katıyla işlediğini, yani test edilen çok dilli tokenizer’lar arasında çok dilli BERT’le birlikte en iyi sonucu paylaştığını gösterdi. Bunlar farklı türden kanıtlar: token sayısı Türkçenin verimli kodlandığını gösterir, ama modelin Türkçede ne kadar doğru ya da güvenilir olduğunu ölçmez. Kart da size modelin ne yapabileceğini değil, Meta’nın arkasında duracağı şeyi söylüyor.
Ölçüm yapmanızın bütün sebebi bu boşluk. Bir kart, modelin sizin dilinizde sizin görevinizde iyi olup olmadığını size söyleyemez, çünkü satıcı bunu değerlendirmedi. Türkçe söz konusu olduğunda bu değerlendirmeyi çoğu zaman sizin yapmanız gerekir.
Hiçbir kartın cevaplamadığı, dolayısıyla kendinize sormanız gereken dört soru:
- Değerlendirme kümem eğitim verisinin içinde miydi? Bunu genelde bilemezsiniz. Modelden eski açık benchmark’larda bulaşma olasılığını ciddiye alın, mümkünse araştırın ve kendinize ait, ayrılmış bir küme (held-out) saklayın (Kapoor ve Narayanan 2023; Oren vd. 2024).
- Dilimden ne kadarı oradaydı? Llama 3’ün %8’lik çok dilli dilimi onlarca dil arasında paylaşılıyor. Az olduğunu varsayın.
- Model, belgelenmiş kapsamının sınırında ne yapıyor? Test edin. Bölüm 22 bunun için var.
- Bu model kullanımdan kaldırıldığında ne olur? Bir API için cevap “prompt’larınız, kontrol etmediğiniz bir takvime göre çalışmayı bırakır” olabilir. Açık ağırlıklarda sağlayıcının takvimine bağımlılık kalkar — gerçek bir bedeli olan gerçek bir özellik: lisans, çalışma ortamı, güvenlik ve bakım sorumluluğu sizde kalır.
8.6.3 Pratikte birini seçmek
Kararın dört girdisi var ve bunlar birlikte ele alınmalı. Ama işe yetenekten başlamak çoğu zaman verimsizdir: önce kullanımın zorunlu koşullarını yazıp onları karşılamayan adayları elemek, ardından kalanları ölçmek daha az iş çıkarır. Şu sıra bunun için iyi bir başlangıç:
- Verinin nerede işlenmesine izin var? Bir dış API’nin uygunluğu, verinin işlendiği yere ve sözleşme koşullarına bağlıdır; kişisel verinin ülkeden ya da binadan çıkmasına izin yoksa ve bunu karşılayan bir API seçeneği de yoksa API satırı elenir ve hiçbir benchmark puanı onu geri getirmez. Önce buna karar verin; çoğu zaman diğer her şeyden daha fazla seçenek eler.
- Lisans neye izin veriyor? Kullanıcı sayısı maddesini, adlandırma maddesini ve atıf maddesini gerçek ürününüzle karşılaştırın. Bunu ikinci sırada yapın; fikir değiştirmek hâlâ ucuzken.
- Neyi sunmaya gücünüz yeter? Yukarıdaki aritmetikten: üretilen token başına \(2N\) FLOP. Beklediğiniz trafikle çarpın. Bu, parametre sayınızı genelde sizin yerinize seçer ve genelde sandığınızdan küçük bir şey seçer.
- Ve ancak şimdi: yeterince iyi mi? Elemeden geçenleri kendi verinizde değerlendirin. Açık lider tablosu en iyi ihtimalle bir ön eleme aracıdır; bulaşmayı da hesaba katınca zar zor o kadardır.
8.7 Lab: Türkçe bir ön eğitim koşusunu fiyatlandırın
Bu labdaki her şey aritmetik ve tokenizer çağrılarından ibaret; hiçbiri GPU gerektirmiyor. Amaç, büyük bir koşuya başlamadan önce varsayımları görünür kılmak: bu bölümün konusu olan karar, eğitim başlamadan çok önce veriliyor.
- Kendi metninizde fertility ölçün. Önemsediğiniz bir alandan 2.000–5.000 Türkçe cümle alın — destek talepleri, hukuk metni, haber, klinik not, kendi teziniz. En az dört tokenizer ile tokenize edin: biri İngilizce öncelikli (
openai-community/gpt2), ikisi çok dilli (NousResearch/Meta-Llama-3-8B,Qwen/Qwen2.5-7B) ve biri Türkçe öncelikli (dbmdz/bert-base-turkish-cased). Bunlar, tokenizer bütçesi kısmındaki tablonun (Bölüm 8.4) dayandığı tanımlayıcılar; ama kendi alan metninizde aynı sayıları beklemeyin, farkları alan, uzunluk ve yazım dağılımıyla açıklamaya çalışın. Bölüm tablosunu yeniden üretmek isterseniz aynı çiftleri kullanın: OPUS-100en-treğitim kümesinin ilk 3.000 çifti, aynı süzgeç, cümleler boşlukla birleştirilip tokenize edilmiş. Her biri için kelime başına token’ı ve toplam token sayısını raporlayın. Kelime başına token’ı tek başına diller arası bir iddia olarak raporlamayın; artık sebebini biliyorsunuz. - Aynı içerik oranını bulun. Bu cümlelerin 200’ünü İngilizceye çevirin ya da mevcut bir paralel sürümünü bulun. Oranı eşleşmiş içerik üzerinde yeniden hesaplayın. Kendi alanınızın sayısının, bu bölümde Llama 3 için verilen 1,23 kattan ne kadar uzak olduğunu belirtin ve fark için somut bir sebep gösterin. Çoğu zaman sebep, alanın kendi sözlüğüdür: özel isimler, kod, sayılar ve kısaltmalar iki dilde de neredeyse aynı şekilde tokenize olur ve oranı 1’e doğru çeker.
- Oranı paraya çevirin. Gerçek bir API modeli ve onun güncel fiyat listesini seçin. Türkçe ve İngilizce örneklerin girdi ve çıktı token sayılarını o modelin kendi tokenizer’ıyla ölçün ve bir milyon Türkçe belgenizin işlenmesinin ne tutacağını hesaplayın; sonra aynısını İngilizce çeviriler için yapın. Aradaki fark, kendi ürününüz için, kendi para biriminizle ek ücrettir. Diğer tokenizer’ları sıkıştırma karşılaştırması için kullanın; onların sayılarını uyumsuz bir modelin faturasına taşımayın.
- Bağlam tavanını bulun. Her modelin kendi tokenizer’ı ve sohbet şablonuyla temsilî Türkçe ve İngilizce belgelerin token sayısını ölçün. 128K token’lık pencereden sistem istemini, erişilen parçaları ve yanıta ayırdığınız bütçeyi düşün; kalan yere kaç Türkçe kelimenin, kaç İngilizce kelimenin sığdığını raporlayın. Bir belgenin bağlam penceresine tek parça hâlinde mi sığacağına, yoksa bölünüp erişimle (Bölüm 19) parça parça mı verilmesi gerektiğine karar veren sayı budur.
- \(C = 6ND\) ile bir koşu bütçeleyin. Türkçe öncelikli bir temel model istediğinizi varsayın. \(N\) ve \(D\)’yi kendiniz seçin ve ikisini de gerekçelendirin: \(N\)’i sunmayı planladığınız modelden (Bölüm 31), \(D\)’yi ihtiyaç duyduğunuz kalitede gerçekten var olan Türkçe metinden. Bölüm 8.5’teki hesap makinesini kullanarak FLOP’u, GPU-saati, makul olarak kiralayabileceğiniz bir filodaki wall-clock süresini ve dolar rakamını bulun. Sonra varsaydığınız MFU’yu belirtin ve savunun — %40’ın üstünde bir sayı yazdıysanız hangi makaleyle eşleştiğinizi söyleyin.
- Gerçeğe karşı sağlama testi yapın. Bütçenizi yayımlanmış üç Llama 3.1 koşusuyla karşılaştırın. Sayınız çok daha küçükse, farkı yaratan varsayımı bulun. Çoğu zaman ya MFU’dur ya da token sayısı.
- Şimdi duyarlılık analizi yapın. İki ayrı senaryo kurun: (A) seçtiğiniz Türkçe öncelikli tokenizer ile temsilî Türkçe derleminizin gerçek token sayısı; (B) aynı derlemin seçtiğiniz çok dilli tokenizer ile gerçek token sayısı. \(6ND\)’yi ve MFU varsayımını her senaryoya ayrı uygulayın; farkı, mevcut \(D\)’ye sabit bir 1,23 katsayısı ekleyerek değil, ölçtüğünüz token sayılarıyla bulun (1,23 başka bir derlemde, başka tokenizer’larla ölçüldü; ikinci kez uygulamak çifte sayım olabilir). Fazladan çıkan doları raporlayın. Sonra bu sayının ortaya attığı soruyu cevaplayın: Türkçe bir tokenizer ve daha küçük bir model eğitmek, çok dilli bir modelde ek ücreti ödemeye devam etmekten hangi noktada daha ucuz hâle gelir?
- Kendi başa baş noktanızı iki kez hesaplayın. Üretilen token başına \(2N\) FLOP’u kullanarak, servis maliyetinin eğitimi aşması için servisinizin kaç token üretmesi gerektiğini bulun. Bu, FLOP eşitliği cevabıdır ve artık bunun iyimser uç olduğunu biliyorsunuz. O yüzden aynı hesabı bir de GPU-saat cinsinden yapın; decode’un, eğitim koşunuzun %35’ine karşılık %2–5 MFU sürdürdüğünü varsayın. İkisini de öngördüğünüz trafikte aya çevirin. Cevap bir yılın altındaysa, çıkarım-optimal ile hesap-optimalin neden farklı hedefler olduğunu daha yeni keşfetmişsiniz demektir. Bu hesap açıklayıcı; ürün kararı için kalite eşiğini geçen adayların eğitim ya da uyarlama, dağıtım, bakım ve API maliyetlerini aynı zaman ufkunda karşılaştırın.
Teslim edilecek: belirli bir Türkçe ürün için eğit, fine-tune et ya da API kullan önerisinde bulunan, gerçekten göndereceğiniz cinsten bir sayfalık bir not; üç kanıtı aynı içerik oranı tablosu, hesap bütçesi ve başa baş ayı olsun. Veri erişimi, lisans ve kalite varsayımlarınızı ve yanlış çıkması hâlinde önerinizi tersine çevirecek varsayımı da belirtin.
8.8 Sezgi kontrolleri
Açmadan önce kendi gerekçenizle cevaplayın. Çoğunda sezgisel cevap maliyetli bir yönde yanılıyor; açılır cevaplardaki sayıların hangi varsayımlar altında geçerli olduğuna dikkat edin.
Not1. Llama 3’ün tokenizer’ıyla Türkçe kelime başına 2,12, İngilizce 1,28 token istiyor. Türkçe %66 daha mı pahalı?
Hayır; bu karşılaştırma bu hâliyle geçersiz. Bu bölümdeki paralel derlemde aynı içerik için Llama 3 tokenizer’ı Türkçede yaklaşık %23 fazla token üretti. Bu bir girdi token farkı; model fiyatı, çıktı ve trafik hesaba katılmadan toplam ücret değil.
Kelime başına token, farklı boyuttaki birimleri karşılaştırıyor. Türkçe eklemeli bir dil: evlerinizden tek kelimedir, İngilizcede ise “from your houses” olur. Doğru ölçü, aynı içerik için harcanan token sayısıdır — bir cümleyi ve onun profesyonel çevirisini tokenize edip bölün.
Bunu 1.157 eşleşmiş çift üzerinde yaptığınızda BERTurk, İngilizcenin maliyetinin 0,58 katına mal oluyor; test edilenler arasında Türkçenin daha ucuz olduğu tokenizer’lar yalnızca Türkçe öncelikli olanlar. GPT-2 1,98 kat, Llama 3 ile çok dilli BERT ise 1,23 kat tutuyor.
Aynı derlemde, eşleşmiş içerikte 10.862 İngilizce kelimeye karşılık 8.058 Türkçe kelime var. Eklemeli yapı, metin daha hiçbir tokenizer’dan geçmeden ham sayımlarda görünüyor.
Not2. Modeliniz Türkçeyi kötü tokenize ediyor. Fine-tuning ile bundan kurtulabilir misiniz?
Sıradan bir fine-tuning ile hayır — ve tokenizer’ın bir ön işleme bölümünde değil, bir ön eğitim bölümünde yer almasının sebebi de bu.
Tokenizer’ı değiştirmek ya da genişletmek yeni token kimlikleri ve bunlar için embedding (gerekiyorsa çıkış) satırları gerektirir. Eski ağırlıklar kendiliğinden değişmez; ama geri kalan ağırlıklar eski bölünmeye göre öğrenildiği için yeni token’larla güvenilir kullanım uyarlama eğitimi ister ve bu eğitim onları da günceller. İmkânsız değildir: sözlüğü genişletebilir, yeni embedding’leri yerini aldıkları parçalardan başlatabilir ve model oturana kadar ön eğitime devam edebilirsiniz (Bölüm 9.8; Türkçe için Bölüm 16) — belgelenmiş ve zaman zaman değecek bir yordam; üstelik yeni satırları sıfırdan değil eskilerinden başlatan sözlük uyarlama yöntemleri de var. Ama ne bedelsizdir ne de güvenli. Maliyeti sözlüğün ne kadarını değiştirdiğinize, nereden başladığınıza ve hangi kaliteyi kabul edeceğinize göre ölçeklenir; modelin hâlihazırda iyi yaptığı şeyleri bozma riski taşır. Otomatik olarak ikinci bir ön eğitim koşusu değildir, sıradan bir fine-tuning de değildir. Hesap bütçesinin diller arasında nasıl bölüşüleceğini tokenizer belirler ve o bölüşümü geri almak, kendi bütçesi olan bir projedir. O proje yoksa 1,98 katlık bir tokenizer’ın kullanıcısı bu ek ücreti bağlam penceresinde, gecikmede ve her API faturasında, modelin ömrü boyunca öder.
Llama 3, bu kararın bilinçli olarak nasıl verildiğini gösteriyor: tiktoken’dan 100.000 token, artı özellikle İngilizce dışındaki diller için eklenen 28.000 token; bunun, İngilizceye hiçbir maliyet yüklemeden o dillerdeki sıkıştırmayı iyileştirdiği bildiriliyor. Bu, fiyat etiketi olan, bir kez ve ilk gradyan adımından önce verilmiş bir tasarım kararı.
Not3. Bir satıcı %40 MFU söylüyor. İyi mi bu?
Paydaya neyin girdiğini sormadan cevaplanamaz; sorunun bütün amacı da zaten o soruyu sordurmaktır.
Aynı GPU’nun bir yoğun tepe değeri, bir de iki katı büyüklükte bir seyreklik tepe değeri vardır ve cevabı payda belirler: büyük olana bölmek bildirilen MFU’yu yarıya indirir. Llama 3’ün Tablo 4’ü GPU başına 430 TFLOP/s bildiriyor; H100’ün yoğun BF16 tepe değerine göre bu \(430/989 = \%43{,}5\), 2:4 seyreklik tepe değerine göre ise aynı koşu \(430/1{.}979 = \%21{,}7\) bildirir. %43,5 rakamı yoğun değeri kullandıklarını doğruluyor. İki MFU ancak aynı tepe değerine göre hesaplandıklarında karşılaştırılabilir ve satıcılar hangisini kullandıklarını her zaman söylemeyebilir; sorun. Sayımın hangi model işlemlerini içerdiğini ve oranın hangi süre için hesaplandığını da sorun: Llama 3’ün belirli bir aşamadaki %41’i ile model kartındaki toplam GPU-saatten türetilen oran aynı tür ölçüm değil.
İkinci tuzak paydır. Llama 3.1 405B’yi yalnızca \(6ND\)’den yeniden kurmak %34,5 veriyor; attention terimi eklendiğinde %36,0–37,1 çıkıyor. Bu aralık, makalenin %41’lik MFU’sundan %90 etkin eğitim süresi varsayımıyla türettiğimiz açıklayıcı %36,9’luk tahmini de içine alıyor. \(6ND\) attention’ı dışarıda bırakır; bu bir bütçe tahmini için sorun değildir, ama bir kullanım oranı karşılaştırması için sorundur.
Karşılaştırılabilir görünen ama olmayan iki sayı, verimlilik üzerine mühendislik sohbetlerinin raydan çıkmasının en yaygın yoludur.
Not4. \(C = 6ND\)’deki 6 nereden geliyor?
Her birinin ayrı bir sebebi olan üç tane 2; bunları bilmek, formülü ezberden okumak yerine uyarlayabilmenizi sağlar.
İleri geçişte parametre başına iki FLOP, çünkü her ağırlık bir çarpmaya ve bir toplamaya katılır. Girdiler üzerinden geri geçiş için iki tane daha, çünkü hatanın önceki katmanlara ulaşmaya devam etmesi gerekir. Ağırlıklar üzerinden geri geçiş için de iki tane daha, çünkü optimizer neyi değiştireceğini bilmek zorundadır.
Yani ileri geçiş \(2ND\)’dir ve faturanın yalnızca üçte biridir — bu da size hemen, çıkarımın token başına \(6N\) değil kabaca \(2N\) FLOP’a (yani \(D\) token için \(2ND\)’ye) mal olduğunu söyler; bütçenize servisin mi yoksa eğitimin mi hâkim olduğuna karar veren sayı da budur. Ayrıca \(6ND\)’nin neden bir ön eğitim kuralı olduğunu ve dondurulmuş ağırlıklarla yapılan fine-tuning’e olduğu gibi taşınmadığını da anlatır.
Not5. Daha fazla hesabınız var. Daha büyük bir model mi eğitmelisiniz, daha fazla veri mi kullanmalısınız?
Chinchilla’nın deney koşullarında ve yeterli yeni veri varsa, kabaca eşit ölçüde ikisi de — işin ilginç yanı, alanın birkaç yıl boyunca tam da bu konuda yanılmış olması. Bölüşüm, verinin bulunabilirliğine ve hedef kayba bağlı.
Chinchilla’nın bulgusu, parametrelerin ve token’ların birlikte ölçeklenmesi gerektiği; daha önceki modeller boyutlarına göre fena hâlde az eğitilmişti. Ama modeli sunacaksanız hesap-optimal cevap, istediğiniz cevap değildir: daha uzun eğitilmiş daha küçük bir modelin eğitimi daha pahalı, çalıştırılması ise token başına daha ucuzdur; üretim modellerinin rutin olarak hesap-optimal noktanın epeyce ötesinde eğitilmesinin sebebi budur.
Labdaki başa baş sorusu bunun pratik hâli: modeliniz çok sayıda istek sunacaksa, çıkarım-optimal ile hesap-optimal farklı hedeflerdir. Hangisine yöneleceğinizi hizmet süresi tek başına değil, beklenen toplam istek hacmi, kalite eşiği ve token başına maliyet belirler.
Not6. Daha fazla veri toplamak yerine aynı veriyle iki kez eğitim yapsanız olmaz mı?
Bir noktaya kadar olur; sonra marjinal yarar azalır.
Muennighoff ve arkadaşları, ölçtükleri rejimde yaklaşık dört epoch’a kadar tekrarlanan verinin “benzersiz veriye kıyasla kayıpta ihmal edilebilir değişiklikler ürettiğini” buldu. Bunun ötesinde her ek epoch daha az değer taşıyor; makale 16 epoch civarına kadar hâlâ kazanım görüyor, sonrasında ise getiri hızla düşüyor ve ek hesabın değeri sıfıra yaklaşıyor.
Türkçe gibi bir dil için bunun pratikteki anlamı şu: birçok Türkçe ön eğitim koşusunda kısıt GPU’lardan çok derlem olabilir ve tekrar size bir kaçış yolu değil, küçük bir çarpan kazandırır. Veri filtreleme (Bölüm 8.2) kararlarının bu kadar ilgi görmesinin sebebi de bu — daha fazla metin bulamıyorsanız, neyi tuttuğunuz çok daha önemli hâle gelir.
8.9 Mülakat soruları
Ön eğitim soruları nadiren gerçekten bir koşu yapıp yapmayacağınızla ilgilidir. Devraldığınız bir sistem hakkında — hesap, veri ve tokenizer kararları, model seçiminin koşulları — nicel akıl yürütüp yürütemediğinizi ölçer. Cevaplarda sayısal tahmini, dayandığı varsayımlarla birlikte verin.
Mülakata giren neredeyse hiç kimse bir modeli ön eğitimden geçirmemiştir ve mülakatı yapan bunu bilir. Cevapları ayıran şey, eğit, fine-tune et ya da satın al kararını veren aritmetiği yapabilmeniz — ve hangi ön eğitim kararlarını sonradan değiştirmenin pahalı olduğunu bilmenizdir.
2 trilyon token üzerinde 7B’lik bir model için hesabı tahmin edin. \(C \approx 6ND = 6 \times 7\times10^9 \times 2\times10^{12} \approx 8{,}4\times10^{22}\) FLOP. Sonra bunu, bütçeyi tutan birinin anlayacağı bir şeye çevirin: seçtiğiniz hızlandırıcının yoğun tepe değerini, bu iş için ölçülmüş ya da senaryo olarak seçilmiş bir MFU aralığıyla (örneğin %25–40) çarpın, sonra 3.600 saniyeyle; bütçeyi buna bölünce karşınıza GPU-saat aralığı çıkar. \(6ND\)’nin attention’ı yok saydığını, bunun 32 katmanlı, 4096 genişlikli bir 7B model için 2K bağlamda kabaca %4, 4K’da %8, 8K’da %15, uzun bağlamda ise çok daha fazla olduğunu açıkça söyleyin ve şunu ekleyin: bir ön eğitim programını sarsan şey çoğu zaman FLOP değil, takvimdir — kesintiler, yeniden başlatmalar ve checkpoint yüklemeleri.
Hangi ön eğitim kararlarını sonradan değiştirmek pahalıdır? Tokenizer bunların başında gelir. Talimat davranışı, güvenlik, alan bilgisi, hatta olgusal içeriğin epey bir kısmı eğitim sonrası aşamada değiştirilebilir (Bölüm 9). Tokenizer ise direnir: sözlüğü değiştirmek ya da genişletmek yeni embedding satırları ve geri kalan ağırlıkların da güncellendiği bir uyarlama eğitimi ister — mümkün, ama bir fine-tuning değil, bir proje. Veri bileşimi, mimari ve temel kapasite de sonradan değiştirmesi pahalı kararlardır; “geri alınamaz tek karar” diye sıralamak yerine hangi değişikliğin ne gerektirdiğini açıklayın. Riski tokenizer tablosundaki aynı içerik oranıyla sayısallaştırın: GPT-2’nin tokenizer’ında Türkçe yazan bir kullanıcı, aynı içerik için İngilizce yazan birinin 1,98 katı token öder; BERTurk’te ise 0,58 katı. Aynı dil, aynı metin ve tamamen eğitim başlamadan önce verilmiş bir karardan doğan 3,4 katlık bir yelpaze.
Türkçe bir ürün için ön eğitim mi, fine-tuning mi yapacağınıza, yoksa API mi kullanacağınıza nasıl karar verirsiniz? Önce eleme koşulları: hedef görevde kalite, veri işleme koşulları ve lisans. Sonra şu sırayla üç sayı. Gerçek Türkçe isteklerde ölçülen aynı içerik oranı (Türkçe ÷ İngilizce token), çünkü o tokenizer’ı kullandığınız sürece içerik başına maliyetinizi belirler; ama tek başına bir Türkçe model gerekçesi değildir. İşe yarayabilecek en küçük model için \(6ND\) bütçesi; bu çoğu zaman konuşmayı bitirecek kadar büyüktür. Ve başa baş ayı: öngördüğünüz trafikte API harcamasının eğitim artı servis maliyetini aştığı nokta. O ay yıllar ötedeyse satın alın. (Bu, “kendin yap ya da satın al” başa baş noktasıdır; Bölüm 8.5’teki çıkarım-optimal başa baş noktasıyla karıştırmayın.) Seçenekleri aynı zaman ufkunda karşılaştırın ve bir varsayım değiştiğinde kararın nasıl değiştiğini gösterin. Cevap çoğu zaman fine-tune et ya da satın al çıkar; ama bunu varsayılan olarak değil, aritmetik ve kendi kalite ölçümünüzle göstermelisiniz.
Ön eğitim verisi gerçekte nereden geliyor ve neler atılıyor? Common Crawl’dan ya da FineWeb gibi temizlenmiş bir türevinden; işin asıl özeti ise ne kadarının atıldığı: filtreleme, tekilleştirme ve kalite sınıflandırması ham taramanın büyük çoğunluğunu siliyor. Adımları tek tek sayın — kalıp metin temizliği, dil tespiti, taramalar arası tekilleştirme, kalite sınıflandırıcıları — ve FineWeb’in yazarlarının karşılaştığı sezgiye aykırı bulguyu anlatın: bütün taramalar boyunca agresif tekilleştirme, eski bir taramada tutulan verideki düşük kaliteli metnin oranını yükseltti ve eşit token bütçeli denemede daha kötü sonuç verdi. Daha fazla tekilleştirme her zaman daha iyi değildir; bir filtrenin sertliğini küçük, kontrollü koşularla sınamak bu yüzden gerekir.
Bir model 128K bağlam penceresi olduğunu söylüyor. Neye şüpheyle yaklaşmalısınız? Kalitenin bu pencere boyunca aynı olduğuna ve bunu karşılayabileceğinize. Kalite tarafında: eğitim nadiren baştan sona tam uzunlukta yapılır — Llama 3’te olduğu gibi bağlam çoğu zaman sonlara doğru aşamalar hâlinde uzatılır — yani son 100K token, ilk 8K’ya göre çok daha az eğitim görmüş olabilir. Maliyet tarafında ilgili aritmetiği (Bölüm 7.6) alın: 32 katmanlı, 4096 genişlikli bir modelin (Llama 3 8B’nin boyutları) 100.000 token’daki KV önbelleği, 16 bit ve tek istek varsayımıyla, sıradan multi-head attention olsaydı 14 GB’lık ağırlığa karşılık eşzamanlı istek başına 52,4 GB olurdu; Llama 3 8B’nin kullandığı grouped-query attention ile (32 yerine 8 KV head’i) aynı önbellek 13,1 GB. Başka 7B–8B modellerin belleği farklı olabilir; kendi modelinizde uzun bağlam kalitesini ve istek başına KV kullanımını ölçün. Tek bir yapılandırma satırından çıkan 4 katlık bir fark. Reklamı yapılan pencere ile sizin bütçenizde kullanılabilir pencere farklı sayılardır.
Küçük ön eğitim koşuları neden büyüklere göre bu kadar verimsiz görünüyor? Çünkü buradaki verimlilik büyük ölçüde bir hızlandırıcıyı meşgul tutmakla ilgili ve küçük modeller ona daha az malzeme veriyor: iletişim birimi başına daha az aritmetik, gecikmeyi arkasına gizleyecek daha az iş. Llama 3.1 için yeniden kurulan MFU 8B’de %15,8–17,2, 70B’de %27,4–29,0, 405B’de %36,0–37,1. Sonra cevabı eksiksiz kılan çekinceyi ekleyin: yayımlanan GPU-saatlerin duruşları, değerlendirmeyi ya da checkpoint almayı ne ölçüde kapsadığını kart söylemiyor ve karşılaştırılacak yayımlanmış bir MFU’ya sahip tek model 405B — dolayısıyla etkenlerin payını belirleyemezsiniz ve 8B rakamını kernel kalitesinin ölçümü olarak okumamalısınız.
Türkçe (ya da Arapça, ya da Fince) ürününüz İngilizce olandan istek başına çok daha pahalıya mal oluyor. Açıklayın ve çözün. Önce aynı içeriğin kullanılan tokenizer altında kaç token ürettiğini karşılaştırın. Diller arası farklar; eğitim verisinin dağılımı, sözlük, yazı sistemi ve tokenleştirme kurallarıyla ilişkili olabilir (Petrov vd. 2023). İstek maliyetinde girdi ve çıktı uzunluklarını, model fiyatlarını ve varsa önbellek koşullarını da ayrı inceleyin. Bu bölümdeki kısa paralel metinde Türkçe/İngilizce token oranı
cl100k_baseiçin 1,82,o200k_baseiçin 1,39 çıktı. Bunlar tokenizer’a bağlı farkı örnekler; ürününüzün maliyet oranını kestirmek için temsili çok sayıda istek üzerinde ölçüm yapın. Çareler, artan emek sırasıyla: tokenizer’ı bu dilde daha az token üreten bir model seçmek; maliyeti istek başına değil görev başına token cinsinden ölçmek; yeterli ölçek ve eğitim bütçesi varsa, alana ve dile özgü bir tokenizer ile uyumlu bir modeli birlikte eğitmeyi veya mevcut modeli buna uyarlamayı değerlendirmek (Kudo ve Richardson 2018). Önceden eğitilmiş bir modelin tokenizer’ı, model uyumluluğu sağlanmadan bağımsız bir parça gibi değiştirilemez.BPE’yi anlatın. Tokenizer’ın hiç görmediği bir kelimeye ne olur? Birleştirme döngüsünü anlatın, sonra asıl soruyu cevaplayın: başlangıç alfabesi kelimenin karakterlerini kapsıyorsa özel bir şey olmaz; kelime bilinen alt kelimelere, en kötü durumda tek tek karakterlere ayrışır. Başlangıç alfabesi girdiyi kapsıyorsa veya tokenizer bilmediği karakteri baytlarıyla yazabiliyorsa (byte fallback), temsil edilemeyen karakter nedeniyle
<UNK>kullanmak gerekmez. Ancak bu kapsama, ön işleme sırasında hiçbir bilginin silinmediği anlamına gelmez; kayıpsızlığı tokenleştirme hattının tamamı için değerlendirmek gerekir. Bilinmeyen karakterlerin işlenmesinde başlangıç alfabesi ve byte fallback desteği belirleyicidir; algoritmanın parçalama kuralları ve uygulamanın sınırları da önemlidir. Klasik BERT WordPiece tokenizer’ında sözlükte olmayan bir karakter[UNK]üretebilir. Karakterler bilinse bile kelime uzunluğu sınırı aynı sonucu verebilir: mBERT tokenizer’ı 100 taneaharfinden oluşan bir kelimeyi 50 parçaya ayırır, 101 harflik olanı ise tek bir[UNK]yapar. Bayt düzeyinde çalışan ya da byte fallback kullanan tasarımlarda bilinmeyen karakter baytlarıyla yazılır. Bu bölümdeki işlenmiş örneği kullanın: BPE tokenizer’ının eğitim örneğinde bulunmayanlowestkelimesi, öğrenilmiş birleştirmelerlelow + estolarak parçalanır.
8.10 Daha derine inmek için
Makalelerden herhangi birini okumadan önce yapmaya değer iki şey var. FineWeb’in etkileşimli raporunu açın ve ablasyon grafiklerini okuyun — yayına alınan sürümün yanında başarısız varyantları da gösteren, kontrollü veri filtresi karşılaştırmalarını görebileceğiniz bir rapor. Sonra tokenizer oyun alanını açın ve bildiğiniz en uzun Türkçe kelimeyi yapıştırın; tokenizer bütçesi kısmının (Bölüm 8.4) ana fikrini, kelime bölünmelerini karşılaştırarak birkaç saniyede görürsünüz.
Sonra ön eğitimi gerçekten yapan birini izleyin: Karpathy’nin Let’s reproduce GPT-2 (124M) videosunda dört saat boyunca küçük ölçekli gerçek bir ön eğitim uçtan uca yapılıyor (bölümdeki büyük ölçek sayılarını doğrulamaz, ama onları somutlaştırır); Stanford CS336 ise tamamen bunu kendiniz yapmanız üzerine kurulmuş bir ders.
Tokenization, uygulamalı.
- Hugging Face LLM Course, 6. bölüm. BPE, WordPiece ve Unigram tokenizer’larını sıfırdan kurar ve hangi modelin hangisini kullandığını anlatır. BPE dersi bizim buradaki küçük uygulamamızın doğrudan devamıdır.
- minbpe ve eşlik eden iki saatlik video, Andrej Karpathy (Karpathy 2024). GPT sınıfı bir tokenizer’ı sıfırdan kuran birkaç yüz satır temiz Python. Videoyu izledikten sonra kodu satır satır okuyun; ikisi birlikte tasarlanmış.
- The Tokenizer Playground. Metni yapıştırın, tokenizer değiştirin, bölünmeyi izleyin. Kendi adınızı, şirketinizin parça numaralarını ve bir paragraf Türkçe deneyin.
- tiktoken. Bu bölümdeki maliyet ölçümlerinde kullanılan kütüphane.
- sentencepiece (Kudo ve Richardson 2018). Kendi tokenizer’ınızı eğitmeniz gerektiğinde — örneğin Türkçe ağırlıklı bir derlem için — BPE ve Unigram modelleri eğitmekte kullanılan açık kaynak araçlardan biri.
Aşağıdaki makaleler, bu bölümdeki sayıların geldiği kaynaklar. Kabaca şu sırayla okuyun:
| konu | kaynak |
|---|---|
| belgelenmiş, eksiksiz bir ön eğitim koşusu | Grattafiori vd. (2024) |
| veri pipeline’ının ne yaptığı, ablasyonlarla | Penedo vd. (2024); Penedo vd. (2023) |
| açıkça yayımlanmış derlemler | Gao vd. (2020); Soldaini vd. (2024) |
| baştan sona açık bir model — ağırlıklar, veri ve kod | Groeneveld vd. (2024) |
| tekrar ve tekilleştirmenin etkisi; eğitim verisinden ezberlenmiş pasaj çıkarımı | Lee vd. (2022); Carlini vd. (2021) |
| veri kısıtlı koşulda epoch tekrarı | Muennighoff vd. (2023) |
| hesap-optimal sınır | Kaplan vd. (2020); Hoffmann vd. (2022) |
| alt kelime tokenizasyonu, kaynağından | Sennrich vd. (2016); Kudo ve Richardson (2018) |
| tokenizer’ların diğer dillerin konuşucularına maliyeti | Petrov vd. (2023) |
| verinin gerçekte nereden geldiği ve lisansları | Longpre vd. (2024); Dodge vd. (2021) |
| kartlar ve veri sayfaları | Mitchell vd. (2019); Gebru vd. (2021) |
| model çıktısı üzerinde eğitim | Shumailov vd. (2024) |
| hesapla ölçeklenen genel yöntemlerin elle kodlanmış bilgiyi yendiği savı | Sutton (2019) |
8.11 Alıştırmalar
- Bir açık model kartı ve bir kapalı model kartı alın. Her birinin, kendiniz doğrulayabileceğiniz üç iddiasını ve doğrulayamayacağınız üç iddiasını listeleyin. Sonra bu altı doğrulanamaz iddiadan hangisinin yanlış çıkması hâlinde kararınızı en çok değiştireceğini belirtin.
- FineWeb ekibi küresel tekilleştirmeyi iyi tasarlanmış bir deneyle test etti. Tek bir eski 2013-48 anlık görüntüsünün içinde, küresel tekilleştirmenin tuttuğu ~31B token ile çıkardığı ~460B token’ı (bunlar kendi içinde yeniden tekilleştirilince 171B’ye iniyor) aldılar, her biriyle bir model eğittiler ve çıkarılan veriyle eğitilen modelin daha iyi olduğunu buldular. Mekanizmayı açıklayın — deneyin iki derlemi değil, tek bir anlık görüntünün iki dilimini karşılaştırdığına dikkat edin; onu temiz bir test yapan şey de bu. Sonra hunideki başka bir yerde aynı şekilde bozulabilecek bir filtre adı verin ve bunu yakalamak için neyi ölçeceğinizi söyleyin.
- Llama 3 405B’nin yayımlanan koşusunun sonunda 40M token’lık bir tavlama aşaması var: koşunun %0,00026’sı. Makale ayrıca, yüksek kaliteli kod ve matematiğin ağırlığı artırılmış bir karışımla yapılan ayrı bir tavlama deneyinde, 8B modelde GSM8k doğrulama kümesinde %24,0 iyileşme, 405B’de ise neredeyse hiç iyileşme olmadığını bildiriyor. Makale %24,0’ın göreli bir iyileşme mi yoksa yüzde puan cinsinden bir kazanç mı olduğunu söylemiyor; iki okumanın, ne kadar etkilenmeniz gerektiğini nasıl değiştireceğini söyleyin. Bu ayrı deneyden yayımlanan 405B koşusuna hangi sonuçların aktarılamayacağını belirtin. Sonra her iki sonuçla da tutarlı bir açıklama verin. Açıklamanız bir şey öngörmeli — ne öngördüğünü söyleyin.
- Bir satıcı hızlandırıcısı için 1.979 TFLOP/s reklamı yapıyor. Siz kendi eğitim işinizde sürekli 310 TFLOP/s ölçüyorsunuz. Aradaki farkı, her biri için bu bölümün rakamlarını kullanarak adı konmuş üç adımda açıklayın ve eksiğin ne kadarını daha iyi mühendislikle makul biçimde geri kazanabileceğinizi, ne kadarının yapısal olduğunu belirtin.
- 2T token üzerinde 3B’lik bir model için \(6ND\)’yi hesaplayın. Sonra %40 MFU’da kaç H100-saat gerektiğini ve bunun 64 GPU’da ne kadar süreceğini hesaplayın. Şimdi aynı hesabı %25 MFU ile tekrarlayın — henüz ayarlanmamış bir kümedeki ilk koşu için varsaymanız gereken değer bu. İki wall-clock süresi rakamını da raporlayın ve hangisinin bir proje planına yazılacağını söyleyin.
- Derlem ölçümümüz, Qwen 2.5’in (sözlük 151.643) Türkçeyi İngilizcenin 1,40 katıyla tokenize ettiğini, Llama 3’ün ise (sözlük 128.000) 1,23 katı başardığını buldu. Sözlük büyüklüğünün oranı tek başına açıklamadığını gösterin. Ön tokenleştirme, tokenizer eğitim verisinin dil karışımı ve sözlük içeriği için ayrı hipotezler kurun; her biri için neyi karşılaştırmanız gerektiğini, açıklamanızı doğrulayacak en küçük deneyi ve hangi sonucun onu çürüteceğini söyleyin.
evlerinizdeniçin Llama 3ev|ler|iniz|denüretiyor — burada seçtiğimiz çözümlemedeki dört biçimbirimle örtüşen dört token — Cosmos GPT-2 iseev|lerinizdenüretiyor: iki token, yarı maliyet ve tek bir biçimbirim olmayan ikinci bir token. Her birini ayrı ayrı daha iyi tokenleştirme olarak savunun. Sonra meseleyi çözmek için neyi ölçeceğinizi söyleyin ve görev konusunda somut olun, çünkü cevap her görev için aynı değil.- GPT-3 parametre başına 1,7 token kullandı; Llama 3.1’in 8B’si 1.868 kullandı. İkisi de akılcı kararlardı. Her birinin arkasındaki muhakemeyi yeniden kurun ve hesap-optimal eğitimle düşük çıkarım maliyeti arasındaki farkı açıklayın. Sonra iki eşit kaliteli model için eğitim ve token başına servis maliyetleri olmadan trafik başa baş noktasının neden hesaplanamayacağını gösterin; gereken verileri listeleyin ve açıkça varsaydığınız değerlerle bir eşik hesaplayın.
- Size varsayımsal olarak 10.000 H100-saatlik sabit bir bütçe veriliyor. Önce yoğun BF16 tepe değerini ve ulaşılabilir bir MFU aralığı seçin. Bu bölümün aritmetiğiyle, Chinchilla çalışmasındaki yaklaşık token/parametre oranını bir senaryo olarak kullanıp sıfırdan ön eğitimden geçirebileceğiniz birkaç model boyutunu ve token bütçesini hesaplayın. Sonra aynı tahsisi bunun yerine mevcut bir açık ağırlıklı modelin sürdürülen ön eğitimine harcamayı sayılarla savunun; hedef görev kalitesini ve veri erişimini de hesaba katın. Gerçekte hangisini yapacağınızı ve nedenini belirtin.
- Common Crawl’ın WET dosyaları “fazla miktarda kalıp metin ve menü metni barındırdığı” için FineWeb, metni WARC’tan trafilatura ile yeniden çıkardı. Kalıp metin son derece tekrarlıdır. Tekilleştirmenin bunu neden öylece temizlemediğini ve bunun bir veri pipeline’ındaki işlem sırası hakkında size ne anlattığını açıklayın.
- Tokenizer ekonomisi. Kendi yazdığınız teknik bir metinden Türkçe bir paragraf ve onun İngilizce çevirisini alın. Tokenizer Playground ya da
tiktokenile iki farklı tokenizer’da token sayın. Önce aynı içeriğin iki dildeki token sayısı oranını hesaplayın. Ardından seçtiğiniz modelin, tarihini belirttiğiniz birim fiyatlarıyla ayda 100.000 istek için yıllık maliyeti kestirin. Girdi ve çıktı token’larını, ortak istemi ve varsa önbellekli girdileri ayrı belirtin; tek paragrafın bütün istekleri temsil ettiği varsayımını açıkça yazın. - Türkçe morfoloji ve token sayısı.
evlerimizdenörneğini kendi alanınızın terimleriyle tekrarlayın: bir teknik terim seçin (basınç,sıcaklık,dayanım) ve bu terimin beş farklı çekimli biçimini belirleyin. Her biçimin token sayısını aynı tokenizer ile, örneğintiktokenile ölçün. Kelime başına token sayısı nasıl değişiyor? Ardından Türkçe yazımı koruyan biçimlerle ASCII’ye indirgenmiş biçimlerin token sayılarını karşılaştırın. Sonucu bu örnekler ve bu tokenizer ile sınırlı yorumlayın: dönüşüm yazımı ve ayırt edici bilgiyi değiştirir; daha az token üretmek daha doğru veya daha yararlı bir temsil anlamına gelmez. - Türkçe token maliyetini çok sayıda örnekte ölçün. Bölüm 8.3.3’teki Bildirge ölçümü tek bir kısa metin çifti üzerinde yapıldı ve oradaki 1,82 (
cl100k_base) ile 1,39 (o200k_base) oranları genel değil; Bölüm 8.4 ise başka tokenizer’larla 1.157 çiftlik ayrı bir ölçüm sunuyor. Elinizdeki paralel bir metinden — İnsan Hakları Evrensel Bildirgesi’nin maddeleri, bir yazılımın iki dildeki arayüz metinleri, kendi çift dilli raporlarınız — 50 ile 100 arası cümle çifti toplayın. Her tokenizer için iki ayrı ölçüm yapın: eşleştirilmiş her metin çiftinde Türkçe/İngilizce token sayısı oranı ve her dilde 1.000 Unicode kod noktası başına token sayısı. İlk ölçüm eş içerik için token farkını, ikincisi yazı uzunluğuna göre token yoğunluğunu gösterir. Medyanı ve çeyrekler arası aralığı raporlayın; toplam maliyet kestirimi için ayrıca bütün örneklerdeki toplam token sayılarını ve beklenen istek dağılımını kullanın. Tek metin çiftindeki ölçüm bu dağılımın neresine düşüyordu?
Not11–13. alıştırmalar için beklenen gözlemler
Alıştırmaların çözümü burada değil; ama neyi görmeniz beklendiğini bilmek kendinizi kontrol etmenizi kolaylaştırır.
- Türkçe paragraf bazı tokenizer’larda daha fazla token üretebilir. Farkın yönünü ve büyüklüğünü ölçün; sonucu seçtiğiniz metin çifti ve tokenizer sürümüyle birlikte raporlayın.
- Ek sayısı arttığında token sayısı artabilir; ancak öğrenilmiş parçalar nedeniyle artış monoton olmak zorunda değildir. ASCII dönüşümü de her örnekte token sayısını azaltmaz. Yazımsal ayrımların kaybını örnekleyin; arama kalitesindeki değişimi ileri sürecekseniz bunu ayrıca ölçün.
- Her iki dilin token yoğunluğunu ve eş içerikli metin çiftlerinin token oranlarını ayrı raporlayın. Farkın yönü ve yayılımı örneklere ve tokenizer’a bağlıdır. Tek örnek, dağılımın içindeki bir gözlemdir; dağılımın özeti değildir.