미니프로젝트

CNN을 활용하여 드론과 새 분류하기

728x90

앞선 글에서 구글 이미지 크롤링을 했다.

durian9s-coding-tree.tistory.com/56

 

구글에서 파이썬 셀레니움을 통한 이미지 크롤링

3월 초부터 해결 방법을 알지 못해 손을 놓고 있던 이미지 크롤링을 몇 일 전부터 계속 구글링했다. 뭐가 문제인지 정말 많이 찾아봤었는데 범인은 코랩이었나보다.. 나는 정말 코랩이를 좋아했

durian9s-coding-tree.tistory.com

드론과 새의 이미지를 크롤링하여 저장했는데, 필요없는 사진은 제거하고 1:9의 비율로 트레이닝 셋과 테스트 셋으로 나누었다.

 

CNN을 통한 드론/새 분류기를 만들어 보도록 하겠다.

 

CNN의 설명을 내가 잘하면 좋겠는데.. 설명을 잘 못하니까 정말 정리가 잘되어있는 블로그를 첨부하겠다.

taewan.kim/post/cnn/

 

CNN, Convolutional Neural Network 요약

Convolutional Neural Network, CNN을 정리합니다.

taewan.kim

 

 

 

 

라이브러리 import

import random
import tensorflow as tf
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from shutil import copyfile
import tensorflow as tf
from tensorflow.keras.datasets import fashion_mnist
import tensorflow.keras
from keras.models import Sequential
from keras.layers import Dense, Flatten, Dropout
from keras.optimizers import Adam
from keras.utils import np_utils
from keras.layers import Conv2D, MaxPool2D

 

model=Sequential()
model = Sequential()
model.add(Conv2D( filters =16, kernel_size= (2,2), activation= 'relu', input_shape=(512,512,3)))
model.add( MaxPool2D( 2 , 2 ) ) 
model.add( Conv2D ( 32,(3,3), activation='relu' ) )
model.add( MaxPool2D( 2 , 2 ) )
model.add( Conv2D ( 64,(3,3), activation='relu' ) )
model.add( MaxPool2D( 2 , 2 ) )

model.add( Flatten()  ) 
model.add(Dense( units = 512, activation= 'relu'))
model.add(Dense( units = 128, activation= 'relu'))
model.add(Dense(units = 1, activation='sigmoid'))

모델을 구축해준다.

여기서 문제가 하나 생겼는데,, input shape가 일정해야 하는데 내 사진들은 제각각이었다.

 

도와줘요 구글님!

www.soft2000.com/14297

 

알씨 | 이미지 크기 일괄 변경하는 방법

인쇄용 이미지는 높은 해상도가 필요하지만, 웹이 게시하거나 메일에 첨부하거나 메시지로 보낼 때는 낮은 해상도도 괜찮습니다. 이미지의 크기는 이미지 편집 프로그램에서 변경할 수 있습니

www.soft2000.com

검색을 했더니 알씨로 일괄변경 하면 된다고 하여 512 x 512로 변경하였다.

 

model.summary()

model.summary를 통해 모델을 살펴보았다.

 

cnn을 할 때 더 효율적으로 학습하기 위해 이미지 증강도 해주었다.

그리고 모델 컴파일까지.

from keras.preprocessing.image import ImageDataGenerator

TRAINING_DIR = '/content/drive/MyDrive/Colab Notebooks/drone_bird/training'
train_datagen = ImageDataGenerator(rescale = 1/255.0,
                                   rotation_range=40, 
                                   width_shift_range=0.2, 
                                   height_shift_range = 0.2,
                                   shear_range = 0.2,
                                   zoom_range = 0.2, 
                                   horizontal_flip = True,
                                   vertical_flip = True,
                                   fill_mode = 'nearest')

train_generator = train_datagen.flow_from_directory(TRAINING_DIR, batch_size = 10, class_mode = 'binary', target_size=(512,512))
VALIDATION_DIR = '/content/drive/MyDrive/Colab Notebooks/drone_bird/testing'
validation_datagen = ImageDataGenerator(rescale = 1/255.0)

validation_generator =validation_datagen.flow_from_directory(VALIDATION_DIR, batch_size = 10, class_mode = 'binary', target_size=(512,512))

model.compile(loss='binary_crossentropy',optimizer = RMSprop(lr=0.001), metrics=['accuracy'])

 

모델을 학습한다.

처음 학습을 시킬때는 집 컴퓨터로 작업을 해서 엄청 느렸고, 에포크를 15로 설정했다.

테스트의 정확성이 최대 68% 까지 나온다.

history = model.fit(train_generator,
                              epochs=15,
                              verbose=1,
                              validation_data = validation_generator)

이제 차트로 확인을 해보자.

def learning_curve(history, epoch):
  # 정확도 차트
  plt.figure(figsize = (10, 5))

  epoch_range = np.arange(1, epoch + 1)

  plt.subplot(1, 2, 1)

  # history는 fit 결과값을 저장하는 변수
  plt.plot( epoch_range, history.history["accuracy"])
  plt.plot( epoch_range, history.history["val_accuracy"])
  plt.title("Model Accuracy")
  plt.xlabel("Epoch")
  plt.ylabel("Accurach")
  plt.legend( ["Train", "Val"] )


  # loss 차트
  plt.figure(figsize = (10, 5))

  plt.subplot(1, 2, 2)

  plt.plot( epoch_range, history.history["loss"])
  plt.plot( epoch_range, history.history["val_loss"])
  plt.title("Model Loss")
  plt.xlabel("Epoch")
  plt.ylabel("Loss")
  plt.legend( ["Train", "Val"] )
  
  plt.show()

learning_curve(history, 15)

 

 

 

 

에포크 15개로는 만족스럽지 못해서 피씨방으로 가서 epoch 75로 설정하고 새로 학습시켜봤다.

앞의 컴파일까지의 과정은 동일하므로 생략하고 학습 코드만 기록하겠다.

 

history = model.fit(train_generator,
                              epochs=75,
                              verbose=1,
                              validation_data = validation_generator)

ㅎㅎㅎ 에포크가 많다고 학습이 잘 되는것은 아니지만 73.42%까지 정확도가 높아졌다. 

정확도 차트도 다시 확인해보자.

이 또한 에포크의 숫자만 달리하였기에 차트만 첨부한다.

그래프와 에포크 를 보게 되면 59번째 에포크에 정확도가 최대로 올라간 뒤 이후에는 계속 낮은 정확도를 보인다.

 

조금 더 공부를 하고나서 이미지를 넣으면 드론인지 아닌지 판별하는 코드를 사용해보겠다.

 

오늘도 재밌었다.

 

===================================================================

오류를 발견했다.

풀링의 경우 상관없지만 커널 사이즈는 (3,3)이나 (5,5)같이 홀수여야 하기 때문에 피씨방을 다시 방문했다.

왜 저것만 (2,2)로 했지..?

 

모델링부터 다시~

model=Sequential()
model = Sequential()
model.add(Conv2D( filters =16, kernel_size= (3,3), activation= 'relu', input_shape=(512,512,3)))
model.add( MaxPool2D( 2 , 2 ) ) 
model.add( Conv2D ( 32,(3,3), activation='relu' ) )
model.add( MaxPool2D( 2 , 2 ) )
model.add( Conv2D ( 64,(3,3), activation='relu' ) )
model.add( MaxPool2D( 2 , 2 ) )

model.add( Flatten()  ) 
model.add( Dropout( 0.4 ) )
model.add(Dense( units = 512, activation= 'relu'))
model.add(Dense( units = 128, activation= 'relu'))
model.add(Dense(units = 1, activation='sigmoid'))
model.summary()

이미지 증강

from keras.preprocessing.image import ImageDataGenerator

TRAINING_DIR = '/content/drive/MyDrive/Colab Notebooks/drone_bird/training'
train_datagen = ImageDataGenerator(rescale = 1/255.0,
                                   rotation_range=40, 
                                   width_shift_range=0.2, 
                                   height_shift_range = 0.2,
                                   shear_range = 0.2,
                                   zoom_range = 0.2, 
                                   horizontal_flip = True,
                                   vertical_flip = True,
                                   fill_mode = 'nearest')


train_generator = train_datagen.flow_from_directory(TRAINING_DIR, batch_size = 10, class_mode = 'binary', target_size=(512,512))
VALIDATION_DIR = '/content/drive/MyDrive/Colab Notebooks/drone_bird/testing'
validation_datagen = ImageDataGenerator(rescale = 1/255.0)

validation_generator =validation_datagen.flow_from_directory(VALIDATION_DIR, batch_size = 10, class_mode = 'binary', target_size=(512,512))

model.compile(loss='binary_crossentropy',optimizer = RMSprop(lr=0.001), metrics=['accuracy'])

학습

history = model.fit(train_generator,
                              epochs=75,
                              verbose=1,
                              validation_data = validation_generator)

적중률이 크게 높아졌다.

오류를 일찍발견해서 다행이다.ㅎㅎ

 

집에서는 CNN을 계속 못돌리니 모델을 저장하겠다.

from keras.models import load_model

model.save('bird_and_drone.h5')

파일이 생겼음.

 

나중에 언제라도 꺼내쓸 수 있다.

 

 

아 그리고 마지막으로

import numpy as np
from google.colab import files
from keras.preprocessing import image

uploaded = files.upload()

for fn in uploaded.keys():
 
  # predicting images
  path = '/content/drive/MyDrive/Colab Notebooks/drone_bird/' + fn
  img = image.load_img(path, target_size=(512,512))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)

  images = np.hstack([x])
  classes = model.predict(images, batch_size=10)
  print(classes[0])
  if classes[0]>0.5:
    print(fn + " is a drone")
  else:
    print(fn + " is a bird")

이미지를 입력해서 사진이 새인지, 드론인지 판별하는 코드이다.

처음엔 위의 사진을 사용하려했는데 (512,512,3)으로 일괄 학습시켜서인지 (512,512,3)이 아니면 사용이 불가능했다.

그래서 늘렸다.

이미지의 크기가 다르기 때문인지는 모르지만 정확한 분류가 되진 않는 것 같다.

 

  if classes[0]>0.5:
    print(fn + " is a drone")
  else:
    print(fn + " is a bird")

 

 

이상으로 길었던 드론과 새를 구별하는 CNN을 마치도록 하겠다.

728x90