2 puan yazan GN⁺ 2024-07-02 | 1 yorum | WhatsApp'ta paylaş
  • 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, identifieropen_parenclose_paren gibi 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çe State ile 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()
    • FTPSACK
    • debug_error()
    • NULL
    • IS_ERROR()
    • aarch64, amd64
    • if (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 ama if (err) goto cleanup; ifadesini kaçırır
    • Tamamı büyük harfli kelimeleri kod sayan kural, FTPSACK ve IS_ERROR() örneklerini yakalar ama AFAICT gibi 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
  • Kural 2 ve Kural 3'ü iyileştirmek için AFAICT, LGTM, USD, COVID, aarch64, amd64 gibi 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_identifieropen_parenclose_paren desenini kod referansı olarak değerlendirir
  • Python uygulaması, önceki token durumunu saklamak için State veri sınıfını kullanır
    • previous_was_identifier
    • previous_was_open_paren
    • previous_previous_was_identifier
    • seen_code
  • contains_code, token'lar üzerinde dolaşırken process fonksiyonunu çağırır ve sonunda state.seen_code değerini döndürür
  • process, mevcut token close_paren ise, bir önceki token open_paren ve ondan önceki de tanımlayıcıysa seen_code değerini True yapar
  • 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 State alanları ile if/elif/else dalları artar ve kurallar daha fazla rafine edildikçe bakım zorlaşır

Durum makinesini RNN'e taşımak

  • contains_code ve process, 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 State karşılığı olan değerler, RNN'in gizli durumu olarak ifade edilir
    • State_0 başlangıç durumudur
    • Her State_t, mevcut token ile önceki durumu f fonksiyonuna 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 t için birinci katman, token t-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
  • 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

 
GN⁺ 2024-07-02
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.

    • Yazarın spagetti kod konusunu açmasının biraz konuyu saptırmaya yakın olduğunu düşünüyorum. Bir algoritmanın çıktısı girdinin bir fonksiyonu olarak kesin biçimde tanımlı değilse ama gösterebileceğiniz örnekler varsa, makine öğrenmesinin yararlı olduğu yer orasıdır.
      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.
    • Spagetti kod yaklaşımı temelde bir uzman sistemdir. Eski usul algoritmik yapay zeka olarak görülebilir. Sınırlı alanların dışında bu tür sistemlerin gerçekten iyi çalıştığı pek olmamıştır; gerçek dünya fazla dağınıktır.
      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.
    • Çirkin spagetti kodu tertemiz bir 1000x1000 kayan noktalı matrisin arkasına saklayalım deniyormuş gibi geliyor.
  • 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 kanıt sık sık gündeme getirilir, ama aslında gösterdiği şey sinir ağlarının lookup table ile eşdeğer olduğu kadardır. Yeterli belleğe sahip bir lookup table herhangi bir fonksiyonu yaklaştırabilir.
      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.
    • Bu arada sinir ağlarından çok daha önce evrensel fonksiyon yaklaştırıcı olduğu kanıtlanmış pek çok algoritma vardı. Sinir ağları ne tek ne de ilk örnek. Çoğu durumda sinir ağlarından çok daha uygun yöntemler de var.
    • Her fonksiyon için geçerli değil. Evrensel yaklaştırma teoreminin uygulanabildiği fonksiyon türleri üzerinde kısıtlar var.
      İlginç biçimde bu teorem tek katmanlı ağlarla ilgili. Pratikte ise birden çok katman kullanmak çok daha iyi çalışıyor.
    • Yalnızca sürekli fonksiyonları modelleyebilir; daha doğrusu ℝⁿ’nin kompakt bir altkümesi üzerindeki herhangi bir sürekli fonksiyonu, yeterli nöron olduğunda istenen doğrulukla yaklaştırabilir.
    • O hâlde öğrenmenin ne anlama geldiğini merak ediyorum.
  • 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 soruya gelirsek, üç gizli katman kullanmak ağın ne yaptığını biraz daha netleştiriyor. Her katman hesaplamanın bir adımını gerçekleştiriyor.
      İ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.

    • Bu soruyu daha karmaşık hâle getirmek gerekirse, “Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention” makalesine bakmaya değer - https://arxiv.org/pdf/2006.16236
      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.
    • Transformer’larda sonlu bir bağlam vardır, RNN’lerde ise yoktur. Pratikte RNN’in gradyan sinyali, zaman içinde geri yayılım nedeniyle sınırlanır ve sönümlenir.
      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.
    • Makine öğrenimi doktorası yapmak ya da araştırmacı olmak istiyorsan hayır; onun dışında evet.
      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

    • İnsan düzeyinde rekabetçi sonuçları gösteren Humies Awards’ı da eklemek isterim. Gönderilen makalelere şöyle bir göz atmak bile bu alanda nelerin mümkün olup olmadığını anlamak için çok şey öğretir.
      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.

    • Karpathy’nin 2015 tarihli RNN yazısı[1], Shakespeare eserleriyle karakter düzeyinde eğitilmiş bir RNN’in, LLM’lerdeki gibi anlatı tutarlılığı olmasa da Shakespeare tarzı metin üretebildiğini göstermişti.
      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.
      1. https://karpathy.github.io/2015/05/21/rnn-effectiveness/
  • Ö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”.