본문 바로가기
딥러닝

[딥러닝] horse-or-human CNN 실습, 압축, 이미지 처리: extractall, ImageDataGenerator, flow_from_directory

by eyoo 2022. 6. 15.

이미지 파일을 다운로드하여 말과 사람을 구분하는 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]
# 오차값이 5.38 이며 정확도는 0.81이다.

 

 

학습 정확도와 벨리데이션 정확도를 차트로 그리자.

 

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인것에 주의하자.

# 잘 작동한다.

 

 

 

 

 

댓글