Posts 고양이, 강아지 사진으로 해보는 CNN
Post
Cancel

고양이, 강아지 사진으로 해보는 CNN

1. Cat and Dogs


1.1 Cat and Dgos

  • PCA 할때 사용했던 데이터. https://hmkim312.github.io/posts/강아지와_고양이_분류기_on_PCA/
  • kaggle : https://www.kaggle.com/c/dogs-vs-cats/data
  • 위의 링크에서 Donwload all 버튼을 눌러 dogs-vs-cats를 받으면 된다.
  • 압축을 2번 풀어 train과 test1 폴더를 구한다.
  • 용량이 약 900메가정도되는 개와 고양이 이미지 데이터이다.
  • rian에는 강아지 사진 12500장, 고양이 사진 12500장이 있으며, test1데이터에는 고양이와 강아지 사진이 12500장 있다.


2. 실습


2.1 Data Load

1
2
3
4
import os

path = './data/dogs-vs-cats/train/'
os.listdir(path)[:5]
1
2
3
4
5
['dog.8011.jpg',
 'cat.5077.jpg',
 'dog.7322.jpg',
 'cat.2718.jpg',
 'cat.10151.jpg']
  • 고양이와 개 사진의 데이터.
  • jpg 파일로 되어있음


2.2 라벨과 id로 나눔

1
2
3
full_name = os.listdir(path)
labels = [each.split('.')[0] for each in full_name]
file_id = [each.split('.')[1] for each in full_name]
1
set(labels), len(file_id)
1
({'cat', 'dog'}, 25000)
  • Cat와 Dog로 라벨을 나누고, 총 파일은 25000개.


2.3 데이터 보기

1
2
3
4
5
6
7
8
9
import random
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

sample = random.choice(full_name)
image = mpimg.imread(path + sample)
plt.imshow(image)
plt.title(sample)
plt.show()

  • Dog 라벨인데, 6725번은 사람과 개가.. 이런 사진이 있다.


2.4 사진의 크기

1
2
3
4
5
6
sample = random.choice(full_name)
image = mpimg.imread(path + sample)
print(image.shape)
sample = random.choice(full_name)
image = mpimg.imread(path + sample)
print(image.shape)
1
2
(132, 249, 3)
(500, 320, 3)
  • 각각의 사진의 크기가 다름


1
2
3
4
5
6
7
8
9
10
11
12
13
from skimage.transform import resize
resized = resize(image, (128, 128, 3))

fig, axes = plt.subplots(1, 2, figsize=(8, 4))
ax = axes.ravel()

ax[0].imshow(image, cmap = plt.cm.gray)
ax[0].set_title('image')
ax[1].imshow(resized, cmap = plt.cm.gray)
ax[1].set_title('Resized')

fig.tight_layout()
plt.show()

  • 사이즈를 128 x 128로 리사이즈를 하였음


2.5 Resized

1
2
3
4
5
6
7
8
9
from skimage.color import rgb2gray
import numpy as np

images = []
bar_total = full_name
for file in bar_total:
    image = mpimg.imread(path + file)
    images.append(resize(image, (128, 128, 3)))
images = np.array(images)
  • 총 25000개의 데이터를 모두 128 x 128 x 3으로 리사이즈함


1
images.shape, labels[:3]
1
((25000, 128, 128, 3), ['dog', 'cat', 'dog'])


  • 총 25000개의 데이터가 128 x 128 x 3의 사이즈이고, dog, cat으로 라벨링 되어있음


2.6 Label 인코딩

1
2
3
4
5
6
from sklearn.preprocessing import LabelEncoder

encoder = LabelEncoder()
encoder.fit(labels)
labels_encoded = encoder.transform(labels)
labels_encoded[:3], encoder.classes_
1
(array([1, 0, 1]), array(['cat', 'dog'], dtype='<U3'))
  • Label 인코딩하고 (dog = 1, cat = 0)


2.7 Data 나누기

1
2
3
4
5
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(images, labels_encoded, test_size = 0.2, random_state = 13, stratify = labels_encoded)

X_train.shape, X_test.shape
1
((20000, 128, 128, 3), (5000, 128, 128, 3))
  • 총 2만개의 학습용 데이터와 5천개의 테스트 데이터


2.8 이미지 확인

1
2
3
4
5
6
7
8
9
10
samples = random.choices(population = range(0,20000),k=8)

plt.figure(figsize = (14,12))
for idx, n in enumerate(samples):
    plt.subplot(2,4, idx+1)
    plt.imshow(X_train[n], cmap = 'Greys', interpolation = 'nearest')
    plt.title(y_train[n])

plt.tight_layout()
plt.show()

  • 욕조에 들어간 고양이도있고.. 이미지가 제각각임


2.9 CNN 모델 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from tensorflow.keras import layers, models

model = models.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', input_shape = (128, 128, 3)),
    layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
    layers.Dropout(0.25),
    
    layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
    layers.MaxPooling2D(pool_size=(2, 2)),
    layers.Dropout(0.25),
    
    layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
    layers.MaxPooling2D(pool_size=(2, 2)),
    layers.Dropout(0.25),
    
    layers.Flatten(),
    layers.Dense(512, activation='relu'),
    layers.Dropout(0.25),
    layers.Dense(2, activation='softmax')
])

model.summary()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 126, 126, 32)      896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 63, 63, 32)        0         
_________________________________________________________________
dropout (Dropout)            (None, 63, 63, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 63, 63, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 31, 31, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 31, 31, 64)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 31, 31, 64)        36928     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 15, 15, 64)        0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 15, 15, 64)        0         
_________________________________________________________________
flatten (Flatten)            (None, 14400)             0         
_________________________________________________________________
dense (Dense)                (None, 512)               7373312   
_________________________________________________________________
dropout_3 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 2)                 1026      
=================================================================
Total params: 7,430,658
Trainable params: 7,430,658
Non-trainable params: 0
_________________________________________________________________


2.10 Fit

1
2
3
4
5
6
7
8
9
import time
model.compile(
    optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])


start_time = time.time()
hist = model.fit(X_train.reshape(20000, 128, 128, 3), y_train, epochs = 5, verbose=1, validation_data= (X_test.reshape(5000, 128,128,3), y_test))

print(f'Fit Time : {time.time() - start_time}')
1
2
3
4
5
6
7
8
9
10
11
Epoch 1/5
625/625 [==============================] - 143s 229ms/step - loss: 0.6912 - accuracy: 0.5497 - val_loss: 0.6332 - val_accuracy: 0.6434
Epoch 2/5
625/625 [==============================] - 141s 225ms/step - loss: 0.5874 - accuracy: 0.6835 - val_loss: 0.5333 - val_accuracy: 0.7388
Epoch 3/5
625/625 [==============================] - 134s 215ms/step - loss: 0.5083 - accuracy: 0.7490 - val_loss: 0.4638 - val_accuracy: 0.7764
Epoch 4/5
625/625 [==============================] - 134s 214ms/step - loss: 0.4518 - accuracy: 0.7847 - val_loss: 0.4352 - val_accuracy: 0.8002
Epoch 5/5
625/625 [==============================] - 134s 215ms/step - loss: 0.4071 - accuracy: 0.8144 - val_loss: 0.4200 - val_accuracy: 0.8084
Fit Time : 689.2392101287842
  • 시간도 오래걸림..


2.11 학습 상황

1
2
3
4
5
6
7
8
9
plot_target = ['loss', 'val_loss', 'accuracy', 'val_accuracy']
plt.figure(figsize = (12,8))

for each in plot_target:
    plt.plot(hist.history[each], label = each)
    
plt.legend()
plt.grid()
plt.show()

  • loss도 떨어지고, accuracy도 올라가는데 어느정도 지나면 두개가 역전이 된다 오버피팅을 의심해볼만함


2.12 점수 확인

1
2
3
score = model.evaluate(X_test, y_test)
print(f'Test Loss : {score[0]}')
print(f'Test Accuracy  : {score[1]}')
1
2
3
157/157 [==============================] - 6s 37ms/step - loss: 0.4200 - accuracy: 0.8084
Test Loss : 0.42004361748695374
Test Accuracy  : 0.8083999752998352
  • Accuracy가 0.8.. 데이터가 그렇게 좋지 않아서 그런듯 하다


2.13 예측

1
2
3
predicted_result = model.predict(X_test)
predicted_labels = np.argmax(predicted_result,  axis=1) 
predicted_labels
1
array([0, 1, 0, ..., 0, 1, 1])
  • np.argmax : 가장 최대값을 가지는 인덱스 가져옴


2.14 틀린데이터 확인

1
2
3
4
5
6
wrong_result = []
for n in range(0, len(y_test)):
    if predicted_labels[n] != y_test[n]:
        wrong_result.append(n)
        
len(wrong_result)
1
958
  • 총 5000개 데이터 중에 958개 틀림


2.15 그중 16개만 그려보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import random

samples = random.choices(population=wrong_result, k=16)

plt.figure(figsize=(14, 12))

for idx, n in enumerate(samples):
    plt.subplot(4, 4, idx + 1)
    plt.imshow(X_test[n].reshape(128, 128, 3),
               cmap='Greys', interpolation='nearest')
    plt.title('Label ' + str(y_test[n]) +
              ', Predict ' + str(predicted_labels[n]))
    plt.axis('off')

plt.show()

  • 이상한 이미지도 보이고, 그렇다.. (0 : Cat, 1 : Dog)


2.16 이미지 하나 넣고 확인

1
2
3
4
5
6
7
8
9
import cv2
import matplotlib.pyplot as plt

image_bgr = cv2.imread("./data/dogs-vs-cats/cat_test.jpeg")
test_image = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
test_image = resize(test_image, (128, 128, 3))
plt.imshow(test_image)
plt.title('cat')
plt.show()

  • 집에서 키우는 반려묘의 사진을 집어넣기로 했음.
  • 데이터를 opencv로 불러오고, 이미지 사이즈를 128 x 128 x 3 으로 리 사이즈함


2.17 예측

1
2
3
4
if np.argmax(model.predict(test_image.reshape(1, 128, 128, 3))) == 0:
    print('Cat')
else :
    print('Dos')
1
Cat
  • 고양이 사진을 넣고, 예측하기를 고양이로 해주었다.


3. 요약


3.1 요약

  • CNN을 이용하여 강아지, 고양이 구별하는 모델을 생성
  • 데이터에 다른 사람이나 기타 사물이 같이 찍혀있어서, 예측이 너무 안되긴 한다.
  • 정제가 잘 안된데이터를 넣으면 예측모델도 좋지 않다는 한 예인듯하다.
  • 그래도 집에서 키우는 반려묘의 사진을 넣고 고양이로 예측해줘서 다행이다..
This post is licensed under CC BY 4.0 by the author.