Python kodum bir sinir ağı
(blog.gabornyeki.com)- Belirsiz bilgi çıkarma programları, istisna kuralları biriktikçe kolayca spagetti koda dönüşür; bu tür durum tabanlı mantık, yinelemeli sinir ağları (RNN) olarak yeniden düşünülebilir
- Kod inceleme mesajlarında C kodu referanslarını bulma örneği,
identifier–open_paren–close_parengibi token desenlerini durum olarak izleyen el yazımı bir sınıflandırıcıyla uygulanır - Bu kural örnekte %100 kesinlik gösterse de
if (err) goto cleanup;gibi vakaları kaçırdığı için duyarlılık %50'de kalır ve kural eklendikçeStateile dallanma ifadeleri karmaşıklaşır - Aynı durum makinesi, RNN'in gizli durumu ve katman hesaplamalarıyla kodlanabilir; bunu öğrenilebilir hale getirmek için ikili gösterge fonksiyonları yerine ReLU·sigmoid ve öğrenilebilir ağırlıklar·bias'lar gerekir
- PyTorch'taki Elman RNN, GRU, LSTM gibi uygulamalar ve uzun token dizilerindeki gradyan sönmesi sorunu, gerçek öğrenmenin kısıtları haline gelir; veri kümesini·etiketleri·kayıp fonksiyonunu belirleme sürecinin kendisi de el yapımı kural tasarımına yardımcı olur
Belirsiz veri çıkarımının nasıl spagetti koda dönüştüğü
- Ham veriden bilgi çıkaran araştırma programlarında, veri açık bir spesifikasyona uymadığında veya sıra dışı biçimler aldığında kurallar hızla karmaşıklaşır
- Örnek görevler arasında haber makalelerinde şirketleri ve yöneticileri tanımlamak, kamu tedarik sözleşmelerini hizmet türüne göre etiketlemek ve mühendis mesajlarının içinde program kodu olup olmadığını belirlemek yer alır
- Mükemmel çıktı isteniyorsa her gözlem dikkatle incelenebilir ve temsilî örnekler için birim testleri yazılabilir
- Hem R hem de Python bunun için test kütüphaneleri sunar
- Takma adlar, eşanlamlılar, İngilizce ile kod arasındaki sınır gibi karmaşık karar kuralları gereken durumlarda el yapımı kurallar kolayca kırılgan hale gelir
- Sinir ağı öğrenme algoritmaları, bu tür kural birleşimlerini insanların sürekli ayarlaması yerine veriden bulma yönünde problemi değiştirir
Kod inceleme mesajlarında kod referanslarını bulmak
- Amaç, kod incelemesi sırasında gönderilen bir mesajın program koduna açıkça atıf yapıp yapmadığını tespit etmektir
- İncelenen kod tabanının C ile yazıldığı varsayılır
- Temsilî mesajlar şu tür kod referansları içerir
render_ipa_alloc()FTPSACKdebug_error()NULLIS_ERROR()aarch64,amd64if (err) goto cleanup;
- Basit kural adaylarının her biri farklı biçimde başarısız olur
- Bir kelimeden sonra parantez gelirse bunu kod sayan kural,
render_ipa_alloc()gibi durumları yakalar amaif (err) goto cleanup;ifadesini kaçırır - Tamamı büyük harfli kelimeleri kod sayan kural,
FTPSACKveIS_ERROR()örneklerini yakalar amaAFAICTgibi kısaltmaları yanlış pozitif olarak işaretler - İngilizce olmayan kelimeleri kod sayan kural, mühendislik terimlerini veya mimari adlarını da yanlışlıkla kod olarak işaretleyebilir
- Bir kelimeden sonra parantez gelirse bunu kod sayan kural,
- Kural 2 ve Kural 3'ü iyileştirmek için
AFAICT,LGTM,USD,COVID,aarch64,amd64gibi kısaltma ve uzmanlık terimlerinden oluşan listeler gerekir
El yazımı durum makinesiyle yapılmış sınıflandırıcı
- Basit algoritma, bir mesajda kod olup olmadığını iki adımda belirler
- Ön işleme: Mesajı, C kodunun sözdizimsel öğelerini yansıtan bir token dizisine dönüştürür
- Çıkarım: Token dizisinin kuralları sağlayıp sağlamadığını kontrol eder
- Kural 1,
underscore_identifier–open_paren–close_parendesenini kod referansı olarak değerlendirir - Python uygulaması, önceki token durumunu saklamak için
Stateveri sınıfını kullanırprevious_was_identifierprevious_was_open_parenprevious_previous_was_identifierseen_code
contains_code, token'lar üzerinde dolaşırkenprocessfonksiyonunu çağırır ve sonundastate.seen_codedeğerini döndürürprocess, mevcut tokenclose_parenise, bir önceki tokenopen_parenve ondan önceki de tanımlayıcıysaseen_codedeğeriniTrueyapar- Bu sınıflandırıcı örnekte yanlış pozitif üretmez ve %100 kesinlik gösterir; ancak çok sayıda örneği kaçırdığı için duyarlılık %50'de kalır
- Kural 2 eklendiğinde
Statealanları ileif/elif/elsedalları artar ve kurallar daha fazla rafine edildikçe bakım zorlaşır
Durum makinesini RNN'e taşımak
contains_codeveprocess, birer durum makinesidir ve durum makineleri yinelemeli sinir ağları (RNN) ile kodlanabilir- RNN, token dizisini teker teker işleyerek mesajın kod içerme koşullu olasılığını yaklaşıklar
- Python'daki
Statekarşılığı olan değerler, RNN'in gizli durumu olarak ifade edilirState_0başlangıç durumudur- Her
State_t, mevcut token ile önceki durumuffonksiyonuna vererek hesaplanır - Son durum, çıktı katmanı
güzerinden geçerek sınıflandırma sonucuna dönüşür
- Örnek RNN üç gizli katman kullanır
- Birinci katman, mevcut token ile önceki durumu saklar veya kopyalar
- İkinci katman, Kural 1'e karşılık gelen deseni kontrol eder
- Üçüncü katman, daha önce bir kod deseni görülüp görülmediğini hatırlar
- Token'lar one-hot biçiminde ikili vektörlerle temsil edilir
- El yazımı algoritmayı birebir taklit etmek için ikili gösterge fonksiyonu
1{x > 0}kullanılabilir- Gizli katmanlar ikili değerlerde tutulabilir
- Ancak türevi neredeyse her yerde 0 olduğu için öğrenmeye uygun değildir
- Desen,
identifier,open_paren,close_parençarpımıyla da kontrol edilebilir; ancak ikili gizli katmanlarda aynı kontrol toplamla ifade edilebilir - Giles et al. (1992), durum makinelerini keşfetmek için second-order RNN kullanan bir örnekle bağlantılıdır
Öğrenilebilir bir ağa dönüştürmek
- Öğrenme için ikili gösterge fonksiyonu yerine ReLU kullanılır
- Sayısal sabitler ağırlıklar ve bias'larla değiştirilir ve gradyan inişi bu parametreleri tahmin eder
- Çıktı katmanı, son olasılık değerini hesaplamak için sigmoid aktivasyon fonksiyonunu kullanır
- Bu biçim PyTorch'a konup eğitilebilir, ancak doğrudan bu haliyle eğitildiğinde performansı çok yüksek olmaz
- Bunun nedenlerinden biri, mimarinin genel amaçlı olmaması ve öğrenme sürecinin daha büyük bölümünün Python bağlayıcı kodunda çalışarak PyTorch'un C++ kütüphane uygulamalarından daha az yararlanmasıdır
PyTorch uygulaması ve uzun mesajların kısıtları
- PyTorch'un torch.nn.RNN modülü, Elman RNN tabanlı bir uygulama sunar
- Örnek mimari ile Elman RNN'in gizli katman bağlantı yapıları farklıdır
- Örnek mimaride token
tiçin birinci katman, tokent-1in üçüncü katmanını girdi olarak alır ve her katman yalnızca bir önceki katmandan girdi alır - Elman RNN'de her gizli katman, aynı katmanın önceki zaman adımındaki durumunu da girdi olarak alır
- Elman RNN'in birinci gizli katmanı, önceki zaman adımının son katmanını girdi olarak almaz
- Örnek mimaride token
- Gerçek kod inceleme mesajları uzun olabilir ve uzun mesajlar uzun token dizilerine dönüşür
- Uzun dizilerde, gradyan inişi teorik olarak çalışsa bile gradyan sönmesi nedeniyle sayısal kararlılık sorunları ortaya çıkabilir
- Elman RNN de bu probleme açık olabilir; GRU veya LSTM, kod tespit görevinde daha iyi performans verebilir
Veri odaklı disiplin
- RNN'ler, elle yönetilmesi zor kural birleşimlerini öğrenme problemine dönüştürür ve problem tanımını daha açık hale getirmeye zorlar
- Bir ağı eğitmek için şunlar gerekir
- Eğitim veri kümesi ve doğrulama veri kümesinin seçilmesi
- Ön etiketleme
- Sınıflandırıcının neyi başarması ve nelerden kaçınması gerektiğini belirten kayıp fonksiyonu
- Bu süreç, öngörülmeyen gri alanları ortaya çıkarır ve karar ölçütlerini daha net hale getirir
- Bu veri odaklı disiplin, problem sinir ağıyla değil el yazımı algoritmalarla çözülse bile faydalıdır
1 yorum
Hacker News görüşleri
Bu yazı testlerden ya da eğitim verisi elde etmekten pek bahsetmiyor; oysa kilit nokta bu gibi görünüyor.
Anladığınızı hissettiğiniz kod, tüm girdilere genellenen bir özelliği en azından gayriresmî biçimde kendi içinde kanıtladığınız koddur. Örneğin bir sıralama algoritması yalnızca test ettiğiniz listeleri değil, her listeyi sıralar.
Sinir ağlarında belirsiz olan nokta, nasıl genelleneceklerini bilmememizdir. Görülmemiş bir girdi biraz farklı olduğunda garantili bir özellik yoktur; hatta en başta istediğiniz özelliği matematiksel olarak belirtmesi zor bir problem de olabilir.
Bir özelliği QuickCheck gibi özellik tabanlı testlerde kullanacak kadar net tanımlayabiliyorsanız, rastgeleleştirme yoluyla çok sayıda test ya da eğitim verisi üretebilirsiniz. İstenen tek bir örnekten başlayıp olumlu/olumsuz örneklerin olası varyasyonlarını üreten testler yazmanız yeterli.
Bu bir kanıt değildir ama bir başlangıç noktasıdır. En azından kanıtlayabiliyorsanız, neyi kanıtlamanız gerektiğini bilirsiniz.
Böyle bir şey varsa, spagetti koda dayanmakla sinir ağına dayanmak oldukça benzer görünür. Başka özellikleri de sağlamak istiyorsanız bir özellik tabanlı test daha yazarsınız. Sinir ağını doğrudan değiştirmek yerine eğitebilirsiniz; ama kod değişiklikleri için de yapay zeka destekleri var.
Yine de koda daha çok güvenirdim. En azından debugging yapılabiliyor.
Pratik işler yapan sinir ağları oluşturmanın bir yolu olarak okununca ilginç bir yazı. Ama bir dahaki sefere bir girdiyi ayrıştırmam gerektiğinde bu yöntemi aynen izleyeceğinizi söylerseniz, açıkçası ne diyeceğimi bilemem.
Yazar, gevşek tanımlı kalıplara sahip keyfî girdileri ayrıştırma gibi zor bir problemi ele alıyor ve bunun okunması zor spagetti kod üretme ihtimalinin yüksek olduğunu doğru şekilde söylüyor.
Ama alternatif olarak, çalışma prensibini hâlâ araştırdığımız kadar okunması zor bir kodu, yani sinir ağını öneriyor.
Anlayabiliyorum; ama “çirkin” olan yerine tamamen yorumlanamaz olanı fazla yüceltmemek gerekir. Bazı işler için makine öğrenmesi modeli uygun olabilir; fakat çoğu durumda, çaba gerektirse de neden öyle çalıştığını okuyup doğrulayabildiğiniz bir şey, bunu yapmanın imkânsız olduğu bir şeye göre daha iyidir.
Sonuçta makine öğrenmesi yalnızca bir seçenek daha sunar. Uygun olup olmadığı değerlendirme sonuçlarına ve seçilen algoritma için gereken belirlenimcilik/açıklanabilirlik düzeyine bağlıdır.
Göze çarpan nokta, RNN’in doğru seçim olup olmadığı. Eğitim gerekir ve elinizdekinden çok daha fazla örneğe ihtiyaç duyabilir. Yine de bilinen kurallara dayanarak olumlu/olumsuz vakalar için sentetik veri üretmek mümkün gibi görünüyor.
Neden öyle çalıştığını görebildiğiniz sistemler iyidir; ama sürekli yanlış cevap veriyorsa bunun anlamı yoktur. Gerçek kullanımda çoğu zaman cevaba nasıl ulaşıldığını bilmekten çok doğru cevabı almak daha önemlidir.
Sinir ağları için evrensel fonksiyon yaklaştırma teoremi var. İstenen doğruluk düzeyine kadar keyfî bir fonksiyonu ifade edebileceklerini ya da kodlayabileceklerini söyler[0].
Ama böyle bir yaklaştırmanın öğrenilebileceğine ya da nasıl öğrenileceğine dair bir teorem yok.
[0] https://en.m.wikipedia.org/wiki/Universal_approximation_theo...
Bu, konvolüsyonel sinir ağları, Transformer’lar, LSTM gibi gerçekçi ve kullanışlı sinir ağlarının pratikte nasıl çalıştığını açıklamaktan çok uzaktır.
İlginç biçimde bu teorem tek katmanlı ağlarla ilgili. Pratikte ise birden çok katman kullanmak çok daha iyi çalışıyor.
Gerçekten iyi bir yazı; RNN çevresindeki daha derin matematiksel kavramları tamamen anlamamış olsam da pek çok fikir uyandırıyor.
Son zamanlarda araştırdığım şeye benzer geliyor: bir uygulamayı ileri çıkarım algoritmasıyla birlikte kurma yaklaşımı. Yazar RNN kullanıyor, ben ise bunu Rete algoritmasına yerleştirerek yapıyorum.
Girdi dizgesini karakter karakter sindirme şeklinde düşünmek de güçlü bence. Böylece çıkarım mantığını algoritmaya bırakırız; biz yalnızca çok ince bir giriş/çıkış mantığı yazarız, geri kalanını algoritma halleder.
Bu yazının iyi yanı, bir fonksiyonu RNN’e dönüştürmenin pratikte ne anlama geldiğini ve bunu PyTorch’ta “piller dahil” gelen RNN ile karşılaştırarak bir öğrenme deneyimi olarak anlatması.
Sorum şu: Durumu modellemek için ağa üç gizli katman eklemek gerektiğini söylüyordu; neden üç? Uygulamaya çalıştığı belirli kuralın bir sonucu mu, yoksa bu tür kuralları bu mimariyle uygularken genel olarak kullanılan katman sayısı mı? Elman yapısıyla daha az katmanla mümkün olup olmayacağını da merak ediyorum.
İlk katman, mevcut tokenden anlaşılabilen şeylerle önceki tokenin hesaplanmasından sonra bilinenleri toplar. İkinci katman, karar kuralının sağlanıp sağlanmadığını kontrol ederek mevcut tokenin program kodu gibi görünüp görünmediğine karar verir. Üçüncü katman ise bu kararı önceki tokenler hakkındaki kararlarla karşılaştırır.
Bunun tek bir gizli katmana da sıkıştırılabileceğini düşünüyorum. ReLU doğrusal olmayanlığı yakalamak için yeterli olduğundan mümkün görünüyor. Elman yapısıyla karşılığına henüz yeterince bakmadığım için cevabı bilmiyorum.
RNN’ler tamamen Transformer’ların içine mi karıştı? RNN’lerle uğraşmayı unutup sadece Transformer’lara odaklanmak yeterli mi, merak ediyorum.
Burada belirli ve dar bir Transformer tanımının, yani nedensel maskeleme kullanan Transformer’ların RNN’lere denk olduğu ve bunun tersinin de mümkün olduğu gösteriliyor.
Benzer şekilde, bugünlerde çok konuşulan bir mimari olan Mamba(https://arxiv.org/abs/2312.00752) da kapılı RNN’lerle denk birimlere sahip. Bildiğim kadarıyla performans nedenleriyle eğitim sırasında denk bir CNN, çıkarım sırasında ise RNN kullanıyor.
Aslında Transformer’ların temel avantajı budur. Yakın ve uzak mesafeli ilişkiler daha zor ya da daha kolay değildir. Ancak teorik olarak RNN’ler sonsuz derecede uzak geçmişi de hatırlayabilir.
Son 7 yıldır araştırma mühendisi olarak makine öğrenimi/LLM’lerle çalıştım, FAANG araştırma laboratuvarında da görev aldım; RNN öğrenmem gerektiğini hep düşündüm ama fiilen hiç öğrenmedim ve buna hiç ihtiyaç duymadım.
İlginç geliyorsa genetik programlamaya bakmaya değer. Aynı probleme daha basit bir yaklaşım olarak görüyorum ve matematik gerektirmiyor.
Programları soyut sözdizim ağacına göre yeniden birleştiriyor; bir sezgisel ölçüt verdiğinizde programı bu ölçüte göre optimize ediyor. Sihir, sezgisel fonksiyonda: hız, program uzunluğu, karmaşık yapıları veya fonksiyon çağrılarını en aza indirme, ağ verimliliği ya da bunların bir kombinasyonu gibi neyi isterseniz optimizasyon hedefi olarak seçebiliyorsunuz.
https://youtu.be/tTMpKrKkYXo
https://www.human-competitive.org/
Yakın zamanda bu tür belirsiz işler için yerel LLM ile arayüz kurma fikrini araştıran bir blog yazısı yazdım.
Bana göre bu, sinir ağını doğrudan kodlamaktan daha mantıklı olabilir. llama.cpp gibi bir şey kullanıp küçük bir modelin problemi olduğu gibi çözüp çözemediğini değerlendirmek; olmazsa ince ayar yaptıktan sonra istediğiniz sarmalayıcıyla llama.cpp’ye programatik olarak bağlanmak daha pratik görünüyor.
Tekrarlayan sinir ağları rastgele hesaplamalar için kullanılabilir ve Turing makineleriyle denkliği de kanıtlanmıştır. Ama bu iş için tamamen gerçek dışıdır.
Bu yazıdaki yöntem bir şekilde öğrenilmiş durum makinesi gibi görünüyor. Yazıda daha uzun bir özet olsa iyi olurdu; ayrıca “Python” hiç ilgili görünmüyor. Gerçek Python semantiğini öğrenmek, dilin doğası gereği epey zor olacaktır. Çünkü standartla tanımlanan bir dil değil; CPython ne yapıyorsa onu yapan bir dil.
O hâlde kod inceleme yorumları gibi resmî doğal dili işleyememesi için bir neden var mı?
O örnekte çıkarım, rastgele “Shakespeare” üretmek için rastgele girdilerle çalıştırılıyordu; ama dil yapısı ve üslup yine de RNN tarafından öğrenilmişti. Sınıflandırma için de kullanılabilir belki.
Önce Python’u bir sinir ağına derleyip, sonra onu Transformer tabanlı sinir ağına biraz zorlayarak yerleştirmek yeterli.
Böylece Transformer Virtual Machine(TVM) rastgele programları çalıştırabilir.
Aktarım öğrenimi, yani ağırlıkları birbirinin üzerine koyma yöntemi kullanılırsa LLM, algoritmaları derinlemesine kodlamış hâlde “doğabilir”.