ML/모두의 딥러닝

16장) 이미지 인식의 꽃, CNN 익히기

busy맨 2023. 7. 17. 22:49

1. 컨볼루션 신경망(CNN)

  • 입력된 이미지에서 다시 한번 특징을 추출하기 위해 커널(슬라이딩 윈도우)을 도입하는 기법

입력된 이미지가 다음과 같을 때

각 칸에 가중치가 들어있는 2x2 커널을 준비

2x2 커널

커널을 이미지에 한 칸씩 움직이며 적용

결과를 정리하면 다음과 같다.

이렇게 해서 새롭게 만들어진 층을 컨볼루션(합성곱)이라고 부름

컨볼루션을 통해 입력 데이터로부터 더욱 정교한 특징을 추출 가능

 

  • 케라스에서 컨볼루션 층을 추가하는 코드
model.add(Conv2D(32, kernel_size=(3,3), input_shape=(28, 28, 1), activation='relu'))
  • Conv2D()
    • 첫 번째 매개변수
      • 커널을 몇 개 적용할 것인지 결정
      • 예제에서는 32개의 커널 적용
    • kernel_size=(행, 열)
      • 커널의 크기를 정함
      • 예제에서는 3x3 크기의 커널 사용
    • input_shape=(행, 열, 색상 또는 흑백)
      • 입력 이미지가 색상이면 3, 흑백이면 1 지정
      • 예제는 28x28 크기의 흑백 이미지 사용
    • activation
      • 활성화 함수 정의

 

2. 맥스 풀링

  • 풀링(=서브 샘플링) 기법의 한 종류
    • 풀링(pooling)
      • 컨볼루션 층을 통해 이미지 특징을 도출한 결과가 여전히 크고 복잡하여 축소하는 과정
  • 맥스 풀링(max pooling)
    • 정해진 구역 안에서 최댓값을 뽑아내는 과정
  • 평균 풀링(average pooling)
    • 정해진 구역 안에서 평균값을 뽑아내는 과정

다음과 같은 이미지가 있을 때

맥스 풀링을 적용하면

여기서 각 영역 별 가장 큰 값을 추출

이 과정을 거쳐 불필요한 정보를 간추림

model.add(MaxPooling2D(pool_size=2))
  • MaxPooling2D()
    • 맥스 풀링 구현
    • pool_size
      • 풀링 창의 크기 정함
      • 예제에서는 2를 사용하여 전체 크기를 절반으로 감소시킴

 

3. 드롭아웃

  • 딥러닝 학습을 실행할 때 가장 중요한 것은 과적합을 얼마나 효과적으로 피하는지
  • 이런 작업을 도와주는 것이 드롭아웃
  • 드롭아웃(drop out)
    • 과적합을 피하는 방법 중 간단하면서 효과가 큰 기법
    • 은닉층에 배치된 노드 중 일부를 임의로 끄는 것
    • 랜덤하게 노드를 꺼서 학습 데이터에 지나치게 치우쳐서 학습되는 과적합을 방지

  • 25%의 노드 끄기
model.add(Dropout(0.25))

컨볼루션 층이나 맥스 풀링은 주어진 이미지를 2차원 배열로 다룸

이를 1차원 배열로 변환해야 활성화 함수를 적용할 수 있다.

  • 2차원 배열을 1차원 배열로 변환하기
model.add(Flatten())

 

Code)

  • CNN 사용 O
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from keras.callbacks import ModelCheckpoint,EarlyStopping

import matplotlib.pyplot as plt
import numpy
import os
import tensorflow as tf

# seed 값 설정
seed = 0
numpy.random.seed(seed)
tf.random.set_seed(3)

# 데이터 불러오기

(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32') / 255
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32') / 255
Y_train = np_utils.to_categorical(Y_train)
Y_test = np_utils.to_categorical(Y_test)

# 컨볼루션 신경망의 설정
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), input_shape=(28, 28, 1), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128,  activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

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

# 모델 최적화 설정
MODEL_DIR = './model/'
if not os.path.exists(MODEL_DIR):
    os.mkdir(MODEL_DIR)

modelpath="./model/{epoch:02d}-{val_loss:.4f}.hdf5"
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='val_loss', verbose=1, save_best_only=True)
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=10)

# 모델의 실행
history = model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=30, batch_size=200, verbose=0, callbacks=[early_stopping_callback,checkpointer])

# 테스트 정확도 출력
print("\n Test Accuracy: %.4f" % (model.evaluate(X_test, Y_test)[1]))

# 테스트 셋의 오차
y_vloss = history.history['val_loss']

# 학습셋의 오차
y_loss = history.history['loss']

# 그래프로 표현
x_len = numpy.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c="red", label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c="blue", label='Trainset_loss')

# 그래프에 그리드를 주고 레이블을 표시
plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

  • CNN 사용 X
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy
import os

from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import ModelCheckpoint,EarlyStopping

# seed 값 설정
seed = 0
numpy.random.seed(seed)
tf.compat.v1.set_random_seed(3)

# MNIST 데이터 불러오기
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()

X_train = X_train.reshape(X_train.shape[0], 784).astype('float32') / 255
X_test = X_test.reshape(X_test.shape[0], 784).astype('float32') / 255

Y_train = np_utils.to_categorical(Y_train, 10)
Y_test = np_utils.to_categorical(Y_test, 10)

# 모델 프레임 설정
model = Sequential()
model.add(Dense(512, input_dim=784, activation='relu'))
model.add(Dense(10, activation='softmax'))

# 모델 실행 환경 설정
model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

# 모델 최적화 설정
MODEL_DIR = './model/'
if not os.path.exists(MODEL_DIR):
    os.mkdir(MODEL_DIR)

modelpath="./model/{epoch:02d}-{val_loss:.4f}.hdf5"
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='val_loss', verbose=1, save_best_only=True)
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=10)

# 모델의 실행
history = model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=30, batch_size=200, verbose=0, callbacks=[early_stopping_callback,checkpointer])

# 테스트 정확도 출력
print("\n Test Accuracy: %.4f" % (model.evaluate(X_test, Y_test)[1]))

# 테스트 셋의 오차
y_vloss = history.history['val_loss']

# 학습셋의 오차
y_loss = history.history['loss']

# 그래프로 표현
x_len = numpy.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c="red", label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c="blue", label='Trainset_loss')

# 그래프에 그리드를 주고 레이블을 표시
plt.legend(loc='upper right')
# plt.axis([0, 20, 0, 0.35])
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

CNN을 사용한 모델이 성능이 더 좋은 것을 확인