Keras/Tensorflow ile Rakamları tanıma (MNIST Dataset)

Keras; Tensorflow veya Theano üzerinde çalışan python ile yazılmış bir derin öğrenme kütüphanesidir. Yapay sinir ağları(neural network) kurulumunda hızlıca ve kolayca prototipleme yapmamızı sağlar.

An itibari ile Python 2.7 ve 3.5 ile uyumlu olduğu için 3.6 kurulu bir sisteminiz varsa çalışmayacaktır.

Tensorflow; işin daha çok matematik kısmını halleden ve bunu görselleştiren Google’ın sahip olduğu kütüphane.

MNIST; (Modified National Institute of Standards and Technology database) cümlesinin kısaltmasıdır. El yazısı ile yazılmış ve uygun bir şekilde sınıflandırılmış rakamlardan oluşur. 60.000 öğrenme(train) ve 10.000 doğrulama(test) görseli barındırır.

Bu iki kütüphane de GPU üzerinde çalışabiliyor. Nvidia ekran kartları için CUDA gibi kütüphaneler kurulması gerektiği için basit tutmak adına bu örneği CPU üzerinde çalıştıracağız.

Geliştirme ortamını oluşturmak için pek çok kurulum yapmamız gerekli. Bunun basit bir yolu Anaconda kurmak. Linkten indirip kurduktan sonra Anaconda Navigator’ı açtığımızda root Environment’ı ve üzerinde bir kaç uygulama kurulu geliyor. Burada Spyder uygulaması kurulu değilse Install’a tıklayarak kuruyoruz sonra Launch ile başlatıyoruz.

Örnek kodu şu gist‘te görebilirsiniz. Burada kodları paylaşıp açıklamaya çalışayım.

# Türkçe olan kısımları ben ekledim, diğer her şey kaynaktan alınmıştır.
'''Trains a simple convnet on the MNIST dataset.

Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''

from __future__ import print_function
import keras
# MNIST verisini ayrıca indirmemize gerek yok
# Keras sayesinde bu şekilde kolayca alabiliriz
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

# Tek seferde ne kadar verimizin ağdan geçeğini belirtir
# RAMimiz yüksekse yüksek tutmakta fayda var, daha hızlı öğrenme sağlar
batch_size = 128

# Verimizin kaç sınıfa ayrıldığı 
# Mnist için sıfırdan dokuza kadar 10 veri sınıfımız var
num_classes = 10

# Verimiz yapay sinir ağı üzerinden kaç kez geçecek.
# Kaynakta 12 epoch olarak verilmiş fakat hızlı olması için 2 epochda bitiriyorum
epochs = 12

# input image dimensions
img_rows, img_cols = 28, 28

# Veri 4 parçaya bölünmüş olarak ve 
# Her bir görsel için 28x28 boyutunda bir matris olarak verimizi alabiliriz
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# Veriyi channel bilgisine göre tekrar düzenliyoruz.
# Tensorflow ve Theano farklı veri şekilleri ile çalışıyorlar 
if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# y değerlerimiz x verimizin hangi rakama yani hangi sınıfa ait olduğunu tutan rakamlardı
# Yani y verilerimizin birinci boyutu x içerisindeki indexe karşılık gelirken
# ikinci boyutu 0 indexi alabiliyor ve y, 0-9 aralığında tek değer alabiliyordu
# Burada to_categorical metodu ile verimizin ikinci boyutunu sıfır ve birlerden oluşan
# 10 değer alabilecek şekilde genişletiyoruz.
# Örneğin bir verimizin y değeri 8 ise, yeni şekliyle 9 adet sıfır ve 
# yedinci(indexler sıfırdan başladığı için sekizinci değil) indexi 1 olacak hale getiriyoruz

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# Keras Sequential sınıfı Yapay sinir ağımızın temelidir
# Bu sınıfa istediğimiz kadar katman ekleyerek tüm ağı oluşturabiliriz
# Hangi katmanı ne zaman eklenmesi gerektiği ile ilgili, 
# en az kayıp vereni bulana kadar deneme-yanılma yapılır

model = Sequential()

# Buradaki adımları aşağıda açıklamaya çalıştım
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

Neden y verimizi to_categorical ile genişlettik?
Yapay sinir ağımız bir tahminde bulunduğunda bize her bir sınıf için 0-1 aralığında bir sayı verecektir. Bu sayı hangi sınıf için daha yüksek ise o sınıf bizim tahminimiz olacaktır. Ağımızın hata hesaplamaları yapabilmesi ve kendini daha iyi eğitebilmesi için verdiğimiz verinin hangi sınıfa ait olduğunu ağa uygun bir şekilde(shape) vermemiz gerekir. Ağ sonuçta bulduğu/tahmin ettiği 10 sayıyı bizim verdiğimiz 10 sayı ile (bu örnekte 9 adet sıfır 1 adet bir) karşılaştırıp bir sonraki epochta hatasını en aza indirmeye çalışır.

Conv2D(32, kernel_size=(3, 3), activation=’relu’, input_shape=input_shape)
Modelimize bir 2 boyutlu Convolutional katman(layer) ekler. İlk parametresi kaç adet filtrenin bu katmanda kullanılacağıdır. İkinci parametre filtrenin/kernelin boyutudur. Bu modelin ilk katmanı olduğu için input_shape parametresi vermemiz gerekli, boş bırakılırsa compile edilirken hata verecektir.

MaxPooling2D(pool_size=(2, 2))
MaxPooling işlemi, verimizden, verilen pool_size boyutunda kümeler alıp bu kümeler içerisindeki en büyük değerleri kullanarak yeni bir matris oluşturur. Oluşan matrisin boyutu daha küçüldüğü için sonraki katmanlarda işlem hızımızı arttıracaktır ayrıca MaxPooling overfit durumunun önüne geçer.

Dropout
Verilen oranda train matrisinden rastgele veri siler/sıfırlar yani etkisiz hale getirir. Yine Overfit durumlarının önüne geçmek için ve train verimizin çeşitliliğini arttırmak için kullanılır. Dropout katmanı test verisi ağdan geçiyorsa kullanılmaz.

Flatten
Genellikle Convolutional bölümün sonuna konan Flatten metodu çok boyutlu olan verimizi tek boyutlu hale getirerek standart yapay sinir ağı için hazır hale getirir.

Dense
Bir standart yapay sinir ağı katmanı oluşturur, ilk parametrede verilen sayı kadar nöron barındırır.

Eğitme(Train) işlemi Intel i5 – 1.60GHz işlemci, 8 GB DDR3 ram üzerinde yaklaşık 30 dakika sürdü. Çıktılar bu şekilde;

Train on 60000 samples, validate on 10000 samples
Epoch 1/2
60000/60000 [==============================] - 921s - loss: 0.3414 - acc: 0.8960 - val_loss: 0.0849 - val_acc: 0.9746
Epoch 2/2
60000/60000 [==============================] - 892s - loss: 0.1203 - acc: 0.9651 - val_loss: 0.0562 - val_acc: 0.9825
Test loss: 0.056160167551
Test accuracy: 0.9825

loss/acc: train verisi üzerindeki hata oranı ve başarımdır.
val_loss/val_acc: test verisi üzerindeki hata oranı ve başarımdır.
Bu değerlerin hesaplanmasında model.compile metoduna verdiğimiz parametreler kullanılır.

Son epochta görüldüğü gibi test verimizin üzerinde %98 başarı ile tahmin yürütebiliyoruz.

Bir Cevap Yazın