13  Dizi Etiketleme ve Bilgi Çıkarma

Bölüm durumu: çevrildi. Kaynak metin: İngilizce 13. bölüm. Bu sayfadaki her sayı WikiANN Türkçe (PAN-X.tr) üzerinde ölçüldü — derlemi Pan vd. (2017) kurdu, dengeli 20.000/10.000/10.000 bölmesini ise Rahimi vd. (2019) tanımladı. load_dataset’in döndürdüğü bölme bu; Bölüm 13.2’deki sızıntı da bu bölmede. Veri kümesi hiç değiştirilmeden, geldiği hâliyle kullanıldı; böylece herkes tek bir load_dataset çağrısıyla aynı sayıları üretebilir. Bölüm 13.2, bu derlemin denetiminde ortaya çıkanları anlatıyor. Aralarında bir sızıntı problemi de var ve bu problem, bölümün geri kalanındaki skorların nasıl okunacağını değiştiriyor. Yazılım: scikit-learn 1.9.0, sklearn-crfsuite 0.5.0, transformers 5.15.1, PyTorch 2.13.0, datasets 5.0.1, seqeval 1.2.2, Python 3.14.5. Encoder (kodlayıcı) için fine-tuning (ince ayar): batch (yığın) boyutu 16, öğrenme oranı 3e-5, üç epoch, seed (tohum) 42, bir Apple M serisi GPU’da MPS arka ucuyla — bütçe başına tek koşu, hiperparametre taraması yok. Yerel LLM: 4 bite nicemlenmiş bir qwen3.5:9b, ollama 0.24.0 üzerinden, sıcaklık 0 ve düşünme kapalı. Aşağıdaki süre oranlarını taşınabilir, mutlak saniyeleri taşınamaz sayın.

Öğrenme hedefleri. Bu bölümün sonunda:

13.1 Tek mimari, üç görev

Bölüm 12 her belge için tek bir soru soruyordu: bu hangi sınıf? Bu bölüm her token için bir soru soruyor. Üstelik sorular artık bağımsız değil: 4. token’ın cevabı 5. token’ın cevabını kısıtlıyor.

Etiketleme birimini belgeden token’a taşıyan bu tek değişiklik, alanın bilgi çıkarma (information extraction) dediği şeyin büyük kısmını kapsıyor:

Üç görev, tek biçim
görev her token’daki soru tipik etiketler
POS tagging bu kelimenin sözcük türü nedir? NOUN, VERB, ADJ, …
Chunking bu kelime bir isim öbeğinin içinde mi? B-NP, I-NP, O
NER bu kelime bir ismin parçası mı, öyleyse ne tür? B-PER, I-ORG, O, …

named entity recognition (NER) (adlandırılmış varlık tanıma) — metindeki kişi, kurum ve yer adlarını bulmak ve hangisinin hangisi olduğunu söylemek. Dizi etiketlemenin tipik örneği ve bu bölümün ölçtüğü görev. ↩︎

Mimari üçünde de aynı: cümleyi, token başına bir vektör üreten bir şeyden geçirin, üstüne bir sınıflandırıcı koyun, token başına bir etiket okuyun. Bu kısmın adı token classification ve gerçekten de işin kolay yarısı.

token classification (token sınıflandırma) — belge başına bir etiket yerine token başına bir etiket. NER, POS tagging ve chunking’in paylaştığı mimari; aralarındaki fark etiket kümesinde, modelde değil. ↩︎

Zor yarısı şu: aslında istediğiniz şey etiketler değil, span’lerdir. İstediğiniz, “Türkiye Büyük Millet Meclisi bir kurumdur” bilgisidir; dört ayrı token kararı (B-ORG I-ORG I-ORG I-ORG) değil. Birini diğerine çevirmek bir kod çözme problemi. Bu bölüm modellerden çok kod çözmeye ve ölçüme yer ayırıyor, çünkü asıl kusurlar orada.

13.1.1 Derlem

Bu bölümdeki her şey tek bir veri kümesi üzerinde ölçülüyor; bu yüzden sayılar gelmeden önce ona iki dakika ayıralım.

from datasets import load_dataset

ds = load_dataset("unimelb-nlp/wikiann", "tr")
train        20,000 sentences   149,786 tokens   median length 6, mean 7.5
             26,482 entities    PER 8,833   ORG 7,970   LOC 9,679
validation   10,000 sentences    75,930 tokens
             13,517 entities    PER 4,374   ORG 4,129   LOC 5,014
test         10,000 sentences    75,731 tokens
             13,587 entities    PER 4,519   ORG 4,154   LOC 4,914

Üç varlık türü — PER, ORG ve LOC — ve dikkat çekici bir eksik: bu derlemdeki her cümle en az bir varlık içeriyor. Gerçek metin böyle çalışmaz. Bir haber akışındaki ya da destek kuyruğundaki cümlelerin çoğu kimseden bahsetmez. Skorları okurken bunu aklınızda tutun; bu, görevi sizin karşılaşacağınız görevden kolay kılıyor.

13.1.2 Her şeyden önce: taban

Bölüm 12, işe tabanı — hiçbir şey öğrenmeyen bir modelin alacağı skoru — hesaplayarak başlamakta ısrar ediyordu. Bu alışkanlık burada, kitabın her yerinden daha çarpıcı biçimde işe yarıyor. Her token için O üreten bir model düşünün — öznitelik yok, parametre yok, eğitim yok:

everything-is-O      token accuracy 61.36%      span-level F1 0.00

Token doğruluğu, etiketi doğru olan token’ların oranıdır. Span düzeyinde F1 ise bir varlığı ancak türü ve iki sınırı da doğruysa bulunmuş sayar; tam tanımı Bölüm 13.7’de.

Yüzde altmış bir doğru, ama tek bir varlık bile bulmuyor. Bu iki sayı arasındaki uçurum bir merak konusu değil; Bölüm 13.7 tam da bu uçurum yüzünden var. Bunun gibi bir etiketleme görevinde “%94 doğruluk” bildiren her makale, model kartı ya da meslektaş, bu derlemde tabanı 61 olan bir sayı bildiriyor demektir.

Neye bakacağız. Önce derlem; üzerinde bir şey ölçülmeden önce denetleniyor, çünkü o denetimin ortaya çıkardığı şey sonraki her skorun nasıl okunacağını değiştiriyor. Sonra token başına etiketleri span’lere çeviren biçim ve bir modelin ürettiği, bu biçimin yasakladığı diziler. Sonra kelimelerle alt kelimeler arasındaki hizalama adımı; sessiz hataların saklandığı yer. Sonra işi kurmanın üç yolu — bir sözlük, bir CRF (conditional random field, yani koşullu rastgele alan; klasik istatistiksel dizi modeli, Bölüm 13.5’te tanıtılıyor), fine-tune edilmiş bir encoder — altı etiket bütçesinde, çünkü soru hangisinin kazandığı değil, ne zaman kazandığı. Sonra herkesin raporladığı metriğin neden yanlış metrik olduğu. Ve son olarak bunların hepsini atlayıp şemayı bir LLM’e tarif ederseniz ne olduğu.

13.2 Derlemde gerçekte ne var

Bölüm 5 şunu savunuyordu: bir etiketli derlem üzerinde hesaplanan bir sayıya güvenmeden önce derlemi denetleyin. WikiANN otomatik olarak kuruldu; Wikipedia’nın iç bağlantıları diller arası bağlantılar üzerinden yansıtıldı (Pan vd. 2017). Bu sayede derlem devasa, ücretsiz ve 282 dilde mevcut — ama onu hiç kimse gözden geçirmemiş. İşte denetim.

Bu denetim bir ilk değil. Lignos vd. (2022), WikiANN’in içeriğini daha az kaynaklı diller için inceledi ve derlemin zero-shot (sıfır atışlı) diller arası transferi olduğundan iyi gösterdiği sonucuna vardı. Aşağıda aynı argümanı Türkçe üzerinde, sayılar önünüzdeyken yeniden sınıyoruz. Buna bir bulgu daha ekleniyor; ne derlem makalesi ne de denetim makalesi sizi bu bulguya hazırlıyor.

Bunların çoğu cümle değil.

ends with . ! ?       6,896   34.5%
does not             13,104   65.5%
3 tokens or fewer       172    0.9%

Üçte ikisi, Wikipedia biçimlendirmesinden kırpılmış parçalar. Bu, alan (domain) hakkında bir olgu: burada ölçülenler düzyazıya olduğu gibi taşınmayacak.

Varlık diye işaretlenen bazı ifadeler aslında varlık değil.

pure punctuation or digits    160   0.60%
containing wiki markup         63   0.24%

  ORG: '1966–67'
  ORG: '2012'
  ORG: '2013'
  ORG: '2000'

Kurum olarak etiketlenmiş yalın yıl sayıları. Bu sayımlar eğitim bölmesindeki 26.482 varlık ifadesi (entity mention) üzerinde; test bölmesi de aynı yolla kuruldu. Küçük bir oran, ama herhangi bir modelin alabileceği skora tavan koyuyor — çünkü test kümesinin bir kısmı düpedüz yanlış.

Aynı dizgi (string) iki farklı şekilde etiketleniyor.

distinct surface forms                16,591
forms carrying more than one label       116   (0.7%)
mentions affected                      1,397   (5.3%)

  'Türkiye'      {LOC: 82, ORG: 4}
  'Almanya'      {LOC: 80, ORG:  2}
  'Fransa'       {LOC: 69, ORG:  5}
  'İtalya'       {LOC: 55, ORG:  1}

Bunun bir kısmı gerçek belirsizlik — Türkiye İtalya’yı yendi derken kastedilen millî futbol takımıdır, kara parçası değil — bir kısmı ise etiketleme gürültüsü. Her hâlükârda varlık ifadelerinin %5,3’ünde aynı dizgi başka bir etiketle de geçmiş; hangisinin burada geçerli olduğunu modelin tahmin etmesi gerekiyor.

13.2.1 Her skoru okuma biçiminizi değiştiren kısım

Buraya kadarki her şey bir baş ağrısıydı: cümle yerine parçalar, bir avuç kötü etiket, modelin tahmin ederek aşması gereken bir miktar belirsizlik. Can sıkıcı, atlatılabilir ve otomatik kurulmuş bir derlemden aşağı yukarı beklediğiniz şey. Sıradaki ise farklı türde bir problem.

Test kümesinin %13,06’sı eğitim kümesinin içinde.

test sentences identical to a train sentence   1,306 / 10,000   13.06%
  of those, carrying an identical gold tagging  1,305
  carrying a different gold tagging                 1

validation sentences also in train             1,265   12.65%
test sentences also in validation                846    8.46%
duplicate sentences inside train itself        1,565
duplicate sentences inside test itself           540

Benzer cümleler değil, bayt bayt aynı token dizileri. Karşılaştırma, datasets’in döndürdüğü token listeleri üzerinde yapıldı; büyük/küçük harf eşitlemesi, Unicode yeniden normalleştirmesi ya da boşluk onarımı yok. Daha gevşek bir eşleştirme ancak daha fazlasını bulabilirdi; dolayısıyla %13,06, örtüşmenin üst sınırı değil alt sınırı. Bu cümlelerin 1.305’i bayt bayt aynı referans etiketleri de taşıyor. Eğitim verisini ezberlemekten başka bir şey yapmayan bir model, bu 1.306 cümleyi zahmetsizce doğru bilir.

Elangovan vd. (2021) tam da bu konuda uyarmıştı. Sızıntının kimi kayırdığını açıkça söylemekte fayda var. Bu bölümün ilerisinde üç sistem, test kümesinin sızmış ve temiz yarılarında ayrı ayrı puanlanıyor:

Span düzeyinde F1, test cümlesinin eğitimde olup olmamasına göre ayrılmış. Son sütun, farkı temiz yarının üstünde bıraktığı boşluğa bölüyor
sistem sızmış 1.306 temiz 8.694 fark fark / boşluk
Gazetteer (varlık sözlüğü; saf ezber) 77,54 51,04 +26,50 %54
Elle öznitelikli CRF 99,81 83,56 +16,25 %99
Fine-tune edilmiş BERTurk 98,69 91,04 +7,65 %85

CRF, sızmış yarıda 99,81 alıyor. Orada daha iyi bir model değil; cevabı görmüş bir arama tablosu.

Fark sütununu yukarıdan aşağı okuyun, çünkü bu kısımdaki en işe yarar şey o. Üç sistem ne kadar ezberlediklerine göre sıralı — bir sözlük, öznitelik tabanlı doğrusal bir model, ön eğitimli bir encoder — ve sızıntı primi de aynı sırayla düşüyor: +26,50, +16,25, +7,65.

Ama son sütunu da okuyun, çünkü ham fark, temiz yarının üstünde bıraktığı boşlukla yukarıdan sınırlı: temiz yarıda 91,04 alan bir sistem, ne kadar ezberlerse ezberlesin 8,96’dan fazla kazanamaz; bu yüzden farkı bu tavana bölüyoruz. Normalleştirdiğinizde sıralama değişiyor: gazetteer birincilikten sonunculuğa düşüyor. CRF’nin +16,25’i, elindeki 16,44 puanın %99’unu kullanıyor; encoder’ın +7,65’i 8,96’sının %85’ini; gazetteer’ın daha büyük olan +26,50’si ise 48,96’sının yalnızca %54’ünü. İki okuma pratik sonuçta örtüşüyor, sıralamada ayrışıyor. Farkın bir ezber skoru değil bir teşhis aracı olmasının sebebi de bu: büyük bir fark, daha dikkatli bakın demektir; modelinizin ne kadar ezberlediğini ölçtünüz demek değildir. Tek bir derlem ve üç sistemden gelen bu kanıtın söyleyebileceği bu kadar.

İki okumanın da desteklediği şey şu: %13 sızıntılı bir benchmark (kıyaslama), skorları yalnızca şişirmez; eşitsiz şişirir, üstelik en çok kayırdığı sistemler tam da üretimde sizi hayal kırıklığına uğratacak olanlar.

Tabloya dönüp gazetteer’ın sızmış yarıdaki skoruna bir kez daha bakalım. Eğitimdeki her dizgiyi ezberlemiş bir sözlüğün, birebir gördüğü cümlelerde 100’e yakın alması gerekirdi; 77,54 alıyor. Eksik yirmi iki puan, bu kısmın başındaki iki sıkıntının bir araya gelmesinden kaynaklanıyor: en uzun eşleşme, eğitimde bir yerde varlık olan ama burada olmayan dizgilerde de devreye giriyor; bir yüzey biçimi iki etiket taşıdığında da — yukarıdaki tablodaki varlık ifadelerinin %5,3’ü — sözlük birini seçmek zorunda kalıyor. Saf ezber bile sızmış bir test kümesinin tamamını kendiliğinden doğru bilmiyor; yalnızca çoğunu biliyor.

Bu bölümde öne çıkan sayıların hepsi tam test kümesi üzerinde hesaplandı, çünkü literatür böyle raporluyor ve karşılaştırmaların denk koşullarda olması gerekiyor. Ama güvenilecek sütun, temiz yarının sütunu.

Temiz çözüm, puanlamadan önce eğitim kümesinde de bulunan test örneklerini ayıklamak ve bunu açıkça söylemek. Daha ucuz alışkanlık — ve bu bölümden akılda tutulacak olan — şu: bir sonuç fazla iyi görünüyorsa test girdilerinizin hash’ini alın ve modelin kaçını daha önce gördüğünü sayın. Dört satırlık bir iştir ve bu kitaptaki herhangi bir modelleme numarasından daha fazla projeyi kurtarmıştır.

13.3 Etiketleme şemaları: etiketlerden span’lere kod çözme

Bir etiketleyici token başına bir etiket üretir. Sizin istediğiniz ise span’ler. Aradaki köprü bir etiketleme şeması ve standardı BIO: B-X X türünde bir span açar, I-X onu sürdürür, O ise geri kalan her şeydir.

BIO tagging (BIO etiketleme) — B- bir span’in ilk token’ını, I- devamını, O ise dışarıda kalan her şeyi işaretler. Token başına çalışan bir sınıflandırıcının çok token’lı span’leri ifade etmesini sağlayan numara; aynı türden iki span’in arka arkaya gelmesi dâhil. ↩︎

BIO, span'leri token başına etiketlere çevirir — ve bir gramer yaratır
İNSANIN ÇİZDİĞİ — SPAN'LER PER LOC Mustafa Kemal 1919 yılında Samsun'a çıktı . MODELİN TAHMİN ETTİĞİ — TOKEN BAŞINA BİR ETİKET B-PER I-PER O O B-LOC O O B- span açar · I- sürdürür · O span dışıdır bu yüzden yan yana iki kişi B-PER B-PER olur ve iki kişi kalır BUNUN YARATTIĞI GRAMER — I-PER NEYİ İZLEYEBİLİR B-PER geçerli I-PER geçerli O yasak B-LOC yasak CRF kırmızılardan kaçınmayı öğrenir onları yalnızca açık bir kısıt dışlar

Üstteki span etiketlemesi bir insanın çizdiği şey; alttaki etiket satırı ise modelin tahmin etmek üzere eğitildiği şey. Yasak geçişler kısmındaki (Bölüm 13.3.1) her şey, bu ikisinin aynı nesne olmamasından çıkıyor.

Gramerden önce bir açıklama, çünkü neyin geçersiz sayıldığını o belirliyor. Bu bölümün kullandığı şema — ve datasets’in WikiANN’i sunarken kullandığı şema — IOB2: her span istisnasız B- ile açılır. Genellikle IOB1 diye anılan özgün CoNLL-2003 şeması ise farklıdır: orada B- yalnızca aynı türden yan yana iki span’i ayırmak için görünür, dolayısıyla bir span normalde I- ile açılır ve O → I-PER gayet meşrudur. Aşağıdaki yasak geçişlerle ilgili her şey IOB2 hakkında bir ifadedir. Dağıtıldığı hâliyle CoNLL-2003 üzerinde bir geçersiz geçiş sayacı çalıştırırsanız, ihlal olmayan binlerce ihlal raporlar.

B/I ayrımı süs değil. O olmadan, aynı türden yan yana iki varlık tek bir varlıkta birleşirdi: Ali Veli dizisi PER PER olarak bir span mı iki span mı, ayırt edemezsiniz. BIO ile B-PER B-PER tartışmasız iki span demektir.

BIOES şemasında bir span’in son token’ı için E-, tek token’lık span için S- eklenir. Modele öğrenmesi için daha özgül sınıflar, kod çözücüye denetlemesi için daha fazla artıklık verir. Bedeli ise etiket kümesinin neredeyse iki katına çıkması: \(K\) varlık türüyle BIO’da \(2K+1\) etiket (burada 7), BIOES’te \(4K+1\) etiket (13) vardır. Ratinov ve Roth (2009) ikisini dikkatle karşılaştırdı ve kendi kurulumlarında BIOES’i (onların adlandırmasıyla BILOU) önde buldu. Bunu bilmek çoğunlukla şunun için işe yarar: ilk okuduğunuz öğreticide hangisi geçiyorsa onu tekrarlamak yerine, arkasında bir kaynakla derlemden derleme değişir diyebilirsiniz.

13.3.1 Var olmaması gereken diziler

BIO’nun bir grameri var. I-PER, B-PER veya I-PER’i izleyebilir. O’yu izleyemez, B-LOC’u da izleyemez. Her token’ı bağımsız puanlayan bir etiketleyici bunu bilmez.

Referans etiketlerin ve üç sistemin bu kuralı 10.000 test cümlesinde ne sıklıkla çiğnediği:

                              I- after O    I- after a different type
gold test set                          0                            0
gazetteer (longest match)              0                            0
CRF                                    0                            0
fine-tuned BERTurk                    49                           90

CRF, eğitildiği tek bütçede (20.000 cümle) hiç yasak geçiş üretmedi; fine-tune edilmiş transformer ise — bu bölümün en iyi modeli, 91,92 span F1 ile — 139 tane üretiyor. En iyi modelin kuralı çiğneyip daha zayıf olan CRF’nin çiğnememesi insanları şaşırtıyor. Sebebi kalite değil, yapı.

Softmax etiketleyici her konumda en yüksek puanlı etiketi bağımsız seçer. Aritmetikte 4. konumu 5. konuma bağlayan hiçbir şey yok. Bu yüzden puanlar öyle denk geldiğinde O ardından I-ORG her zaman mümkündür. Bir CRF (Lafferty vd. 2001) ise bütün dizileri puanlar: eğitimde gördüğü her etiket çifti için bir geçiş skoru öğrenir ve hiç görmediği çiftleri — O → I-ORG de aralarında — destekleyen hiçbir öznitelik olmadan bırakır. (CRFsuite’in varsayılanı budur; sklearn-crfsuite’te all_possible_transitions=False. Dolayısıyla görülmemiş bir geçiş cezalandırılmaz, skoru yalnızca 0 olur: modeli ona doğru iten bir şey yoktur, meşru geçişler ise veriden öğrendikleri ağırlıkları taşır. Seçeneği True yaparsanız görülmemiş çiftler için de öznitelik oluşturulur ve bunlar negatif ağırlık öğrenebilir.) Sonra Viterbi decoding (Viterbi 1967) her adımdaki en iyi etiketi değil, en yüksek puanlı yolu döndürür; yani yasak bir geçiş, bedelini cümlenin geri kalanının emisyon skorlarından karşılamak zorundadır. Bu koşuda hiçbir zaman karşılayamadı: 10.000 test cümlesinde CRF sıfır yasak geçiş üretti. Bu bir teorem değil, ölçülmüş bir sonuç. Skorlar sonlu, dolayısıyla yol imkânsız değil, yalnızca düşük olasılıklı; ampirik sıfır yerine garanti istiyorsanız, aşağıdaki “Grameri öğrenilmiş değil yapısal kılmak” alt bölümü bu garantiyi nasıl elde edeceğinizi anlatıyor.

Viterbi decoding (Viterbi kod çözme) — her konumda ayrı ayrı en iyi etiketi almak yerine, en yüksek puanlı tek etiket dizisini bulan bir dinamik programlama. Bir CRF’nin yasak bir geçişin bedelini tek bir token’a göre değil, cümlenin tamamına göre hesaplamasını sağlayan şey. ↩︎

Klasik yapay sinir ağı tabanlı NER mimarisinin yalnızca BiLSTM değil de BiLSTM-CRF (Lample vd. 2016) olmasının sebebi budur: encoder öznitelikleri sağlar, CRF katmanı grameri sağlar. Bu katmanın bir transformer’ın üstünde hâlâ maliyetini hak edip etmediği ise bu bölümün çözmediği açık bir soru: Bölüm 13.6 yalnızca düz softmax sınıflandırma katmanını (head) ölçüyor. Bunu araştırmak yerine başvurulabilecek ucuz seçenek, aşağıdaki geçiş maskesi.

13.3.2 Bir kod çözücü bozuk diziye ne yapar

Diyelim modeliniz O I-ORG I-ORG üretti. Bu nedir? Doğru cevabı yok, yalnızca uzlaşımlar var — ve onlar da birbiriyle anlaşamıyor:

Aynı tahminlerin üç okuması
kod çözücü O I-ORG I-ORG şuna dönüşür gerekçe
hoşgörülü (seqeval, conlleval (Tjong Kim Sang ve De Meulder 2003)) 2–3. token’lar üzerinde bir ORG span’i başıboş bir I- span açar; kurtarabildiğini kurtar
katı hiçbir şey dizi geçersiz; tahmin yürütmeyi reddet
önce onar, sonra çöz O B-ORG I-ORG olarak yeniden yaz, sonra çöz önce grameri düzelt, sonra puanla

Mesele hangisini seçeceğiniz değil. Mesele şu: raporladığınız F1, büyük ihtimalle bilerek seçmediğiniz bir kod çözücüye bağlı ve aramadığınız sürece bu fark görünmez. CRF’nin tahminlerinde seçim hiçbir şeye mal olmuyor, çünkü anlaşmazlık konusu olacak bir şey yok:

same CRF predictions, two decoders
  lenient (a stray I- opens a span)    F1 85.45
  strict  (a stray I- is dropped)      F1 85.45

Transformer’ın 139 bozuk geçişinde ise iki kod çözücü farklı sayıda span döndürür, dolayısıyla F1’leri de ayrışır; bu çifti biz ölçmedik, kendi modelinizde ölçün. Kendi sayılarınızı bir makalenin sayılarıyla karşılaştırırken eşleşmesi gereken şeylerden biri de kod çözücüdür.

13.3.3 Grameri öğrenilmiş değil yapısal kılmak

Öğrenilmiş bir modelin yalnızca ampirik olarak sağladığı iyi biçimliliği elde etmek için bir CRF katmanı eklemek zorunda değilsiniz. Softmax logit’leri üzerine bir geçiş maskesi koyup Viterbi ile çözmek, çıkarım anında bunu sağlıyor — fazladan parametre yok, yeniden eğitim yok. Gramer iki kuraldan oluşur: I-X yalnızca B-X veya I-X’i izleyebilir ve bir cümle I-X ile başlayamaz (cümle başı bir O gibi davranır).

Aşağıdaki sabit hakkında bir not: \(-10^4\), \(-\infty\) yerine seçilmiş büyük ama sonlu bir cezadır. Çıkarım anında ikisi de iş görür. Sonlu değer, aynı maskeyi bir eğitim hedefinin içinde yeniden kullanırsanız önem kazanır: orada yollar üzerindeki bir log-sum-exp, bazı uç durumlarda (örneğin bir konumdaki bütün yollar dışlandığında) \(-\infty\)’u nan’a çevirebilir. Bu sonlu ceza, geçersiz bir yolu gerçekçi her puan aralığında kaybettirir; ama onu matematiksel olarak imkânsız kılmaz. Gerçek kısıtı istiyorsanız geçersiz geçişleri ve başlangıç durumlarını fiyatlandırmak yerine arama uzayından çıkarın. Aşağıdaki kod sonlu ceza sürümüdür; çıkarımda gerçek kısıt için NEG = float("-inf") yazmanız yeterli, kodun geri kalanı aynen çalışır. Pratikte ikisi aynı sonucu verir: puanlar log-olasılık olduğunda her geçersiz yol, sorunlu I-X’i B-X’e çeviren geçerli bir yola dönüştürülebilir ve bunun bedeli tek bir token’daki log-olasılık farkıdır. Bu fark gerçekçi modellerde onlarla ölçülür, \(10^4\) ile değil.

import torch

NEG = -1e4
mask = torch.zeros(L, L)                    # L = etiket sayısı
for a, la in enumerate(labels):
    for b, lb in enumerate(labels):
        if lb.startswith("I-"):             # I-X yalnızca B-X veya I-X'i izleyebilir
            if la not in (f"B-{lb[2:]}", f"I-{lb[2:]}"):
                mask[a, b] = NEG
start = torch.tensor([NEG if l.startswith("I-") else 0.0 for l in labels])

def viterbi(logits, mask, start):           # logits: (T, L) log-olasılıklar
    dp, bp = logits[0] + start, []          # hiçbir cümle I- ile açılamaz
    for t in range(1, logits.shape[0]):
        score = dp[:, None] + mask + logits[t][None, :]
        dp, best = score.max(0)
        bp.append(best)
    path = [int(dp.argmax())]
    for back in reversed(bp):
        path.append(int(back[path[-1]]))
    return list(reversed(path))

İki token’lık bir örnek, dinamik programlamanın ne kazandırdığını gösteriyor. Merkez Bankası’nı yalnızca üç etiketle ele alalım ve softmax katmanının şu olasılıkları verdiğini varsayalım:

Oyuncak bir softmax çıktısı; her konumdaki greedy (açgözlü) seçim kalın
token O B-ORG I-ORG
Merkez 0,6 0,3 0,1
Bankası 0,2 0,2 0,6

Her konumda en iyi etiketi almak O I-ORG verir: geçersiz bir dizi. Hoşgörülü kod çözücü bunu yalnızca Bankası üzerinde tek token’lık bir ORG’a çevirir (bir sınır hatası); katı kod çözücü ise tamamen atar. Viterbi ise bütün yolları puanlar: olasılıkların çarpımı (log-olasılıkların toplamı). O → I-ORG ve cümle başında I-ORG dışlandığında geçerli adaylar arasında O O \(= 0{,}6 \times 0{,}2 = 0{,}12\), O B-ORG \(= 0{,}12\) ve B-ORG I-ORG \(= 0{,}3 \times 0{,}6 = 0{,}18\) var. Sonuncusu kazanır: kod çözücü, ikinci token’daki kanıt yüzünden ilk token’ın etiketini değiştirir ve iki token’lık kurumun tamamını döndürür. Token başına argmax bunu asla yapamaz.

Maske, 139 geçersiz geçişi bu koşuda 0’a indirdi — bir matris ve bir dinamik programlama karşılığında. Bu sonuç yapısı gereği bir garanti değil: sonlu bir ceza yine bir fiyattır ve yeterince büyük bir emisyon puanı geçersiz adımın bedelini yine de ödeyebilir. Geçersiz girdileri fiyatlandırmak yerine arama uzayından çıkarırsanız garanti gerçek olur. Maskenin işe yarayıp yaramadığı ise ayrı bir soru; bunu varsaymak yerine kendi şemanız üzerinde ölçmelisiniz. Maske bozuk span’leri iyi biçimli olanlara çeviriyor; hoşgörülü kod çözücü ise bunların bir kısmını zaten kurtarıyordu. Biz o karşılaştırmayı çalıştırmadık; bu alt bölümün açık bıraktığı boşluk da bu. Yine de fazladan eğitilen bir katmandan önce başvurulacak şey maskedir.

13.4 Alt kelime hizalama tuzağı

Etiketleriniz kelime başına. Bir transformer’ın girdileri ise alt kelime (subword) başına. Dolayısıyla her dizi etiketleme hattında bir hizalama adımı vardır ve sessiz hataların en sık girdiği yer de burasıdır. Bu hatalar sessizdir, çünkü model yine de eğitilir, kayıp yine de düşer; skor yalnızca olması gerekenden kötü çıkar.

Türkçe bu problemi çok net gösteriyor. BERTurk’ün tokenizer’ı, bu derlemdeki varlık kelimelerinde şunu yapıyor:

Türkiye'nin      -> ['Türkiye', "'", 'nin']
Takımı'nı        -> ['Takımı', "'", 'nı']
Mississippi'de   -> ['Miss', '##iss', '##ip', '##pi', "'", 'de']
Baudelaire'in    -> ['Ba', '##ude', '##la', '##ire', "'", 'in']
Erdemir          -> ['Erdem', '##ir']
İstanbul         -> ['İstanbul']

Bir kelime, altı alt kelime. Üstelik parçalanma eşit dağılmıyor; tam da etiketlemeye çalıştığınız kelimelerde yoğunlaşıyor:

BERTurk (dbmdz/bert-base-turkish-cased)
  entity words   1.98 subwords/word   53.8% split into more than one piece
  other words    1.45 subwords/word   30.9% split
  -> entity words are 1.36x more fragmented

mBERT (bert-base-multilingual-cased)
  entity words   1.90 subwords/word   47.3% split
  other words    2.00 subwords/word   45.5% split

İsimler, sık kullanılan kelimelerden daha nadirdir. Bu yüzden tokenizer’ın onları bütün tutmak için daha az gerekçesi olur — alt kelime tokenleştirmesinin mekanizması (Bölüm 8.3), burada somut bir bedel olarak karşımıza çıkıyor.

mBERT satırını dikkatle okumak gerek, çünkü fazla yorumlamak kolay. Bu tokenizer Türkçede her şeyi kelime başına 2,00 alt kelimeye bölüyor. Bu, Bölüm 8’in dile özgü tokenizer’lar lehine kurduğu argümanın ta kendisi: aynı metin için daha fazla token demek, kalıcı olarak daha fazla maliyet ve daha az etkin bağlam demektir.

Ama bu satır, mBERT’in bu görevde daha kötü skor alacağının kanıtı değildir. Burada ölçülen şey tokenization; doğruluk değil. Bölüm 16 her iki modeli de tam bu veri kümesinde fine-tune ediyor ve çok dilli olanı bir miktar önde buluyor. Bu da yararlı bir hatırlatma: tokenizer vergisi token’lara konan bir vergidir, F1 hakkında bir öngörü değil.

13.4.1 Hizalamanın kendisi

Uzlaşım şu: her kelimenin ilk alt kelimesini etiketleyin, geri kalanını -100 ile maskeleyin. -100, PyTorch’un cross-entropy fonksiyonunun göz ardı ettiği indekstir. Aşağıdaki şekil bu uzlaşımı yukarıdaki varlık kelimelerinden üçü üzerinde gösteriyor. Hemen altında da hizalamayı atlayıp etiketleri konum konum eşleştirdiğinizde ne olduğunu görüyorsunuz.

Kelime başına bir etiket, kelime başına çok alt kelime — ve eğitimi durdurmayan bir kelimelik kayma
ELİNİZDEKİ — KELİME BAŞINA BİR REFERANS ETİKET B-LOC B-ORG B-LOC İstanbul Erdemir Mississippi'de MODELİN ALDIĞI — AYNI ÜÇ KELİME, AYNI SÜTUNLARDA [CLS] İstanbul Erdem ##ir Miss ##iss ##ip ##pi ' de [SEP] DOĞRUSU — HER KELİMENİN İLK ALT KELİMESİNİ ETİKETLE, DİĞER HER KONUMU MASKELE -100 B-LOC B-ORG -100 B-LOC -100 -100 -100 -100 -100 -100 EĞİTİMİ DURDURMAYAN HATA — ÜÇ ETİKET KONUM KONUM EŞLEŞTİRİLMİŞ B-LOC B-ORG B-LOC — — — — — — — — Her etiket bir kelime erken düşüyor. B-LOC [CLS] üzerinde eğitiliyor ve Mississippi'de hiç etiketlenmiyor. Hiçbir şey hata vermiyor. Kayıp düşüyor, koşu bitiyor ve puan yalnızca olması gerekenden kötü oluyor.

Üç tokenization da BERTurk’ün yukarıda birebir yazdırılan çıktısıdır. Satırları sütunlardan başka hiçbir şey bağlamıyor: her kelime, bölündüğü alt kelimelerin tam üstünde duruyor. word_ids()’in size verdiği ve konum konum eşleştirmenin yok ettiği bilgi de bu.

Kod içinde:

enc = tok(batch["tokens"], is_split_into_words=True, truncation=True)

labels = []
for i, tags in enumerate(batch["ner_tags"]):
    word_ids = enc.word_ids(batch_index=i)
    prev, row = None, []
    for wid in word_ids:
        if wid is None:            # [CLS], [SEP], padding
            row.append(-100)
        elif wid != prev:          # kelimenin ilk alt kelimesi: etiketle
            row.append(tags[wid])
        else:                      # devamı: kayıpta göz ardı et
            row.append(-100)
        prev = wid
    labels.append(row)

word_ids(), Rust tabanlı tokenizers kütüphanesiyle çalışan (“fast”) tokenizer’ların sağladığı bir bilgidir; AutoTokenizer BERTurk için bunu yükler. Çıkarım anında aynı eşlemeyi ters yönde kullanın: her kelimenin tahmini, ilk alt kelimesinin tahminidir; diğer alt kelimelerin tahminleri atılır.

Bunun üç bozulma biçimi var ve hepsinde kod yine de çalışır:

  1. word_ids()’i unutup etiketleri alt kelimelere konum konum eşleştirmek. Herhangi bir kelime bölündüğü anda, sonraki her etiket yanlış token’a bağlanır. Varlık kelimelerinin %53,8’i bölündüğüne göre etiketler neredeyse anında karışır. Eğitim devam eder; F1 gürültü civarına düşer.
  2. Kelimenin etiketini her alt kelimeye yaymak. Savunulabilir bir seçim ve bazen yapılıyor. Ama devam eden parçaları I-PER’e çevirmek yerine B-PER’i yayarsanız, modele bir kişinin adının dört kez başladığını öğretmiş olursunuz.
  3. [CLS] ve [SEP]’in varlığını unutmak. Her etiketi bir konum kaydıran bir off-by-one hatası.

Bir dizi etiketleme modeli beklentinin çok altında skor alıyorsa, modele dokunmadan önce hizalamayı kontrol edin. Tokenize edilmiş bir cümleyi hizalanmış etiketleriyle yan yana yazdırıp okuyun. Bir dakika sürer ve bu bölümdeki en verimli dakikadır.

13.5 Transformer’lardan önce baseline’lar

Bölüm 12’nin disiplini: önce ucuz olanı — baseline’ı (karşılaştırma modeli) — kurun, pahalı olanı da onu geçmeye mecbur bırakın.

13.5.1 Bir gazetteer

Eğitim verisindeki her varlık dizgisini ezberleyin, sonra test cümlelerini en uzun eşleşmeye göre etiketleyin. Öğrenme yok, öznitelik yok, hiçbir genelleme yok.

gazetteer (16,591 memorised phrases, longest match)
  token accuracy 75.73%
  span   P 59.73   R 51.41   F1 55.26      (0.1s to tag 10,000 sentences)

Bir Python sözlüğünden 55 F1. Bir modelin kendini haklı çıkarmak için geçmesi gereken sayı bu ve çoğu kişinin tahmininden yüksek — çünkü isimler tekrarlanır. Bu derlemde test kümesindeki varlık ifadelerinin %52,2’si eğitim verisinde birebir geçiyor. Bu oran gazetteer’ın recall (duyarlılık) tavanı. Bunun bir kısmı isimlerin doğal tekrarı, bir kısmı da derlem denetiminde (Bölüm 13.2) gördüğümüz cümle düzeyindeki sızıntının yan etkisi. Sözlüğün 20.000 eğitim cümlesinin tamamından kurulduğunu da aklınızda tutun; aşağıdaki bütçe karşılaştırmalarında bu önemli olacak.

gazetteer (varlık sözlüğü) — bilinen varlık dizgilerinin ezberlenmiş bir listesi; doğrudan metinle eşleştirilir. Hızlı, tam isabetli ve daha önce görmediği bir ismi tanımaktan tamamen aciz. ↩︎

Gazetteer, sanıldığından daha sık doğru cevaptır. Varlıklarınız kapalı bir kümeyse — kataloğunuzdaki parçalar, bir ilaç listesindeki etken maddeler, Türkiye’nin 81 ili — o zaman liste zaten doğrunun ta kendisidir ve bir model onu ancak yaklaşık olarak taklit edebilir.

13.5.2 Bir CRF

Sözlük daha önce hiç görmediği bir adı tanıyamaz, çünkü bir adın neye benzediğine dair hiçbir fikri yok. O fikri modele elle verin: büyük harf kullanımı, ekler, kelimenin biçimi, komşularının neye benzediği.

Doğrusal zincirli bir CRF, bir \(x\) cümlesi için bütün bir \(y = (y_1, \dots, y_T)\) etiket dizisini iki tür terimin toplamı olarak puanlar — biri token’a, öteki etiket çiftine bakar:

\[ s(x, y) \;=\; \sum_{t=1}^{T} \underbrace{\mathbf{w}^\top \mathbf{f}(x, t, y_t)}_{\text{emisyon}} \;+\; \sum_{t=2}^{T} \underbrace{A_{y_{t-1},\, y_t}}_{\text{geçiş}} \]

ve bu skoru, her etiket dizisi üzerinden normalleştirerek bir olasılığa çevirir. CRF’yi tek tek token’ların değil, bütün dizinin modeli yapan da budur:

\[ p(y \mid x) \;=\; \frac{\exp s(x, y)}{\sum_{y'} \exp s(x, y')} \]

Bu paydadan iki şey çıkıyor. Eğitim, referans etiket dizisinin log-olabilirliğini maksimize ediyor — aşağıdaki koddaki c1 ve c2, \(\mathbf{w}\) ile \(A\) üzerindeki \(L_1\) ve \(L_2\) cezaları — ve öngörü \(\arg\max_y s(x, y)\)’yi alıyor. Hem paydadaki toplam (eğitim için gerekli) hem de argmax (öngörü için gerekli), \(L\) etiket ve \(T\) token için \(L^T\) etiket dizisinin tamamı üzerinde tanımlı; bunları tek tek saymak imkânsız. Her skor yalnızca komşu etiketleri birbirine bağladığı için dinamik programlama ikisini de \(O(T L^2)\)’de hesaplar: toplamı ileri (forward) algoritması, maksimumu Viterbi.

Bu koşullamanın sağladığı avantajın bir adı var. Saklı Markov modeli (hidden Markov model, HMM), CRF’lerden önceki klasik dizi modelidir ve şöyle bir hikâye anlatır: her etiket kendi kelimesini, her etiket de bir sonraki etiketi üretir. HMM üreticidir: ortak dağılım \(p(x, y)\)’yi modeller, dolayısıyla kelimelerin nasıl üretildiğini de anlatmak zorundadır. Bu da kelimeler üzerine güçlü bağımsızlık varsayımları dayatır: “önceki kelimenin baş harfi büyük” ile “bu kelime -nin ile bitiyor” gibi örtüşen kanıtları öylece ekleyemezsiniz, çünkü model onları iki kez sayar. CRF ise ayırt edicidir: doğrudan \(p(y \mid x)\)’i modeller ve \(x\)’in nereden geldiğini hiç açıklamak zorunda değildir; bu yüzden aşağıdaki öznitelik sözlüğü istediğiniz kadar ilişkili, elle tasarlanmış, örtüşen sinyal içerebilir. Öznitelik şablonunun elle yazılmasının bütün sebebi bu özgürlük — ve bir CRF’nin 2001’de bu biçimdeki bir görevde alternatiflerini yenmesinin sebebi de (Lafferty vd. 2001).

conditional random field (CRF) (koşullu rastgele alan) — bütün bir etiket dizisini tek seferde puanlayan ayırt edici bir model; komşu her etiket çifti için öğrenilmiş bir geçiş skorunu token başına öznitelik skorlarına ekler. \(p(x, y)\) yerine \(p(y \mid x)\) modeller; özniteliklerinin serbestçe örtüşebilmesinin sebebi de budur. ↩︎

Elle kurulmuş öznitelikler, yirmi bin cümle:

def features(tokens, i):
    w = tokens[i]
    f = {
        "bias": 1.0,
        "w.lower": w.lower(),
        "w[-3:]": w[-3:], "w[-2:]": w[-2:],        # Türkçe ekler
        "w.isupper": w.isupper(), "w.istitle": w.istitle(),
        "w.isdigit": w.isdigit(),
        "w.hasapos": ("'" in w or "’" in w),        # Türkiye'nin
        "w.shape": shape(w),                        # Xxxxx, 9999
        "w.len": min(len(w), 12),
    }
    for off in (-2, -1, 1, 2):                      # bir bağlam penceresi
        j = i + off
        if 0 <= j < len(tokens):
            v = tokens[j]
            f[f"{off:+d}:w.lower"] = v.lower()
            f[f"{off:+d}:w.istitle"] = v.istitle()
            f[f"{off:+d}:w[-3:]"] = v[-3:]
        else:
            f[f"{off:+d}:BOS_EOS"] = True
    return f
CRF (sklearn-crfsuite, lbfgs, c1=0.1, c2=0.1, 200 iterations)
  fit 18.5s        predict 0.2s for 10,000 sentences

  token accuracy 94.41%      token-level micro-F1 88.73
  span   P 86.27   R 84.64   F1 85.45      macro-F1 85.34

     PER   P 88.64   R 88.56   F1 88.60    (n=4,519)
     LOC   P 84.09   R 86.06   F1 85.06    (n=4,914)
     ORG   P 86.34   R 78.70   F1 82.34    (n=4,154)

Bir CPU’da on sekiz saniyede 85,45 span F1. GPU yok, ön eğitim yok, indirme yok. Bölümün geri kalanının geçmesi gereken sayı bu ve gerçekten zor bir hedef.

Bu tablodaki iki şeyi dikkatle okuyun. ORG recall’u 78,70; PER’in on, LOC’un yedi puan altında. Kurumlar uzun, bileşik ve açık uçludur (Slovenya Millî Basketbol Takımı), bu yüzden uzun bir adın ilk kelimesinin etrafındaki beş token’lık pencere son kelimeye uzanmayabilir; oysa “bu bir kurum” diyen çoğu zaman o son kelimedir (Takımı). Bir de w.hasapos özniteliği gerçekten iş yapıyor: Türkçe yazımda kesme işareti bir eki özel isimden (ya da 1919’da örneğindeki gibi bir sayıdan veya kısaltmadan) ayırır; bu yüzden kendinden önceki karakterlerin bir ad olduğunun güçlü bir işaretidir. Bu, çoğu dilin bu kadar düzenli sunmadığı bir yazım şansı.

13.6 Bir encoder’ı fine-tune etmek

Aynı görev, aynı test kümesi, BERTurk üzerine AutoModelForTokenClassification, yukarıdaki ilk-alt-kelime hizalaması, üç epoch, öğrenme oranı 3e-5. İlginç soru “kazanıyor mu” değil, “hangi etiket bütçesinde kazanmaya başlıyor”. Bu yüzden koşu tek bir nokta değil, bir eğri.

budget    token acc   span P   span R   span F1   macro   illegal   train s
   200        63.43     9.02     1.90      3.14    2.95      1561       5.6
   500        85.04    51.25    58.11     54.47   54.05      3739      12.6
 1,000        92.59    74.99    80.44     77.62   77.26       915      24.6
 2,000        94.68    82.74    85.78     84.23   84.04       538      48.9
 5,000        95.96    87.44    89.24     88.33   88.16       304     121.3
20,000        97.20    91.49    92.35     91.92   91.82       139     476.6

CRF, all 20,000 sentences   94.41    86.27    84.64     85.45   85.34    0    18.5

Bütçe başına tek koşu, seed 42, hiperparametre taraması yok — ve oynak olanlar iki küçük bütçe. 200 cümlede, rastgele ilklendirilmiş bir katmanın her şeye O deme çözümünden kurtulup kurtulamadığı seed’e bağlı olabilir; dolayısıyla 3,14’ü, arkasında iki ondalık olan bir sayı değil tek haneli diye okuyun. Bu tablodaki her karşılaştırmanın altında bir gürültü tabanı da var: test kümesinin 13.587 referans span’i üzerinde %85 civarındaki bir span F1’in, yalnızca test kümesi örneklemesinden gelen standart hatası 0,3 puan kadar; %95 aralığı kabaca \(\pm 0{,}6\) puan. Kesişimi belirleyen 84,23 ile 85,45 arasındaki fark 1,22 puan, yani bu standart hatanın yaklaşık dört katı; belirsizliğin kaynağı test kümesi değil. Kaynak tek eğitim koşusu: başka bir seed’in 84,23’ü ne kadar oynatacağını bilmiyoruz. Bütçe başına üç seed, bu tablonun eksik olan ölçümü.

Tam bütçede encoder, CRF’nin 85,45’ine karşılık 91,92 span F1’e ulaşıyor. Fark altı buçuk puan; bedeli ise 18 saniyelik CPU eğitimi yerine 477 saniyelik GPU eğitimi ve test kümesinde 0,2 saniye yerine 10,3 saniyelik çıkarım.

Üst satırı bir daha okuyun. 200 etiketli cümlede fine-tune edilmiş bir transformer 3,14 span F1 alıyor — ezberlenmiş dizgilerden oluşan bir sözlük ise 55,26.

Karşılaştırmanın iki tarafı eşit değil: o sözlük 20.000 cümlenin tamamından kurulmuş 16.591 ifade içeriyor. Elinde yalnızca 200 etiketli cümle olan biri kabaca 265 varlıklık bir liste kurabilir ve o liste 55,26’nın altında kalır; nerede kalacağını ölçmedik. Bu satırın gerçek karşılığı, dışarıdan hazır bir listenizin (il listesi, ürün kataloğu) olduğu durum.

Encoder’ın 3,14’ü ise bir hata değil ve bu bölümdeki en işe yarar şey. 200 cümlede model, altı varlık etiketi artı O üzerine yayılmış kabaca 265 varlık görmüş oluyor; sınıflandırma katmanı rastgele ilklendirilmiş; ve batch boyutu 16’da üç epoch 39 gradyan güncellemesi demek.

Son sayının teşhisi nasıl değiştirdiğine dikkat edin. Bu tablodaki her satır aynı üç epoch’u aynı 3e-5 ile kullanıyor — tam bütçe için ayarlanmış, küçük bütçeleri aç bırakan bir takvim. Yani o 3,14’ün bir kısmı etiket bütçesinden, bir kısmı takvimden kaynaklanıyor ve bu koşu ikisini birbirinden ayırmıyor. 200 örnekte standart çare on ila yirmi epoch, belki daha yüksek bir öğrenme oranıdır; sonuç çıkarmadan önce denenecek ilk şey budur ve biz denemedik. Bu yüzden 3,14’ü 200 cümlenin alabileceği en yüksek skor diye okumayın. Aynı tarif 500 cümlede, yalnızca 96 güncellemeyle 54,47’ye çıkıyor; 200 cümlede daha uzun bir takvim, sözlükle arasındaki farkın büyük kısmını kapatabilir — bu koşu bunu söyleyemez. Ham sayı, veri bütçesinin olduğu kadar takvimin de ürünü. Geriye kalan pratik ders şu: varsayılan bir tarifle ve hiç ayar yapmadan, küçük bir etiket bütçesi fine-tune edilmiş bir encoder’ı bir dizgi listesinin gerisinde bırakabilir.

Token doğruluğu %63,43; her şeye O diyen tabanın %61,36’sının kıl payı üstünde. Bu da modelin ne öğrendiğini açıkça söylüyor: O demeyi öğrenmiş. Neredeyse hiç varlık yakalamıyor (recall 1,90) ve yakaladığı birkaç tanesi de çoğunlukla yanlış.

20.000 cümlelik CRF ile kesişim noktası 2.000 ile 5.000 etiketli cümle arasında: 2.000’de encoder hâlâ bir puan geride (85,45’e karşı 84,23), 5.000’de ise neredeyse üç puan önde. Yani iki bin beş yüz civarı etiketli cümlelik BERTurk, yirmi bin cümlelik elle mühendislik edilmiş CRF’nin verdiğini veriyor — buna etiketlemede dört ila on kat azalma diyebilirsiniz (\(20.000 / 5.000\) ile \(20.000 / 2.000\) arası); ölçülen kesişimin desteklediği aralık bu. Bu görevde ön eğitimin ölçülmüş gerekçesi budur ve yaygın anlatıların ima ettiğinden küçüktür. Bu karşılaştırmanın ne olduğunu net koyalım: bir etiket verimliliği iddiası; encoder’ın bütçesi değişirken CRF’ninki 20.000’de sabit duruyor. Eşit bütçe karşılaştırması değil: CRF’yi yalnızca 20.000 cümlede eğittik, dolayısıyla 2.000 cümlelik bir CRF’nin encoder’ın önünde mi arkasında mı kalacağını bu tablo söylemiyor. Söylediği şu: o kesişimin altında 20.000 cümlelik klasik hat bir yedek plan değil, daha iyi modeldir. CRF’yi de aynı altı bütçede eğitmek, bu tablonun ikinci eksik ölçümü.

illegal sütununa ikinci kez bakın, çünkü F1 sütununun söylemediği bir şey söylüyor. Burada biçim doğruluğu öğreniliyor, garanti edilmiyor: yasak BIO geçişleri, model varlık etiketi üretmeye başlar başlamaz 3.739’a çıkıyor, sonra model grameri veriden öğrendikçe istikrarlı biçimde düşüyor.

Ve hiçbir zaman sıfıra inmiyor. 20.000 cümle ve 91,92 F1’de bile model, IOB2’nin yasakladığı 139 dizi üretiyor. 20.000 cümlelik CRF ise tek bir tane bile üretmedi, çünkü Viterbi bütün dizinin toplam puanını hesaplıyor ve destekleyen özniteliği olmayan bir geçiş, burada kazanan yolda hiç yer bulamadı. Ampirik sıfır yerine garanti istiyorsanız, yasak geçişleri kod çözmeden önce maskeleyin (Bölüm 13.3.1).

Hataların hangi yöne aktığına dikkat edin. CRF precision’a (kesinlik) yatkın (86,27 P’ye karşı 84,64 R); 500’den yukarı her encoder satırı ise recall’a yatkın. Öznitelik şablonları eşleştiklerinde ateşlenir, eşleşmediklerinde susar; fine-tune edilmiş bir encoder ise tahmin yürütür. Hangi hata türünü tercih edeceğiniz bir ürün kararıdır ve Bölüm 12.7 bu kararı vermenin mekanizmasıdır.

Etiket bütçesine karşı span düzeyinde F1 — ve CRF'yi geçmenin bedeli

13.7 Token doğruluğu yanlış metriktir

Üç sayı; üçü de aynı CRF tahminleri üzerinde, aynı 10.000 test cümlesinde hesaplandı:

token accuracy                94.41
token-level micro-F1          88.73      (entity tags only, O excluded)
span-level F1                 85.45      (exact match on type, start and end)

Farklılar, çünkü farklı sorular soruyorlar. Ve yalnızca sonuncusu sizin umursadığınız soruyu soruyor.

Token doğruluğu her token’ı sayar; O olan %61’lik kısım dâhil. Her token’a O diyen bir model bile 61,36 alıyor. Yani bu metriğin bilgi taşıyan aralığı, 61 ile 90’ların sonu arasındaki otuz beş kadar puan. Üstelik durum, çoğu cümlesinde hiç varlık bulunmayan gerçekçi derlemlerde iyileşmiyor, kötüleşiyor. Bir modeli bitmemişken bitmiş gösteren metrik budur.

Varlık etiketleri üzerinde token düzeyinde F1 O sınıfını atar; bu da taban problemini çözer. Ama hâlâ kısmi puan verir: dört token’lık bir kurumun üç token’ını doğru bilirseniz bir isabetin dörtte üçünü alırsınız. Aşağı akıştaki hiçbir sistem bir kurum adının dörtte üçünü kullanamaz.

Span düzeyinde F1 tür, başlangıç ve bitişin üçünün de doğru olmasını ister. Üçü arasında “kaydı doğru çıkardık mı” sorusuna karşılık gelen tek metrik bu. NER makaleleri de bu nedenle span düzeyinde F1 raporlar.

“Span düzeyinde F1” ifadesinin içinde birbirinden bağımsız iki seçim saklı; bunları ayırmak, ileride çıkacak bir tartışmayı baştan önler. Tam eşleşme sınırlarla ilgili: öngörülen span’in türü, başlangıcı ve bitişi bir referans span’le eşleşiyor mu? Katı ile hoşgörülü ise, herhangi bir eşleştirme yapılmadan önce kod çözücünün bozuk bir etiket dizisiyle ne yaptığıyla ilgili. seqeval her iki kipinde de tam eşleşme kullanır; varsayılan kipi hoşgörülü olandır, mode="strict", scheme=IOB2 ise ötekidir.

Bu bölümde span düzeyinde verilen her sayı hoşgörülü uzlaşımla hesaplandı — seqeval’ın ve conlleval’ın varsayılanı. Bu bölüm boyunca kullanılan puanlayıcı hazır bir kütüphaneden alınmak yerine elle yazıldı; böylece varsaydığı kod çözme görünür oluyor. Kasten bozulmuş tahminler üzerinde seqeval ile karşılaştırıldı ve dört ondalık basamağa kadar aynı sonucu verdi — ikisinden de P 46,2332, R 75,2042, F1 57,2629. Kendinizinkini yazarsanız bu karşılaştırmayı çalıştırın; anlaşmazlıklar her zaman bozuk dizilerdedir.

span düzeyinde F1 — bir tahmin ancak türü, ilk token’ı ve son token’ı bir referans span ile eşleşirse doğru sayılır. Kısmi örtüşmeler sıfır alır; amaç da zaten bu: bir varlığın yarısı, yarısı kadar bile işe yaramaz. ↩︎

Token düzeyindeki 88,73 ile span düzeyindeki 85,45 arasındaki farkın büyük kısmı sınır hatalarından geliyor — türün doğru, bir kenarın yanlış olduğu span’ler. (İki metrik span’leri ayrıca farklı ağırlıklandırıyor; bu yüzden fark saf bir hata sayısı değil.) Bu hatalar, sıradan kelimelerden kurulmuş uzun adlarda, yani bir sonraki alt bölümün gösterdiği gibi ORG’da yoğunlaşıyor.

Türkçe, bu skorların göremediği daha ince bir sınır problemi ekliyor: Samsun’a kelimesindeki varlığın gerçek sonu kelimenin içinde, hâl ekinden hemen önce. WikiANN boşlukla ayrılmış token’ların tamamını etiketlediği için ek, adın parçası sayılıyor ve iki metrik de bunu cezalandırmıyor. Sorun, çıkarılan dizgileri saymak ya da bağlamak gerektiğinde geri dönüyor (Bölüm 13.11).

Tam eşleşme bir uzlaşımdır, bir yasa değil. Çıktınızı aşağı akışta kullanan, vurgulanmış metni gözden geçiren bir insansa, bir token kaymış bir span neredeyse kusursuz olanı kadar işe yarar. Yalnızca tam eşleşme raporlarsanız, kullanıcılarınızın tercih edeceği modelleri elemiş olursunuz.

Alternatifler, MUC tarzı kısmi puan şemaları (Chinchor ve Sundheim 1993) ve nervaluate’in uyguladığı katı / tam / kısmi / tür ayrımıdır. Çıktınızı kullanan tarafa uyduklarında kullanın ve hangisini kullandığınızı söyleyin — kısmi puanla 90 raporlayan bir makale, tam eşleşmeyle 88 raporlayan bir makaleyi geçmiş olmaz.

13.7.1 Hataların yeri

Tek bir F1 sayısı ne kadar hata olduğunu söyler, hatanın ne olduğu hakkında ise hiçbir şey söylemez. Sayıyı varlık türüne göre ayırınca aynı iki sistem oldukça farklı görünür:

                CRF                       BERTurk @ 20,000
        precision  recall      F1     precision  recall      F1   support
  PER       88.64   88.56   88.60         94.19   94.73   94.46     4,519
  LOC       84.09   86.06   85.06         91.16   93.22   92.18     4,914
  ORG       86.34   78.70   82.34         88.93   88.73   88.83     4,154

ORG her iki sütunda da sonuncu ve recall’u aykırı değer — CRF’de 78,70, altı puan önde giden encoder’da bile üçünün en düşüğü olan 88,73. Altı puanlık ek model gücü bile ORG’u sondan kurtaramadı.

Sebep span’lerin kendisinde yatıyor. Kurum adları uzundur — ortalama referans span ORG için 2,68 token; PER için 2,26 ve LOC için 1,61 — bileşiktir ve sıklıkla sıradan kelimelerden kurulur (Türk Silahlı Kuvvetleri, Eurovision Şarkı Yarışması). CRF’nin beş token’lık penceresi uzun bir adın tamamını ilk kelimesinden göremez; bütün cümleyi gören encoder ise adı görür, ama nerede bittiğine yine de karar vermesi gerekir.

Türler arasında başarım bu kadar farklıyken micro’nun yanında macro-F1 de raporlayın. Burada ikisi yakın (85,45 micro’ya karşı 85,34 macro), ama bunun tek sebebi üç türün boyutlarının benzer olması. Bir nadir ve bir yaygın tür içeren bir şemada keskin biçimde ayrışırlar — Bölüm 12’nin belge etiketleri için gösterdiği gibi.

Bütün bunların bir sınırı var, çünkü bölüm üç görevle açıldı ama yalnızca birini ölçtü. Yukarıda span’ler, BIO ve span düzeyinde F1 hakkında söylenen her şey, çıktısı bir span olan görevler için geçerli: NER, chunking, slot doldurma. POS tagging bunlardan biri değil: her token bir etiket taşır, hiçbir token O değildir ve kodu çözülecek bir span yoktur. Dolayısıyla orada token doğruluğu gayet makul bir metriktir. Tabanı da %61 değil, en sık etiket baseline’ıdır (her kelimeye eğitimde en sık aldığı etiket verilir; İngilizcede %90 civarı, birçok kelime biçiminin eğitimde hiç görülmediği Türkçede daha düşük). Mimari ortak; değerlendirme değil. Buraya Türkçe POS tagging için geldiyseniz etiket kümesi Universal Dependencies’inki, derlemler de UD Türkçe ağaç bankalarıdır (BOUN, IMST). Ama Bölüm 13.4 bu bölümün size hâlâ gereken kısmı, çünkü alt kelime problemi etiketlerin ne anlama geldiğinden bağımsız.

13.8 LLM ile şema güdümlü bilgi çıkarma

Bir etiketleyici eğitmenin 2026’daki alternatifi, şemayı tarif edip sormak. Etiketli veri yok, eğitim koşusu yok, bir öğleden sonralık prompt (istem) yinelemesi var. Gerçek bir seçenek sayılacak kadar iyi çalışıyor, ama bir etiketleyicinin asla yapmadığı türden hatalar da yapıyor. Bu yüzden inanmak değil, ölçmek gerekiyor.

Kurulum bilerek elverişli tutuldu: etiketleme kılavuzu prompt’a giriyor, çıktı bir JSON şemasıyla kısıtlanıyor, sıcaklık 0.

SCHEMA = {
  "type": "object",
  "properties": {
    "entities": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "text": {"type": "string"},
          "type": {"type": "string", "enum": ["PER", "ORG", "LOC"]},
        },
        "required": ["text", "type"],
      },
    }
  },
  "required": ["entities"],
}

13.8.1 Bir öğleden sonraya mal olan tuzak

Sonuçlardan önce, sonuçlardan daha değerli bir hata. Aynı şema, aynı model, aynı sunucu — iki uç nokta:

prompt: "What is the capital of France?"
schema: {"answer": integer}

POST /api/generate   with format=<schema>
  -> {"answer": 1}

POST /api/chat       with format=<schema>
  -> "The capital of France is **Paris**.\n\nLocated in the north-central
      part of the country along the Seine River, Paris is..."

Şemaya göre cevap, tam sayı tipinde bir answer alanı içeren bir nesne olmalıydı. /api/generate üzerinde kısıt uygulandı. /api/chat üzerinde ise, Apple Silicon’da ollama 0.24.0 ile ve düşünme kapalıyken, format alanı sessizce yok sayıldı ve model düzyazı döndürdü. Hata yok, uyarı yok, cevapta kısıtın düşürüldüğünü söyleyen bir alan yok.

Yine de hangi değişkeni suçlayacağınıza dikkat edin, çünkü onu yalıtmadık. Bu, /api/chat’in bir özelliğinden çok bilinen bir hata sınıfı. Projenin kendi hata takip sisteminde format’ın uyarı vermeden düşürüldüğüne dair birden fazla rapor var ve bunlar uç noktayı değil, çalıştırıcıyı ve bayrakları işaret ediyor: bir arka uç kısıtı düşürürken aynı modelin başka bir derlemesi onu uyguluyor; think: false ise bazı modellerde kısıtı devre dışı bırakıyor. Bizim kurulumumuz tam da o kesişimde duruyor. Çıkarılacak ders, teşhis hangisi olursa olsun geçerli ve pratik olan da bu: sunucu sürümünüzü sabitleyin ve bir istek kısıtın açık olduğunu kanıtlayana kadar kapalı olduğunu varsayın.

Bu kurulumu bir bilgi çıkarma hattının içinde, ayrıştırma (parse) adımının çevresinde bir try/except json.JSONDecodeError ile çalıştırırsanız, her belge için sıfır varlık döndüren bir çıkarıcı ve sıfırlarla dolu bir metrik tablosu elde edersiniz. Sonra da bir öğleden sonranızı, bu sıfırların suçunu prompt’unuzda arayarak geçirirsiniz.

Kısıtlanmış çağrının ne döndürdüğüne de dikkat edin: {"answer": 1}. Paris bir tam sayı değil; yani gramer kısıtlı kod çözme, şemaya uygun ve anlamsal olarak değersiz bir şey üretti. Şemada “bu soru bir tam sayıyla cevaplanamaz” demenin geçerli bir yolu (örneğin null olabilen bir alan) da yoktu; model bir sayı üretmeye zorlandı. Bir şema biçimi garanti eder, doğruluğu asla. Bunun ardındaki mekanizma — gramerlerin örneklemeyi nasıl kısıtladığı ve neye mal olduğu — Bölüm 18’de anlatılıyor.

Buradan çıkan genel kural: yapılandırılmış çıktı kısıtınızın gerçekten uygulandığını, modelin aksi hâlde ihlal edeceği bir şema göndererek doğrulayın. Uygulandığını sandığınız ama uygulanmayan bir şema, hiç şema olmamasından kötüdür — çünkü size haber verecek olan bozuk çıktıyı ortadan kaldırır.

13.8.2 Cevabı metnin üstüne geri oturtmak

Bir etiketleyici konum döndürür. Bir LLM ise dizgi döndürür. {"text": "Samsun", "type": "LOC"} içinde bunun hangi token’lar olduğunu söyleyen hiçbir şey yok. Span düzeyinde F1 ise token konumları üzerinden tanımlı. Dolayısıyla her LLM cevabının, puanlanabilmesi için önce cümlenin üstüne geri hizalanması gerekiyor.

Bu adım yazılarda genellikle atlanır ve ilginç başarısızlıklar tam burada:

def align_span(tokens, text):
    want = text.split()
    for i in range(len(tokens) - len(want) + 1):      # 1. birebir token dizisi
        if tokens[i:i + len(want)] == want:
            return i, i + len(want)
    ...                                               # 2. boşlukları yok say
    ...                                               # 3. düşmüş bir eke izin ver
    return None                                       # cümlede yok

Üç şey dönebilir:

  • Gerçekten orada olan bir varlık ifadesi — hizalayın, puanlayın.
  • Türkçe eki soyulmuş bir varlık ifadesi. Model Samsun döndürüyor; token ise Samsun'a. Kılavuz birebir kopya istemişti; model ise yardımsever davranıp ifadeyi normalleştirdi. 3 numaralı yedek tam bunun için var ve gerçekten iş yapıyor.
  • Cümlede hiç bulunmayan bir varlık ifadesi. Bir yeniden ifade, bir genişletme, bir çıkarsama. Bunu adil biçimde puanlamanın bir yolu yok; onu isabet saymak, modeli kendi uydurduğu bir metin hakkındaki iddiası üzerinden puanlamak olurdu.

Hizalanamayan her ifadeye halüsinasyon deyip geçmek cazip. Bunun çoğunlukla yanlış olduğu ortaya çıkıyor ve nedeni bu kısmın asıl dersi.

1.000 cümle boyunca model tür etiketi atanmış 1.419 varlık ifadesi döndürdü; bunların 31’i hizalanamadı. O 31 tanesini sebebe göre ayırınca:

aligned directly                              1,388   97.82%
recovered by normalising apostrophes              7    0.49%   ' vs ’
recovered by stripping wiki markup               20    1.41%   ''Gorran ''
genuinely not in the sentence                     4    0.28%

Otuz bir başarısızlığın yirmi yedisi hizalayıcının suçuydu, modelin değil. Yirmisi derlemin kendi Wikipedia biçimlendirmesinden, yedisi ise modelin kıvrık kesme işaretini düz olana normalleştirmesinden geldi. Sonuçlar incelenmeden raporlansaydı ana bulgu “model 31 varlık uydurdu” olurdu — model hakkında gibi görünen, aslında ön işleme hakkında olan bir iddia.

Dersin daha rahatsız edici olan ikinci yarısı şu: hizalayıcıyı düzeltmek skoru neredeyse hiç oynatmıyor; 60,57’den 60,29 F1’e. Recall yükseliyor (60,82’den 61,11’e), precision düşüyor (60,33’ten 59,50’ye) — çünkü kurtarılan ifadeler zaten çoğunlukla yanlıştı. Yani hizalamayı kontrol edin, ama hayal kırıklığı yaratan bir sayının açıklamasını orada bulmayı beklemeyin.

Bu sayıların hangi protokolle hesaplandığını da açık yazalım: hizalanamayan ifadeler precision’ın paydasına girmedi; onları sessizce atmadık, oranlarını yukarıda ayrıca verdik (Bölüm 13.12’deki 6. sorunun ikinci seçeneği). Precision’ın düşmesinin sebebi de bu protokol: kurtarılan 27 ifade paydaya yeni giriyor ve çoğu yanlış. Hizalanamayanları yanlış pozitif sayan öteki protokolde, bu sayılardan geriye doğru hesaplarsak, naif hizalayıcı yaklaşık 59,9, düzeltilmiş hizalayıcı yaklaşık 60,2 F1 alır. Fark yine bir puanın altında, ama yönü tersine döner: kurtarılan ifadeler orada zaten yanlış pozitif sayılıyordu ve dördü doğru pozitife dönüşür.

Gerçekten hizalanamayan dört ifadenin hiçbiri uydurma değil; hepsi ek sınırı karışıklığı: metinde Çin Halk Cumhuriyetini varken — belirtme hâli kaynaşmış ve bölünecek kesme işareti yok — model Çin Halk Cumhuriyeti döndürüyor; metinde Niksar'da varken Niksar'ın döndürüyor. Doğru isim, yanlış hâl.

13.8.3 Sonuçlar

Her sistem için aynı 1.000 test cümlesi, 1.373 referans varlık, aynı puanlama:

qwen3.5:9b etiketleyicilere karşı, birebir aynı dilim üzerinde. LLM satırı naif hizalayıcıyı kullanıyor; düzeltilmiş olan 60,29 alıyor. Hizalanamayan ifadeler precision’ın paydasına katılmadı
sistem kullanılan etiket token doğr. span P span R span F1
Gazetteer 20.000 cümle 76,12 60,28 50,40 54,90
LLM, zero-shot yok 82,87 60,33 60,82 60,57
CRF 20.000 cümle 94,42 84,94 83,39 84,16
Fine-tune edilmiş BERTurk 20.000 cümle 96,98 91,11 91,77 91,44

O satırda iki sayıdan hangisinin yer aldığına dikkat edin, çünkü denetim üzerine bir bölüm, daha parlak görünen sayıyı sessizce aktarmamalı. 60,57, kesme işareti ve wiki işaretleme düzeltmelerinden önceki hizalayıcıdan geliyor; düzeltilmiş hizalayıcı 60,29 veriyor. Fark 0,28 ve burada hiçbir şeyi değiştirmiyor. Ama öne çıkan bir sayı, onu hangi hizalamanın ürettiğini kimse kontrol etmeden tam da böyle durumlarda ileriye taşınır.

İki okuma var ve ikisi de önemli.

Hiç eğitim verisi olmadan LLM, gazetteer’ı altı puan geçiyor. Bu gerçek bir yetenek ve 2019’da mevcut değildi. Elinizde bir şema varsa ve etiket yoksa, yarın elinizde çalışan bir çıkarıcı olur.

Aynı LLM, on sekiz saniyede eğitilen bir CRF’nin 24 puan, fine-tune edilmiş encoder’ın 31 puan gerisinde kalıyor. Zero-shot bilgi çıkarma başlangıç noktasıdır, bitiş noktası değil — ve aradaki fark, yapılandırılmış çıktı etrafındaki pazarlamanın ima ettiğinden çok daha büyük.

Tür bazındaki döküm, LLM’in nerede yanıldığını gösteriyor:

             LLM              BERTurk @ 20,000
        P      R     F1        P      R     F1
  PER 64.63  82.00  72.29    92.97  95.32  94.13
  LOC 59.01  59.24  59.13    92.12  93.93  93.02
  ORG 54.67  40.10  46.26    90.46  87.97  89.20

40,10’luk ORG recall’u en çarpıcı başarısızlık: model beş kurumdan üçünü kaçırıyor. Bu, bölümdeki her sistemde görülen zayıflığın büyütülmüş hâli. Ama etiketleyicilerde görülmeyen bir sebebi de var. Model dizgileri bulmakta başarısız olmuyor; Değişim Hareketi’nin bir kurum olup olmadığı ve adının nerede bittiği konusunda anlaşmazlığa düşüyor. Bir etiketleyici o sınır uzlaşımını 20.000 örnekten öğrenir. Bir prompt ise onu ifade etmek zorundadır ve bir sayfalık kılavuz, insan etiketleyicilerin bir derlem boyunca üzerinde uzlaştığı şeyi kodlayamaz.

PER bunun ayna görüntüsünü gösteriyor: 82,00 recall’a karşı 64,63 precision. Model kişileri hevesle buluyor ve fazla iddialı davranıyor; kılavuzun dışladığı tanımları ve unvanları da etiketliyor.

13.8.4 Maliyeti

Buraya kadar LLM yalnızca isabet üzerinden yargılandı ve bu eksende 31 puan farkla kaybetti. İkinci eksen onun için daha kötü; üstelik aradaki fark, yazıya dökülmüş hâlini görene kadar kolayca küçümsenebilecek türden:

                              LLM (qwen3.5:9b)     BERTurk fine-tuned
per sentence                        1.26 s              0.00103 s
1,000 sentences                    1,265 s                    1.0 s
generated tokens per sentence          26.4                    n/a
malformed JSON responses                  0

LLM cümle başına kabaca 1.200 kat daha yavaş — üstelik bu, 4 bite nicemlenmiş ve yerelde çalışan 9B’lik bir model; düşünme kapalı ve bir şema çıktıyı 26 token’da tutuyor. Bulutta barındırılan en ileri (frontier) bir model muhtemelen daha isabetli olurdu, ama her istek yine milisaniye değil saniye mertebesinde sürerdi; istekleri paralel göndererek işlem hacmi satın alabilirsiniz, ama her birinin parasını ödersiniz.

Bin cümle için bu fark önemsiz. Bir bilgi çıkarma hattının kolayca işlemesi gerekebilecek on milyon cümle içinse, cümle başına 1,26 saniye tek makinede 146 gün eder. Sınıflandırma bölümündeki karar kuralı (Bölüm 12.9) burada da aynen geçerli: düşük hacimde prompt kullanın, hacim geldiğinde bir etiketleyiciye damıtın.

Doğru orta seçenek o tablodan bilerek çıkarıldı, çünkü bir satırdan fazlasını hak ediyor: LLM’i etiketlemek için kullanın, sonra etiketleyiciyi onun çıktısı üzerinde eğitin. 60,57 F1 ile model zayıf bir çıkarıcı, ama veri etiketlemek için iş görür: bir gecede size binlerce gürültülü etiket verir. Encoder eğrisi de (Bölüm 13.6) bunun, fine-tune edilmiş bir encoder’ın çalışmaya başladığı rejim olduğunu söylüyor. Yalnız o eğri referans etiketlerle ölçüldü, gürültülü etiketlerle değil; 60 F1’lik etiketlerle eğitilen bir etiketleyici onların hatalarını da devralır. Bunu kendinizi kandırmadan nasıl yapacağınızı anlatan bölüm ise Bölüm 5.

13.8.5 Bu alt bölümün atladığı seçenek

Yukarıdaki karşılaştırma bir genel amaçlı LLM ile bir eğitilmiş etiketleyici arasında ve tam da aradaki boşluk için kurulmuş aileyi dışarıda bırakıyor. GLiNER (Zaratiana vd. 2024), serbest biçimli tür adlarını aday span’lerle eşleştirmek üzere eğitilmiş BERT boyutunda bir encoder; yani keyfî bir etiket kümesi üzerinde zero-shot bilgi çıkarmayı metin üretme gecikmesiyle değil encoder gecikmesiyle yapıyor. UniversalNER (Zhou vd. 2024) aynı hedefe instruction tuning (talimat ayarı) yolundan gidiyor, NuNER (Bogdanov vd. 2024) ise 125M’lik bir encoder’ı bir LLM’in ürettiği etiketlerle ön eğitiyor. Yayımlanmış karşılaştırmalar 90M’lik bir GLiNER’i, zero-shot kipte 13B’lik bir UniversalNER ile aynı bantta gösteriyor. Türkçe için bir uyarı: temel GLiNER modelleri İngilizce ağırlıklı veriyle eğitildi. Çok dilli bir sürümü (gliner_multi) var, ama Türkçedeki başarımını kendi verinizde ölçmeden varsaymayın.

Yani etiketiniz yokken seçenek iki değil, üç:

Etiketiniz yokken seçenekler
seçenek etiket gecikme ne zaman
bir LLM’i şemayla kısıtlayarak promptlamak yok ~1,3 sn/cümle prototipleme, uzun kuyruk alanlar, koşullu şemalar
GLiNER ailesi, zero-shot yok etiketleyici ölçeğinde herhangi bir düz varlık şeması, hacimde
bir encoder’ı fine-tune etmek 2.000+ etiketleyici ölçeğinde etiketlemesini göze alabildiğiniz, oturmuş bir şema

Bu bölüm birinciyi ve üçüncüyü ölçtü. Ortadaki satır, yapılacak bariz bir sonraki ölçüm. 1.200 kat gecikme cezasını etiketsiz olmanın bedeli diye kabul etmeden önce yapılması gereken ölçüm de bu.

13.9 BIO’nun çalışmayı bıraktığı yer

BIO, token başına bir etiket atar. Bu tek cümle, formatın bütün sınırlamalarını içeriyor ve gerçek şemalar bunların hepsiyle karşılaşıyor.

İç içe varlıklar. Türkiye Cumhuriyeti Merkez Bankası bir ORG; onun içindeki Türkiye ise bir LOC. Tek token, iki doğru etiket ve BIO’da bir tanesine yer var. Pratikte herkes içtekini düşürüyor ve bundan hiç söz etmiyor. İç içe geçmenin istisna değil kural olduğu biyomedikal ve hukuki şemalar ise bunu yapamıyor.

Örtüşen varlıklar. Biri diğerini kapsamadan token paylaşan iki span — ilişki ağırlıklı şemalarda ve klinik metinde yaygın.

Süreksiz varlıklar. sol ve sağ ventrikül iki yapıdan söz ediyor ve bunlardan ilki, sol … ventrikül, ortasında delik olan bir span. Klinik notlarda sıradan, BIO’da ifade edilemez.

Alternatiflerin hepsi token başına tek etiket kısıtından vazgeçiyor:

Token başına tek etiketin ötesi
yaklaşım fikir bedeli
Span sayımı k uzunluğuna kadar her aday span’i puanla, her birini sınıflandır \(O(nk)\) aday — ki bu ancak k, n ile büyüdüğünde \(O(n^2)\) olur; güçlü ve basit bir baseline
Biaffine / bağımlılık tarzı her (başlangıç, bitiş) çiftini biaffine bir katmanla puanla (Yu vd. 2020) iç içe geçmeyi doğal olarak ele alır; standart güçlü sonuç
MRC (machine reading comprehension, makine okuduğunu anlama) çerçevelemesi tür başına bir soru olarak “kurumlar nerede?” diye sor (Li vd. 2020) tür başına bir ileri geçiş (forward pass); tür tanımını modelin içine sokar
Kelime-kelime ızgara etiketleme her token çifti arasındaki ilişkiyi sınıflandır — komşuluk, kuyruk-baş (Li vd. 2022) iç içe geçmeyi ve süreksizliği tek bir formülasyonda ele alır
Üretici (diziden diziye) kayıtları doğrudan metin olarak üret hiç span cebiri yok — ve yukarıdaki hizalama problemine geri dönüş

GLiNER ailesindeki modeller (Bölüm 13.8) örtüşen span’leri de doğal olarak döndürüyor. Bu yüzden şemanızın iç içe geçmeyi destekleyen bir eğitim düzeneğine gerçekten ihtiyaç duyup duymadığını anlamanın en ucuz yolu, zero-shot rota.

Ne kadar kaybedeceğiniz, karar vermeden önce ölçülebilir bir şey: iç içe geçmenin etiketlemeye dâhil edildiği derlemlerde — GENIA, ACE — varlık ifadelerinin altıda biri ile üçte biri arasındaki bir kısmı iç içe; yani içtekini atmak bir yuvarlama hatası değil. Şemanızda iç içe geçme varsa ve hattınız BIO kullanıyorsa, o varlıkları kaybetmeye çoktan karar vermişsiniz demektir. Bu karar genellikle kazara alınır, bir öğreticiden devralınır. Bilerek alın.

13.10 İlişkiler ve olaylar

Ali ile Acme’yi çıkarmak kaydın yarısı. Diğer yarısı ise Ali’nin Acme’de çalıştığı bilgisi.

Standart çerçeveleme, çift bazlı sınıflandırma: bir cümledeki her varlık ifadesi çiftini alın ve aralarındaki ilişkiyi sınıflandırın — etiket dağılımına hâkim olan ilişki yok sınıfı dâhil. Çalışıyor; bir cümlede \(m\) varlık ifadesi varsa sınıflandırılacak \(m(m-1)\) sıralı çift, yani \(O(m^2)\) iş demek. Yaygın yöntemdeki gibi iki ifadeyi girdi metninde işaretlerseniz her çift bir ileri geçiş ister. Maliyet, Bölüm 13.9’daki span sayımının aday span’lerle büyümesiyle aynı sebepten çiftlerle büyüyor: her aday ayrı ayrı puanlanıyor.

Başlamadan önce bilmeniz gereken üç şey:

  1. ilişki yok ezici çoğunluk sınıfı. Bu yüzden dengesizlik için söylenen her şey (Bölüm 12.5) burada daha da güçlü biçimde geçerli. Micro-F1’i ilişki yok’u dışlayarak raporlayın ve ham doğruluğun bilgi taşımayacağını bekleyin.
  2. Etiketleme maliyeti her şeye baskın. Varlık etiketlemesi kabaca token sayısıyla doğrusal; ilişki etiketlemesi ise varlık sayısıyla ikinci dereceden. Üstelik kılavuzları tekrarlanabilir kılmak çok daha zor — PER ve ORG üzerinde anlaşan iki insan etiketleyici, bir cümlenin bir istihdam ilişkisi bildirip bildirmediği konusunda çoğu zaman anlaşamaz. TACRED (Zhang vd. 2017) hem referans veri kümesi hem de bu konudaki en bilinen ibretlik örnek: geliştirme ve test kümelerinin yeniden etiketlenmesi raporlanan F1’i kabaca sekiz puan oynattı (Alt vd. 2020) — bu, herhangi bir modelin değil, etiket gürültüsünün ölçümü.
  3. Açıkça bilinmesi gereken iki sınır. Yukarıdaki çift bazlı çerçeve cümle düzeyinde ve gerçek belgelerdeki ilişkilerin büyük bir kısmı cümle sınırını aşıyor — bu, belge düzeyi problemdir ve belirgin biçimde daha zordur. Ayrıca çerçeve, varlık ifadelerinin zaten bulunmuş olduğunu varsayıyor; yani yukarı akıştaki her varlık hatası aşağı akışta bir ilişki hatasına dönüşüyor.

Olay çıkarma bunun üstüne bir tetikleyici kelime ve tür atanmış argümanlardan oluşan bir küme ekler; aynı mekanizma, daha çok rol ve etiketleyiciler arasında daha düşük uyumla. 2026’daki uygulamalı işlerin çoğu için tavsiyemiz şu: önce şema güdümlü üretimi deneyin (Bölüm 13.8) ve ölçün. Çift bazlı sınıflandırıcıyı ancak onu geçmeye yetecek etiketlemenin maliyetini karşılayabiliyorsanız kurun.

13.11 Bağlama ve normalleştirme

Türkiye’nin ifadesini bulmak tanımadır. Onun Türkiye’de, Türkiye’deki ve Türkiye ile aynı şeye gönderme yaptığını bilmek ise varlık bağlama (entity linking) işidir; eklemeli bir dilde bu iş, ders kitaplarının varsaydığından bir adım önce başlar.

entity linking (varlık bağlama) — bir varlık ifadesini kanonik bir tanımlayıcıya eşlemek; böylece aynı şeyin farklı yüzey biçimleri tek bir kayda toplanır. İfadenin bir varlık olduğunu tanımaktan ayrı bir iş. ↩︎

Bu derlemin eğitim yarısında ölçüldü:

entity mentions                             26,482
  carrying an apostrophe suffix              4,099   15.5%

distinct surface forms                      16,591
distinct after stripping the suffix         14,876   10.3% collapse

most common suffixes on mentions
  -da   587    -nın  352    -de   328    -ın   233
  -in   227    -a    201    -nin  195    -ya   182

Altı varlık ifadesinden biri, kesme işaretiyle eklenmiş bir ek (çoğunlukla hâl eki) taşıyor. Ve yüzey biçimleri varlık başına çoğalıyor:

base forms appearing in more than one surface form   1,122

  ABD       -> ABD, ABD'de, ABD'deki, ABD'li, ABD'nin, ...        13 forms
  Fransa    -> Fransa, Fransa'da, Fransa'daki, Fransa'dan, ...    12 forms
  Türkiye   -> Türkiye, Türkiye'de, Türkiye'deki, ...             12 forms

ABD ifadelerini birebir dizgiyle sayarsanız, toplam sayıyı taşıyan tek bir varlık yerine her biri kendi küçük sayısını taşıyan on üç ayrı “varlık” elde edersiniz. Bunun üstüne kurduğunuz her toplulaştırma — bir sıklık sıralaması, bir eş-oluşum çizgesi, “bu hafta X’ten kaç kez bahsedildi” uyarısı — makul görünen bir biçimde yanlış olur.

Türkçeye özgü ilk adım ucuzdur ve daha akıllıca herhangi bir şeyden önce yapılmaya değer: kesme işaretinden bölün ve gövdeyi tutun. Genel bir çözüm değil — kesme işareti taşımayan pek çok çekimli varlık ifadesi var ve kesme işareti uzlaşımına her yerde uyulmuyor — ama tek satır kodla farklı yüzey biçimi sayısını %10,3 azaltır.

Bunun ötesindeki hat standarttır: bir bilgi tabanından dizgi benzerliğiyle aday kayıtlar üretin, sonra adayları bağlamla sıralayın. Klasik sistemler bunu varlık ifadelerinin eş-oluşum çizgesi üzerinden yapıyordu (Hoffart vd. 2011). Modern sürümü ise bağlam içindeki varlık ifadesini ve kayıt açıklamasını aynı vektör uzayına gömüyor ve adayları erişimle (retrieval) buluyor (Wu vd. 2020) — yani Bölüm 3’ün mekanizmasının farklı bir probleme uygulanmış hâli. O erişim adımını gerektiği gibi kuran bölüm Bölüm 19.

Buradaki değerlendirme tuzağı, denetimdekinin (Bölüm 13.2) aynası. Yüzey biçimi bilgi tabanınızda geçen varlık ifadeleri üzerinde ölçülen bağlama doğruluğu, bağlama doğruluğu değildir; sözlük kapsamıdır. İkisini ayrı raporlayın ve doğru kaydın hiç aday olmadığı durumların oranını da raporlayın — o sayı, sonraki hiçbir adımın yükseltemeyeceği bir tavandır.

13.12 Sezgi kontrolleri

Cevapları okumadan önce siz cevaplayın.

Bilemezsiniz ve bu sayı zaten sormanızı engellemek için tasarlanmış gibidir. Bu derlemde her token’a O diyen bir model %61,36 alıyor. Yani %96, 96 puanlık bir yetkinlik değil; tabanın 35 puan üstü demek. Çoğu cümlesinde hiç varlık bulunmayan gerçekçi bir derlemde taban daha da yüksek olur — %97 ve üstü sıradandır — ve hiçbir şey bulmayan bir model bile %96’yı geçebilir.

Span düzeyinde F1 isteyin. Cevap “o sayı bizde yok” ise, model değerlendirilmemiş demektir.

Sınırlara. Token düzeyinde F1 kısmi puan verir: dört token’lık bir kurumun üç token’ı doğruysa dörtte üç alırsınız. Span düzeyi ise türün, ilk token’ın ve son token’ın üçünün de eşleşmesini ister; aynı tahmin orada sıfır alır.

Ama farkı bir sınır hatası oranı diye okumayın. Farkta birkaç şey iç içe: kısmi örtüşmeler, token token sayılan farklı uzunluktaki span’ler ve uzun varlıklardaki tür hataları. Hepsinin mikro ortalaması alınıyor, yani dört token’lık bir hata bir token’lık hatanın dört katı ağırlık taşıyor. Bu, sınır hatalarının var olduğunun işareti; kaç tane olduğunun ölçüsü değil. Sayıyı istiyorsanız hata türlerini doğrudan sayın: tam, yalnızca sınır, yalnızca tür, fazladan, kaçırılan. Bu yirmi satırlık bir betiktir ve çok daha eyleme dönük bir tablo verir. Her hâlükârda span düzeyini raporlayın, çünkü çıktıyı aşağı akışta kullanan hiçbir sistem bir şirket adının dörtte üçüyle bir şey yapamaz.

Kimsenin. Bu, softmax etiketleyicinin beklenen davranışı: her konumda en iyi etiketi bağımsız seçiyor ve 4. konumu 5. konuma bağlayan hiçbir şey yok. Bu bölümdeki en iyi fine-tune edilmiş BERTurk, 10.000 cümlede bu türden 139 geçiş üretiyor; yalnızca 500 cümleyle eğitilmiş olanı 3.739 tane üretiyor.

Sizin kararınız ise bundan sonra ne olacağı. seqeval sessizce bir ORG span’i kurtarır; katı bir kod çözücü onu düşürür; bir onarım adımı ilk I-’yi B-’ye çevirir. Üçü de savunulabilir ve üçü farklı F1 verir. Hata, yasak geçiş değil; değerlendirmenizin bu üçünden hangisini yaptığını bilmemek.

Sayının nasıl değiştiğini bilmekte fayda var: 500 cümlelik bütçede 3.739’a çıkıyor, tam bütçede 139’a düşüyor ve hiç sıfıra ulaşmıyor. İyi biçimlilik, softmax etiketleyicinin veriden yaklaşık olarak öğrendiği bir şey. CRF bütün diziyi puanladığı için şemayı nadiren bozar. Ama sonlu bir geçiş skoru garanti değildir; garantiyi, yasak geçişleri kod çözme anında Viterbi aramasından tamamen çıkarmak verir.

Bu derlemde ölçüldü: tam bütçe tarifiyle (üç epoch, 39 güncelleme) 200 cümle üzerinde fine-tuning 3,14 span F1 veriyor. Ezberlenmiş dizgilerden oluşan bir sözlük ise 55,26; ama o sözlük 20.000 cümlenin tamamından kurulmuştu. Sizin 200 cümlenizden çıkacak liste birkaç yüz ifade içerir ve daha düşük alır; bu bölüm onu ölçmedi. Listenin asıl avantajı, dışarıdan hazır bir listeniz (il listesi, ürün kataloğu) olduğunda ortaya çıkar. Daha uzun bir takvim de encoder’ın skorunu iyileştirir; ne kadar iyileştireceği, karar vermeden önce yapılacak ölçümdür.

O bütçede encoder, altı varlık etiketi artı O üzerine yayılmış birkaç yüz varlık görmüş oluyor ve sınıflandırma katmanı rastgele ilklendirilmiş. Öğrendiği şey O demek — %63,43’lük token doğruluğu, %61,36’lık tabanın kıl payı üstünde. Tam 20.000 cümleyle eğitilmiş bir CRF ile kesişim noktası ise 2.000 ile 5.000 etiketli cümle arasında bir yere düşüyor: 2.000’de encoder hâlâ bir puan geride (85,45’e karşı 84,23), 5.000’de ise neredeyse üç puan önde.

Yani: hazır bir listeniz varsa önce gazetteer; birkaç bin etiketli cümleyi geçtiğinizde fine-tuning. Arada CRF ucuz ve denenecek ilk aday, ama küçük bütçede eğitilmiş bir CRF’yi bu bölüm ölçmedi; bu sırayı kendi verinizde doğrulayın. Genel ders şu: “sadece bir transformer’ı fine-tune et” tavsiyesinin bir bütçesi vardır ve o bütçe nadiren söylenir.

Kutlamadan önce sızıntıyı kontrol edin. WikiANN’in Türkçe bölümünde test cümlelerinin %13,06’sı eğitim kümesinde birebir geçiyor; 1.305’i aynı referans etiketlerle. Ezberleyen bir model bu cümleleri hiç zorlanmadan doğru etiketler.

Teşhis dört satırlık bir iş: test girdilerinizin hash’ini alın, eğitim girdileriyle kesiştirin ve sızmış ile temiz yarıları ayrı puanlayın. Bu bölümde CRF, sızmış yarıda 99,81, temiz yarıda 83,56 aldı. Farkınız buna benziyorsa, modelinizi değil veri kümenizi ölçmüşsünüz demektir.

Yanlış pozitif olarak sayılır. Asıl önemli olan, bir şekilde sayılması gerektiğidir. Span metrikleri token konumları üzerinden tanımlıdır; konumu olmayan bir dizginin bir referans span’le karşılaştırılacak hiçbir yanı yoktur — bu da satırı değerlendirmeden tümüyle çıkarmayı cazip kılar. Çıkarmayın: hizalanamayan çıktıyı sessizce atmak, uydurmayı cezasız bırakır ve çıkarıcıyı olduğundan iyi gösterir. Ya precision hesabında yanlış pozitif olarak puanlayın ya da F1’in yanında açık bir geçersiz çıktı oranı bildirin. Protokolde hangisini yaptığınızı söyleyin; bu bölüm ikincisini yaptı (Bölüm 13.8).

Ama rapora “halüsinasyon” yazmadan önce kimin hatası olduğunu kontrol edin. Burada ölçüldü: dönen 1.419 varlık ifadesinin 31’i hizalanamadı — ve bunların 27’si hizalayıcının hatasıydı; 20’si derlemdeki wiki biçimlendirmesinden, 7’si kıvrık kesme işaretinin düz kesme işaretine normalleştirilmesinden. 1.419 ifadeden yalnızca 4’ü (%0,28) gerçekten metinde yoktu ve onlar bile uydurma değil, hâl eki karışıklığıydı.

Yani: sayın, sayıyı raporlayın ve sebebe göre ayırın. Bu, bir etiketleyicide yapısal olarak görülemeyecek bir başarısızlık biçimi — bir etiketleyici yalnızca var olan token’ları etiketleyebilir — ama bu hataya benzeyenlerin çoğu aslında ön işlemeden kaynaklanır.

13.13 Mülakat soruları

Kaynak konusunda — Bölüm 2’deki çekincenin aynısı. “Google’ın sorduğu NER soruları” diye liste veren sayfalar, arkasında hiçbir dayanak olmayan arama motoru içeriğidir. Aşağıdakiler, bu kitabın baştan beri kullandığı iki güvenilir açık kaynakta tekrar tekrar geçen sorular. Bu kaynaklar Chip Huyen’in Introduction to Machine Learning Interviews kitabı (Huyen 2021) ve AIMLInterviews deposu. Bunlara, bu bölümün kendi ölçümlerinin cevaplanabilir kıldığı sorular da eklendi.

13.13.1 Görevi anlayıp anlamadığınızı sınayanlar

S: NER neden sadece token sınıflandırma değil?

Çünkü çıktı span’lerdir, model ise etiket üretir; aralarında bir kod çözme adımı vardır ve belirsizlik tam o adımda yatar. BIO’nun ne kazandırdığını (aynı türden bitişik varlıklar ayrılabilir hâle gelir), neyi ifade edemediğini (iç içe geçme, örtüşme, süreksizlik) ve bir kod çözücünün bozuk diziye ne yaptığını söyleyin. “Token başına sınıflandırmadan ibaret” diyen bir aday, hiç NER sistemi yayına almamıştır.

S: CRF katmanı ne işe yarar, BERT’in üstünde hâlâ gerekli mi?

CRF, etiketler arasındaki bağımlılıkları modeller — her etiket çifti için bir geçiş skoru öğrenir ve Viterbi ile çözer; böylece her konumdaki en iyi etiketi değil, bütün olarak en iyi diziyi döndürür. Bu da O → I-ORG gibi yasak bir geçişi, bütün cümleye karşı pahalı ya da en azından desteksiz kılar. İmkânsız değil pahalı deyin, çünkü geçiş skorları sonludur.

Güçlü bir ön eğitimli encoder’ın üstünde kazanç küçüktür, çünkü encoder zaten bütün cümleyi görür ve geçişlerin çoğu bağlamdan öğrenilebilir. Bu tür encoder’ların üstünde bildirilen farklar CoNLL tarzı benchmark’larda genelde bir puanın altındadır. Yine de buna güvenmek yerine kendi şemanızda ölçün; biz burada ölçmedik. Daha ucuz seçeneği de söyleyin: logit’lere uygulanan bir geçiş maskesi ile Viterbi (Bölüm 13.3.1), geçersiz geçişleri kod çözme anında, fazladan parametre ve yeniden eğitim gerektirmeden dışarıda bırakır. Şunu da ekleyin: garanti için bu geçişlerin yalnızca cezalandırılması yetmez, arama uzayından çıkarılmaları gerekir.

S: Bir NER sistemini nasıl değerlendirirsiniz?

Span düzeyinde micro ve macro F1, tam eşleşme, tür bazında raporlanmış. Sonra buna inanmadan önce neyi kontrol edeceğinizi söyleyin: her şeye O diyen taban, test ile eğitim girdileri arasındaki örtüşme ve skorun hangi kod çözme uzlaşımını varsaydığı. “F1” deyip susan biri hiçbir şey değerlendirmemiştir.

13.13.2 Bir tane yayına alıp almadığınızı sınayanlar

S: NER modeliniz çevrimdışı iyi, üretimde kötü. Adım adım anlatın.

Maliyete göre sıralı; ilk dördünün modelle ilgisi yok:

  1. Tokenization uyuşmazlığı. Çevrimdışı değerlendirmeyi önceden tokenize edilmiş referans token’lar üzerinde yaptınız; üretim ise ham metni farklı bir bölücüyle tokenize ediyor, dolayısıyla span’ler tutmuyor. En yaygın sebep ve gözden kaçırması en kolayı.
  2. Hizalama. Etiketler kelime başına, model girdileri alt kelime başına. Bir üretim cümlesini hizalanmış etiketlerinin yanına basıp okuyun.
  3. Alan. Wikipedia parçaları destek talebi değildir. Bu bölümde eğitim için kullanılan cümlelerin %65,5’i noktalama işaretiyle bile bitmiyor.
  4. Çevrimdışı sayıdaki sızıntı. Yukarıda anlatıldı; en çok modelinizin ezberleyen kısımlarını şişirir.
  5. Ancak ondan sonra model.

S: Sözleşmelerden 30 alan çıkarmanız gerekiyor ve etiketli veriniz yok.

Şema güdümlü üretimle başlayın, çünkü alternatif, görevin mümkün olup olmadığını öğrenmeden önce aylarca etiketleme yapmak. Sonra bunun işe yaradığını nasıl anlayacağınızı söyleyin: değerlendirme kümesi olarak birkaç yüz belgeyi elle etiketleyin (değerlendirme verisi, eğitim verisinden çok daha ucuzdur), dönen her dizgiyi kaynağa geri hizalayın ve hizalanmayanları sayın. Yüksek hacimli ve durağan alanlar için eğitilmiş bir çıkarıcıya geçin; uzun kuyruktaki alanlar için üretimle devam edin.

Aranan cevap değerlendirme kümesidir. Prompt’u anlatıp susan adaylar böyle bir sistemi hiç üretimde çalıştırmamıştır.

S: Eğitim verinizde iki kez geçen bir varlık türünü nasıl ele alırsınız?

Bu tür için model eğitmezsiniz. Bir gazetteer veya bir kural yazın, onu yayına alın ve model eğitmeye yetecek kadar veri birikene dek örnek toplayın. Bu bölümdeki ölçüm — 200 cümlede 3,14 F1 — cevabın genel biçimidir: belirli bir bütçenin altında öğrenilmiş modeller elle yazılabilen bir listeden ya da kuraldan kötüdür ve o çizginin sizin göreviniz için nerede olduğunu bilmek asıl beceridir.

13.14 2026 araç çantası

Yukarıdaki her şey tek bir dizüstü bilgisayarda, aşağıdaki sürümlerle çalıştı.

Bu sayıların çıktığı yığın. Python 3.14.5, Apple Silicon
kütüphane kullanılan sürüm burada ne işe yaradı
datasets 5.0.1 WikiANN’i tek çağrıda yüklemek ve denetim (Bölüm 13.2)
sklearn-crfsuite 0.5.0 doğrusal zincirli CRF ve Viterbi kod çözme
transformers 5.15.1 BERTurk, AutoModelForTokenClassification ve hizalama için word_ids()
torch 2.13.0 fine-tuning’in üzerinde koştuğu MPS arka ucu
seqeval 1.2.2 referans span düzeyi puanlayıcı; yukarıdaki açık uygulamayı çapraz kontrol etmek için
ollama 0.24.0 Bölüm 13.8 için qwen3.5:9b sunmak

Yukarıda kullanılmayan ama bilmeye değer olanlar:

Daha geniş ekosistem, yazım anındaki sürümler
kütüphane güncel sürüm ne zaman kullanılır
spaCy 3.8.16 üretim NER hatları için pragmatik varsayılan: hızlı, Türkçe için dil sınıfı ve tokenizer’ı var (resmî eğitilmiş Türkçe hat yok; eğitilmiş hatlar topluluk kaynaklı) ve tokenizer, etiketleyici ile entity ruler’ı tek bir dağıtılabilir nesne olarak veriyor
spacy-llm 0.7.4 şema güdümlü yolu (Bölüm 13.8) bir spaCy hattının içinde kullanmak; prompt güdümlü bir bileşenle eğitilmiş bir bileşeni karıştırabilirsiniz
GLiNER 0.2.28 prompt yerine tür adlarından zero-shot NER (Zaratiana vd. 2024) — üretim gecikmesi yerine encoder gecikmesi; bkz. Bölüm 13.8
nervaluate 1.2.1 tam eşleşme, çıktınızı kullanan taraf için yanlış sözleşmeyse, MUC tarzı kısmi puan dökümü
Label Studio / doccano 1.23.0 / 1.8.4 span etiketleme arayüzleri; bu bölümdeki her projede darboğaz modelleme değil, etiketli veridir
pytorch-crf 0.7.2 etiket gramerinin model içinde öğrenilmesini istediğinizde bir transformer’ın üstüne koyacağınız CRF katmanı — geçiş puanları serbest parametredir, dolayısıyla iyi biçimliliği garanti eden şey yine kısıtlı kod çözmedir
outlines / jsonformer 1.3.3 / 0.12.0 sessizce yok sayılabilecek bir sunucu bayrağına güvenmek yerine kendi kontrolünüzdeki gramer kısıtlı kod çözme (Bölüm 18)
zeyrek 0.1.3 Türkçe morfolojik analiz; normalleştirme adımında (Bölüm 13.11) kesme işareti sezgiseli yetmediğinde

GLiNER, tablodaki yeri yüzünden gözden kaçabilir ama bir kez daha bakmaya değer; Bölüm 13.8 de ona bu ikinci bakışı ayırıyor. Tür açıklamalarını span’lerle eşleştirmek üzere eğitilmiş küçük bir encoder. Yani keyfî bir etiket kümesi üzerinde zero-shot bilgi çıkarma yapabiliyorsunuz, üstelik LLM gecikmesiyle değil, kabaca etiketleyici gecikmesiyle. Biz onu ölçmedik; bu bölümün zero-shot kısmında 1.200 kat gibi bir sayının bulunmasının sebebi de bu.

13.15 Lab: elinizdeki gerçek bütçeyle bilgi çıkarma

Bu labın dayanağı encoder ölçümü (Bölüm 13.6): küçük etiket bütçelerinde öğrenilmiş model, 20.000 cümleden kurulmuş bir listeye kaybediyor; kendi eğitim yarınızdan kuracağınız listeye kaybedip kaybetmediğini bu labda siz ölçeceksiniz. Dolayısıyla lab “bir transformer’ı fine-tune et” değil; “bütçenizin ne kazandırdığını, harcamadan önce öğrenin”.

Etiketli cümleleri kendiniz üretebileceğiniz bir alan seçin: destek talepleri, iş ilanları, maç raporları, bir kaynakça. İkinci bir kişinin de aynı şekilde etiketleyebileceği üç ila beş varlık türü belirleyin.

13.15.1 Adım 1 — hiçbir şey etiketlemeden önce kılavuzu yazın

Bir sayfa. Her tür için: bir tanım, üç olumlu örnek ve o tür olmayan üç yakın örnek. Bölüm 5’in argümanı tek cümlede: kural yazılı değilse etiketler tekrarlanabilir değildir ve model de etiketlediğiniz gün hangi ruh hâlindeyseniz onu öğrenir.

13.15.2 Adım 2 — 300 cümle etiketleyin, 150’sini test için ayırın

30 değil. Değerlendirme kümesi atlayamayacağınız kısımdır ve bu bütçede eğitim yarısından daha değerlidir — bir modeli daha fazla eğitim verisi olmadan iyileştirebilirsiniz, ama değerlendirme verisi olmadan ölçemezsiniz.

Test yarısını en son etiketleyin ve 6. adıma kadar bir daha bakmayın.

13.15.3 Adım 3 — tabanı ve gazetteer’ı hesaplayın

Önce her şeye O, sonra eğitim yarısındaki dizgiler üzerinde en uzun eşleşme. İki sayı, yarım saat — ve sonraki her sonucun geçmesi gereken iki sayı bunlar. Gazetteer’ın utandıracak kadar rekabetçi olmasını bekleyin.

13.15.4 Adım 4 — bir CRF eğitin ve özniteliklerin iş yapıp yapmadığını görün

Baseline’lar kısmındaki öznitelik şablonunu (Bölüm 13.5) kullanın. Sonra ablasyon yapın: sonek (suffix) özniteliklerini çıkarın, bağlam penceresini çıkarın, şekil özniteliğini çıkarın ve her seferinde F1’i kaydedin. Amaç son skor değil; modelinizde asıl işi hangi parçanın yaptığını bilmek.

13.15.5 Adım 5 — üç bütçede bir encoder fine-tune edin

Eğitim yarınızdan 50, 100 ve 150 cümle. Span F1’i bütçeye göre çizin. Encoder eğrisini (Bölüm 13.6) kendi verinizde yeniden üretiyorsunuz ve aranacak şey, eğrinin CRF’yi nerede kestiği, hatta kesip kesmediği.

13.15.6 Adım 6 — şema güdümlü çıkarıcı ve doğrulaması

Kılavuzunuzu prompt’a koyun ve çıktıyı bir şemayla kısıtlayın. Kısıtın gerçekten uygulandığını da doğrulayın: kısıt olmasa modelin şemayı ihlal edeceği bir istek gönderin. Dönen her dizgiyi kaynağa geri hizalayın. Üç sayı raporlayın: span F1, hizalanamayan varlık ifadelerinin oranı ve belge başına saniye.

13.15.7 Adım 7 — test kümesini bir kez açın

Beş sistemin hepsini ayrılmış (held-out) 150 cümlede puanlayın. Tek tablo, tek okuma. Tabloya güven aralığını da ekleyin (Bölüm 13.6’daki standart hata hesabı): 150 cümlede %95 aralık kolayca ±5 puana çıkar, yani birkaç puanlık farklar gürültüdür.

13.15.8 Neyi teslim edeceksiniz

Tablo ve yanında, hangi sistemi yayına alacağınızı ve bunun bin belge başına neye mal olacağını söyleyen bir paragraf. Gazetteer kazanırsa bunu söyleyin — bu bir sonuçtur ve 150 etiketli cümlede olası bir sonuçtur.

13.16 Alıştırmalar

  1. Bozuk bir diziyi elle çözün. Yedi token’lık bir cümle üzerinde O B-PER I-PER I-LOC O I-ORG B-ORG etiketlerini alın. Önce hoşgörülü bir kod çözücünün ürettiği span’leri, sonra katı olanınkini yazın. İkisi hangi token’larda anlaşamıyor ve her biri kaç span döndürüyor?

  2. Token düzeyi ve span düzeyi F1. Bir sistemin tahminlerini alın ve ikisini de hesaplayın. Farkı sınır hataları cinsinden açıklayın ve birincide iyi, ikincide sıfır alan bir tahmin kurgulayın.

  3. Hizalamayı bilerek bozun. Hizalama kısmındaki (Bölüm 13.4) kodu alın, word_ids() çağrısını çıkarın ve etiketleri alt kelimelere konum konum eşleştirin. 2.000 cümlede iki şekilde de eğitin ve iki skoru da raporlayın. Sonra verinizde iki etiketlemenin farklılaştığı en kısa cümleyi bulun ve yazdırın.

  4. Sızıntıyı kendiniz ölçün. Kullandığınız herhangi bir NER derlemindeki token dizilerinin hash’ini alın ve test/eğitim kesişimini raporlayın. Bu derlem CoNLL-2003 (Tjong Kim Sang ve De Meulder 2003), kendi derleminiz ya da başka bir dildeki WikiANN olabilir. Sonra ezberleyen bir baseline’ı sızmış ve temiz yarılarda ayrı puanlayın.

  5. Sonek ablasyonu. w[-3:], w[-2:] ve w.hasapos özniteliklerini CRF’den çıkarıp modeli yeniden eğitin. 85,45’in ne kadarı Türkçe yazıma özgü ipuçlarından (ekler, kesme işareti) geliyordu? Çalıştırmadan önce cevabı tahmin edin.

  6. Varlık ifadelerini normalleştirin. Herhangi bir sistemin çıkardığı varlık ifadelerini alın, kesme işaretinden sonrasını atarak birleştirin ve birleştirmeden önce ve sonra kaç farklı varlığınız olduğunu sayın. Sonra sezgiselin yanlış işlediği bir varlık ifadesi bulun. Böyle ifadeler vardır ve birini tarif etmek alıştırmanın ta kendisidir.

  7. İç içe geçme, kâğıt üzerinde. Kendi alanınızdan, iç içe varlık içeren beş cümle yazın. Önce BIO ile, sonra span sayımı formatıyla kodlayın ve BIO’nun neyi kaybettiğini söyleyin.

13.17 Daha derine inmek için

Her şeyden önce: benchmark’ınızda eğitim/test örtüşmesi olup olmadığını kontrol edin. Bu birkaç satırlık bir iştir. Bu bölümün yaptığı ilk şey de buydu ve sonraki her sayının nasıl okunması gerektiğini değiştirdi.

Makalelerin ötesi
kaynak nedir
seqeval herkesin kullandığı span düzeyi puanlayıcı; “F1”in burada ne demek olduğunu görmek için okuyun, çünkü token doğruluğu değil
flair eğitim döngüsü okunabilir, güçlü dizi etiketleme modelleri ve iyi bir baseline kaynağı
spaCy course ücretsiz, etkileşimli; kuralla istatistiği birleştiren, çalışan bir bilgi çıkarma hattına giden en hızlı yol
CMU CS11-711 Advanced NLP modelleme varsayımlarını açıkta bırakarak yapılandırılmış tahmini işleyen ders materyalleri
Hugging Face token-classification bölümü bu bölümde kullanılan encoder için fine-tuning yolu; hataların çoğuna sebep olan etiket hizalama adımı dâhil
CS224N ders serisi — Stanford dizi modellerini ve yapılandırılmış tahmini, varsayımları tahtada açıkça kurarak işleyen ücretsiz dersler
Birincil kaynaklar
konu kaynak
etiket dizisini bütün olarak puanlayan yapılandırılmış model Lafferty vd. (2001); Viterbi (1967)
etiketleme şeması ve alternatifleri Ratinov ve Roth (2009); Tjong Kim Sang ve De Meulder (2003)
yapay sinir ağı tabanlı dizi etiketlemenin yerleşmiş hâli Lample vd. (2016)
burada kullanılan çok dilli benchmark ve nasıl kurulduğu Pan vd. (2017); Rahimi vd. (2019)
BIO’nun ifade edemediği iç içe varlıklar Yu vd. (2020); Li vd. (2020)
NER’de ezberlemeye karşı genelleme Elangovan vd. (2021)
bir varlık ifadesini gerçek bir varlığa bağlamak Hoffart vd. (2011)
bundan sonraki görev: ilişki çıkarma Zhang vd. (2017)
yoğun erişimle ölçeklenebilir varlık bağlama Wu vd. (2020)

13.18 Akılda kalması gerekenler

  • Tabanı hesaplayın. Her şeye O demek bu derlemde %61,36 token doğruluğu ve 0,00 span F1 alıyor; çoğu cümlesinde hiç varlık olmayan gerçekçi bir derlemde daha da yükseğini. Dizi etiketlemedeki her token doğruluğu sayısı, o tabana olan uzaklık olarak okunmalı — ve o uzaklık genellikle öne çıkarılan sayının ima ettiğinden küçüktür.

  • Span düzeyinde F1 raporlayın. Token doğruluğu 94,41, token düzeyinde F1 88,73, span düzeyinde F1 85,45 — aynı tahminler, üç cevap. Yalnızca sonuncusu kaydın doğru çıkıp çıkmadığını soruyor.

  • Skora güvenmeden önce derlemi denetleyin. WikiANN’in Türkçe bölümünde test kümesinin %13,06’sı eğitimde birebir geçiyor. Ham sızıntı primi, sistemin ezberleme eğilimi azaldıkça düşüyor: gazetteer için +26,50, CRF için +16,25 (sızmışta 99,81’e karşı temizde 83,56), fine-tune edilmiş encoder için +7,65. Temiz yarının bıraktığı boşluğa göre normalleştirildiğinde ise sıra değişiyor (CRF %99 ile en üstte). Bu yüzden farkı bir ezber ölçüsü değil, bir teşhis aracı olarak okuyun: büyükse daha dikkatli bakın. Test girdilerinizin hash’ini alın; bu dört satırlık bir iş.

  • Klasik baseline bir formalite değil. Bir Python sözlüğünden ibaret, 20.000 cümleden kurulmuş bir gazetteer 55,26 alıyor; elle tasarlanmış özniteliklerle çalışan bir CRF ise bir CPU’da 18,5 saniyede 85,45. Fine-tune edilmiş BERTurk, 20.000 cümleyle eğitilmiş CRF’yi yakalamak için 2.000–5.000 etiketli cümleye ihtiyaç duyuyor ve tam bütçede 91,92’ye ulaşıyor. Bu hem gerçek bir tasarruf hem de gerçek bir eşik: bu eşiğin altında transformer, 20.000 cümlelik CRF’den daha kötü modeldir. Aynı küçük bütçede eğitilmiş bir CRF ile karşılaştırmayı ise ölçmedik.

  • Varsayılan tarifle 200 etiketli cümle tek haneli span F1 kazandırdı — üç epoch’luk (39 güncelleme) tek koşumuzda 3,14; bu takvim küçük bütçeleri aç bırakıyor, o yüzden ondalıkları değil büyüklük mertebesini okuyun. O bütçede fine-tune edilmiş encoder O demeyi öğrendi; 20.000 cümleden kurulmuş bir liste ise onu elli puan geçti (200 cümleden kurulacak bir listenin farkı daha küçük olur; onu ölçmedik). “Sadece bir transformer’ı fine-tune et” tavsiyesinin bir bütçesi — ve bir eğitim takvimi — vardır; ikisinin de ne olduğunu sorun.

  • Kod çözme, farkında olsanız da olmasanız da verdiğiniz bir karardır. Tam bütçedeki softmax etiketleyici, 10.000 cümlede 139 yasak BIO geçişi üretti — 500 cümlelik bütçede 3.739. 20.000 cümlelik CRF ise hiç yasak geçiş üretmedi, çünkü Viterbi bütün dizileri puanlıyor ve destekleyen özniteliği olmayan bir yasak geçiş kazanan yola girmedi. Ama bu bir garanti değil, ampirik bir sıfır; garanti gerekiyorsa geçişleri aramadan çıkarın. Değerlendirmenizin o 139’a ne yaptığı, raporladığınız F1’i değiştirir ve uzlaşım çoğu makalede belirtilmez.

  • Sessiz hatalar hizalamada saklanır. Varlık kelimeleri BERTurk’te kelime başına 1,98 alt kelimeye bölünüyor; sıradan kelimeler 1,45’e. İsimler nadirdir, tokenizer da onları parçalara böler. word_ids()’i yanlış kullanırsanız model yine eğitilir, kayıp yine düşer ve etiketler yanlış token’lara bağlanır.

  • Bir şema biçimi garanti eder, doğruluğu asla. ollama 0.24.0, /api/chat üzerinde bir JSON şemasını sessizce yok sayarken /api/generate üzerinde uyguladı — çalıştırıcıya bağlı, bilinen bir hata sınıfı — ve uygulanan çağrı, Fransa’nın başkenti için memnuniyetle {"answer": 1} döndürdü. Modelin aksi hâlde başaramayacağı bir istek gönderin ve kontrol edin.

  • Zero-shot bilgi çıkarma başlangıç noktasıdır, bitiş noktası değil. Aynı 1.000 cümlede: hiç etiket olmadan LLM 60,57 span F1, gazetteer 54,90, CRF 84,16, fine-tune edilmiş encoder 91,44 — ve LLM cümle başına kabaca 1.200 kat daha yavaş. Sözlüğü geçiyor, on sekiz saniyelik CRF’ye 24 puan kaybediyor. En kötü sınıfı 40,10 ile ORG recall’u, çünkü bir prompt, 20.000 etiketli örneğin öğrettiği sınır uzlaşımını kodlayamaz.

  • LLM dizgi döndürür; metrik konum ister. Her varlık ifadesinin kaynağa geri hizalanması gerekir ve o adım, kendi hatalarınızı sessizce başkasına mal edebileceğiniz yerdir: buradaki 31 hizalama başarısızlığının 27’si modelin değil, hizalayıcının hatasıydı. Hizalayıcıyı düzeltmek F1’i 0,28 puan oynattı; yani kontrol edin, ama bu adımın kötü bir sayıyı açıklamasını beklemeyin.

Bir sonraki bölüm (Bölüm 14) çıktıyı kayıttan metne taşıyor: bir özeti karşılaştırabileceğiniz tek bir referans span’i yok ve ölçüm sorusu bu yüzden zorlaşıyor.