[DL]] MNIST 손글씨 숫자 분류 문제
포스트
취소

[DL]] MNIST 손글씨 숫자 분류 문제

본 포스팅은 “케라스 창시자에게 배우는 딥러닝” - (길벗출판사, 프랑소와 숄레 지음, 박해선 옮김)을 바탕으로 공부한 내용을 정리한 것입니다.

  1. MNIST 손글씨 데이터
  2. 손글씨 분류 문제
    • 케라스에 데이터셋 적재
    • 신경망 구조
    • 컴파일
    • 이미지 데이터 준비
    • 레이블 준비
    • 모델 학습
    • 테스트 세트에서 모델 적용

1. MNIST 손글씨 데이터

흑백 손글씨 숫자 이미지 (28 X 28 픽셀)을 10개의 범주 (0~9)로 분류하는 문제.

6만 개의 훈련 이미지와 1만 개의 테스트 이미지로 구성 되어 있다.

traintest 비율은 보통 6:1, 6:2, 7:1 등으로 사용한다. 여기서는 6:1이 되겠다.

MNIST 문제는 딥러닝계의 “hello world”라고 한다.


2. 손글씨 분류 문제

케라스에 데이터셋 적재

1
2
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

MNIST 데이터셋은 Numpy 배열 형태로 케라스에 이미 포함되어 있어서 import 해준다.

train_imagestrain_labels가 모델이 학습해야 할 훈련 세트 (training set)를 구성한다.

모델은 test_imagestest_labels로 구성된 테스트 세트 (test set)에서 테스트 된다.

이미지는 Numpy 배열로 인코딩되어 있고, 레이블은 0 ~ 9의 숫자 배열이다.

이미지와 레이블은 일대일 관계이다.

다음은 훈련 데이터를 살펴보는 과정이다.

정돈된 데이터의 실제 학습에는 필요없지만, 공부를 위해 구조를 확인하는 과정이다.

1
2
3
train_images.shape
len(train_labels)
train_labels

[결과]

1
2
3
(60000, 28, 28)
60000
array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)

image

unit 8 타입의 (60000, 28, 28) 크기의 [0, 255] 사이의 값을 가지는 배열임을 확인할 수 있다.

다음은 테스트 데이터이다.

1
2
3
test_images.shape
len(test_labels)
test_labels

[결과]

1
2
3
(10000, 28, 28)
10000
array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)

image

테스트 데이터는 unit 8 타입의 (10000, 28, 28) 크기의 [0, 255] 사이의 값을 가지는 배열이다.

다섯 번째 train_images를 matplotlib 라이브러리로 확인해보자.

1
2
3
4
5
import matplotlib.pyplot as plt
digit = train_images[4]

plt.imshow(digit, cmap=plt.cm.binary)
plt.show()

image


작업 순서는 다음과 같다.

훈련 데이터 train_imagestrain_labels를 네트워크에 주입시켜서 이미지와 레이블을 연관시킬 수 있도록 학습된다.

test_images에 대한 예측을 네트워크에 요청하면 이 예측이 test_labels와 맞는지 확인을 할 것이다.

다음으로는 신경망을 생성한다.

신경망 구조

1
2
3
4
5
6
from tensorflow.keras import models
from tensorflow.keras import layers

network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))

신경망의 핵심 구성 요소는 층 (layer)다.

여과기 같은 일종의 데이터 처리 필터라고도 생각 할 수 있다.

완전 연결 (fully connected)된 신경망 층인 Dense 층 2개가 연속되어 있다.

마지막 층은 소프트맥스 (softmax) 층이다.

10개의 확률 점수가 들어 있는 배열로, 모두 더하면 1이다.

즉, 각 점수는 현재 숫자 이미지가 0 ~ 9의 숫자 중 하나에 속할 확률이다.

첫 번째 층의 활성화 함수로 relu 함수가 사용되었다.

비선형 함수를 사용하여 딥러닝 모델의 레이어를 깊게 가져갈 수 있다고 한다.

대표적으로 사용되는 활성화 함수는 다음과 같다.

  • Sigmoid 함수
  • Tanh 함수
  • ReLU (Rectified Linear Unit) 함수
  • Leaky ReLU
  • PReLU
  • ELU (Exponential Linear Unit)
  • Maxout

간단하고 빠른 편인 ReLU를 먼저 사용하고 Leakly ReLU, PReLU, ELU 등도 사용해본다. simoid와 tanh는 지양

신경망이 훈련 준비를 마치기 위한 컴파일 단계에 포함되기 위해 세가지가 더 필요하다.

  • 손실함수 (loss function)
  • 옵티마이저 (optimizer)
  • 훈련과 테스트 과정을 모니터링 할 지표 (해당 예제에서는 정확도만)

컴파일

1
2
3
network.compile(optimizer='rmsprop',
                loss='categorical_crossentropy',
                metrics=['accuracy'])

손실함수와 옵티마이저에 대해서는 다다음 포스팅에서 자세하게 작성 예정이다.

이미지 데이터 준비

1
2
3
4
5
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

훈련에 앞서, 데이터를 네트워크에 맞는 크기로 reshape하고 모든 값을 0 ~ 1로 스케일링 한다.

이미지의 경우 일반적으로 픽셀의 최댓값인 255로 나눈다고 한다.

레이블 준비

1
2
3
4
from tensorflow.keras.utils import to_categorical

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

레이블을 범주형으로 인코딩 해주었다.

모델 학습

1
network.fit(train_images, train_labels, epochs=5, batch_size=128)

image

훈련 과정동안 손실 (loss)정확도 (accuracy)가 출력되었다.

훈련 데이터에 대해 0.989(98.9%)의 정확도를 금방 달성했다.

epochs, batch_size는 다다음 포스팅에 작성 예정 중이다.

테스트 세트에서 모델 적용

1
2
test_loss, test_acc = network.evaluate(test_images, test_labels)
print('test_acc:', test_acc)

image

훈련 세트의 정확도보다 낮은 테스트 세트의 97.8%는 과대적합 (overfitting)의 이유이다.

머신 러닝 모델이 훈련 데이터보다 새로운 데이터에서 성능이 낮아지는 경향을 뜻한다.


참고

“케라스 창시자에게 배우는 딥러닝” - (길벗출판사, 프랑소와 숄레 지음, 박해선 옮김)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.