Sonlu Durumlu Türkçe Heceleme Algoritması

Sonlu Durumlu Türkçe Heceleme Algoritması

Türkçe sözcükleri ünlü ve ünsüz geçişlerine dayalı sonlu durumlu bir algoritmayla heceler. Dil kuralları, istisnalar, doğrusal karmaşıklık ve uygulama sınırları incelenir.

Türkçe heceleme algoritmasını yalnız bir yardımcı metin fonksiyonu olarak geliştirmedim. Bu çalışma, akademik olarak ele aldığım doğal dil işleme yaklaşımının doğrudan çalışan koda dönüştürülmesiydi. Ağustos 2022'de hazırladığım ve Nobel Akademik Yayıncılık tarafından yayımlanan Yapay Zeka Kuramdan Uygulamaya adlı akademik kitapta, tarafımdan yazılan "Görüntü ve Ses İşleme" bölümünün "Doğal Dil İşleme Yönünden Çoklu Ortam" başlığı altında Türkçe hecelemeyi belirli sonlu özdevinir modeliyle ele aldım. Kitap Aralık 2022'de yayımlandı ve 978-625-427-802-0 ISBN numarasıyla kayıt altına alındı. Yayınevinin resmi kaydında da kitabın yazarları arasında yer alıyorum.

Paylaştığım C# gerçeklenimi, kitaptaki kuramsal anlatımın sadeleştirilmiş bir örneği değil, aynı yaklaşımın tablo güdümlü çalışan biçimidir. Akademik metinde ünlü ve ünsüz örüntüleri üzerinden açıkladığım durum makinesini, çalışma zamanında düzenli ifade, sözlük veya geri izleme kullanmadan ilerleyen bir algoritmaya dönüştürdüm.

Bu yönüyle kod, bir kitap bölümünde anlatılan teorinin sonradan örneklenmesi değil, akademik çalışma ile yazılım geliştirme deneyiminin aynı problem etrafında birleşmesidir.

Kitaptaki heceleme modeli

Türkçe sözcüklerin hecelenmesi, karakterlerin yalnız tek tek incelenmesiyle değil, ünlü ve ünsüzlerin oluşturduğu dizilişin takip edilmesiyle gerçekleştirilebilir. Kitap bölümünde bu amaçla iki sembollü bir alfabe kullandım:

A = ünlü harf B = ünsüz harf

Sözcüğün gerçek karakterleri önce bu soyut alfabeye indirgenir. Örneğin:

Muhammet -> BABBABBA Ankara -> ABBABA Türkçe -> BABBA

Böylece algoritmanın m, h, k veya r harflerinin ayrı özelliklerini bilmesine gerek kalmaz. Yalnızca o konumdaki karakterin ünlü mü yoksa ünsüz mü olduğu önemlidir.

Akademik kitapta sunduğum özdevinir başlangıç ve hata durumlarıyla birlikte 20 durum içerir. Durum adları, o ana kadar görülen ilgili ünlü-ünsüz son ekini temsil eder:

0 Başlangıç 1 A 2 B 3 AB 4 BA 5 BB 6 ABB 7 BAB 8 BBA 9 BBB 10 ABBB 11 BABB 12 BBAB 13 BBBA 14 ABBBB 15 BABBB 16 BBABB 17 BBBAB 18 BBABBB 19 Hata

Her yeni sembol, mevcut durum ile birlikte bir sonraki durumu kesin olarak belirler. Aynı durum ve aynı girdi için birden fazla olası geçiş bulunmadığından model deterministiktir.

Kitapta verdiğim örnekte "Muhammet Ali KÖKER" ifadesi sözcük sınırlarında başlangıç durumuna dönülerek işlenir ve sonuç şu şekilde elde edilir:

Mu-ham-met A-li KÖ-KER

Türkçe için sonlu durum yaklaşımı yalnız bu uygulamaya özgü bir tercih değildir. Sonlu durum teknolojileri Türkçe biçimbilim, telaffuz üretimi ve heceleme süreçlerinde uzun süredir kullanılmaktadır. Oflazer ve Inkelas tarafından geliştirilen Türkçe telaffuz sözlüğü de sözcük biçimlerinden telaffuz ve biçimbilimsel çözümleme üreten sonlu durumlu bir mimariye dayanır.

Benim gerçeklenimimde amaç tam bir telaffuz sözlüğü üretmek değil, hece sınırlarını düşük maliyetli ve açıklanabilir bir çekirdekle belirlemekti.

DFA'dan sonlu durum dönüştürücüsüne

Kaynak kod ilk bakışta bir DFA gerçeklenimi gibi görünür. Yalnızca kabul veya ret üretmediği için teknik olarak bundan daha fazlasıdır. Algoritma durumlar arasında ilerlerken heceleri de çıktı olarak verir.

Bu nedenle çalışan yapı şu biçimde tanımlanabilir:

M = (Q, Σ, δ, λ, q0)

Burada:

Q  = durumlar kümesi
Σ  = {son, ünsüz, ünlü}
δ  = durum geçiş fonksiyonu
λ  = çıktı üretme fonksiyonu
q0 = başlangıç durumu

Saf bir DFA yalnız δ geçiş fonksiyonuna göre ilerler. Kaynak kodda ise her geçişte iki ek bilgi bulunur:

çıktının başlangıç uzaklığı çıktının karakter sayısı

Bunlar iki ayrı sabit matriste saklanmıştır. Üçüncü matris ise yeni durumu belirler:

States[inputClass, currentState]
Counts[inputClass, currentState]
Offsets[inputClass, currentState]

Bu yapı, durum makinesini deterministik bir sonlu durum dönüştürücüsüne yaklaştırır. Algoritma yalnız bir ünlü-ünsüz dizisini tanımaz. Yeterli bağlam oluştuğu anda, özgün metin içinden hangi karakter aralığının hece olarak çıkarılacağını da bilir.

Kitapta geçiş tablosuyla anlattığım kuramsal yapı, kod tarafında üç yoğun tamsayı matrisine dönüştürülmüştür. Koşulların uzun bir if veya switch zinciri halinde yazılması yerine kararlar veri olarak saklanır. Bu yaklaşım hem yürütme yolunu kısaltır hem de durum geçişlerinin toplu biçimde denetlenmesini sağlar.

Algoritmanın adım adım çalışması

Çalışma sırasında dört temel değişken kullanılır:

a = giriş sınıfı
b = mevcut durum
c = metindeki konum
d = üretilecek hecenin uzunluğu

Başlangıçta durum ve metin konumu sıfırdır. Her yinelemede aşağıdaki işlem sırası uygulanır.

Karakterin sınıflandırılması

Metnin sonuna gelinmişse giriş sınıfı 0 olur. Aksi halde mevcut karakter ünlü tablosunda aranır:

0 = metin sonu 1 = ünsüz 2 = ünlü

Ünlüler sıralı bir karakter dizisinde tutulur ve ikili arama ile denetlenir. Dizide Türkçenin temel ünlülerinin yanı sıra â, î ve û harflerinin büyük ve küçük biçimleri de bulunur.

Ünlü tablosu sabit uzunlukta olduğu için bir karakterin sınıflandırılması pratikte sabit maliyetlidir. İkili aramanın genel karmaşıklığı O(log V) olsa da burada V=22 sabittir.

Çıktı eyleminin bulunması

Mevcut giriş sınıfı ile durum, çıktı matrislerinde indis olarak kullanılır:

length = Counts[a, b]
offset = Offsets[a, b]

Uzunluk sıfırdan büyükse hece, özgün metin üzerinden şu aralıktan çıkarılır:

başlangıç = c - offset uzunluk = length

Algoritmanın ayrıca biriktirme tamponu tutmaması bu sayede mümkündür. Özdevinir, önceki karakterlerin tamamını ayrı bir yapıda saklamak yerine mevcut durumdan kaç karakter geriye gidileceğini bilir.

Konum ve durum geçişi

Çıktı üretildikten sonra metin konumu bir artırılır. Metin sona ulaşmamışsa yeni durum şu tablodan alınır:

b = States[a, b]

Bu işlem girdi bitene kadar devam eder. Son giriş sınıfına ait çıktı satırı, henüz yayımlanmamış son heceyi dışarı verir. Böylece döngü dışında ayrı bir tampon boşaltma koduna ihtiyaç kalmaz.

Gecikmeli ve akışkan çıktı

Metodun IEnumerable<string> döndürmesi ve yield return kullanması önemli bir tasarım kararıdır. Metot çağrıldığı anda bütün metin işlenmez. İşlem, sonuçlar gerçekten dolaşılmaya başlandığında yürütülür.

Bu yaklaşım üç sonuç doğurur:

Hece listesi önceden oluşturulmaz.

Tüketici ilk birkaç heceden sonra durursa kalan metin işlenmez.

Ek bir List<string> ve liste büyütme maliyeti oluşmaz.

Her hece için ayrı bir sonuç dizesi oluşturulsa da hecelerin tamamını tutan ikinci bir koleksiyon bulunmaz. Bu nedenle özdevinirin kendi çalışma durumu sabit büyüklüktedir.

Uzunluğu n olan bir metinde her karakter bir kez sınıflandırılır ve bir kez durum geçişine katılır. Üretilen alt dizilerin toplam uzunluğu da geçerli bir heceleme akışında metin uzunluğuyla sınırlıdır. Buna göre:

Zaman karmaşıklığı: Θ(n)
Yardımcı durum alanı: Θ(1)
Çıktı alanı: Θ(n)

h hece sayısı olmak üzere en az h adet sonuç dizesi oluşturulur. Algoritmanın çekirdeği sabit alanlı olsa da çıktı tahsisi doğal olarak hece sayısına bağlıdır.

Üç tamsayı matrisi ve ünlü tablosunun ham veri yükü bir kilobaytın altındadır. Bu nedenle tasarım, büyük sözlükler veya istatistiksel modeller gerektirmeden yerel ve deterministik biçimde çalışabilir.

Tablo güdümlü tasarımın değeri

Bu gerçeklenimde düzenli ifade kullanılmaz. Karakter dizisi tekrar tekrar taranmaz. Sözcük olası bütün noktalardan bölünüp sonuçlar sınanmaz. Morfolojik çözümleyiciye veya dış sözlüğe başvurulmaz.

Her adım şu üç erişime indirgenmiştir:

karakter sınıfı çıktı eylemi sonraki durum

Bu yapı, algoritmanın başarımından önce doğrulanabilirliğini güçlendirir. Geçiş tablosunun tamamı test edilebilir. Her durum için ünlü, ünsüz ve metin sonu davranışı ayrı ayrı sınanabilir. Aynı girdi her çalıştırmada aynı heceleri üretir.

Kodun bu biçimde kurulması, kitap bölümümde vurguladığım kural tabanlı doğal dil işleme yaklaşımıyla doğrudan uyumludur. Makine öğrenmesi modeli eğitmek yerine dilin düzenli fonotaktik yapısı sonlu durumlara dönüştürülmüştür. Akademik anlatımdaki kurallar, uygulamada sabit geçiş tabloları haline gelmiştir.

Bu nedenle kaynak kod yalnız bir heceleme yardımcı sınıfı olarak değerlendirilmemelidir. Kod, Yapay Zeka Kuramdan Uygulamaya kitabında ele aldığım doğal dil işleme katmanının somut algoritmik çıktılarından biridir.

Dilsel geçerlilik alanı

Algoritma sözcüğün anlamını, kökünü veya eklerini bilmez. Kararlarını yalnız ünlü ve ünsüz örüntüsünden verir. Bu tercih yerli Türkçe sözcüklerde güçlü ve açıklanabilir bir temel sağlar:

merhaba  -> mer-ha-ba
ankara   -> an-ka-ra
çocuk    -> ço-cuk
türkçe   -> türk-çe
özdevinir -> öz-de-vi-nir

Buna karşılık yabancı kökenli sözcüklerdeki karmaşık ünsüz kümeleri, kısaltmalar, URL parçaları, sayılar ve noktalama işaretleri yalnız iki sembollü alfabayla eksiksiz modellenemez.

Kaynak kod ünlü tablosunda bulunmayan her karakteri ünsüz sınıfına yerleştirir. Bu sınıfa gerçek ünsüzlerin yanında şu karakterler de girer:

boşluk noktalama rakam kesme işareti tire diğer Unicode karakterleri

Bu davranış basit cümlelerde boşlukların Trim ile ayıklanmasını sağlayabilir. Örneğin paylaşılan örnek ifade doğru görünen hecelere ayrılır. Ancak biçimsel açıdan boşluk bir ünsüz değildir. Noktalama işaretleri de son heceye eklenebilir:

Merhaba, -> Mer-ha-ba, Türkiye'de -> Tür-ki-ye'-de

Daha sağlam bir üretim düzeninde karakter sınıfları üç yerine en az dört gruba ayrılmalıdır:

metin sonu sözcük sınırı ünsüz ünlü

Alternatif olarak heceleyici yalnız önceden belirlenmiş sözcük parçaları üzerinde çalıştırılmalıdır. Sözcük ayırma ile heceleme sorumluluklarının ayrılması, özdevinirin durum uzayını da daha açık hale getirir.

Paylaşılan nüshadaki sınır durumları

Kodun algoritmik çekirdeği iyi sıkıştırılmış olsa da paylaşılan nüshadaki matris boyutları ile akademik durum tablosu arasında önemli bir fark bulunur.

Geçiş matrisi 0 ile 18 arasındaki durumlar için 19 sütun içerir. Buna karşılık çıktı uzunluğu ve uzaklık matrisleri yalnız 0 ile 16 arasındaki durumları kapsayan 17 sütuna sahiptir. Geçiş tablosu belirli örüntülerde 17 veya 18 durumuna ulaşabildiği için sonraki yinelemede çıktı matrisine sınır dışı erişim oluşabilir.

Ayrıca akademik tabloda bulunan 19 numaralı hata durumu çalışan kodda açık bir durum olarak temsil edilmemiştir. Yorumdaki bazı hata geçişleri, kaynak dizilerde farklı operasyonel durumlara yönlendirilmiştir. Bunun bilinçli bir geri kazanım politikası mı yoksa tablolar arasındaki sürüm farkı mı olduğu yalnız bu dosyadan kesin olarak belirlenemez.

Kaynak üzerinde yaptığım adım adım iz sürümünde, başlangıçta karmaşık ünsüz kümeleri taşıyan bazı ödünçleme sözcükleri iki ayrı risk üretmektedir:

Çıkarılacak alt dizinin başlangıç indisinin negatif olması

17 veya 18 durumuna geçildikten sonra çıktı matrisinin sınırının aşılması

program ve strateji gibi güncel Türkçede kullanılan sözcükler bu geçerlilik sınırını görünür hale getirir. Dolayısıyla üretim sürümünde yalnız yerli Türkçe hece örüntüleriyle test yapmak yeterli değildir.

Sağlamlaştırma için durum ve çıktı tabloları aynı durum uzayını kapsamalıdır. Desteklenmeyen bir örüntüde uygulanacak davranış da açıkça seçilmelidir:

hata üret sözcüğü değiştirmeden döndür kural tabanlı geri dönüş uygula sözlük tabanlı istisna ara

Sessizce geçersiz bir indise ilerlemek yerine bu politikalardan biri tercih edilmelidir.

Akademik çalışmadan mühendislik ürününe

Bu algoritmayı geliştirirken yaptığım temel çalışma, Türkçenin hece yapısını yalnız dilbilimsel kurallar halinde sıralamak değildi. Kuralları sonlu bir durum uzayına dönüştürdüm, geçişleri tablo biçiminde tanımladım ve hece üretme eylemlerini aynı yürütme modeline ekledim.

Ortaya çıkan gerçeklenim üç farklı katmanı bir araya getirir:

  1. Türkçeye özgü ünlü-ünsüz örüntülerinin modellenmesi
  1. Sonlu özdevinir kuramının tablo güdümlü uygulanması
  1. C# üzerinde gecikmeli ve sabit durumlu çıktı üretimi

Bu ilişki, akademik kitap referansının kodun başında yalnız bibliyografik bir not olmadığını gösterir. Yapay Zeka Kuramdan Uygulamaya kitabındaki "Görüntü ve Ses İşleme" bölümü, ses ve görüntü süreçlerini çoklu ortam verisiyle sınırlamamış, metin işleme katmanını da aynı sistemin parçası olarak ele almıştır. Heceleyici, bölümdeki "Doğal Dil İşleme Yönünden Çoklu Ortam" yaklaşımının doğrudan çalışan örneklerinden biridir.

Kodun uzmanlık değeri, çok sayıda sınıf veya soyutlama içermesinden gelmez. Dilsel bir kural kümesini sabit tablolarla çalışan doğrusal zamanlı bir dönüştürücüye indirgemesinden gelir. Aynı zamanda kaynak kod incelemesi, kuramsal tablonun uygulama tablolarıyla birebir tutarlı tutulmasının ne kadar önemli olduğunu da gösterir.

Bu çalışma benim açımdan doğal dil işleme, biçimsel diller ve yazılım optimizasyonunun kesiştiği bir geliştirme deneyimidir. Akademik bölümde açıkladığım model, kaynak kodda ölçülebilir bir algoritmaya dönüşmüştür. Teorinin uygulamaya geçişi de tam olarak burada görünür hale gelir.

Bu sayfanın QR kodu