이미지 파일을 다운로드하여 말과 사람을 구분하는 CNN을 만들자.
# 구글 코랩을 사용했다.
먼저 wget으로 루트 안의 tmp폴더에 말과 사람 사진이 들어있는 압축파일들을 다운로드 한다.
!wget --no-check-certificate \
https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip \
-O /tmp/horse-or-human.zip
!wget --no-check-certificate \
https://storage.googleapis.com/laurencemoroney-blog.appspot.com/validation-horse-or-human.zip \
-O /tmp/validation-horse-or-human.zip
# 코랩은 리눅스 기반이므로 리눅스 언어를 활용한다.
# !를 사용하여 리눅스 코드를 사용한다.
# horse-or-human.zip과 validation-horse-or-human.zip 이 두개의 압축파일을 다운로드 했다.
다운로드 받은 압축파일을 zipfile라이브러리의 extractall함수로 압축해제하자.
import zipfile
zip_ref = zipfile.ZipFile('/tmp/horse-or-human.zip')
zip_ref.extractall('/tmp/horse-or-human')
zip_ref = zipfile.ZipFile('/tmp/validation-horse-or-human.zip')
zip_ref.extractall('/tmp/validation-horse-or-human')
zip_ref.close()
# ZipFile함수로 압축파일 경로를 설정하여 변수로 지정하고
# extractall 함수에 압축을 풀기 위해 만들 폴더 이름을 정하고 경로로 설정하여 압축해제했다.
# 압축해제가 끝나면 close 함수로 닫는다.
다운받은 데이터들이 들어있는 폴더:
학습데이터:
벨리데이션 데이터:
이제 사진이 저장된 폴더의 경로를 변수로 만든다.
train_horse_dir = '/tmp/horse-or-human/horses'
train_human_dir = '/tmp/horse-or-human/humans'
validation_horse_dir = '/tmp/validation-horse-or-human/horses'
validation_human_dir = '/tmp/validation-horse-or-human/humans'
각 폴더에 저장되어 있는 사진파일들을 변수로 저장한 후 개수를 알아보자.
in:
import os
train_horse_names = os.listdir(train_horse_dir)
train_human_names = os.listdir(train_human_dir)
validation_horse_names = os.listdir(validation_horse_dir)
validation_human_names = os.listdir(validation_human_dir)
print(len(train_horse_names))
print(len(train_human_names))
print(len(validation_horse_names))
print(len(validation_human_names))
out:
500
527
128
128
파일들을 시각화하여 사진을 확인해볼수 있다.
in:
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4
# Index for iterating over images
pic_index = 0
#####
# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)
pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname)
for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname)
for fname in train_human_names[pic_index-8:pic_index]]
for i, img_path in enumerate(next_horse_pix+next_human_pix):
# Set up subplot; subplot indices start at 1
sp = plt.subplot(nrows, ncols, i + 1)
sp.axis('Off') # Don't show axes (or gridlines)
img = mpimg.imread(img_path)
plt.imshow(img)
plt.show()
out:

이제 모델링 해보자.
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D
from tensorflow.keras.models import Sequential
def build_model():
model = Sequential()
model.add(Conv2D(16,(3,3),activation='relu',input_shape= (300,300,3)))
model.add(MaxPooling2D((2,2),2))
model.add(Conv2D(32,(3,3),activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPooling2D(2,2))
model.add(Flatten())
model.add(Dense(512,activation='relu'))
model.add(Dense(1,activation='sigmoid'))
return model
model = build_model()
# 컨볼루션을 세번했다.
# 두개로 분류하기때문에 시그모이드를 사용했다.
만들어진 모델의 상테를 확인해보자.
in:
model.summary()
out:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 298, 298, 16) 448
max_pooling2d (MaxPooling2D (None, 149, 149, 16) 0
)
conv2d_1 (Conv2D) (None, 147, 147, 32) 4640
max_pooling2d_1 (MaxPooling (None, 73, 73, 32) 0
2D)
conv2d_2 (Conv2D) (None, 71, 71, 64) 18496
max_pooling2d_2 (MaxPooling (None, 35, 35, 64) 0
2D)
flatten (Flatten) (None, 78400) 0
dense (Dense) (None, 512) 40141312
dense_1 (Dense) (None, 1) 513
=================================================================
Total params: 40,165,409
Trainable params: 40,165,409
Non-trainable params: 0
_________________________________________________________________
# 약 4천만개의 파라미터가 있다.
RMSprop optimization algorithm을 사용하여 컴파일 해보자
from tensorflow.keras.optimizers import RMSprop
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(learning_rate=0.001),
metrics=['accuracy'])
이제 학습을 해야 하는데 학습시킬 데이터가 png로 존재한다.
이미지 파일을 넘파이로 바꿔주는 라이브러리인 ImageDataGenerator를 사용하자.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale= 1/255.0)
validation_datagen = ImageDataGenerator(rescale= 1/255.0)
train_generator = train_datagen.flow_from_directory('/tmp/horse-or-human',target_size= (300,300),class_mode='binary')
validation_generator = validation_datagen.flow_from_directory('/tmp/validation-horse-or-human',target_size= (300,300),class_mode='binary')
# ImageDataGenerator 함수의 rescale 파라미터에 1/255.0를 입력하여 사진 파일을 스케일링 한다.
# ImageDataGenerator를 사용하여 변수로 만든 후 flow_from_directory를 사용하여 이미지가 들어있는 디렉토리의 정보, 이미지 사이즈 정보, 분류할 개수 정보를 입력해야 한다.
# target_size와 input_shape는 가로 세로가 같아야 한다. (input_shape를 참고하여 작성한다.)
# class_mode는 디폴트 값으로 categorical이 있기에 두개를 분류하기 위해 binary로 입력한다.
# 변수 train_generator는 학습할 넘파이 어레이와 해당 이미지의 검증 데이터도 가지고있다. (즉 X_train과 y_train을 모두 가지고 있다.)
이제 학습한다.
epoch_history = model.fit(train_generator, epochs=20, validation_data = (validation_generator))
# validation_data에 벨리데이션 하려고 변수로 만들었던 validation_generator를 입력한다.
모델을 평가해보자.
in:
model.evaluate(validation_generator)
out:
8/8 [==============================] - 1s 118ms/step - loss: 5.3871 - accuracy: 0.8125
[5.387092113494873, 0.8125]
학습 정확도와 벨리데이션 정확도를 차트로 그리자.
in:
import matplotlib.pyplot as plt
plt.plot(epoch_history.history['accuracy'])
plt.plot(epoch_history.history['val_accuracy'])
plt.legend(['train','validation'])
plt.show()
out:
# 오버피팅된듯하다.
인터넷에서 말 사진을 가져와서 분류해보자.
in:
import numpy as np
from google.colab import files
from tensorflow.keras.preprocessing import image
uploaded = files.upload()
for fn in uploaded.keys() :
path = '/content/' + fn
img = image.load_img(path, target_size=(300,300))
x = image.img_to_array(img) /255.0
print(x.shape)
x = np.expand_dims(x, axis = 0)
print(x.shape)
images = np.vstack( [x] )
classes = model.predict( images, batch_size = 10 )
print(classes)
if classes[0] > 0.5 :
print(fn + " is a human")
else :
print(fn + " is a horse")
out:
horse-g93a5a5f07_640.jpg
horse-g93a5a5f07_640.jpg(image/jpeg) - 59151 bytes, last modified: 2022. 6. 15. - 100% done
Saving horse-g93a5a5f07_640.jpg to horse-g93a5a5f07_640.jpg
(300, 300, 3)
(1, 300, 300, 3)
[[0.]]
horse-g93a5a5f07_640.jpg is a horse
# 오름차순으로 0이 horse 1이 human인것에 주의하자.
# 잘 작동한다.
'딥러닝' 카테고리의 다른 글
[딥러닝] 이미지 증강(Augmentation): 이미지 , 넘파이 어레이 (0) | 2022.06.15 |
---|---|
[딥러닝] 디렉토리를 따로 만들어서 학습데이터 저장: mkdir, listdir (0) | 2022.06.15 |
[딥러닝] 분류 CNN: Conv2D, MaxPooling2D, Base, Head (0) | 2022.06.14 |
[딥러닝] CNN (Convolutional Neural Network) 이해 (0) | 2022.06.14 |
[딥러닝] MNIST 손글씨 숫자 실습, 원핫인코딩: to_categorical, categorical_crossentropy (0) | 2022.06.14 |
댓글