
MNIST 손글씨 숫자 이미지 분류 모델 구현
들어가며
딥러닝의 Hello World와도 같은 MNIST 데이터를 활용한 딥러닝 모델을 소개합니다. MNIST는 손글씨 숫자 이미지 데이터로 6만 개의 훈련 이미지와 1만 개의 테스트 이미지로 구성되어 있습니다. 이 글에서는 딥러닝 입문 모델인 MNIST 손글씨 숫자 이미지 분류 모델의 과정을 설명하고, 이를 통해 딥러닝의 전체적인 과정을 파악할 수 있습니다.
- MNIST 데이터셋
- 신경망 모델 구조 및 컴파일
- 데이터 전처리 및 학습
- 예측 및 모델 평가
MNIST 데이터셋
MNIST 데이터셋은 keras 패키지에 이미 포함되어 있습니다. keras.dataset을 통해 데이터를 로드합니다.
학습 데이터셋은 60,000개의 이미지와 라벨로 구성되어 있고, 테스트 데이터셋은 10,000개의 이미지와 라벨로 구성되어 있습니다. 이미지는 28*28 픽셀의 손글씨 숫자이며, 라벨은 해당 이미지의 숫자를 정수로 표현한 값입니다. 이미지와 레이블은 일대일 관계입니다.
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
print('학습 데이터셋: ')
print(train_images.shape)
print(train_labels.shape)
print('테스트 데이터셋: ')
print(test_images.shape)
print(test_labels.shape)

신경망 모델 구조 및 컴파일
신경망 모델 구조
위의 데이터셋을 활용하여 가장 기본적인 신경망 모델을 설계하겠습니다. 신경망의 핵심 구성 요소는 층(layer)입니다. 신경망 모델은 여러 개의 층이 연속된 형태입니다. 층이 추가될수록 더 복잡한 문제를 해결할 수 있습니다. 이 글에서는 2개의 층으로 구성된 신경망 모델을 구현하겠습니다. Sequential 모델은 레이어를 순차적으로 쌓아올리는 가장 단순한 신경망 모델 구조입니다.
첫 번째 층은 512개의 뉴런을 가진 은닉층으로, 입력 데이터를 고차원 공간에서 feature로 변환합니다. 활성화 함수로 relu를 사용하여 비선형성을 추가하고, 신경망이 복잡한 패턴을 학습할 수 있도록 합니다.
두 번째 층은 0~9까지의 숫자 10개에 대하여 각 클래스에 속할 확률을 계산하는 출력층입니다. softmax 활성화 함수를 사용하여 출력 값을 0~1 사이의 확률로 변환하며, 모든 확률의 합은 1이 됩니다.
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
# 첫 번째 층: 은닉층
layers.Dense(512, activation="relu"),
# 두 번째 층: 출력층
layers.Dense(10, activation="softmax")
])
컴파일
위에서 생성한 신경망 모델을 학습하기 위해 '컴파일' 단계가 필요합니다. 컴파일은 모델 학습 과정의 설정을 정의하는 단계로 옵티마이저, 손실 함수, 평가 지표를 선택해야 합니다.
옵티마이저는 모델의 학습을 효율적으로 수행하기 위해 가중치를 업데이트하는 알고리즘입니다. 손실 함수를 최소화하기 위해 모델의 파라미터(가중치, 편향)를 조정하는 역할을 합니다.
손실 함수는 모델이 예측한 값과 실제 정답 간의 차이를 계산하는 지표입니다. 손실 함수는 모델의 성능을 수치적으로 평가하며, 이를 기반으로 모델의 가중치가 업데이트됩니다.
평가 지표는 학습 과정을 모니터링하기 위해 사용합니다. 모델의 최적화를 직접적으로 돕지는 않지만, 학습 성과를 이해하는 데 도움을 줍니다.
즉, 모델 컴파일은 신경망이 어떻게 학습할지(옵티마이저), 무엇을 최적화할지(손실 함수), 성능을 어떻게 평가할지(평가 지표)를 정의하는 필수 단계입니다.
이 글에서는 위에서 설계한 모델을 다음과 같이 컴파일합니다.
옵티마이저는 rmsprop을 사용합니다. 딥러닝 모델의 가중치를 효율적으로 업데이트하기 위해 사용되는 옵티마이저 중 하나입니다. 학습률을 동적으로 조정하여 학습의 안정성과 속도를 개선합니다. 가중치 업데이트 시 각 매개변수의 변화량을 제곱 평균으로 나누어, 너무 큰 변화나 작은 변화를 조정합니다.
손실 함수는 sparse_categorical_crossentropy를 사용합니다. 다중 클래스 분류 문제에 적합한 손실 함수이며 정답 레이블이 정수 형태로 주어진 경우에 사용됩니다. 모델의 출력(softmax 결과)과 실제 레이블 간의 차이를 계산하여 손실 값을 반환합니다. 손실 값이 작을수록 모델이 예측을 잘하고 있다는 뜻입니다.
평가 지표는 accuracy를 사용합니다. 분류 문제에서 가장 기본적인 평가 지표이며, 모델이 올바르게 예측한 샘플의 비율을 측정합니다.
model.compile(optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
데이터 전처리 및 학습
데이터 전처리
학습을 시작하기 전에 데이터를 모델에 맞는 크기로 바꾸고 모든 값을 0과 1사이로 스케일을 조정합니다.
현재 학습 이미지 크기는 (60000, 28, 28)으로 28x28 픽셀의 2D 이미지입니다. 하지만, 딥러닝 모델의 Dense 층은 1D 벡터 형태의 데이터를 입력으로 받습니다. 따라서, (28, 28) 형태의 이미지를 (28*28, )의 1D 벡터로 변환해야 합니다.
또한, 현재 데이터셋의 데이터는 0~255 사이의 정수입니다(보통 흑백 이미지의 픽셀 최대값이 255입니다). 하지만, 딥러닝 모델은 float32와 같은 부동소수점 타입의 데이터를 처리하므로 255로 나누어 데이터의 범위를 0~1로 맞춥니다. 정규화를 통해 특정 특성이 과도하게 영향을 미치는 것을 방지하고, 학습 효율을 높입니다.
# 학습 데이터셋 전처리
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
모델 학습
모델 설계, 데이터 전처리 등 모델 학습을 위한 준비가 끝났다면, fit을 사용하여 딥러닝 모델을 학습합니다. 입력 데이터는 train_images, 정답 레이블은 train_labels를 사용하고, 에포크(epochs)는 5, 배치 크기(batch_size)는 128로 설정했습니다.
에포크는 전체 데이터셋을 모델이 한 번 학습하는 과정을 의미합니다. 즉, 모델이 학습 데이터셋 전체를 5번 반복해서 학습한다는 의미입니다.
배치 크기는 모델이 학습 데이터셋을 나누어 처리하는 단위입니다. 한 번에 128개의 데이터를 가져와 학습하고, 그 결과로 가중치를 업데이트합니다.
이 모델은 train_images가 60,000개이므로 한 에포크에서 469번(60,000/128)의 학습이 이루어집니다.
model.fit(train_images, train_labels, epochs=5, batch_size=128)

예측 및 모델 평가
예측
위에서 학습한 모델을 활용하여 실제 예측 결과는 다음과 같습니다. 테스트 데이터셋의 첫 번째 예측 결과입니다. 인덱스 7에서 가장 높은 확률 값(0.99999106)을 출력했습니다. 따라서, 모델의 예측 결과는 7입니다.
predictions = model.predict(test_images)
predictions[0]

모델 평가
전체 테스트 데이터셋에 대해 평균적인 정확도를 계산하겠습니다. 테스트 데이터셋의 정확도는 97.8%입니다.
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"테스트 정확도: {test_acc}")

참고 도서:
케라스 창시자에게 배우는 딥러닝
'Python' 카테고리의 다른 글
[파이썬] 토이 프로젝트 - PC 알림 프로그램 noti-py, plyer (2) | 2025.02.23 |
---|---|
[파이썬] 한글 워드 클라우드 생성 및 특정 모양 적용 - KoNLPy, mask (2) | 2025.01.04 |
[파이썬] 파이썬으로 텍스트를 이모지로 변환하는 방법 - emoji (0) | 2024.12.26 |
[파이썬] 지수 표현 없이 숫자 출력하는 방법 - numpy 배열, 데이터프레임 (2) | 2024.12.17 |
[파이썬] 도커에서 파이썬 스크립트 차례대로 실행하는 방법 (1) | 2024.12.11 |