Friday 7 April 2017

TENSORFLOW : Google Makine Öğrenmesi Kütüphanesine Giriş



Şekil 1. Tensorflow
 Tensorflow  graflar arasındaki veri akışındaki sayısal hesaplamaların (numerical computation)  yapılabildiği bir makine zekası kütüphanesidir. Aslında bu tanım Google tarafından yapılmış olsa da günümüzde Deep Learning çalışmalarında oldukça popüler kullanımı sebebiyle aynı zamanda “Deep Learning Library” olarak da ifade edilebilir. Bu kütüphane(TF)  Google tarafından açık kaynak olarak sunulmaktadır. Resmi sitedeki yönergeleri takip ederek kütüphaneyi kullanabilirsiniz. Şu anda 2 dilde API mevcuttur: C++, Python. Ancak gerek hızlı işlem yapma kapasitesi gerek topluluk desteği gibi avantajlarından ötürü Python dili  tercih edilmektedir. (Baknz : Tensorflow Web sitesi)


Tensorflow içerisinde data n-boyutlu bir dizi olarak sunulur. Bu n- boyutlu dizilere  de TENSOR adı verilir.  Graflar bu veriler(Tensor) ve matematiksel işlemlerden oluşur. 
Graflardaki Düğümler(Nodes on the Graph):  Matematiksel işlemleri temsil eder.  (Nodes=Operations)
Graflardaki Kenarlar(Edges on the Graph )  : İşlemler arası akan verileri(Tensor) temsil eder.(Edges=Tensors)

Aşağıdaki imgede basit bir TensorFlow  diyagramı örneği  gösterilmiştir.  Anlaşılacağı üzere TensorFlow diyagramı düğümler (nodes)  oval şekilde ve kenarlar(edges)  ise dikdörtgen şekilde ifade gösterilmiştir. 
Şekil 2. Örnek bir Tensorflow grafı
Tensorflow’un bu özellikleri kullanıcılara karmaşık modelleri bile esnek biçimde tasarlama fırsatı tanımaktadır. Aynı zamanda graflar arası akışın adım adım takip edimesi ve hesaplamaların incelenmesi de mümkündür. Bunun gibi birçok üstün özellikleri sayabiliriz TensorFlow için…

Gelelim grafların modellenmesine  yani Tensorflow kütüphanesini kullanmaya…
Temel Yaklaşım: Başlangıçta graf oluşturulur ve graf  herhangi  bir veriye sahip olmaz. Daha sonra graf oluşturma tamamlandıktan sonra bir ‘Session ’ içerisinde run edilmesi gereklidir.
Gelelim Python Komut satırından kütüphaneyi kullanmaya … İlk olarak kütüphane import edilir. 
Şekil 3. Tensorflow import edilmesi
 2.GRAPH(Graf):
Graflar Tensorflow’un temelidir denilebilir. Çünkü her bir hesaplama/işlem/değişken graf üzerinde yapılmaktadır.
Kod içerisinde yapılan herbir şey Tensorflow tarafından sağlanan default Graflar üzerinde tutulur. Bu grafa Tensorflow kütüphanesinin “get_default_graph()” metodu ile erişebiliriz.

PYTHON kodu>>>graph=tf.get_default_graph()

Graflar üzerinde yapılan tüm işlemlere grafların “get_operations()” adlı metoduyla erişilebilir. Şu anda çalıştırıldığında “[]” şeklinde bir çıktı verecektir. Çünkü graf üzerinde yapılan herhangi bir işlem bulunmamaktadır.

PYTHON Kodu>>> graph.get_operations()

Graf üzerinde yapılan tüm işlemlerin isimlerini öğrenmek için şu şekilde bir kod yazılabilir:

PYTHON Kodu>>>for op in graph.get_operations() : print(op.name)

3.SESSION(Oturum):
Graflar bildiğimiz gibi işlemleri tanımlamak için kullanılıyordu ama bu işlemler sadece bir Session(oturum) içerisinde run edilir. Graflar ve Sessionlar birbirinden bağımsız şekilde oluşturulur. Aslında graflar oluşturulan modelin teknik bir taslağı iken Sessionlar ise yapılan işin çalışma sahasına benzer.  
Graflar sadece  hesaplamaları belirler ve teknik taslağı oluşturur. Bir Session içerisinde graf veya grafın bir kısmı çalıştırılmadığı sürece grafda ne bir değişken ne bir değer vardır. Bir Session şu şeklilde oluşturulabilir:
PYTHON Kodu:
sess=tf.Session()
#…Yazılmak istenen kod buraya yazılabilir.
sess.close 

Bir Session başlatıldığında sonlandırlması gerektiği unutulmamalıdır. Alternatif olarak ‘with block’ yapısı kullanılabilir.
PYTHON Kodu:
with tf.Session() as sess:
                sess.run(f)
Bu şekilde kullanımın en önemli avantajı Session’ın otomatik olarak kapanmasıdır. ‘With’ bloğunun sonlanmasıyla Session da sonlanacaktır. Bu şekide kullanım oldukça popülerdir ve şiddetle tavsiye edilmektedir.
4. TENSORS(N-Boyutlu Diziler):
Tensorflow verileri n-boyutlu dizilerde(Tensors) tutar . Tıpki NUMPY n-boyutlu dizileri gibi. Ancak Tensorflow’un oldukça fazla üstün yanları vardır.
a)      Constants(Sabitler):  Değerleri değişmeyen verilerdir. Şu şekilde tanımlama yapılabilir:
PYTHON Kodu:
 A=tf.constant(5.0)
print(A)
Ancak burada Tensorflow’un diğer programlama dillerinden farkı belirmektedir. Yukarıdaki gibi bir kod yazıldığında ‘A’ sabitinin değeri olan 5.0 çıktı olarak verilmeyecektir. Çünkü bir session başlatılmadan değer ataması yapılamaz Tensorflow’da…
Bu koda Session başlatılarak değer çıktı verilmesi gerekmektedir.

PYHON Kodu:
with tf.Session() as sess:
                sess.run(A)
şeklinde bir kod yazılırsa 5.0 değeri çıktı olarak alınabilecektir.

b)      Variables(Değişkenler):
Şu şekide tanımlama yapılabilir:

PYTHON Kodu:
B=tf.Variable(10.0,name=”test_degisken”)

Tensorflow içerisinde bu değişkenlerin kullanılabilmesi için “initialize” edilmesi gerekmektedir. Bu konuda Tensorflow sağladığı mekanizma ile sorunu bir satır kod ile halletmektedir.
Eğer TF versiyonu 0.11 ve daha öncesi ise => “init_op=tf.initialize_all_variables()”
Eğer TF versiyonu 0.12 ve daha sonrası ise=> “init_op=tf.gloabal_variables_initializer()”
Şeklinde kullanılır ve değişkenler ‘initialize’ edilmiş olur.Daha sonra bu değişken default grafa eklenir ki bu değişkene erişim mümkün olsun…

PYTHON Kodu:
with tf.Session() as sess:
                sess.run(init_op)
                print(sess.run(B))

şeklinde bir kod yazarak B değişkeni olan 10.0 değeri çıktı olarak verilir.

c)       PlaceHolders(Yer Tutucular):İnitialize(ilkleme) ve Fed(veri besleme) bekleyen tensorlardır.  PlaceHolder’lar  eğitim zamanında parametrelerin belirlenmesinde kullanılabilir. PlaceHolder’lar için veri beslemesini  key,value ikiliğini kullanarak veri tutan ‘feed_dict’ adlı yapı sağlar. Mesela örnek bir çalışma olarak 2 sayının çarpımını ekrana basalım.

PYTHON Kodu:
a=tf.placeholder("float")
b=tf.placeholder("float")
y=tf.mul(a,b)   # iki sayının çarpımılmesi
feed_dict={a:5.0,b:10.0}  # verilerin beslenmesi. Mesela eğitim  esnasında güncellenen verileri bu şekilde bir yapıyla besleyebiliriz.
with tf.Session() as sess:   #graf yapısının üzerinde işlem yapabilmek için Session başlatılıyor
                print(sess.run(y,feed_dict))   # ‘feed_dict’ parametresine bağlı olarak çarpma işlemi yapılıyor. 


5. DEVICE in TENSORFLOW(TENSORFLOW’da AYGIT )
Tensorflow’un diğer numerik hesaplama kütüphanelerin oldukça fazla üstün yanları vardır. Bunlardan en önemlilerinden birisi de dağıtık programlamaya imkan sağlayabilmesidir. Yazılan kod içesinde farklı Session’lar oluşturarak her Session farklı bir aygıt kullanılabilmektedir.  Mesela bir görevi CPU ile diğer bir görevi GPU kullanarak yapmak gibi.  

Şekil 4. Tensorflow  dağıtık programlama
 Şekilde bir dağıtık hesaplama örneği mevcuttur. Bir ANN(Artificial Neural Network) modelinin geliştirilmesi aşamasında yapılan bir yük dağılımıdır. TF bu gibi özellikleri kullanıcılara sağlamaktadır.
Burada önemli bir ayrıntıyı belirtmekte fayda var: İş yükü dağılımı yapıldıktan sonra her bir iş yükü için ayrı bir Session başlatılması gerekmektedir.

BASİT BİR TENSORFLOW ÖRNEĞİ :

Bu aşamada adım adım Linear Regression örneği yapılacaktır. Ama bundan önce gerekli metodları tanımlamaya çalışalım:
a)       Rasgele Normal Dağılım Oluşturma: Bu örnek için 784*10  büyüklüğünde ve standart sapması 0.01 olan bir dağılım oluşturalım. Bu dağılım ağırlıklar(W) olarak kullanılacaktır.
PYTHON Kodu:
W=tf.Variable(tf.random_normal([784,10],stddev=0.01))

b)      Reduce_Mean: Verilen bir dizinin ortalamasının bulunması gerekmektedir.
PYTHON Kodu:
b=tf.Variable([10,20,30,40,50,60],name="t")
with tf.Session() as sess:
                sess.run(tf.global_variables_initializer())
                print(sess.run(tf.reduce_mean(b)))

şeklindeki bir kod ile b dizisinin ortalamasını bulabiliriz.
c)       ArgMax: Özel olarak belirlenen eksenler arasındaki max değerin elde edilmesi
Python Kodu:
a=[
   [0.1,0.2,0.3],
   [20 ,2  ,3  ]
]
b=tf.Variable(a,name='b')
with tf.Session() as sess:
                sess.run(tf.global_variables_initializer())
                print(sess.run(tf.argmax(b,1)))

şeklindeki kodun çıktısı her satırdaki max değerlerin indexi olacaktır. Yani: [2,0] .

Linear Regression Örneği:
Öncelikle Linear Regression kısaca problem uzayından verilerin sınıflandırılması için belirli lineer bir doğrunun çıkarılması işlemidir. Bu işlem genellikle ANN yapısı kullanılarak çözülmeye çalışılmaktadır.
Yapacağımız örnek için 100 adet veri noktası oluşturulacak ve daha sonra bu verileri ifade eden eğri elde  edilmeye çalışılacaktır.
Adım1: Eğitim datasının oluşturulması:
Python Kodu:
import tensorflow as tf
import numpy as np

trainX=np.linspace(-1,+1,101)
trainY=3* trainX+ np.random.randn(*trainX.shape)*0.33

şeklinde kod yazarak verileri oluşturduk. Veriler tamamen rasgele varsayımlarla şu şekilde oluşmuştur.  Sırasıyla (TrainX ve TrainY değerleri )
Şekil 5. Eğitim için koordinat sistemi için veriler
 Oluşturulan bu veriler sonrasında şu şekilde bir grafik oluşmuştur:
Şekil 6. Şekil 5'teki verilerin koordinat sistemine yerleşmiş hali

Adım2: PlaceHolder oluşturulması:
Python Kodu:
x=tf.placeholder("float")
y=tf.placeholder("float")

Adım3: Modelin oluşturulması:
Linear Regression modeli aslında “y_model=w*x” denkliğine dayanır. Modelin eğitimi sırasında W değerleri optimize edilir.  Cost parametresi için ise “cost=(y_model-y)^2” şeklinde bir denklik kullanılabilir.  Bu aşamada Tensorflow ağırlıkların optimize edilmesi için her bir iterasyonda ağırlık güncellemelerini yapar. Bu çalışmada oldukça popüler bir teknik olan “GradientDescentOptimizer” kullanılacaktır. Parametre olarak “learning rate” değerini almaktadır.
Python Kodu:
w=tf.Variable(0.0,name="weights")
y_model=tf.mul(x,w)
cost=(tf.pow(y-y_model,2))
train_op=tf.train.GradientDescentOptimizer(0.01).minimize(cost)

Adım4: Eğitim yapılması:,
Bu aşamaya kadar sadece grafı tanımladık. Herhangi bir hesaplama yapmadık. Bu aşamada ‘Session’ oluşturarak eğitim işlemi yapılacaktır.   Tabi öncelikle değişkenlerin “global_variables_initializer()” metodu ile initialize edilmesi gerekmektedir.
Python Kodu:
init=tf.global_variables_initializer()  # değişkenlerin init edilmesi
with tf.Session() as sess:    
                sess.run(init)
                for i in range(100):       # 100 epoch
                                for (x,y) in zip(trainX,trainY):
                                                sess.run(train_op,feed_dict={X:x,Y:y})    # ağırlıklar optimize edilir.
                print(sess.run(w))    # en son olarak belirlenen ağırlık ekranan yazdırılır.

Şeklinde kod yazarak eğitim işlemi 100 iterasyon ile yapılmış oldu. Amaç eğrinin y=w*x şeklinde ifade edilmesiydi.  Bu eğitim kısmında w değerinin optimize edilmesi gerçeklendi.  Veriler rasgele oluşturulmasına rağmen y değerinin denklemini biz belirlediğimiz için w değerinin 3 değeri civarında bir değer olduğunu tahmin edebiliriz.
Sonuç olarak sıklıkla yapılan bir hatadan bahsetmekte fayda var. Daha önceden Session olayından bahsetmiştik. Aslında hesaplamaların döndüğü kısım olarak da ifade edebilmiştik. Buna bağlı olarak da her session kendine özgü hesaplamalara sahiptir, diyebiliriz. Mesela ; yukarıda yazdığımız koda ilave olarak şöyle bir Session oluşturalım:
Python Kodu:
 with tf.Session() as sess:
                sess.run(init)
                print(sess.run(w))
Bu kodun çıktısı ne olabilir? Cevabımız çok basit: Tensorflow mimarisi gereği 0.0 !!! Çünkü farklı bir Session içerisinde aynı değerlerin elde edilebilmesi için aynı hesaplamaların yapılması gerekmektedir…

SONUÇ:
 Bu yazıda WEB üzerinde çeşitli dökümanları kullanarak TENSORFLOW kütüphanesinin giriş seviyesinde bilgilerini aktarmaya çalıştım. Bir nebze olsun faydam olduysa ne mutlu bana…J
Gerek Deep Learning ile ilgili gerekse Tensorflow ile ilgili öğrendiğim şeyleri fırsat buldukça paylaşmayı düşünüyorum.
Teşekkürler. Kolay gelsin . İyi çalışmalar…

NOT: Buradan Standford Üniversitesi'ndeki "Tensorflow for Deep Learning" dersini takip edebilirsiniz. Oldukça faydalı dökümanlar mevcut.  

YASİR KILIÇ
SELÇUK ÜNİVERSİTESİ
FEN BİLİMLERİ ENSTİTÜSÜ
Bilgisayar Mühendisliği (Tezli Yüksek Lisans öğrencisi)
MAİL:  14yasir@gmail.com

KAYNAKLAR:

[3] http://web.stanford.edu/class/cs20si/syllabus.html