✨ 딥러닝·머신러닝

MNIST 손글씨 - 숫자 이미지를 모델로 학습하여 인식

Vento AI Lab 2026. 5. 20.
반응형

 

1. MNIST 데이터셋

파이썬으로 딥러닝을 학습하다 보면 "MNIST 손글씨 숫자 이미지"가 자주 등장한다. MNIST 손글씨는 미국 국립표준기술원에서 사람이 직접 쓴 70,000개의 숫자를 수집하여 데이터 셋으로 만들었다. MNIST는 머신러닝 및 인공 신경망 분야에서 널리 사용되는 손글씨 숫자 인식 작업을 위한 데이터 세트이다.

이 데이터셋은 원래 미국 국립표준기술원(NIST)이 수집한 손글씨 숫자 데이터베이스를 수정한 것으로, 이미지 분류 및 숫자 인식 알고리즘의 성능을 평가하고 테스트하는 데 사용된다. 컴퓨터 비전 및 딥 러닝 분야에서 초기 학습과 알고리즘 개발을 위한 표준 데이터 세트로 사용되어왔다.

2. 학습 데이터 준비

머신러닝의 입력 데이터로 사용하기 위해 60,000개의 트레이닝 이미지와 10,000개의 테스트 이미지를 사용한다.

 

 

3. 이미지 출력

60,000개의 트레이닝 이미지를 사용하여 모델을 학습하고 10,000개의 테스트 이미지를 사용하여 학습한 모델이 얼마나 정확한지 평가한다. MNIST 데이터셋에서 첫 번째(숫자 5)와 네 번째(숫자 1)의 이미지를 한번 출력해 보았다. 하나의 이미지를 0부터 255까지 범위의 숫자 배열로 해석할 수 있다.

 
import numpy as np

# MNIST 데이터 로드
def load_mnist(flatten=True, normalize=False):
    from tensorflow.keras.datasets import mnist  # Tensorflow 사용
    (x_train, t_train), (x_test, t_test) = mnist.load_data()
    
    if normalize:
        x_train = x_train.astype(np.float32) / 255.0
        x_test = x_test.astype(np.float32) / 255.0
    
    if flatten:
        x_train = x_train.reshape(x_train.shape[0], -1)
        x_test = x_test.reshape(x_test.shape[0], -1)
    
    return (x_train, t_train), (x_test, t_test)

(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)

# 숫자 5
i = 1
for x in x_train[0]:
    print('{:3} '.format(x), end='')
    if i == 28:
        print()
        i = 1
    else:
        i = i + 1

# 숫자 1
i = 1
for x in x_train[3]:
    print('{:3} '.format(x), end='')
    if i == 28:
        print()
        i = 1
    else:
        i = i + 1
 

 

가로 28 x 세로 28 = 784개의 픽셀로 되어 있고 각각의 픽셀은 0부터 255까지의 정보를 담고 있다. 0이면 흰색 255이면 검정이다. 

 

4. 코드 실행

이미지는 28x28 픽셀 단위이기 때문에 입력층 뉴런은 784개가 필요하다.

출력층 뉴런은 0부터 9까지로 10개가 필요하다.

  • 입력층 : 28x28 = 784
  • 출력층 : 0 ~ 9 = 10
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt

# MNIST 데이터 로드
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# 데이터 전처리 : 모델에 맞게 이미지를 정규화
train_images, test_images = train_images / 255.0, test_images / 255.0

# 모델 생성 : 다층 퍼셉트론(MLP)을 사용
# 28x28 픽셀 이미지를 1차원 배열로 변환
model = models.Sequential([
    layers.Flatten(input_shape=(28, 28)),  
    layers.Dense(128, activation='relu'),
    layers.Dropout(0.2),
    layers.Dense(10, activation='softmax')
])

# 모델 컴파일 : 손실 함수, 옵티마이저, 평가 지표를 설정
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 모델 훈련 : 훈련 데이터를 사용하여 모델을 학습
model.fit(train_images, train_labels, epochs=10)

# 모델 평가 : 테스트 데이터로 모델의 성능을 평가
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(f'\nTest Accuracy: {test_acc*100:.2f}%')

# 테스트 이미지에서 예측값 얻기
predictions = model.predict(test_images)
predicted_labels = [tf.argmax(p) for p in predictions]

# 예측 결과 시각화
plt.figure(figsize=(9, 9))
for i in range(25):
    plt.subplot(5, 5, i + 1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(test_images[i], cmap=plt.cm.binary)
    plt.xlabel(f'real: {test_labels[i]} - predict: {predicted_labels[i]}')

plt.show()

 

실행 결과

테스트 데이터로 검증해 보니 정확도가 97.94% 나왔다.

Epoch 1/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8504 - loss: 0.5007
Epoch 2/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9539 - loss: 0.1563
Epoch 3/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9669 - loss: 0.1074
Epoch 4/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9735 - loss: 0.0833
Epoch 5/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9758 - loss: 0.0757
Epoch 6/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9790 - loss: 0.0648
Epoch 7/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9834 - loss: 0.0539
Epoch 8/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9827 - loss: 0.0506
Epoch 9/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9849 - loss: 0.0482
Epoch 10/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9855 - loss: 0.0433
313/313 - 0s - 735us/step - accuracy: 0.9794 - loss: 0.0665

Test Accuracy: 97.94%
313/313 ━━━━━━━━━━━━━━━━━━━━ 0s 609us/step

 

실제값과 예측값이 모두 일치한다.

 

반응형

댓글