28 Eylül 2017 Perşembe

Keras ile Derin Öğrenmeye Giriş - Sınıflama Örneği

Keras Tensorflow ya da Theano kütüphaneleri üzerinde çalışan Python ile yazılmış yüksek seviye bir API'dir. Kullanıcıyı daha düşük seviyedeki bu kütüphanelerin karmaşıklığından kurtararak, daha basit şekilde yapay sinir ağı modellerinin oluşturulması ve eğitilmesine olanak sağlar. Keras kurulumunu daha önceki bir yazımda anlatmıştım, kurulum için bu yazıyı inceleyebilirsiniz.


Basit olarak açıklayacak olursak; Keras ile bir ağ modeli oluşturuyoruz ve elimizdeki eğitim verisi ile bu modeli eğitiyoruz. Eğitim işlemini gerçekleştirdikten sonra test verisi ile olması gereken/beklenen değeri tahmin edip modelimizin performansını sorguluyoruz.

Keras 'taki temel yapı model olarak adlandırılıyor ve en basit model tipi ise katmanlar yığınından oluşan  Sequential model. Yaygın kullanılan yapı bu olmakla birlikte; paylaşımlı katmanların, daha kompleks mimarilerin tasarlanabildiği bir diğer model tipi ise Functional API

Modellerin katmanlardan oluştuğundan bahsettik, katmanlar sinir ağını oluşturan temel bloklar olarak düşünülebilir. İnsan sinir hücrelerinden esinlenilerek gerçekleştirilmeye çalışılan bu yapıda, katmanlar girdi verilerini işleyerek bir çıkış üretirler ve bu çıkışlar ise bir başka katmanın girdisi olabilir. Keras 'ın içerdiği temel(çekirdek) katman çeşitlerinden bazıları ;

Dense layer : girdideki her bir düğüm çıkıştaki her bir düğüm ile bağlıdır.
Activation layer ReLu,tanh,sigmoid gibi aktivasyon fonksiyonları içerir, çıktı değerini aktivasyon fonksiyonuna göre belirler.
Dropout layer : Eğitim aşamasında overfitting i azaltmak için kullanılır. (ayrıntılı bilgi için)
Flatten layer : Matris formundaki veriyi düzleştirmek için kullanılır.
Reshape layer : Girdi boyutlarını dönüştürmek için kullanılır.

Projemize ilgili katmanı eklemek için ;
from keras.layers.core import Dense,Activation,Dropout,Flatten,Reshape

Çekirdek katmanların dışındaki bazı katman çeşitleri ise Convolution layer, Pooling layer, Recurrent layer ...vs.

Bu yazı kapsamında Sequential tipinde bir model oluşturup, örnek veri seti üzerinde eğitim işlemi gerçekleştirip farklı ağ yapıları için performansları inceleyeceğiz. Kullanacağımız veriseti sonar dataset , 60 girdi değişkeninden oluşan bir sınıflandırma problemi için hazırlanmış. Tüm değişkenler genelde 0-1 arasında ve çıkış değeri (tahmin edilecek değer) M (mine) ya da R (rock).

Veri setini indirdikten sonra pandas ile .csv dosyayı okuyalım.
# load dataset
dataframe = pandas.read_csv("sonar.all-data.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]

X değerlerine göre  Y yani sınıflandırma sonucu ('R' ve 'M' değerleri) elde ediliyor. İlk olarak string tipindeki Y değerlerini integer değerlere dönüştürmeliyiz. Daha önceki bir yazımda bu konudan bahsetmiştim. Kategorik verileri integer değere dönüştürmek için;
from sklearn.preprocessing import LabelEncoder
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

Veri setimizi ikiye bölüp, eğitim ve test verileri olarak ayrıştıralım.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, encoded_Y, test_size=0.30, random_state=0)
Veriyi okuduk, girdi ve çıktıları ayarladık. Artık modelimizi oluşturabiliriz. Sequential model oluşturmak için
from keras.models import Sequential

model = Sequential()

Modelimize ilk katmanı eklerken girdi boyutunu belirtmemiz gerekiyor, diğer katmanlarda ise buna gerek yok zaten bir katmanın çıkışı bir diğerinin girişi olduğundan bu işlem otomatik olarak gerçekleştiriliyor. Modelimize iki adet dense katman ekleyelim.
model.add(Dense(60, input_dim=60))
model.add(Dense(1))

Modelimizi hazırlarken öğrenme işlemi için de konfigürasyon ayarları gerçekleştiriyoruz. Bunlar ;

- optimizer: ağırlık katsayılarının güncellenmesi için kullanılacak optimizasyon yöntemi
  •             SGD
  •             Adam
  •            RMSprop
  •            AdaGrad, ...vs.
- loss function: gerçek değer ile tahmin edilen değer arasındaki hatayı ifade eden metrik.
  •            binary-cross-entropy
  •            categorical-cross-entropy
  •            mean-squared-entropy,  ...vs.

- metrics: eğitim ve test sırasındaki değerlendirme parametreleri
  •            mae
  •            msc
  •            acc,  ...vs.


Modelimizi konfigüre ettiğimiz değerler ile eğitmek için;

model.compile(optimizer='rmsprop', loss='mse', metrics=['mse', 'mae'])

model.fit(X_train, y_train, batch_size=4, epochs=1000)

model.summary()



Şimdi eğittiğimiz bu modele test verisini girdi olarak verelim ve  sonuçlara bakalım.
Y_pred = model.predict(X_test)
print (y_test[0:10])
print (Y_pred[0:5])

Gördüğünüz gibi bu işte bir terslik var, normalde problemimiz bir sınıflandırma problemi idi. Yani sonuç olarak istediğimiz şey 0 ya da 1 bulmak, Oysa ki elde ettiğimiz sonuçlar (tahmin sonuçları) sürekli değerler! Sonuçlarda eksi değerler olduğunu da görüyoruz. Tahmin değerlerini 0-1 aralığına çekmek için sigmoid aktivasyon katmanı ekleyebiliriz ve 0.5 'den küçük değerleri 0 , diğer değerleri ise 1 olarak ayarlayabiliriz.
model.add(Dense(60, input_dim=60))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mse', 'mae'])


model.fit(X_train, y_train, batch_size=4, epochs=100)
 
model.summary()

 
Y_pred = model.predict(X_test)

Y_pred[Y_pred>=0.5] = 1
Y_pred[Y_pred<0.5] = 0

print (y_test[0:10])
print (Y_pred[0:10])

Ve artık 0,1 sınıflandırma sonuçları elde etmeyi başardık. Tahmin doğruluğunu ölçmek için y_test ve Y_pred dizilerini karşılaştırabiliriz. Bir başka yöntem olarak ise scikit-learn 'deki cross validation sınıfını performans değerlendirmesi için kullanabiliriz. Böylece veri k parçaya bölünerek her bir alt küme için eğitim ve test işlemi gerçekleştirilirek daha güvenilir olan ortalama bir skor elde edilir. Keras modellerini scikit-learn ile kullanmak için KerasClassifier wrapper kullanmalıyız. Bu sınıf ağ modelini oluşturup geri döndüren bir fonksiyonu parametre olarak alır. Bunun için, ağ modelimizi oluşturduğumuz kod parçacıklarını bir fonksiyon içerisine alalım.
def create_model():
 model = Sequential()
 model.add(Dense(60, input_dim=60))
 model.add(Dense(1))
 model.add(Activation('sigmoid'))
 # Compile model
 model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
 return model

cross-validation ile performans/doğruluk sonucunu hesaplayalım.
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

estimator = KerasClassifier(build_fn=create_baseline, nb_epoch=100, batch_size=4, verbose=0)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
results = cross_val_score(estimator, X, encoded_Y, cv=kfold)
print("Results: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
Results: 75.42% (10.15%)

Ortalama %75 doğruluk elde ettik, standart sapma ise %10.

Modelimizde bazı değişiklikler yapıp performansları kıyaslayalım. Modelimize eklediğimiz katmanların aktivasyon fonksiyonlarını belirtelim ve 2. bir katman daha ekleyelim.
def create_model():
    model = Sequential()
    model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))
    model.add(Dense(30, kernel_initializer='normal', activation='sigmoid'))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))
    # Compile model
    model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
    return model
Results: 76.37% (8.57%)

Bir katman daha ekleyince doğruluk kısmen de olsa arttı ve standart sapma da azaldı. Optimizasyon algoritmasını rmsprop dan adam algoritmasına değiştirmeyi deneyelim.

def create_model():
    model = Sequential()
    model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))
    model.add(Dense(30, kernel_initializer='normal', activation='sigmoid'))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))
    # Compile model
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    return model
Results: 76.88% (2.74%)

Performansta biraz daha iyileşme olduğunu görüyoruz. Ayrıca yapay sinir ağı modelimizi oluşturmadan evvel veri üzerinde önişlem yaparak veriyi eğitim için daha elverişli hale getirmek de bazen gerekli olabilir. Şöyle ki, bağımsız değişkenlerin (feature) yani sinir ağımızın girdilerinin ölçek ve dağılım olarak daha tutarlı olması eğitim aşamasında daha iyi sonuç verecektir. Örneğin; kimi değişken 0-1000 arasında değerler alıyor, bir diğeri ise 3.5-4.0 aralığında seyrediyorsa bunların yeniden ölçeklenmesi gerekmektedir. Bunun için scikit-learn kütüphanesinin StandardScaler sınıfını kullanabiliriz. X girdi değerlerimizi aşağıdaki gibi yeniden ölçekleyip, son oluşturduğumuz model ile eğitim ve test işlemini gerçekleştirirsek elde edilen performans sonucu aşağıdaki gibi olacaktır.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_X = X
scaler.fit(scaled_X)
scaled_X = scaler.transform(scaled_X) 
scaled_X ile eğitim yaptığımızda elde ettiğimiz sonuç:
Results: 83.18% (2.08%)


Alternatif olarak, girdi değerlerini yeniden ölçekleyip modele input olarak vermenin dışında, estimators isminde bir değişken tanımlayıp StandardScaler ve KerasClassifier modellerini ard arda bu değişkene ekleyebiliriz.
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp',KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=4, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Results: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
Results: 82.20% (3.98%)


Başlangıca göre iyi bir doğruluk oranına ulaştığımızı söyleyebiliriz.  Son olarak daha büyük bir ağ modeli kuralım, eğitim aşamasındaki adım sayısını(nb_epoch=1000) artıralım ve yukarıda parça parça verdiğim kodların tamamını bir arada paylaşmış olayım. 
import pandas

# load dataset
dataframe = pandas.read_csv("sonar.all-data.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]


from sklearn.preprocessing import LabelEncoder
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)



from keras.models import Sequential


def create_model():
    model = Sequential()
    model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))
    model.add(Dense(30, kernel_initializer='normal', activation='relu'))
    model.add(Dense(15, kernel_initializer='normal', activation='relu'))
    model.add(Dense(10, kernel_initializer='normal', activation='relu'))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))
    # Compile model
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    return model

from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp',KerasClassifier(build_fn=create_model, nb_epoch=1000, batch_size=4, verbose=0)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Results: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

Results: 83.65% (3.22%)

Böylece ikili bir sınıflama problemini adım adım gerçekleştirmiş olduk. Özetleyecek olursak;
  • Keras için verisetini hazırlama ve yüklemeyi
  • Temel bir yapay sinir ağı modeli oluşturmayı
  • Keras modelini scikit-learn ve k-fold cross validation ile kullanmayı
  • Veri önişleme ile modelin performansının artabileceğini

bir sınıflama problemi özelinde açıklamış olduk. Umarım faydalı olmuştur, bazı ingilizce terimleri olduğu gibi yazdım ki bu şekilde daha net anlaşılabildiğini düşünüyorum. 

Kaynaklar : 
http://www.learnopencv.com/deep-learning-using-keras-the-basics/
https://machinelearningmastery.com/binary-classification-tutorial-with-the-keras-deep-learning-library/

8 yorum:

  1. selamlar hocam. ilk baştan söylemek isterim ki tüm emekleriniz için çok teşekkür ederim. derin öğrenmeyle ilgili yazılarınızı ilgiyle takip ediyorum. konuyla ilgili test modelleri yapıyorum. bazen bu modelleri oturtmakta bazı sorunlar yaşıyorum. mesela loss, acc, val_loss, val_acc gibi değerler arasındaki optimal ilişki nasıl olmalı. bu ilişkileri dengeleyebilmek için nasıl (droplar, hangi probleme göre nasıl bir fonksiyon, katman sayısı vb) bir sinir yapısı kurmalıyız. bunun tip sorunlarla ilgili bir paylaşım yapabilirseniz inanın çok memnun kalacağım. saygılarımla. selamlar.

    YanıtlaSil
    Yanıtlar
    1. Selamlar, sorunuz çok spesifik ve cevaplaması da bir o kadar zor. Bana kalırsa net bir cevabı da yok. Bahsettiğiniz sorunları literatür araştırması yaparak bir nebze olsun çözebilirsiniz, insanlar neler denemiş ve nasıl sonuçlar almış görmek için.

      Sil
  2. En son kodlarınızı denedim bende %61.95 accuracy çıktı. Siz 83.65% yazmışsınız. Neden olabilir?

    YanıtlaSil
  3. Hocam selamlar, Keras sequential model kullanarak duygu durumlarına göre text sınıflandırması gerçekleştiriyorum, sequential model tam olarak hangi sinir ağlarına girmekte bunu öğrenmek istemiştim. Araştırdım ama net bir bilgi bulamadım açıkçası. Sequential bir MLP midir yoksa CNN mi LSTM mi RNN mi bilemiyorum. Yanıtlarsanız çok sevinirim. Saygılar

    YanıtlaSil
    Yanıtlar
    1. Merhabalar,

      Sequential model denilen şey aslında Keras ın bize sunmuş olduğu sinir ağı kurma yöntemi. Sequential kelime anlamı olarak ardışık demek ve bu api ardışık katmanlardan oluşan bir sinir ağını kolayca oluşturmamızı sağlıyor. Bunun alternatifi olan functional API ile daha karmaşık yapıda sinir ağları tasarlanabiliyor.

      RNN, CNN, LSTM ise bir çeşit sinir ağları diyebiliriz. Örneğin CNN (convalutional neural network) görüntüler (iki boyutlu matrisler) üzerinde işlem (konvolusyon çarpımı) yapan bir sinir ağı diyebiliriz kabaca. LSTM keras da bir çeşit katman tipi, mesela aşağıda verdiğim linkteki yazıda LSTM örneği mevcut;

      http://ibrahimdelibasoglu.blogspot.com/2017/10/keras-lstm-ile-zaman-serisi-tahmini.html

      Bu yazıda Sequential model ile oluşturulmuş LSTM sinir ağı örneği var. Özet olarak bunlar farklı kavramlar, birisi keras'ın sunduğu model oluşturma metodu diğerleri ise ağ çeşitleri.

      Sil
  4. KerasClassifier(build_fn=create_baseline

    Bu satırda create_model yerine create_baseline yazılmış.

    YanıtlaSil
  5. Hocam iyi çalışmalar accuracy: 98.167% sonucumu buldum.F1 recall precision accuracy değerlerini bulabilmemin kolay yolu var mı tesekkurler.

    YanıtlaSil
    Yanıtlar
    1. sklearn'de metrik fonksiyonları mevcut. Onları kullanabilirsiniz

      https://scikit-learn.org/stable/modules/classes.html#module-sklearn.metrics

      Sil