[딥러닝]5. 딥러닝 활용 <1>CNN

1. CNN

* MNIST를 이용한 손글씨 인식하기

1) 데이터 전처리

from keras.datasets import mnist
from keras.utils import np_utils

import numpy
import sys
import tensorflow as tf

seed = 0
numpy.random.seed(seed)
tf.random.set_seed(3)

(X_train, Y_train),(X_test, Y_test) = mnist.load_data()
print(X_train.shape[0]) #60000
print(X_test.shape[0] #10000

import matplotlib.pyplot as plt

plt.imshow(X_train[0], cmap='gray')
plt.show()

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

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

print("class : %d " % (Y_train[0])) #Y 클래스(레이블값) 확인
#class : 5

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

print(Y_train[0])
# [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
  • mnist 데이터 : 케라스를 이용해서 부를 수 있음
    • 미국 국립표준기술원(NIST)이 고등학생과 인구조사국 직원 등이 쓴 손글씨를 이용해 만든 데이터로 구성
    • 70,000개의 글자 이미지에 각각 0부터 9까지 이름표를 붙인 데이터셋
    • 총 70,000개의 이미지 중 60,000개를 학습용으로, 10,000개를 테스트용으로 미리 구분해 놓음
  • plt.imshow(X_train[0], cmap='gray') : 이미지 출력
    • imshow() : 이미지 출력
      - X_train[0] : 첫 번째 이미지
      - cmap='gray' : 이미지 흑백 출력
      • 데이터
    • X : 이미지 데이터
      • X_train : 학습셋 이미지
      • X_test : 테스트셋 이미지
    • Y : 0부터 9까지 이름표
      • Y_train : 학습셋 이미지
      • Y_test : 테스트셋 이미지
        ➡️ 784개의 속성을 이용해 10개 클래스 중 하나를 맞추는 문제임
        • 이미지 인식 방법
      • 가로 : 28, 세로 : 28 = 총 784개의 픽셀로 구성
      • 각 픽셀의 밝기 : 0 ~ 255
      • 0 ~ 255로 이루어진 긴 행렬로 이루어져 있음
        for x in X_train[0]:
           for i in x:
             sys.stdout.write('%d\t' % i)
           sys.stdout.write('\n')
    • ➡️ 2차원 배열(28 X 28 행렬)에서 1차원 배열로 변경해줘야 함
      • reshape(총 샘플 수, 1차원 속성의 수)
  • 데이터 정규화(normalization) : 데이터 폭이 클 때 적절한 값으로 분산의 정도를 바꿈
    • 현재 값인 0~255 ➡️ 0~1사이의 값으로 변경
    • astype(float) 후 255로 나눠줌
  • 원-핫 인코딩 방식 : 딥러닝 분류 문제 해결
    • 0~9까지의 클래스를 0과 1로 이루어진 벡터로 변경
    • to_categorical(클래스, 클래스 개수)

2) 딥러닝 기본 프레임 만들기

  • 총 784개의 속성, 10개의 클래스로 구성
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

import numpy
import sys
import tensorflow as tf
import os

# 모델 프레임 설정
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"
checkpoint = 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, checkpoint])
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()
  • model.add(Dense(512, input_dim=784, activation='relu')) : 은닉층 512개, 입력값 784개,
  • 은닉층의 활성화 함수 : relu, 출력층의 활성화 함수 : softmax
  • 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, checkpoint]) : 샘플 200개를 모두 30번 실행하게 설정.
  • 학습셋의 오차 그래프 표현 : 오차 = 1 - 정확도
  • 베스트 모델 : 10번째 에포크 ➡️ 정확도 98.21%

은닉층이 하나인 딥러닝 모델 도식

3) 컨볼루션 신경망(CNN)

  • 입력된 이미지에서 다시 한번 특징을 추출하기 위해 마스크(커널, 필터, 윈도)를 도입함
    • 예시

      ⬆️ 입력된 이미지

      ⬆️ 마스크 : 각 칸에 가중치있음

      ⬆️ 마스크를 옮겨가면서 적용 : 적용된 부분은 원래 있던 값에 가중치를 곱하고 그 결과를 합산해서 새로운 값 도출⬇️

      ➡️ 컨볼루션(합성곱) : 새롭게 만들어진 층. 입력 데이터로부터 더욱 정교한 특징을 추출할 수 있음

      여러개의 마스크 대입 시 여러개의 컨볼루션 만들 수 있음.
model.add(Conv2D(32, kernel_size=(3,3), input_shape=(28,28,1), activation='relu')
model.add(Conv2D(64, (3, 3), activation='relu')) #마스크 64개를 적용한 컨볼루션 층 추가
  • Conv2D(숫자, kernel_size, input_shape, activation) : 케라스에 컨볼루션 층 추가하는 함수
    • 첫 번째 인자 : 마스크를 몇개 적용할지 결정
      • 32개의 마스크 적용
    • kernel_size : 마스크(커널)의 크기 결정
      • 3x3 사이즈의 마스크 사용
    • input_shape=(행, 열, 색상 또는 흑백) : 맨 처음 층에 입력되는 값 알려주기
      - 입력이미지가 색상인 경우 3, 흑백인 경우 1 선택

4) 맥스 풀링

  • 풀링(pooling)(=서브 샘플링(sub sampling)) : 컨볼루션 층으로부터 얻은 특징 결괏값이 여전히 크고 복잡하여 축소함
    • 맥스 풀링(max pooling) : 정해진 구역안에서 최댓값을 뽑아냄
    • 평균 풀링(average pooling) : 정해진 구역안에서 평균값을 뽑아냄

ex) 맥스 풀링 예시

  • 이미지
  • 맥스 풀링을 적용하여 구역을 나눔
  • 각 구역에서 가장 큰 값 추출 : 불필요한 정보 간추림
model.add(MaxPooling2D(pool_size=2))
  • MaxPooling2D() : 맥스 풀링 적용
    • pool_size : 풀링 창의 크기 결정
      - 2로 설정 : 전체 크기가 반으로 줄어듦

5) 드롭아웃, 플래튼

  • 드롭아웃(dropout) : 은닉층에 배치된 노드 중 일부를 임의로 꺼줌 ➡️ 랜덤하게 노드를 끔으로써 학습 데이터에 지나치게 치우쳐서 학습되는 과적합 방지 가능

model.add(Dropout(0.25)) #25%의 노드 끔
  • 플래튼(flatten) : 2차원 배열을 1차원 배열로 바꿔줌
    • 컨볼루션 층, 맥스풀링 층 : 2차원 배열
    • 입력층 : 1차원배열 필요(활성화 함수 적용 시 필요)

참고:컨볼루션 신경망 레이어 도식화

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()

좋은 웹페이지 즐겨찾기