본문 바로가기
Deep Learning

[딥러닝] 밑바닥부터 시작하는 딥러닝 공부 3-2 : MNIST 손글씨 숫자 인식 및 구현

by 단깅수 2024. 2. 17.
728x90

이번에 소개할 내용은 MNIST 손글씨 숫자 인식 및 구현입니다.

 

1. MNIST 데이터셋

이번 포스팅에서 사용할 데이터셋은 MNIST 손글씨 숫자 이미지 집합입니다. MNIST는 기계학습 분야에서 매우 유명한 데이터셋으로 간단한 실험부터 논문으로 발표되는 연구까지 다양하게 활용되고 있습니다. 이미지 인식 혹은 기계학습 논문에서 실험용 데이터로 자주 등장하는 걸 볼 수 있습니다.

 

MNIST 데이터셋은 아래와 같이 0 ~ 9 까지의 숫자 이미지로 구성됩니다. TRAIN 이미지가 60,000장, TEST 이미지가 10,000장으로 구성되어 있습니다. 일반적으로 이 TRAIN 이미지들을 사용해 모델을 학습 후 학습 모델로 TEST 이미지를 얼마나 정확하게 분류하는 지를 평가합니다.

 MNIST 이미지 데이터는 28 X 28 크기의 회색조 이미지이며 각 픽셀은 0에서 255까지의 값을 취합니다.  각 이미지에는 또한 그 이미지가 실제로 의미하는 숫자가 레이블로 함께 있습니다.

1-1. MNIST 데이터셋 내려받기

  • tensorflow 패키지를 임포트해 keras 패키지 내에 내장되어 있는 mnist 데이터셋 활용해주었습니다.
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)   # Tensorflow의 버전을 출력

mnist = keras.datasets.mnist

# MNIST 데이터를 로드. 다운로드하지 않았다면 다운로드까지 자동으로 진행됩니다. 
(x_train, t_train), (x_test, t_test) = mnist.load_data()   

print(x_train.shape) # x_train 배열의 크기를 출력
print(t_train.shape) # t_train 배열의 크기를 출력
print(x_test.shape) # x_test 배열의 크기를 출력
print(t_test.shape) # t_test 배열의 크기를 출력

1-2. MNIST 데이터 살펴보기

  • train 데이터 셋의 2번째 데이터 불러와서 시각화하였습니다.

  • index를 지정해서 해당 index의 숫자를 불러오는 작업도 할 수 있습니다.
  • 아래 예시는 5001번째의 이미지를 불러오는 코드입니다.
# index에 0에서 59999 사이 숫자를 지정해 보세요.
index=5000 
plt.imshow(x_train[index],cmap=plt.cm.binary)
plt.show()
print( (index+1), '번째 이미지의 숫자는 바로 ',  y_train[index], '입니다.')


2. MNIST 신경망 구현

이번에는 MNIST 데이터셋을 가지고 추론 수행하는 신경망을 구현하겠습니다. 이 신경망은 입력층 뉴런을 784개, 출력층 뉴런을 10개로 구성합니다. 입력층 뉴런이 784개인 이유는 이미지 크기가 28 x 28 = 784이기 때문이고, 출력층 뉴런이 10개인 이유는 0에서 9까지의 숫자 레이블이 있기 때문입니다. 이번 예시에서는 은닉층 개수를 임의로 2개로 설정하고 구현해보겠습니다.

  • 신경망 코드 구현
    • get_data() : MNIST 데이터셋 로드 > 데이터 정규화 > 레이블 변환
    • init_network() : 두 개의 은닉층 설정 > 모델 컴파일
    • predict() : 모델 예측
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical

def get_data():
    # MNIST 데이터셋 로드
    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    
    # 데이터 전처리: 이미지를 0과 1 사이의 값으로 정규화하고, 레이블을 one-hot 인코딩으로 변환
    X_train = X_train / 255.0
    X_test = X_test / 255.0
    y_train = to_categorical(y_train, 10)
    y_test = to_categorical(y_test, 10)
    
    return X_train, y_train, X_test, y_test

def init_network():
    # 신경망 모델 구성
    model = tf.keras.Sequential([
        tf.keras.layers.Flatten(input_shape=(28, 28)),  # 입력층
        tf.keras.layers.Dense(50, activation='relu'),  # 첫 번째 은닉층
        tf.keras.layers.Dense(100, activation='relu'), # 두 번째 은닉층
        tf.keras.layers.Dense(10, activation='softmax') # 출력층
    ])
    
    # 모델 컴파일
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    
    return model

def predict(model, X):
    # 모델을 사용하여 예측
    predictions = model.predict(X)
    return predictions
  • 실제 사용
# 데이터 가져오기
X_train, y_train, X_test, y_test = get_data()

# 신경망 초기화
model = init_network()

# 모델 훈련
model.fit(X_train, y_train, epochs=5, batch_size=32, validation_data=(X_test, y_test))

# 모델 평가
loss, accuracy = model.evaluate(X_test, y_test)
print("Test Accuracy:", accuracy)

 

이번 3장에서는 신경망의 순전파를 살펴보았습니다. 이번 장에서 설명한 신경망은 각 층의 뉴런들이 다음 층의 뉴런으로 신호를 전달한다는 점에서 2장의 퍼셉트론과 같습니다. 하지만 다음 뉴런으로 갈 때 신호를 변화시키는 활성화 함수에 큰 차이가 있었습니다. 신경망에서는 시그모이드 함수를, 퍼셉트론에서는 계단 함수를 활성화 함수로 사용했었죠. 4장에서는 신경망 학습에 대해서 보겠습니다.

 

3. 정리

  • 신경망에서는 활성화 함수로 시그모이드 함수와 ReLU 함수같은 매끄러운 형태의 함수를 이용한다.
  • Numpy의 다차원 배열을 사용하면 신경망을 효율적으로 구현할 수 있다.
  • 기계학습 문제는 크게 회귀와 분류로 나눌 수 있다.
  • 출력층의 활성화 함수로는 회귀 문제에서는 항등 함수를, 분류 문제에서는 소프트맥스를 주로 이용한다.
  • 분류에서는 출력층의 뉴런 수를 분류하려는 클래스 수와 같게 설정한다.
  • 입력 데이터를 묶은 걸 배치라고 하며, 추론 처리를 이 배치 단위로 진행하면 결과를 훨씬 빠르게 얻을 수 있다.

이렇게 오늘은 MNIST 손글씨 숫자 인식에 대해 알아보았습니다.

다음 포스팅은 신경망 학습에 대해 다룰 예정입니다.

728x90