CNN - Cat Dog Classifier

Kategori: Deep Learning , 24 Nisan 2020 , JanFranco


Daha önce üzerinde çalıştığımız MNIST veriseti keras kütüphanesinin içinde bulunuyordu ve keras methodlarını kullanarak import etme, split etme işlemleri kolayca yapılabiliyordu. Bu dökümanda, resimlerden veriseti oluşturacağız ve bu oluşturduğumuz veriseti üzerinde çalışarak kedi - köpek sınıflandırıcısı yapacağız. İlk olarak resimleri çekelim:


import os
import cv2
import sys
import shutil
import numpy as np

myPath = "drive/ColabNotebooks/images/"

fileNames = [f for f in os.listdir(myPath) if os.path.isfile(os.path.join(myPath, f))]

print(str(len(fileNames)) + ' images loaded...')
Çektiğimiz resimleri 4 klasöre bölünecek şekilde ayıracağız. training klasöründe 2000, test klasöründe 1000 resim olacak. Training ve test klasörleri kendi içerisinde cats - dogs klasörleri olarak ikiye ayrılacak. Cats - dogs klasörlerinde, training altında ise 1000 - 1000, test altındaysa 500 - 500 resim olacak:


dogCount = 0
catCount = 0
trainingSize = 1000
testSize = 500
trainingImgs = []
trainingLabels = []
testImgs = []
testLabels = []
size = 150
dogTrainDir = "drive/ColabNotebooks/datasets/catvsdog/traing/dogs/"
catTrainDir = "drive/ColabNotebooks/datasets/catvsdog/traing/cats/"
dogTestDir = "drive/ColabNotebooks/datasets/catvsdog/test/dogs/"
catTestDir = "drive/ColabNotebooks/datasets/catvsdog/test/cats/"

def make_dir(dir):
  if os.path.exists(dir):
    shutil.rmtree(dir)
  os.makedirs(dir)
  
make_dir(dogTrainDir)
make_dir(catTrainDir)
make_dir(dogTestDir)
make_dir(catTestDir)

def get_zeros(number):
  if(number > 10 and number < 100):
    return "0"
  if(number < 10):
    return "00"
  else:
    return ""
  
for i, file in enumerate(fileNames):
  
  if(fileNames[i][0] == "d"):
    dogCount += 1
    img = cv2.imread(myPath+file)
    img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA)
    
    if(dogCount <= trainingSize):
        trainingImgs.append(img)
        trainingLabels.append(1)
        zeros = get_zeros(dogCount)
        cv2.imwrite(dogTrainDir + "dog" + str(zeros) + str(dogCount) + ".jpg", img)
        
    if(dogCount > trainingSize and dogCount <= trainigSize + testSize):
        testImgs.append(img)
        testLabels.append(1)
        zeros = get_zeros(dogCount - 1000)
        cv2.imwrite(dogTestDir + "dog" + str(zeros) + str(dogCount - 1000) + ".jpg", img)
        
  if(fileNames[i][0] == "c"):
    catCount += 1
    img = cv2.imread(myPath+file)
    img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA)
    
    if(catCount <= trainingSize):
        trainingImgs.append(img)
        trainingLabels.append(0)
        zeros = get_zeros(catCount)
        cv2.imwrite(catTrainDir + "cat" + str(zeros) + str(catCount) + ".jpg", img)
        
    if(catCount > trainingSize and catCount <= trainigSize + testSize):
        testImgs.append(img)
        testLabels.append(0)
        zeros = get_zeros(catCount - 1000)
        cv2.imwrite(catTestDir + "dog" + str(zeros) + str(catCount - 1000) + ".jpg", img)
        
  if(dogCount == trainingSize + testSize and catCount == trainingSize + testSize):
    break
        
print("Completed!")
Şimdi veri setini bölelim. İlk olarak numpy kütüphanesinin savez methodu ile, numpy kütüphanesinin array methodu ile, numpy arraye çevirdiğimiz listeleri, npz dosyalarına kaydedelim:


np.savez("catsvsdogs_training_data.npz", np.array(trainingImgs))
np.savez("catsvsdogs_training_labels.npz", np.array(trainingLabes))
np.savez("catsvsdogs_test_data.npz", np.array(testImgs))
np.savez("catsvsdogs_test_labels.npz", np.array(testLabels))
Dosyaları okuyacak ve train, trainLabels, test, testLabels listelerine atacağımız bir fonksiyon yazalım:


def load_data_training_test(datasetName):
  
  npzFile = np.load(datasetName + "_trainig_data.npz")
  train = npzFile['arr_0']
  
  npzFile = np.load(datasetName + "_trainig_labels.npz")
  trainLabels = npzFile['arr_0']
  
  npzFile = np.load(datasetName + "_test_data.npz")
  test = npzFile['arr_0']
  
  npzFile = np.load(datasetName + "_test_labels.npz")
  testLabels = npzFile['arr_0']
  
  return (train, trainLabels), (test, testLabels)
Fonksiyonu kullanarak verisetini bölelim ve preprocessing işlemlerini gerçekleştirelim:


(x_train, y_train), (x_test, y_test) = load_data_training_test("catvsdogs")

y_train = y_train.reshape(y_train.shape[0], 1)
y_test = y_test.reshape(y_test.shape[0], 1)

x_train = x_train.astype("float32")
x_test = x_test.astype("float32")

x_train /= 255
x_test /= 255

print(x_train.shape)
print(x_test.shape)
print(y_train.shape)
print(y_test.shape)
Modeli oluşturalım:


from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D

inputShape = (150, 150, 3)

model = Sequential()

model.add(Conv2D(32, (3, 3), input_shape=inputShape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
          
model.compile(loss = 'binary_crossentropy', optimizer = 'rmsprop', metrics = ['accuracy'])
          
print(model.summary())
          
history = model.fit(x_train, y_train, batch_size = 16, epochs = 25, validation_data = (x_test, y_test), shuffle = True)
          
model.save("drive/ColabNotebooks/models/catsvsdogs.h5")
          
scores = model.evaluate(x_test, y_test, verbose = 1)
print("Test Loss: ", scores[0])
print("Test Accuracy: ", scores[1])
Input boyutumuz 150, 150, 3. MNIST veri seti üzerinde çalışırken 3. boyut 1 idi. Burada resimlerimiz renkli olduğundan 3 değerini yazdık. Modelde 3 adet Convolutional Layer mevcut. Her bir katmandaki filtre boyutu 3x3 ve filtre sayıları sırasıyla 32, 32 ve 64. Convolutional katmanlarda ReLu aktivasyon fonksiyonunu kullandık. Her katmandan sonra Pooling işlemi gerçekleştirdik. Son olarak 64 - 1 bileşen sayılı yapay sinir ağına bağladık. Daha önce oluşturduğumuz modellerden farklı olarak, son katmanın aktivasyon fonksiyonu softmax değil sigmoid fonksiyondur. Bunun sebebi, class yani sınıf sayımız 2, kedi ve köpek. Bu nedenle sigmoid kullanmamız daha mantıklı olur. Modeli compile ederken de loss fonksiyon olarak binary_crossentropy kullandık. Bunun sebebi yine aynı, sınıf sayımız 2. Training işlemine geçelim:


history = model.fit(x_train, y_train, batch_size = batchSize, epochs = epochs, validation_data = (x_test, y_test), shuffle = True)
          
model.save("drive/ColabNotebooks/catsvsdogs.h5")

>>

Train on 2000 samples, validate on 1000 samples
Epoch 1/25
2000/2000 [==============================] - 2s 1ms/step - loss: 0.7057 - acc: 0.5295 - val_loss: 0.6785 - val_acc: 0.6500
Epoch 2/25
2000/2000 [==============================] - 2s 934us/step - loss: 0.6615 - acc: 0.6235 - val_loss: 0.6352 - val_acc: 0.6200
Epoch 3/25
2000/2000 [==============================] - 2s 943us/step - loss: 0.6021 - acc: 0.6910 - val_loss: 0.5896 - val_acc: 0.6970
Epoch 4/25
2000/2000 [==============================] - 2s 942us/step - loss: 0.5579 - acc: 0.7250 - val_loss: 0.5521 - val_acc: 0.7340
Epoch 5/25
2000/2000 [==============================] - 2s 948us/step - loss: 0.4825 - acc: 0.7790 - val_loss: 0.5574 - val_acc: 0.7390
Epoch 6/25
2000/2000 [==============================] - 2s 953us/step - loss: 0.4357 - acc: 0.8030 - val_loss: 0.5730 - val_acc: 0.6970
Epoch 7/25
2000/2000 [==============================] - 2s 947us/step - loss: 0.3728 - acc: 0.8390 - val_loss: 0.5481 - val_acc: 0.7510
Epoch 8/25
2000/2000 [==============================] - 2s 952us/step - loss: 0.3353 - acc: 0.8555 - val_loss: 0.6093 - val_acc: 0.7410
Epoch 9/25
2000/2000 [==============================] - 2s 961us/step - loss: 0.2944 - acc: 0.8800 - val_loss: 0.6715 - val_acc: 0.7390
Epoch 10/25
2000/2000 [==============================] - 2s 961us/step - loss: 0.2445 - acc: 0.9020 - val_loss: 0.6813 - val_acc: 0.7360
Epoch 11/25
2000/2000 [==============================] - 2s 958us/step - loss: 0.2019 - acc: 0.9150 - val_loss: 0.7812 - val_acc: 0.7460
Epoch 12/25
2000/2000 [==============================] - 2s 963us/step - loss: 0.1728 - acc: 0.9330 - val_loss: 0.8849 - val_acc: 0.7490
Epoch 13/25
2000/2000 [==============================] - 2s 955us/step - loss: 0.1544 - acc: 0.9365 - val_loss: 0.9103 - val_acc: 0.7160
Epoch 14/25
2000/2000 [==============================] - 2s 966us/step - loss: 0.1372 - acc: 0.9490 - val_loss: 1.0289 - val_acc: 0.7290
Epoch 15/25
2000/2000 [==============================] - 2s 963us/step - loss: 0.1119 - acc: 0.9605 - val_loss: 1.1710 - val_acc: 0.7290
Epoch 16/25
2000/2000 [==============================] - 2s 958us/step - loss: 0.0921 - acc: 0.9685 - val_loss: 1.1511 - val_acc: 0.7250
Epoch 17/25
2000/2000 [==============================] - 2s 959us/step - loss: 0.1036 - acc: 0.9630 - val_loss: 1.2049 - val_acc: 0.7320
Epoch 18/25
2000/2000 [==============================] - 2s 954us/step - loss: 0.0938 - acc: 0.9735 - val_loss: 1.1989 - val_acc: 0.7430
Epoch 19/25
2000/2000 [==============================] - 2s 967us/step - loss: 0.0909 - acc: 0.9625 - val_loss: 1.2355 - val_acc: 0.7340
Epoch 20/25
2000/2000 [==============================] - 2s 950us/step - loss: 0.0959 - acc: 0.9680 - val_loss: 1.4185 - val_acc: 0.7460
Epoch 21/25
2000/2000 [==============================] - 2s 952us/step - loss: 0.0911 - acc: 0.9710 - val_loss: 1.6115 - val_acc: 0.7460
Epoch 22/25
2000/2000 [==============================] - 2s 949us/step - loss: 0.0854 - acc: 0.9730 - val_loss: 1.7168 - val_acc: 0.7510
Epoch 23/25
2000/2000 [==============================] - 2s 946us/step - loss: 0.1076 - acc: 0.9695 - val_loss: 1.7136 - val_acc: 0.7390
Epoch 24/25
2000/2000 [==============================] - 2s 955us/step - loss: 0.0816 - acc: 0.9715 - val_loss: 0.8445 - val_acc: 0.6890
Epoch 25/25
2000/2000 [==============================] - 2s 960us/step - loss: 0.0986 - acc: 0.9680 - val_loss: 1.7886 - val_acc: 0.7380
Sonuçlar ile ilgili grafikleri görelim:


import matplotlib.pyplot as plt

history_dict = history.history

loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1, len(loss_values) + 1)

line1 = plt.plot(epochs, val_loss_values, label="Validation Loss")
line2 = plt.plot(epochs, loss_values, label="Training Loss")
plt.setp(line1, linewidth=2.0, marker='+', markersize=10.0)
plt.setp(line2, linewidth=2.0, marker='4', markersize=10.0)
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.grid(True)
plt.legend()
plt.show()

import matplotlib.pyplot as plt

history_dict = history.history

acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']
epochs = range(1, len(loss_values) + 1)

line1 = plt.plot(epochs, val_acc_values, label="Validation Accuracy")
line2 = plt.plot(epochs, acc_values, label="Training Accuracy")
plt.setp(line1, linewidth=2.0, marker='+', markersize=10.0)
plt.setp(line2, linewidth=2.0, marker='4', markersize=10.0)
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.grid(True)
plt.legend()
plt.show()






Yorumlamak gerekirse, accuracy ve loss değerleri gayet iyi gözükmesine rağmen validation loss değeri çok fazla, validation accuracy değeri ise düşüktür. Train set üzerinden güzel sonuç alıp, test set üzerinden kötü sonuç almamızın sebebini overfitting'e bağlayabiliriz. Overfitting yani verilerin ezberlenmesi olayını çözmek için en etkili yol olan data augmentation tekniğini önümüzdeki dökümanlarda anlatacağız. Şimdi teste geçelim:


import cv2
import numpy as np
from keras.models import load_model
from google.colab.patches import cv2_imshow

classifier = load_model("drive/ColabNotebooks/models/catsvsdogs.h5")

def draw_test(name, pred, inputImg):
  BLACK = [0, 0, 0]
  if pred == "[1]":
    pred = "cat"
  if pred == "[0]":
    pred = "dog"
  expandedImg = cv2.copyMakeBorder(inputImg, 0, 0, 0, imageL.shape[0], cv2.BORDER_CONSTANT, value=BLACK)
  cv2.putText(expandedImg, str(pred), (252, 70), cv2.FONT_HERSHEY_COMPLEX_SMALL, 4, (0, 255, 0), 2)
  cv2_imshow(expandedImg)
  
for i in range(10):
  rand = np.random.randint(0, len(x_test))
  inputImg = x_test[rand]
  
  imageL = cv2.resize(inputImg, None, fx = 2, fy = 2, interpolation = cv2.INTER_CUBIC)
  cv2_imshow(imageL)
  
  inputImg = inputImg.reshape(1, 150, 150, 3)
  
  res = str(classifier.predict_classes(inputImg, 1, verbose = 0)[0])
  
  draw_test("Prediction", res, imageL)
>>








Sonraki Yazı: Data Augmentation
Yorumlar

Henüz bir yorum bulunmuyor.
Yorum bırakın