akaSonny

[Tensorflow/Keras] MNIST 학습시키기 본문

Study (Programming)/Tensorflow-Keras

[Tensorflow/Keras] MNIST 학습시키기

Jihyeoning 2022. 10. 18. 15:04

딥러닝을 처음 시작하면, 가장 먼저 만나게 되는 데이터셋인 MNIST.

 

  • MNIST (Modified National Institute of Standards and Technology database): 손으로 쓴 숫자들로 이루어진 대형 데이터베이스

 

MNIST 샘플 이미지 (출처: 위키백과)

 

이런 숫자들을 분류하는 것을 목적으로 훈련을 시켜보자!

 

(tensorflow 2.0 이상 버전)

 

#1. 필요한 라이브러리 import

import numpy as np

import tensorflow as tf
import tensorflow.keras import utils
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Activation, Input

 

#2. 데이터 로드 및 전처리

  • 훈련셋은 6만개, 테스트셋은 1만개로 이루어져 있다. 훈련셋 중 5만개만 train으로, 1만개는 validation에 쓰도록 하자.
  • 픽셀값들을 255로 나누어 0~1로 이루어지게 정규화시키기
width = 28
height = 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, width*height).astype('float32') / 255.0
x_test = x_test.reshape(10000, width*height).astype('float32') / 255.0

x_val = x_train[50000:]
y_val = y_train[50000:]
x_train = x_train[:50000]
y_train = y_train[:50000]

 

#3.  one-hot encoding

one-hot encoding (원-핫 인코딩): 0과 1로 이루어진 벡터이며, 한 개의 요소에만 1로 설정을 해준다. 이렇게 하는 이유는 인간은 '개', '고양이', '새' 등등.. 이라고 분류할 수 있지만 컴퓨터는 그렇게 생각을 하지 못하기 때문에 컴퓨터에게 전달해주기 위한다고 생각할 수 있다.

예를 들어, 우리가 카테고리화하는 대상이 ['개', '고양이', '새'] 라고 했을 때, 컴퓨터에게는,
   - 개: [1, 0, 0]
   - 고양이: [0, 1, 0]
   - 새: [0, 0, 1]
라고 전달해줄 수 있다.

 

다시 MNIST로 돌아와서, 우리는 0~9까지의 숫자를 분류하고 싶은 것이 목적이다. 

위에서 만든 y_train (아니면 y_test)의 값들과 shape을 확인해보면 다음과 같다. 

 

print(y_train)
# [5 0 4 ... 5 6 8]

print(y_train.shape)
# (60000,)

 

이러한 값들을 우리는 위에서 설명한 원-핫 인코딩을 통해 0과 1로 만들어진 벡터로 만들어야 한다.

(즉 0은 [1, 0, 0, ...] 이 되고, 1은 [0, 1, 0, 0, ...], 2는 [0, 0, 1, 0, 0, ...] 이런 식으로 해당 숫자의 자리에만 1이 위치하도록)

이는 tensorflow.keras.utilsto_categorical 이라는 내장함수를 통해 아주 쉽게 만들 수 있다!

y_train = utils.to_categorical(y_train)
y_val = utils.to_categorical(y_val)
y_test = utils.to_categorical(y_test)

다시 y_train의 값들과 shape을 확인해보면 다음과 같다.

print(y_train)
#[[0. 0. 0. ... 0. 0. 0.]
# [1. 0. 0. ... 0. 0. 0.]
# [0. 0. 0. ... 0. 0. 0.]
# ...
# [0. 0. 0. ... 0. 0. 0.]
# [0. 0. 0. ... 0. 0. 0.]
# [0. 0. 0. ... 0. 1. 0.]]
 
print(y_train.shape)
# (60000, 10)

 

#4.  모델 만들기

inputs = Input(shape=(width*height, ))
dense = Dense(256, activation='relu')(inputs)
dense = Dense(256, activation='relu')(dense)
dense = Dense(256, activation='relu')(dense)
outputs = Dense(10, activation='softmax')(dense)

model = Model(inputs=inputs, outputs=outputs)

keras의 모델 구성 방법은 Sequential을 사용하는 방법, 혹은 Functional API를 사용하는 방법이 있는데 위에서 쓴 코드는 후자를 사용한 것이다. 지금같이 단순한 구조는 Sequential을 사용해도 되지만, 복잡한 구조를 만들 때는 Functional API를 쓰는 것이 더 편해서.. 나는 이 방법만 쓰는데 나중에 이 두 가지 방법에 대해서 포스팅해야겠다.

 

# 5.  모델 컴파일 및 학습

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

hist = model.fit(x_train, y_train, epochs=30, batch_size=32, validation_data=(x_val, y_val))

컴파일 부분에는 손실 함수로 무엇을 할 것인지, 최적화 함수는 무엇으로 할 것인지, 그리고 loss function은 아니지만 모니터링하고 싶은 메트릭이 있을 때 metrics라는 인자를 통해 설정할 수 있다.

내가 torch를 안 쓰고 keras를 계속 쓰는 젤 첫 번째 이유.. 훈련이 너무 편하다... !!!!!!! 걍 fit 함수만 잘 사용하면 된다 ㅎㅎ

 

#6.  모델 결과 확인 및 예측에 사용하기

loss_and_metrics = model.evaluate(x_test, y_test, batch_size=32)
print('## evaluation loss and_metrics ##')
print(loss_and_metrics)

yhat_test = model.predict(x_test, batch_size=32)

evaluate 함수를 통해 loss와 metric으로 사용했던 값들의 결과를 알 수 있고, predict 함수를 통해 예측에 사용하면 된다! 

모델의 평가는 test set으로 하면 된다.

 

전체 코드

import numpy as np

from tensorflow.keras import utils
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Activation, Input

width = 28
height = 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, width*height).astype('float32') / 255.0
x_test = x_test.reshape(10000, width*height).astype('float32') / 255.0

# one-hot 인코딩
y_train = utils.to_categorical(y_train)
y_val = utils.to_categorical(y_val)
y_test = utils.to_categorical(y_test)

# 모델 설계
inputs = Input(shape=(width*height, ))
dense = Dense(256, activation='relu')(inputs)
dense = Dense(256, activation='relu')(dense)
dense = Dense(256, activation='relu')(dense)
outputs = Dense(10, activation='softmax')(dense)

model = Model(inputs=inputs, outputs=outputs)

# 모델 학습시키기
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])

hist = model.fit(x_train, y_train, epochs=30, batch_size=32, validation_data=(x_val, y_val))

# 모델 평가
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=32)
print('## evaluation loss and_metrics ##')
print(loss_and_metrics)

# 모델 사용하기
yhat_test = model.predict(x_test, batch_size=32)