Keras ile Sınıflandırma : Cats & Dogs

Buse Yaren Tekin
Operations Management Türkiye
8 min readDec 17, 2019

CNN Sinir Ağı Modeli Kullanımı

Herkese yeniden merhaba, bugün yazdığım yazıda sizlere bir Tensorflow üzerinde çalışabilmekte olan Keras kütüphanesi ağırlıklı olmak üzere diğer yardımcı kütüphanelerin de kullanımı ile basit bir uygulama hakkında yorumlama yapacağım. IDE olarak localhostta çalışan Jupyter IDE’sini kullanacağım. Sizlere de şiddetle kullanmanızı tavsiye ederim. Dilerseniz öncelikle ufak bir bilgi vererek başlayalım.

Keras Nedir?

👉 Keras, Python’da yazılmış CPU ve GPU’ da sorunsuz olarak çalışabilen açık kaynaklı bir sinir ağı kütüphanesidir. Ben arkaplanda TensorFlow ile çalışacağım fakat bunun dışında Theano ve CNTK gibi backend engineleri mevcuttur. Dilediğinizi kullanabilirsiniz.Aynı zamanda kütüphanelerimizi de import edelim

import numpy as np
import pandas as pd
from keras.preprocessing.image import ImageDataGenerator, load_img
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import random
import os

👉 Bu şekilde eğitim için gerekli kütüphaneleri importlamış olduk. Run ettiğimiz sırada bize şu şekilde bir geri bildirimin dönmesi gerekiyor.

👉 Daha sonra bulunduğunuz dizin üzerinde kullanılacak eğitim ve test verilerini görmek adına os.listdir( ) ile listeleyebiliriz. Bu komut ile klasör içerisinde hangi verilerin yer aldığını görebiliriz.

Veri Seti İncelenmesi

Kullanılan veriler için Kaggle’ dan Dogs. vs. Cats veri setini ücretsiz olarak indirebilirsiniz, böylelikle birlikte ilerleyebiliriz.

print(os.listdir("../Data/"))
Dizin içerisinde bulunan klasörler

Bu arada çalışmakta olduğum proje, çoklu kategorili görüntülerde derin öğrenme kullanılarak sınıflandırma yapılmasıdır. İçerisinde barındırdığı resimleri ‘dogs’ ya da ‘cats’ etiketleri olarak kullanacağız.

filenames = os.listdir(“Data/train”)
categories = []
for filename in filenames:
category = filename.split(‘.’)[0]
if category == ‘dog’:
categories.append(1)
else:
categories.append(0)

👉Eğitim kümesi verileri üzerinde kedi veya köpek kategorisine göre 1 veya 0 eklemesi yukarıdaki kodda yapılmaktadır. Label olarak 1 köpeği temsil ederken 0 kediyi temsil etmektedir.

df = pd.DataFrame({
'filename': filenames,
'category': categories
})

👉Pandas kütüphanesi ile veri için okuma ve yazma yapabildiğimiz pd ile veri setimiz yani DataFrame’de filenames ve categories ile dosya adı kategoriyi ilişkilendirdik. filename ve category veri setindeki dosyanın ismini ve kedi mi köpek mi hangi sınıfa ait olduğunu belirtecektir.
Ardından bu dataframe üzerinde head( ) komutu ile default olarak ilk 5 veri getirildi. df.head( ) içerisine aldığı değer kadar dataframe içerisindeki verileri getirir.

df.head( ) 
İlk 5 verinin döndürülmesi

👉Veri setinde kedi ve köpek olarak tanıtılan kategoriler öncelikle işlem görmesi için 0 ve 1’e dönüştürüldü.

20000 görüntünün kontrolü
test_df[‘category’]=test_df[‘category’].replace({‘dog’: 1, ‘cat’: 0 })

👉 Daha sonra yukarıda görüldüğü üzere en son işlem olarak test aşamasında yeniden kedi ve köpek kategorisine dönüştürüldü.

df[‘category’].value_counts().plot.bar()

Yukarıda veri setindeki category classındaki 0 ve 1 etiketlerine sahip verileri value_counts( ) ile sayarak matplotlibe ait sayılarına göre bar( ) fonksiyonu ile bar grafiği çıkartılmaktadır.

Tahmini 10000'er tane kedi ve köpek görüntüsü

Rastgele Veri Setinden Resim Alma

sample = random.choice(filenames)
image = load_img(“Data/train/”+sample)
plt.imshow(image)

👉Toplamda 20000 adet bulunan görüntü üzerinde veri setini ayırma işlemi gerçekleştirirsek 12000 adet train ( eğitim) , 8000 adet test verisi bulunmaktadır. Bu projedeki veri setinin %60’ı eğitim ve %40’ı ise test veri kümesine ayrılmıştır.

12000 adet eğitim kümesi değerlerinin grafikselleşmesi

❗️CNN, görüntüyü çeşitli katmanlarla işleyerek sınıflandırmaya yarayan bir sinir ağı modelidir. Görüntüden farklı ilgi alanları alınarak o bölgedeki nesnenin varlığı CNN yardımıyla sınıflandırılmaktadır.
❗️CNN sinir ağı modeli kullanacağımız için yapısının bize sağladığı katmanları iyi bilmek ve oluşturulacak modeli iyi tasarlamak gerekmektedir. Bu projede kullanılacak sinir ağı mimarisini aşağıda göstermekteyim. CNN modeli taslak olarak Convolutional Layer (Evrişimsel Katman), Pooling Layer( Havuzlama Katmanı) ve Fully Connected (Tam Bağlı Katman) yapılarından oluşmaktadır. Genellikle overfitting engellenmesi için çeşitli regülarizasyon yöntemleri (Dropout, Early Stopping, vs) ile aşırı öğrenme önlenmektedir. Bu çalışmada herhangi bir regülarizasyon yöntemi kullanmadım, daha iyi sonuçlar elde etmek için dilerseniz kullanabilirsiniz.

CNN Katman Mimarisi

👉Projede, bir evrişimsel tabaka, aktivasyon fonksiyonu olarak RELU fonksiyonu, bir havuzlama tabakası ve tam bağlı bir tabakadan oluşan bir evrişimsel sinir ağı kullanılmaktadır.

KATMAN MODELİNİN YAPISI

Sınıflandırma amacıyla, evrişimsel ağı [INPUT-CONV-RELU-POOL-FC] olacak şekilde mimariye sahiptir. INPUT olan ilk yapıda kullanılacak görüntü verileri yer almaktadır. Giriş görüntüleri olarak veri seti içerisinde bulunan 20000 adet kedi ve köpek resimleri seçilmiştir. Bu görüntüler üzerinde sınıflandırma yapmak için CNN sinir ağı modeli seçilmiştir.

👉Öncelikle Convolution denilen Evrişim katmanı ile belirli bir filtre sayısında kernel oluşturulmuştur (kernel_size isteğe göre seçilebilir). Bu evrişim çekirdeği ile görüntü üzerinde özellik çıkarımı yapılması için filtreler uygulanmıştır. Bu katman CNN modelinin yapıtaşıdır. Bunu tıpkı görüntü işlemedeki görüntü üzerinde Mean,Gaussian, Laplas, Sobel filtelerinin piksel piksel uygulanışı gibi düşünebilirsiniz. Kullanacağım görüntü boyutlarım 64 x 64 ve IMAGE_CHANNEL olarak belirtilen kullanılacak görüntü kanalım ise 3 olarak belirlenmiştir. Aşağıda RGB olarak seçilen bu renk kanalının görüntü pikselleri üzerinde nasıl davranış gösterdiği görülmektedir.

RGB Kanalları ile Evrişim Filtresi Uygulanması
Convolutional Katmanı ile Özellik Çıkarımı

🤗Bu Convolution katmanı sayesinde görüntüler üzerinde feature detection denilen özellik çıkarımı gerçekleştirilmiştir. Bu özelliklere örnek olarak kedinin gözü, köpeğin kuyruğu verilebilir. Bu sayede görüntüler derinleştirilmiştir. Ardından bu çıkarım yapılan feature map üzerinde aktivasyon fonksiyonu olan RELU uygulanmıştır.

ReLU fonksiyonu

👉Çok katmanlı sinir ağlarında aktivasyon yoğun yani çok işlem gerektiriyor demektir. Ağdaki bazı nöronların aktif olup, aktivasyon seyrek yani verimli bir hesaplama yükü olsun istenir. ReLU ile diğer aktivasyon fonksiyonlarına göre hesaplama yükünün daha verimli olması sağlanır.

👉Evrişim katmanından gelen görüntüler ve özellikler üzerinde Pooling adı verilen Havuzlama katmanı söz sahibidir. Bu katman ile modelin karmaşıklığı, performansı düşürmeden parametre sayısını düşürerek azaltılır. Sınıflandırmayı etkilememek için görüntüdeki her tanımayı yapacaktır. Aynı zamanda bu işlemler ile Overfitting denilen aşırı öğrenme işlemini de engeller. Pooling yapısı olarak MaxPooling kullanılmıştır. Bu şekilde kernel boyutlarında en büyük sayı alınmıştır. Bu işlem ile sinir ağının doğru karar vermesi için yeterli bilgiyi içeren daha küçük çıktılar kullanılmış olur.

👉Pooling ile gösterimin kayma boyutunu, ağ içindeki parametreleri ve hesaplama sayısını azaltmak içindir. Bu sayede ağdaki uyumsuzluk kontrol edilmiş olur.

MaxPooling Çalışma Mantığının Görselleştirilmesi

👉Alınan kernellar ile mimarinin son katmanı olan Fully Connected katmanı için öncelikle bu veriler tek girişli matrise dönüştürülecektir. Fully Connected Katmanındaki sinir ağları birbirine tamamen bağlanmaktadır. Her bir nöronun ayrı bir weight değeri vardır.Burada oluşturulacak ağ sadece bu tip katmanlardan oluşacak.Bunu sağlayacak işlem ise Flatten ( ) sayesinde gerçekleştirilir. Daha sonra hazırlanan bu veriler Dense ile yoğunluk filtresi verilerek bağdaştırılır. Bu katmanda girişte alınan input veriler Fully Connected Layerda kullanılmak üzere hazırlanmaktadır.

Tek girişli veri elde edilmesi
Dense katmanının eklenmesi

CNN Mimarisinin Python Kodunda Oluşturulması

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization
model = Sequential()model.add(Conv2D(64, (3, 3), activation='relu',use_bias=True, input_shape=(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS)))
model.add(MaxPooling2D(pool_size=(2, 2)))
#fully connected işlemi, 2 hidden layers
model.add(Flatten())
model.add(Dense(512, activation = 'relu',use_bias=True))
model.add(Dense(2, activation = 'relu',use_bias=True))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
model.summary()

🤗Ben Convolution katmanında 64 filtresini ve kernel_size olarak da (3,3) belirlemiş oldum. İlk Conv katmanında görüntünün width, height değerleri mutlaka girilmek zorundadır. Bu değerlere göre filtreleme işlemi yapılacaktır. İçerisindeki aktivasyon fonksiyonu zaten relu olarak belirtilmişti.Dilerseniz Dense katmanında softmax’i kullanabilmeniz mümkündür.Üzerinde çalıştığım makalede yalnızca relu kullanılmakta olduğu için makale dışarısına çıkmadım. Yapay Sinir Ağları’nda ağırlık güncellemeleri sırasında hesaplanan Z sinyalindeki formülde eğer kullanılacak ise bias değerleri de toplama katılmak zorundadır. Bu makalede bias değerleri de kullanıldığı için use_bias=True olarak belirttim. Ve Pooling katmanında ise (2,2) lik bir pool_size oluşturarak verileri küçülttüm. Sinir ağı yapımda 2 adet gizli katman bulunduğu için Fully Connected kısmında ona göre işlem gerçekleştirdim.

YSA Yapısı

❗️Yapay Sinir Ağlarında bildiğiniz üzere bir maliyet hesaplaması söz konusudur. Bu hesaplamada maliyetin minimum olmasını istiyoruz. Bu sebeple loss (kayıp) değeri hesaplanması bizim için oldukça önem arz etmektedir.

👉 Oluşturduğumuz modelin compile edilebilmesi için kullanılacak loss parametresi seçilmelidir. Bunun için Keras’ da loss kullanımı ile ilgili çok güzel açıklamalar yer almaktadır, inceleyebilirsiniz. Ben iki kategorili bir sınıflandırma yaptığım için categorical_crossentropy yapısını kullandım.

Model Özeti

👉Projede kullanılacak batch_size değişkeni 100 olarak eşitlendi.

batch_size=100

👉Ardından veri artımı olarak bilinen Data Augmentation bölümüne geçildi. Kesme ve dönme aralıkları belirtilerek yakınlaştırma, uzaklaştırma, döndürme, yatay çevirme gibi veri artırımı yöntemine başvurulmuştur.

train_datagen = ImageDataGenerator(
rotation_range=15,
rescale=1./255,
shear_range=0.1,
zoom_range=0.2,
horizontal_flip=True,
width_shift_range=0.1,
height_shift_range=0.1
)
#Data augmentation
train_generator = train_datagen.flow_from_dataframe(
train_df,
"Data/train/",
x_col='filename',
y_col='category',
target_size=IMAGE_SIZE,
class_mode='categorical',
batch_size=batch_size
)
2 sınıf için geçerli eğitim kümesi görüntüleri
plt.figure(figsize=(12, 12))
for i in range(0, 9):
plt.subplot(5, 3, i+1)
for X_batch, Y_batch in example_generator:
image = X_batch[0]
plt.imshow(image)
break
plt.tight_layout()
plt.show()
Veri artırımı sonuçlarının grafikselleştirilmesi

👉Daha sonra eğitmek için sırasıyla 100, 500 ve 1000 epochluk iterasyonlar ile çalışıldı. Bu değerlerden sonra loss değerinden kaynaklanan sebep ile accuracy — doğruluk değeri düşmeye başladı. Aşağıda 100 iterasyonluk bir işlem gösterilmektedir.

epochs=1 if FAST_RUN else 100 
history = model.fit_generator(
train_generator,
epochs=epochs,
validation_data=validation_generator,
validation_steps=total_validate//batch_size,
steps_per_epoch=total_train//batch_size,
)
100 Epoch için Loss ve Accuracy Sonuçları

👉 Kayıp değerlerinin değişimi ve doğruluk değerleri grafiği için aşağıdaki kod parçası çalıştırılarak grafikler oluşturulmuştur.

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))
ax1.plot(history.history['loss'], color='b', label="Training loss")
ax1.plot(history.history['val_loss'], color='r', label="validation loss")
ax1.set_xticks(np.arange(1, epochs, 1))
ax1.set_yticks(np.arange(0, 1, 0.1))
ax2.plot(history.history['acc'], color='b', label="Training accuracy")
ax2.plot(history.history['val_acc'], color='r',label="Validation accuracy")
ax2.set_xticks(np.arange(1, epochs, 1))
legend = plt.legend(loc='best', shadow=True)
plt.tight_layout()
plt.show()
Loss & Accuracy Değişim Grafiği

👉Daha sonra tahmin aşamasına geçilerek klasörde bulunan test görüntüleri makineye verilmiştir.

test_filenames = os.listdir("Data/test1")
test_df = pd.DataFrame({
'filename': test_filenames
})
nb_samples = test_df.shape[0]

Test görüntülerinde de data augmentation(veri artırımı) gerçekleştirilmektedir.

test_gen = ImageDataGenerator(rescale=1./255)
test_generator = test_gen.flow_from_dataframe(
test_df,
"Data/test1/",
x_col='filename',
y_col=None,
class_mode=None,
target_size=IMAGE_SIZE,
batch_size=batch_size,
shuffle=False
)
8000 adet test verisi bulunması

👉Model predict methodu ile tahmine gönderilerek yukarıda oluşturulan kategoride 1:dog 0:cat temsil ederken artık bu etiketleme aşağıda değiştirilmiştir.

predict = model.predict_generator(test_generator, steps=np.ceil(nb_samples/batch_size))test_df['category'] = np.argmax(predict, axis=-1)
label_map = dict((v,k) for k,v in train_generator.class_indices.items())
test_df['category'] = test_df['category'].replace(label_map)
test_df['category'] = test_df['category'].replace({ 'dog': 1, 'cat': 0 })

👉Ardından tahmin sonucu etiketler (label) CSV dosyasına bastırılarak tahmin kontrolü sağlanmıştır.

submission_df = test_df.copy()
submission_df[‘id’] = submission_df[‘filename’].str.split(‘.’).str[0]
submission_df[‘label’] = submission_df[‘category’]
submission_df.drop([‘filename’, ‘category’], axis=1, inplace=True)
submission_df.to_csv(‘Test_submission.csv’, index=False)
Oluşturulan test dosyası

Oluşturulan CSV dosyasında kontrolü sağlamak için öncelikle 1085 ve 1079 id’lerine sahip görüntüyü ele alalım. Görüntüde kedi bulunmaktadır. CSV dosyasında da kategorisi 0 ve 1 olarak belirtilmiştir. Klasörde de bunun kontrolü sağlanarak aşağıda bu bilgilere yer verilmiştir.

Tahmin kontrolü

👉Test verilerinin bulunduğu CSV dosyasının görünümü;

CSV dosyasındaki etiketlendirmeler
6136 nolu image: Cat

Umarım anlattıklarım sizler için bir nebze faydalı olabilmiştir. Herkese iyi kodlamalar dilerim ve güzel günler dilerim 😇

--

--