Tokenization ve BPE
Önkoşul:Metin ön işleme
Kanca
- derste kural tabanlı gövde bulmanın Türkçede sık hata yaptığını gördük. Modern NLP, bu sorunu FARKLI bir yaklaşımla çözüyor: kuralları ELLE yazmak yerine, hangi karakter gruplarının SIK bir arada göründüğünü VERİDEN öğrenmek. Bu yönteme Byte Pair Encoding (BPE) deniyor.
Sezgi
BPE, bir metni karakterlerden başlayıp, en SIK yan yana gelen çifti tekrar tekrar BİRLEŞTİREREK “alt kelimeler” (subword) öğrenir. Sonuç: sık geçen kelimeler (the, running) TEK bir token’a inerken, nadir kelimeler karaktere yakın parçalara bölünür.
Bir cümle yaz — her kelimenin kaç token’a bölündüğünü, bir kelimeye tıklayıp adım adım NASIL birleştiğini gör.
Toplam: 4 kelime → 25 token (kelime başına ortalama 6.25)
"Köpekler" nasıl birleşti? (adım 0 / 3)
Bu tokenizer, İngilizce ağırlıklı küçük bir metinden öğrenildi (gerçek tokenizer'lar da böyle eğitilir). Türkçe kelimeler, çekim ekleri (-ler, -ıyor, -dan) hiç görülmediği için genelde KARAKTERE yakın parçalanıyor -- İngilizce kelimeler ise genelde TEK bir token'a iniyor.
Mekanizma
Küçük (İngilizce ağırlıklı) bir metinden BPE kurallarını öğretelim:
BPE eğitimi: en sık çiftleri bul, birleştir
# BPE (Byte Pair Encoding), en SIK yan yana gelen karakter çiftini bulup
# BİRLEŞTİREREK, karakterlerden yola çıkıp kademeli olarak "alt kelimeler"
# (subword) öğrenen istatistiksel bir yöntemdir. Küçük bir İNGİLİZCE corpus'la
# eğitelim -- gerçek tokenizer'lar (GPT gibi) da İngilizce ağırlıklı veriyle eğitilir.
corpus = """
the quick brown fox jumps over the lazy dog
the dog runs after the fox in the forest
a fox and a dog are running together
the forest is quiet and the trees are tall
she walks through the forest looking for the fox
the lazy dog sleeps under the tall tree
running and jumping are fun activities
the quick fox jumps over another lazy dog
i am learning how computers understand language
computers do not understand words the way people do
they only understand numbers so we convert words into numbers
this process is called tokenization
a tokenizer breaks text into smaller pieces called tokens
some tokenizers split text into words other split into characters
byte pair encoding learns which letters often appear together
it starts with individual characters and merges the most common pairs
after many merges common words become single tokens
rare words stay broken into smaller pieces
this is why understanding tokenization matters for language models
language models like gpt use this kind of tokenizer
the model reads tokens one after another and predicts the next token
training data shapes which words the tokenizer knows well
if a word never appears in training it gets split into many pieces
that is often what happens with words from other languages
turkish words often get split into many more pieces than english words
because turkish adds many suffixes to a single root word
english also has suffixes but fewer than turkish
understanding this helps explain why some languages cost more tokens
more tokens can mean slower and more expensive processing
developers should keep this in mind when building multilingual systems
""".strip().lower()
kelimeler = re.findall(r"[a-z]+", corpus)
kelime_sayaci = Counter(kelimeler)
print(f"Corpus: {len(kelimeler)} kelime, {len(kelime_sayaci)} benzersiz kelime.")
def kelimeyi_hazirla(kelime):
return list(kelime) + ["</w>"] # </w>: kelime sonu işareti
sozluk = {tuple(kelimeyi_hazirla(k)): sayi for k, sayi in kelime_sayaci.items()}
def ciftleri_say(sozluk):
ciftler = Counter()
for kelime, sayi in sozluk.items():
for i in range(len(kelime) - 1):
ciftler[(kelime[i], kelime[i + 1])] += sayi
return ciftler
def cifti_birlestir(sozluk, cift):
a, b = cift
yeni_sozluk = {}
for kelime, sayi in sozluk.items():
yeni_kelime, i = [], 0
while i < len(kelime):
if i < len(kelime) - 1 and kelime[i] == a and kelime[i + 1] == b:
yeni_kelime.append(a + b)
i += 2
else:
yeni_kelime.append(kelime[i])
i += 1
yeni_sozluk[tuple(yeni_kelime)] = sayi
return yeni_sozluk
MERGE_SAYISI = 250
birlestirme_kurallari = []
for _ in range(MERGE_SAYISI):
ciftler = ciftleri_say(sozluk)
if not ciftler:
break
en_sik = ciftler.most_common(1)[0][0]
birlestirme_kurallari.append(en_sik)
sozluk = cifti_birlestir(sozluk, en_sik)
print(f"Toplam {len(birlestirme_kurallari)} birleştirme kuralı öğrenildi.")
print("İlk 10 kural (en SIK çiftlerden en NADİRE doğru):")
for i, (a, b) in enumerate(birlestirme_kurallari[:10], 1):
print(f" {i}. '{a}' + '{b}' -> '{a}{b}'")Corpus: 272 kelime, 149 benzersiz kelime.
Toplam 250 birleştirme kuralı öğrenildi.
İlk 10 kural (en SIK çiftlerden en NADİRE doğru):
1. 's' + '</w>' -> 's</w>'
2. 'e' + '</w>' -> 'e</w>'
3. 'e' + 'r' -> 'er'
4. 't' + 'h' -> 'th'
5. 'i' + 'n' -> 'in'
6. 'a' + 'n' -> 'an'
7. 't' + '</w>' -> 't</w>'
8. 't' + 'o' -> 'to'
9. 'e' + 'n' -> 'en'
10. 'er' + '</w>' -> 'er</w>'Şimdi TEK bir kelimenin, öğrenilen kuralları sırayla uygulayarak nasıl birleştiğini izleyelim:
'running' adım adım birleşiyor
# BPE ile bir kelimeyi kodlamak: öğrenilen kuralları, ÖĞRENİLME SIRASINA göre uygula.
def bpe_encode(kelime, kurallar, iz_tut=False):
parcalar = kelimeyi_hazirla(kelime)
izler = [list(parcalar)]
for a, b in kurallar:
yeni_parcalar, i = [], 0
degisti = False
while i < len(parcalar):
if i < len(parcalar) - 1 and parcalar[i] == a and parcalar[i + 1] == b:
yeni_parcalar.append(a + b)
i += 2
degisti = True
else:
yeni_parcalar.append(parcalar[i])
i += 1
parcalar = yeni_parcalar
if degisti and iz_tut:
izler.append(list(parcalar))
return (parcalar, izler) if iz_tut else parcalar
sonuc, izler = bpe_encode("running", birlestirme_kurallari, iz_tut=True)
print(f"\n'running' kelimesinin adım adım birleşimi ({len(izler)} adım):")
for i, adim in enumerate(izler):
print(f" adım {i}: {adim}")
'running' kelimesinin adım adım birleşimi (8 adım):
adım 0: ['r', 'u', 'n', 'n', 'i', 'n', 'g', '</w>']
adım 1: ['r', 'u', 'n', 'n', 'in', 'g', '</w>']
adım 2: ['r', 'u', 'n', 'n', 'in', 'g</w>']
adım 3: ['r', 'u', 'n', 'n', 'ing</w>']
adım 4: ['r', 'un', 'n', 'ing</w>']
adım 5: ['run', 'n', 'ing</w>']
adım 6: ['run', 'ning</w>']
adım 7: ['running</w>']8 adımda, r-u-n-n-i-n-g-</w> tek bir running</w> token’ına indi. Şimdi bu (İngilizce ağırlıklı) tokenizer’ı Türkçe kelimelerde deneyelim:
Türkçe vs İngilizce: token sayısı
# Şimdi bu (İNGİLİZCE ağırlıklı eğitilmiş) tokenizer'ı, hem İngilizce hem
# Türkçe kelimelerde deneyelim.
ingilizce_kelimeler = ["dogs", "forest", "running", "fox", "tokenizer", "language"]
turkce_kelimeler = ["köpekler", "ormanda", "koşuyorlar", "tilkiyi", "kovalıyor", "kelimeler"]
print(f"\n{'İngilizce kelime':<16} {'Token sayısı':<14} {'Parçalar'}")
ingilizce_toplam = 0
for k in ingilizce_kelimeler:
sonuc = bpe_encode(k, birlestirme_kurallari)
ingilizce_toplam += len(sonuc)
print(f"{k:<16} {len(sonuc):<14} {sonuc}")
print(f"\n{'Türkçe kelime':<16} {'Token sayısı':<14} {'Parçalar'}")
turkce_toplam = 0
for k in turkce_kelimeler:
sonuc = bpe_encode(k, birlestirme_kurallari)
turkce_toplam += len(sonuc)
print(f"{k:<16} {len(sonuc):<14} {sonuc}")
ing_ort = ingilizce_toplam / len(ingilizce_kelimeler)
tr_ort = turkce_toplam / len(turkce_kelimeler)
print(f"\nOrtalama token/kelime -- İngilizce: {ing_ort:.2f}, Türkçe: {tr_ort:.2f}")
print(f"Türkçe kelimeler, AYNI tokenizer ile {tr_ort/ing_ort:.1f} KAT daha fazla token'a bölünüyor!")
print("Neden: bu tokenizer İNGİLİZCE ağırlıklı bir corpus'tan öğrendi -- Türkçenin çekim ekleri")
print("(köpek+ler, koş+uyor+lar) hiç görülmediği için, karakterlere yakın parçalanıyor.")
print("Gerçek dünyada da (GPT gibi modellerde) AYNI şey oluyor -- bu, Türkçe kullanıcılar için")
print("hem daha YAVAŞ hem daha PAHALI (token başına ücretlendirme) bir deneyim demek.")
İngilizce kelime Token sayısı Parçalar
dogs 3 ['do', 'g', 's</w>']
forest 1 ['forest</w>']
running 1 ['running</w>']
fox 1 ['fox</w>']
tokenizer 1 ['tokenizer</w>']
language 1 ['language</w>']
Türkçe kelime Token sayısı Parçalar
köpekler 6 ['k', 'ö', 'pe', 'k', 'l', 'er</w>']
ormanda 4 ['or', 'man', 'd', 'a</w>']
koşuyorlar 9 ['k', 'o', 'ş', 'u', 'y', 'or', 'l', 'ar', '</w>']
tilkiyi 7 ['ti', 'l', 'k', 'i', 'y', 'i', '</w>']
kovalıyor 8 ['k', 'o', 'v', 'al', 'ı', 'y', 'or', '</w>']
kelimeler 6 ['k', 'e', 'li', 'm', 'el', 'er</w>']
Ortalama token/kelime -- İngilizce: 1.33, Türkçe: 6.67
Türkçe kelimeler, AYNI tokenizer ile 5.0 KAT daha fazla token'a bölünüyor!
Neden: bu tokenizer İNGİLİZCE ağırlıklı bir corpus'tan öğrendi -- Türkçenin çekim ekleri
(köpek+ler, koş+uyor+lar) hiç görülmediği için, karakterlere yakın parçalanıyor.
Gerçek dünyada da (GPT gibi modellerde) AYNI şey oluyor -- bu, Türkçe kullanıcılar için
hem daha YAVAŞ hem daha PAHALI (token başına ücretlendirme) bir deneyim demek.İngilizce kelimeler ortalama 1.33 token’a inerken, Türkçe kelimeler 6.67 token’a bölünüyor — 5 KAT fark! Çoğu kişi “tokenizer, her dile eşit davranır” sanır. Yanlış, çünkü tokenizer SADECE eğitildiği veride SIK gördüğü örüntüleri öğrenir — İngilizce ağırlıklı veriyle eğitilen bir tokenizer, Türkçenin çekim eklerini hiç görmemiştir.
Matematik
BPE algoritmasının özü
| Sembol | Anlamı |
|---|---|
| İki bitişik parça (başta karakterler, sonra karakter grupları) | |
| Bu çiftin, TÜM corpus’ta yan yana kaç kez geçtiği | |
| Birleştirme sırası | Öğrenilen kurallar SIRALI bir listedir — kodlama sırasında bu sıra ile uygulanır |
Bu süreç, önceden belirlenen bir birleştirme sayısına (örn. 250) ulaşana kadar TEKRARLANIR. Her tur, dağarcığa TAM OLARAK bir yeni token ekler.
Kod
Bu neden ÖNEMLİ? Çünkü modern dil modelleri (GPT gibi), metni token BAŞINA ücretlendirir ve İŞLER.
- Türkçe bir cümle, AYNI anlamı taşıyan İngilizce bir cümleden 2-5 KAT daha fazla token tutabilir.
- Bu, Türkçe kullanıcılar için hem DAHA YAVAŞ (daha çok token = daha çok hesaplama) hem DAHA PAHALI (token başına ücretlendirme) bir deneyim demek.
- Bu fark, İNGİLİZCE ağırlıklı eğitim verisinin doğal bir SONUCUDUR — kasıtlı bir “ayrımcılık” değil, ama pratik bir dezavantaj.
Nerede işe yarar
BPE (ve türevleri), günümüz dil modellerinin standart tokenization yöntemidir:
- GPT ailesi, BPE’nin bir varyantını (byte-level BPE) kullanır.
- Dağarcık boyutu (kaç token öğrenileceği) bir tasarım kararıdır — büyük dağarcık az token ama çok bellek, küçük dağarcık çok token ama az bellek gerektirir.
- BPE, karakter tabanlı ve kelime tabanlı yaklaşımlar arasında bir DENGE noktasıdır — sık kelimeleri TEK token’da tutar, nadir kelimeleri KARAKTERE indirger (hiçbir kelime “bilinmeyen” olarak işaretlenmez).
Bu 3 hatayı yaparsın:
- Bir dil modelinin “kelime” ile çalıştığını sanmak — gerçekte TOKEN’larla çalışır, ve bir kelime birden fazla token’a bölünebilir.
- Türkçe metinlerde token maliyetini hesaba katmadan bütçe/hız planlaması yapmak.
- BPE’yi “akıllı bir dilbilimsel analiz” sanmak — aslında SADECE istatistiksel sıklık sayımı, dilbilgisi kuralı BİLMİYOR.
Kendini test et
1. Notebook'ta Türkçe kelimeler neden İngilizce kelimelerden ortalama 5 kat daha fazla token'a bölündü?
- Türkçe kelimeler her zaman daha uzundur
- Tokenizer İngilizce ağırlıklı bir corpus'tan öğrenildi -- Türkçenin çekim ekleri (-ler, -ıyor, -dan) hiç görülmediği için karaktere yakın parçalanıyor (doğru cevap)
- Türkçe karakterler (ç, ğ, ı, ö, ş, ü) desteklenmiyor
- Kod hatalıydı
Neden: BPE, SADECE eğitim verisinde sık gördüğü çiftleri birleştirmeyi öğrenir; İngilizce ağırlıklı bir corpus, Türkçe çekim eklerini hiç içermediği için bu ekleri birleştirecek kural öğrenilmemiş oluyor.
2. BPE algoritmasının her turda yaptığı işlem nedir?
- Rastgele iki parçayı birleştirir
- Corpus'ta EN SIK yan yana gelen parça çiftini bulur ve bu çifti TEK bir yeni parçada birleştirir (doğru cevap)
- Her kelimeyi ayrı ayrı bir token yapar
- Sadece ünlü harfleri birleştirir
Neden: BPE'nin her turu aynıdır: mevcut parçalanmadaki TÜM bitişik çiftleri sayar, en sık geçeni seçer, birleştirir -- bu döngü belirlenen sayıda tekrarlanır.
3. Türkçe kullanıcılar için daha yüksek token sayısının pratik sonucu nedir?
- Hiçbir pratik etkisi yoktur
- Aynı anlamı taşıyan metin daha fazla token tuttuğu için, İngilizce ağırlıklı eğitilmiş bir modelle çalışmak Türkçe kullanıcılar için hem daha YAVAŞ hem token başına ücretlendirmede daha PAHALI olabilir (doğru cevap)
- Türkçe metin hiç işlenemez
- Model Türkçeyi otomatik olarak İngilizceye çevirir
Neden: Dil modelleri token başına hesaplama yapar ve genelde token başına ücretlendirilir; aynı anlam için daha fazla token gerekmesi, doğrudan daha fazla işlem süresi ve maliyet anlamına gelir.
Özet
Özet
- Tokenization, metni modele verilecek parçalara (token) ayırma işlemidir.
- BPE, karakterlerden başlayıp en sık yan yana gelen çiftleri tekrar tekrar birleştirerek alt-kelime dağarcığı öğrenir.
- Sık geçen kelimeler tek token'a iner, nadir kelimeler karaktere yakın parçalanır.
- İngilizce ağırlıklı eğitilen tokenizer'lar, Türkçe kelimeleri 2-5 kat daha fazla token'a bölebilir.
- Bu fark, Türkçe kullanıcılar için gerçek bir hız ve maliyet dezavantajı yaratır.