/ DEEP-LEARNING, TENSORFLOW, EXPLAINED

TF-Coder Nasıl Çalışıyor?

TF-Coder, “superhuman” seviyesinde, StackOverflow’daki TensorFlow sorularının yanıtlarını nasıl sentezliyor? Arkasındaki teknolojiler nelerdir?

Paper: TF-Coder: Program Synthesis for Tensor Manipulations

Code: TF-Coder Github

Son yıllarda derin öğrenme ile computer vision, audio processing, NLP(natural language processing), ve robotik dahil olmak üzere birçok alanda sınırlar aşıldı. Tabiki bunun büyük etkenlerinden biri ise karmaşık sinir ağlarını kolay bir şekilde oluşturmamızı, kullanmamızı ve eğitmemizi sağlayan TensorFlow, PyTorch gibi frameworklerdir. Fakat bunları öğrenmek ayrı bir zorluktur çünkü normal programlama paradigmasından biraz farklıdır.

Mesela tf.where komutunun açıklaması Return the elements where condition is True (multiplexing x and y).‘dır, yani normal programlama paradigmasındaki if/else TensorFlow içerisinde bu şekilde bu şekilde kullanılmaktadır. Çünkü tf.where, tf.tensor‘u da desteklemektedir ki tf.tensor TensorFlow’un yapı taşlarındandır.

Bir çok derin öğrenme modeli farklı farklı Tensor manipülasyonları, özel loss fonksiyonları gibi kendine özgü algoritmalar kullanırlar, ve frameworklerin işlemlerinin sayısı hiç de az değildir. Mesela TensorFlow’da alias’lar da dahil yaklaşık 2000 işlem bulunmaktadır ve 500’ü Tensor manipülatör işlemlerdir. Ve bu kadar işlem arasından doğru olanı bulmak gerçekten çok zor bir iş. Bunun yanında Stack OverFlow’da bir çok girdi/çıktı verilerek işlem adı sorulan soruların çokluğundan da etkilenilerek TF-Coder projesine başlanmış.

Evet artık TF-Coder’ın ne yaptığına bir bakalım. Aşağıdaki, paper’dan alınan resim yeterince açıklayıcı.

TF-Coder input ve output dışında bir bilgi verilmediğinde de sorunu çözebilir fakat performans açısından zayıftır. Birazdan nasıl çalıştığını açıkladığımda performans kaybının nedenini öğreneceksiniz.

Şuanda TF-Coder 3-4 işlem içeren problemleri 1 dakikadan az sürede çözmektedir, fakat 6’dan daha fazla işlem içeren problemler çok daha kompleks olduğu için makul bir zamanda çözemez. Ayrıca complex, tensor ve string gibi verilen veri tiplerini çözemez. TF-Coder sadece çözümlerinin verilen giriş-çıkış örneği için çalışmasını garanti eder ancak bazen bu çözüm verilen input-output değerine göre çok basit olabilir ve genelleştirilemez yani amaçlanan davranışı doğru bir şekilde bulduğundan emin olmak için TF-Coder’ın çözümlerini kontrol edin.

TF-Coder Nasıl Çalışır


TF-Coder bottom-up enumerative search denen 2017 yılında yayınlanan TRANSIT‘de kullanılan arama algoritmasını temel alır. Bu algoritmayı biraz daha akıllı hale getirmek için rehber iki yapay zeka modeli oluşturulmuş. Verilen input ile output arasındaki bağlantıyı yakalaması için bir model ve bir de verilen tanımı anlaması için geliştirilen doğal dil modeli eklenmiş. Permütasyonları azaltabilmek için de geliştirilen 2 aşamalı filtre kullanılmış. StackOverflow’daki sorulardan oluşturulan testte TF-Coder 70 sorudan 62 tanesini 5 dakika içinde çözerken TRANSIT’de kullanılan algoritma sadece 44’ünü çözmüştür.

Şimdi gelelim detaylara.

TF-Coder’ın çözümü bulması için tüm işlemleri araması ve denemesi gerçekten büyük bir iştir. Tekli bir işlem kolayca bulunabilir fakat 3lü veya 4lü işlemlerin permütasyonları gerçekten fazladır. Bunu çözmek için Weighted Value Search denen algoritmayı geliştirmişler. Bu algoritma ağırlıklara göre arama sıralamasını düzenliyor. Peki Weighted Value Search nedir?

TF-Coder işlemleri artan ağırlık sırasına göre numaralandırır ve ağırlık ifadenin karmaşıklığı ile doğru orantılıdır. İşlemler, inputlar ve sabit değerlerin belirli ağırlıkları vardır. Ve bir ifadenin ağırlığı bunların toplamına göre belirlenir. Bunlardan sonra ise algoritma, eksenleri, input-output tensörlerinin boyut uzunluklarını ve şekillerini de çıkarır ve bunlara da ayrı değerler atar. Mesela input ve sabit değer ağırlığımız 8 olsun ve işlemimiz tf.expand_dims(input, axis)‘ın ağırlığı ise 18 olsun, yani tf.expand_dims(input, axis="sabit değer") ifadesinin ağırlığı 34’tür. İşlemlerin de ağırlıkları karmaşıklığına ve ne kadar kullanıldığına göre değişir. Mesela tf.reverse, tf.expand_dims‘den daha karmaşıktır ve daha az kullanılır, bu yüzden daha ağırdır. Peki neye göre karmaşık derseniz, geliştiriciler ne kadar yaygın veya yararlı olduğunu, anlamının ne kadar karmaşık olduğunu ve kaç argüman gerektirdiğini göz önünde bulundurarak tamamen manual olarak atamışlar.

Her denenen/işlenen işlemler, argümanlar ve sonucu saklanır bu sayede çoklu operator aramalarında tekrardan kullanılacağı zaman bir kez daha hesaplanmaz.

Operation Filtering

Bir işlemde çok az sayıda bağımsız değişken, işlemin gerektirdiği ön koşulları sağladığı için tüm değişkenleri denemek gereksiz ve büyük maliyetli olacaktır, bunu önlemek adına iki aşamalı esnek bir filtreleme yaklaşımına gidilmiştir.

Argument Filter

Filtreleme işleminin birinci aşamasında, işlemin alabileceği argümanları kontrol eder. Mesela tf.argmax(input, axis), input olarak nümerik değerleri, axis ise sadece integer değerleri kabul eder. İlk aşamadaki filtre ise kabul edilmeyen değerleri (mesela axis için boolean) reddeder ve büyük permütasyon listesinin boyutunu büyük ölçüde düşürür.

Combination Filter

Argüman filtresinden geçen değerlerin işleme uygunluğunu kontrol eder. Mesela axis değerinin alabileceği integer değerler, verilen giriş matrixine göredir. Yani 2 boyutlu bir matrix, axis değeri olarak sadece 0 ve 1 alabilir. Yani kombinasyon filtresinin amacı hızlı kontrollerle ortadan kaldırılabilecek pahalı TensorFlow işlemlerini yürütmekten kaçınmaktır.

Ayrıca TF-Coder aynı argüman içeren işlemlere aynı argüman ve kombinasyon filtrelerini kullanarak işlem yükünden kaçınır. Mesela tf.reduce_sum(input, axis) tf.argmax(input, axis) ile aynı filtreleri kullanır.

Filtrelerin ne işe yaradığını aşağıdaki örnekte inceleyelim.

in1 = [101, 103, 105, 109, 107]

in2 = [105, 107, 103]

output = [2, 4, 1]

Solution:
tf.cast(tf.argmax(tf.cast(tf.equal(in1, tf.expand_dims(in2, 1)), tf.int32),axis=1), tf.int32)

Yukarıdaki zor görev için, argüman filtreleri özel argümanların %73’ünü ortadan kaldırır ve daha sonra kombinasyon filtresi kalan bağımsız değişken seçimlerinin kartezyen çarpımının %60’ını daha ortadan kaldırır. Yani iki aşamalı filtreleme stratejisi birlikte tüm potansiyel aday programlarının %98,6’sı ortadan kaldırdı.

Aramaya Yapay Zeka ile Yol Gösterme


TF-Coder, hangi işlemlerin kullanılacağını tahmin eden iki makine öğrenimi modelini kullanır. Biri giriş ve çıkış tensörlerinin özelliklerine göre şartlandırılmış bir neural model ve diğeri sorunun tanımına göre Naive Bayes, Bag of Words modeli. Bu modellerin tahminleri 0.75 ile çarpılarak işlemlere uygulanır.

Şartlandırılmış neural model Tensor Features Model olarak adlandırılmış, diğer NLP modeli ise Natural Language Model olarak adlandırılmış. Ben de yazımda bu isimleri kullanacağım. Şimdi modellerin biraz daha ayrıntısına girelim.

Tensor Features Model


Bu modelde, giriş ve çıkış tensörlerinin özelliklerine bağlı olarak, her işlem üzerinde ki Bernoulli dağılımını öğrenmesi beklenmiştir. Yani örüntüleri tanıyarak işlemleri tahmin eden bir model. Peki bu model nasıl bir veri ile eğitilmiştir?

Dataset

Tabiki böyle bir veri seti bulunmadığı için veri setini sentetik olarak üretmişler. Daha sonra veri seti en az 2 işlem içerecek şekilde filtrelenmiş çünkü zaten bir işlem value search ile 1 saniyeden az sürede bulunabiliyor. Sonuç olarak toplam 39,930,863 training verisi, 99,852 evaluation verisi sentezlenmiştir. Veri setine sadece input ve output değil, input ve output’tan çıkarılan bir çok veri de eklenmiştir.

Mesela sadece input değerinden: input veri tipi, derecesi, boyutu, min-max-mean değerleri, değerlerin hangi aralıklarda hangi yoğunlukta olduğu, değerlerin bir çok boolean özellikleri(tüm elemanlar unique mi, sıralı mı, pozitif mi gibi) gibi özellikler çıkarılmıştır.

Ayrıca input ve output değerleri arasındaki ilişkiyi anlamak için de bir çok özellik karşılaştırılmıştır. Eleman sayısı, derecesi, boyutu eşit mi, tüm giriş elemanları çıktı da görünüyor mu gibi bir çok özellik karşılaştırılarak veri setine eklenmiştir.

Tüm veriler düzenlenerek 2049 uzunluğunda bir vektör olarak modele verilmiştir.

Model

Model 1 ve 2’nci katmanları dense katmanıdır. Final katmanında ise her işlem için bir logit oluşturulmuş ve her işlemin olasılığını almak için her işleme elementwise sigmoid uygulanmıştır. Farklı loss fonksiyonları da test edilmiştir, mesela standart sigmoid cross entropy loss ile test edildiğinde, çoğu örnek çözümünde az sayıda işlem bulunduğu için büyük bir çoğunluktaki sonuç negatif olarak çıkmıştır. Daha sonra loss fonksiyonu olarak türevlenebilir Fβ metric denenmiş. F1 precision ve recall’ı eşit derecede önemserken F2 recall’ı precision’dan iki kat daha fazla önemsediğine varılmış. Yani kısacası şuna varmışlar, bir işlemin doğru şeklini aramak, hiç denenmemiş bir işlemi aramaktan daha iyidir.

Bu 3 loss fonksiyonu 3 epoch boyunca farklı varyasyonlar ile hiper parametre araması yapılıp eğitilerek en düşük evaluation loss değerine sahip olan seçilmiş. Herhangi bir overfitting olayı da gözlenmemiş. 1’inci ve 2’nci katmanda hidden layers değerleri 512, 1024 ve 2048 olarak denenmiş ve learning rate 1e-5 ve 1e-3 arasındaki 7 farklı değer denemiş. Ve optimizer olarak da Adam kullanılmış.

Modelin tüm varyasyonları için, olasılığı 0.5’ten büyük olan tüm işlemlere öncelik vericek şekilde ayarlanmış.

Natural Language Model


Bu model input ve output dışında verilen description kısmında verilen açıklamayı anlayabilmek için geliştirilmiştir. Nasıl bir veri ile eğitildiğine bakalım.

Dataset

Tabiki sırf bu iş için hazırlanmış bir veri seti olmadığı için kendileri TensorFlow’un dökümantasyonunu ve Github’dan kodunu indirerek bir veri seti hazırlanmış. Toplam 14,094 veri toplanmış.

Model

TF-IDF ve Naive Bayes modellerini geliştirmişler. 2 model de verilen açıklamaya göre, işlemleri bir sıraya koyuyor. Ve iki model de en yüksek skora sahip k işleme öncelik veriliyor.(k değeri farklı değerler verilerek test edilmiştir, sonuçlar aşağıdaki tablodadır.) Fakat çoğunlukla dökümantasyondaki açıklama ile description olarak verilen olayın gerçek tanımı farklıdır. Ama genede sözcüklerden bir bağlam yakalayabileceklerine inandıkları için daha basit olan Bag of Words modelini denemişler ve karmaşık modeller daha iyi anlayabilmesine rağmen, bu problem için diğerlerinden daha iyi bir şekilde genellemiştir.

TF-IDF için sadece dökümantasyonu kullanmışlardır ve stop word’leri silmişlerdir. Naive Bayes modeli tam olarak yapılandırılmış bir veri seti üzerinde eğitilmiştir. Bu model veri seti olarak, TF-IDF modeli ile aynı kelime dağarcığı ve belge frekansları ve aynı tanım kullanılmış . Tabi modelin kelime dağarcığının bu şekilde sınırlandırılması onun daha fazla gelişmesinin önünde engeldir.

Denenen parametreler şunlardır; TF-IDF, minScore ∈ {0.1,0.15}, Naive Bayes p ∈ {0.5,0.75}, her iki model için de maksimum işlem sayısı k ∈ {3,5,10}.

Karşılaştırma

TF-Coder, Transit’te kullanılan arama algoritmasını çeşitli şekillerde geliştirmiştir:

  1. TF-Coder aramak için değerlere ağırlık vererek sıralar. TRANSIT ise ağırlık kullanmaz.
  2. TRANSIT sadece type-checking yaparken, TF-Coder esnek bir filtreleme sistemi kullanır.
  3. TF-Coder işlem ağırlıklarını 2 model ile düzenler.

Modellerin Etkisi

Aşağıdaki resimde farklı parametrelerin, modellerin nasıl sonuçlar verdiğini görebilirsiniz.

TF-Coder Kullanımı

Basitçe yazarları tarafından hazırlanan Colab’daki Jupyter Notebook‘u inceleyebilirsiniz.

Eğer kendi bilgisayarınıza kurmak isterseniz Python paket manager’i ile kurabilirsiniz.

pip install --user tf-coder

Daha sonra import edelim.

from tf_coder.value_search import colab_interface
from tf_coder.value_search import value_search_settings as settings_module

Input bir dictionary, list veya tf.tensor tipinde olabilir. Dictionary kısmında input isimlerini belirleyebiliriz. Fakat list tipinde her elemanı bir giriş olarak algılar ve in1, in2 şeklinde adlandırır. Peki bu ne için önemlidir? Tabiki description kısmı için.

inputs = {
    'rows': [10, 20, 30],
    'cols': [1, 2, 3, 4],
}

Output ise bir tek bir tensördür.

output = [[11, 12, 13, 14],
          [21, 22, 23, 24],
          [31, 32, 33, 34]]

Constants, sorunu çözmek için gerekli olan skaler sabitlerin bir listesidir. TF-Coder, bazı sabitleri otomatik olarak tanımlayabilir, ancak önemli sabitleri açıkça sağlamak aramayı hızlandıracaktır. Eğer var ise bir list’in içine ekleyebilirsiniz.

constants = []

Description, tensör manipülasyonunun İngilizce bir açıklamasıdır. Bu alakalı TensorFlow işlemlerini tanımlamasını sağlar. Fakat doğru bir input-output ve skaler bir sabit listesi kadar önemli değildir.

description = 'add two vectors with broadcasting to get a matrix'

Kodu çalıştırırken bazı ayarlamalar yapabilirsiniz. Ayarlar: timeout timeout zamanı, only_minimal_solutions ile minimal sonucu bulduğunda durması gerektiğini boolean bir şekilde verebilirsiniz, max_solutions ile maximum bulacağı sonuç sayısını, require_all_inputs_used veya require_one_input_used da boolean değer vererek tüm inputların gerekliliğini belirtebilirsiniz. Eğer belirtmezseniz default ayarlarını kullanacaktır.

settings = settings_module.from_dict({
    'timeout': 60,
    'only_minimal_solutions': False,
    'max_solutions': 1,
    'require_all_inputs_used': True,
    'require_one_input_used': False
})

Hadi çalıştıralım.

results = colab_interface.run_value_search_from_colab(inputs, output, constants, description, settings)

Sonucumuz hazır.

Input 'rows':
tf.Tensor([10 20 30], shape=(3,), dtype=int32)

Input 'cols':
tf.Tensor([1 2 3 4], shape=(4,), dtype=int32)

Output:
tf.Tensor(
[[11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]], shape=(3, 4), dtype=int32)

Constants: [0, 1, -1, True, False, 3, 4]

Description: add two vectors with broadcasting to get a matrix

Searching...

Found solution: tf.add(cols, tf.expand_dims(rows, 1))

Solution was found in 0.2 seconds:
tf.add(cols, tf.expand_dims(rows, 1))

Anlatacaklarım bu kadar, umarım sizin için anlaşılabilir ve faydalı bir yazı olmuştur. Herhangi bir soru için mail(rahmetsaritekin@gmail.com) veya twitter üzerinden iletişime geçebilirsiniz.