Data Story

데이터 사이언스, 쉽게 설명하기

DL/Computer Vision

Computer Vision - [CNN with tensorflow]

_data 2024. 2. 20. 23:15

CNN(Convolution Neural Network)를 활용해 호머와 심슨을 분류해보자.

1. Import the library

import matplotlib.pyplot as plt
import seaborn as sns
import zipfile
import numpy as np
from google.colab.patches import cv2_imshow
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Dense, Flatten, MaxPool2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator
tf.__version__ # 2.15.0

 

 

2. Load the images

dataset : https://www.kaggle.com/datasets/aasousa/images-simpsons

 

Images of Simpsons: Homer and Bart

Images of Homer and Bart to classification with Convolutional Neural Network

www.kaggle.com

# google drive
from google.colab import drive
drive.mount('/content/drive')

# homer bart dataset
path = '~/homer_bart_2.zip'
zip_object = zipfile.ZipFile(file=path, mode='r')
zip_object.extractall('./')
zip_object.close()

 

tf.keras.preprocessing.image.load_img("./bart100.bmp')

 

3. dataset generator

# 어떻게 데이터셋을 생성할 것인가?
training_generator = ImageDataGenerator(rescale=1./255, rotation_range=7, horizontal_flip=True, zoom_range=2)
test_generator = ImageDataGenerator(rescale=1./255)

# 데이터셋 정의
train_dataset = training_generator.flow_from_directory('/homer_bart_2/training_set',
  target_size=(64,64), batch_size=8, class_mode='categorical', shuffle=True)
test_dataset = test_generator.flow_from_directory('/homer_bart_2/test_set',
  target_size=(64,64), batch_size=1, class_mode='categorical', shuffle=False)
더보기

Found 215 images belonging to 2 classes.

Found 54 images belonging to 2 classes.

 

- training_generator에는 데이터 증강을 해주지만, test_generator에는 scale만 조정해준다. training dataset을 학습하지

test dataset은 학습할 필요가 없기 때문이다. 이후 데이터를 정의해준다.

- flow_from_directory를 하면 해당 경로 하위 폴더들을 사용한다. bart, homer 폴더가 있기 때문에 binary task가 된다.

- target_size로 사이즈를 동일하게 정의해준다. 해당 폴더 내 이미지들은 size가 달라, batch_size는 8로, 8개의 이미지를 가지고 신경망에 투입한 후, 다음 8장을 가져와 신경망에 또 투입힌다. 이 과정에서 가중치는 업데이트 된다.

- class_mode는 'binary'해도 되지만, 'categorical'로 해도 상관없다. 이진 분류가 아닌 다중 분류라면 'categorical'은 필수다.

- shuffle은 데이터셋을 섞는다. 데이터의 순서가 학습에 영향을 줄 수 있기 때문에 섞어준다.

- train_dataset과 test_dataset은 다르다. batch_size=1로 한 이유는 한 장씩 확인하기 위해서고, shuffle=False는 test data는 학습에 쓰이지 않기 때문에 False로 해준다.

 

print(train_dataset.class_indices)
print(test_dataset.class_indices)
더보기

{'bart': 0, 'homer': 1}

{'bart': 0, 'homer': 1}

 

4. Modeling

model = Sequential()

model.add(Conv2D(filters=32, kernel_size=(3,3), strides=(1,1), activation='relu', input_shape=(64,64,3)))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Conv2D(filters=32, kernel_size=(3,3), strides=(1,1), activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Conv2D(filters=32, kernel_size=(3,3), strides=(1,1), activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Flatten()) #행렬 -> 벡터

model.add(Dense(units=577, activation='relu'))
model.add(Dense(units=577, activation='relu'))
model.add(Dense(units=2, activation='softmax'))
model.summary()

 

 

Dense층에서 units 577을 한 이유는 (input의 값 + output 값) / 2 의 값이다. Dense층 앞 input값을 보면 1152이고 output은 2다. 

 

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# fit_generator 사용
history = model.fit_generator(train_dataset, epochs=50)
Epoch 1/50
27/27 [==============================] - 6s 39ms/step - loss: 0.6662 - accuracy: 0.6140
.
.
.
Epoch 49/50
27/27 [==============================] - 0s 18ms/step - loss: 0.1475 - accuracy: 0.9488
Epoch 50/50
27/27 [==============================] - 0s 18ms/step - loss: 0.0756 - accuracy: 0.9628

 

accuracy가 0.96으로 나왔다. train dataset 기준으로 구한 것이라 높다. test data로 검증을 해봐야 한다.

 

5. Evalution

test_dataset.class_indices # {'bart':0, 'homer':1}

predictions = model.predict(test_dataset)
predictions = np.argmax(predictions, axis=1)

cm = confusion_matrix(test_dataset.classes, predictions)
sns.heatmap(cm, annot=True)

 

6. Model save & Load

# 1. json 저장으로 신경망 모델 구조를 저장하자.
model_json = model.to_json()
with open('model.json', 'w') as json_file:
  json_file.write(model_json)
  
# 2. keras로 모델 가중치 저장하자.
from keras.models import save_model
model_saved = save_model(model, './weights.hdf5')

# 3. open json! 다시 모델 구조를 불러오자.
with open('model.json', 'r') as json_file:
  json_saved_model = json_file.read()

# 4. open weights! 다시 모델 가중치를 불러오자.
model_loaded = tf.keras.models.model_from_json(json_saved_model)
model_loaded.load_weights('weights.hdf5')
model_loaded.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model_loaded_summary()

잘 불러와졌다.

 

마지막으로 한 장을 예측해보자.

import cv2
image = cv2.imread('homer7.bmp')
cv2_imshow(image)

 

image = cv2.resize(image, (64,64))
cv2_imshow(image)

image = image/255
print(image.shape)
# (64,64, 3)

image = image.reshape(-1, 64, 64, 3) # 한 장이라 -1로 지정함. 10장을 예측하려면 10으로 두면 됨.
print(image_shape)
# (1, 64, 64, 3)

 

test_dataset.class_indices
# {'bart': 0, 'homer': 1}

result = model.predict(image)
result = np.argmax(result)
result
1/1 [==============================] - 0s 18ms/step
1

 

homer로 잘 예측했다.