4-4. MNIST 손글씨 숫자 인식: TensorFlow/Keras 실습
title: "date: 2026-01-06" category: '' tags: [] summary:
1. MNIST 손글씨 숫자 인식 문제 소개
MNIST(Modified National Institute of Standards and Technology) 손글씨 숫자 인식 문제는 기계 학습 분야에서 가장 널리 사용되는 예제 중 하나입니다. 0부터 9까지의 손으로 쓴 숫자로 이루어진 60,000개의 훈련 이미지와 10,000개의 테스트 이미지로 구성된 데이터셋을 사용하여, 주어진 이미지에서 어떤 숫자가 나타나는지 정확하게 예측하는 것을 목표로 합니다.
1) 문제의 중요성
MNIST는 딥러닝 모델의 성능을 평가하고, 새로운 알고리즘을 개발하는 데 매우 유용한 벤치마크 역할을 합니다. 비교적 단순한 데이터셋이지만, 다양한 딥러닝 기법(신경망, CNN 등)을 적용하고 실험하기에 적합합니다. MNIST를 통해 기본적인 딥러닝 개념을 익히고, 모델 훈련, 평가, 개선 과정을 경험할 수 있습니다.
2) 왜 MNIST를 배우는가?
MNIST는 딥러닝 입문자가 기본적인 신경망 구조와 훈련 과정을 이해하는 데 매우 효과적인 도구입니다. MNIST를 성공적으로 해결하는 것은, 실제 문제 해결 능력을 향상시키는 첫걸음이 됩니다. 또한, MNIST를 통해 얻은 지식은 이미지 인식, 자연어 처리 등 다양한 분야에 적용될 수 있습니다.
2. TensorFlow/Keras를 이용한 MNIST 모델 구현
TensorFlow와 Keras는 딥러닝 모델을 쉽고 효율적으로 구축하기 위한 강력한 프레임워크입니다. Keras는 TensorFlow를 포함한 여러 백엔드(Theano, CNTK 등)를 지원하는 고수준 API로, 딥러닝 모델을 직관적이고 간결하게 정의할 수 있도록 돕습니다.
1) 데이터 로딩 및 전처리
MNIST 데이터셋은 Keras에 내장되어 있어 쉽게 불러올 수 있습니다. 데이터 로딩 후, 모델 훈련에 적합하도록 전처리 과정을 거칩니다.
import tensorflow as tf
from tensorflow import keras
# MNIST 데이터셋 로드
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# 이미지 정규화 (0~255 -> 0~1)
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# 레이블 원-핫 인코딩
y_train = keras.utils.to_categorical(y_train, num_classes=10)
y_test = keras.utils.to_categorical(y_test, num_classes=10)
x_train,x_test: 훈련 및 테스트 이미지 데이터. 각 이미지는 28x28 픽셀의 흑백 이미지로, 픽셀 값은 0에서 255 사이의 정수입니다.y_train,y_test: 훈련 및 테스트 이미지의 레이블(0~9 숫자).- 정규화: 픽셀 값을 0과 1 사이로 조정하여 모델 훈련의 효율성을 높입니다. 이는 경사 하강법의 수렴 속도를 향상시키는 데 기여합니다.
- 원-핫 인코딩: 각 레이블을 10차원 벡터로 변환합니다. 예를 들어, 숫자 5는
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]으로 표현됩니다. 이는 다중 클래스 분류 문제에 적합한 형식입니다.
2) 모델 정의
MNIST 문제를 해결하기 위한 기본적인 모델은 완전 연결 계층(Dense layer)을 여러 겹 쌓은 Sequential 모델로 구현할 수 있습니다.
model = keras.Sequential(
[
keras.layers.Input(shape=(28, 28)), # 입력 형태 지정
keras.layers.Flatten(), # 28x28 이미지를 784차원 벡터로 변환
keras.layers.Dense(128, activation="relu"), # 은닉층 1: 128개 유닛, ReLU 활성화 함수
keras.layers.Dropout(0.2), # 과적합 방지
keras.layers.Dense(10, activation="softmax"), # 출력층: 10개 유닛 (각 숫자 클래스), Softmax 활성화 함수
]
)

위 그림은 모델 구조를 시각적으로 나타냅니다.
Input(shape=(28, 28)): 입력 이미지의 형태를 지정합니다.Flatten(): 28x28 픽셀의 이미지를 784차원 벡터로 변환합니다. 완전 연결 계층에 입력하기 위해 필요한 과정입니다.Dense(128, activation="relu"): 128개의 유닛을 가진 완전 연결 계층입니다.relu활성화 함수를 사용하여, 비선형성을 도입하고 모델의 표현력을 높입니다.Dropout(0.2): 훈련 과정에서 20%의 뉴런을 무작위로 비활성화합니다. 이는 과적합을 방지하는 효과적인 기법입니다.Dense(10, activation="softmax"): 10개의 유닛을 가진 출력 계층입니다.softmax활성화 함수를 사용하여, 각 클래스(0~9)에 대한 확률 분포를 출력합니다.
3) 모델 컴파일
모델을 훈련하기 전에, 손실 함수, 옵티마이저, 평가 지표를 설정해야 합니다.
model.compile(
loss="categorical_crossentropy", # 다중 클래스 분류 문제에 적합한 손실 함수
optimizer="adam", # 경사 하강법 기반 옵티마이저
metrics=["accuracy"], # 모델 평가 지표
)
loss="categorical_crossentropy": 다중 클래스 분류 문제에 적합한 손실 함수입니다. 모델의 예측과 실제 레이블 간의 차이를 계산합니다.optimizer="adam": 학습률을 자동으로 조절하는 경사 하강법 기반 옵티마이저입니다. 빠른 수렴과 안정적인 학습을 지원합니다.metrics=["accuracy"]: 모델의 정확도를 평가 지표로 사용합니다.
4) 모델 훈련
fit 함수를 사용하여 모델을 훈련합니다. 훈련 데이터, 검증 데이터, 에폭 수, 배치 크기 등을 지정할 수 있습니다.
model.fit(x_train, y_train, batch_size=128, epochs=15, validation_split=0.1)
batch_size: 한 번의 훈련에 사용할 샘플의 수입니다.epochs: 전체 훈련 데이터셋을 몇 번 반복하여 학습할지 결정합니다.validation_split: 훈련 데이터의 일부를 검증 데이터로 사용하여, 훈련 과정에서 모델의 성능을 평가합니다. 과적합 여부를 확인하는 데 유용합니다.
5) 모델 평가
훈련된 모델의 성능을 테스트 데이터셋으로 평가합니다.
score = model.evaluate(x_test, y_test, verbose=0)
print("Test loss:", score[0])
print("Test accuracy:", score[1])
evaluate함수는 테스트 데이터셋에 대한 손실 값과 정확도를 반환합니다.
3. 핵심 원리: 딥러닝, 경사 하강법, 활성화 함수
1) 딥러닝과 신경망
딥러닝은 인공 신경망(Artificial Neural Network, ANN)을 기반으로 하는 기계 학습의 한 분야입니다. 인공 신경망은 생물학적 신경망에서 영감을 받아 만들어졌으며, 여러 층(layer)으로 구성된 연결된 노드(node)들의 집합입니다. 각 노드는 입력 값을 받아, 가중치(weight)를 곱하고, 편향(bias)을 더한 후 활성화 함수(activation function)를 적용하여 다음 층으로 전달합니다.

위 그림은 단일 레이어의 신경망 구조를 보여줍니다. 딥러닝 모델은 이러한 레이어들을 여러 겹 쌓아 복잡한 패턴을 학습할 수 있습니다.
2) 경사 하강법 (Gradient Descent)
경사 하강법은 신경망의 가중치를 업데이트하여 모델의 손실을 최소화하는 최적화 알고리즘입니다. 손실 함수(loss function)는 모델의 예측과 실제 값 간의 차이를 나타내는 함수입니다. 경사 하강법은 손실 함수의 기울기(gradient)를 계산하고, 기울기의 반대 방향으로 가중치를 조금씩 조정하여 손실을 줄여나갑니다.

위 그림은 경사 하강법의 개념을 2차원 공간에서 시각화한 것입니다. 경사 하강법은 손실 함수의 기울기를 따라 내려가며 최솟값(손실이 가장 작은 지점)을 찾습니다.
3) 활성화 함수 (Activation Function)
활성화 함수는 신경망의 각 노드에서 입력 값을 변환하는 함수입니다. 활성화 함수는 신경망에 비선형성을 부여하여, 모델이 복잡한 패턴을 학습할 수 있도록 합니다.
ReLU (Rectified Linear Unit): 입력 값이 0보다 작으면 0을, 그렇지 않으면 입력 값 자체를 출력합니다.- 장점: 계산이 빠르고, 기울기 소실 문제를 완화하는 데 도움을 줍니다.
Softmax: 다중 클래스 분류 문제의 출력층에서 사용되며, 각 클래스에 대한 확률을 계산합니다. 출력 값의 합은 1이 됩니다.
4. CNN (Convolutional Neural Network)을 이용한 MNIST 개선
완전 연결 계층만을 사용한 모델보다, 합성곱 신경망(Convolutional Neural Network, CNN)을 사용하면 MNIST 데이터셋에 대해 더욱 높은 정확도를 얻을 수 있습니다. CNN은 이미지 인식 분야에서 뛰어난 성능을 보이는 딥러닝 모델입니다.
1) CNN 구조
CNN은 합성곱 계층(Convolutional layer), 풀링 계층(Pooling layer), 그리고 완전 연결 계층으로 구성됩니다.
- 합성곱 계층: 이미지의 지역적인 특징(예: 선, 모서리)을 감지하는 필터(filter)를 사용합니다.
- 풀링 계층: 특징 맵(feature map)의 크기를 줄이고, 과적합을 방지하며, 특징의 위치 변화에 대한 불변성을 확보합니다.
- 완전 연결 계층: 합성곱 및 풀링 계층에서 추출된 특징을 사용하여 최종 예측을 수행합니다.

위 그림은 CNN의 일반적인 구조를 보여줍니다.
2) CNN 모델 구현 (예시)
model = keras.Sequential(
[
keras.layers.Input(shape=(28, 28, 1)), # 흑백 이미지의 형태 지정
keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), # 합성곱 계층 1
keras.layers.MaxPooling2D(pool_size=(2, 2)), # 풀링 계층 1
keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), # 합성곱 계층 2
keras.layers.MaxPooling2D(pool_size=(2, 2)), # 풀링 계층 2
keras.layers.Flatten(), # 특징 맵을 1차원 벡터로 변환
keras.layers.Dropout(0.25), # 과적합 방지
keras.layers.Dense(128, activation="relu"), # 완전 연결 계층 1
keras.layers.Dropout(0.5), # 과적합 방지
keras.layers.Dense(10, activation="softmax"), # 출력층
]
)
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
model.fit(x_train.reshape(-1, 28, 28, 1), y_train, batch_size=128, epochs=15, validation_split=0.1) # 훈련 데이터 형태 변경
Conv2D: 2차원 합성곱 계층입니다.kernel_size는 필터의 크기,activation은 활성화 함수를 지정합니다.MaxPooling2D: 2차원 풀링 계층입니다.pool_size는 풀링 영역의 크기를 지정합니다.Flatten: 합성곱 및 풀링 계층의 출력을 1차원 벡터로 변환합니다.Dropout: 과적합을 방지하기 위해 사용됩니다.
5. 모델 개선 및 주의사항
1) 하이퍼파라미터 튜닝
모델의 성능을 향상시키기 위해, 하이퍼파라미터(hyperparameter)를 튜닝할 수 있습니다. 하이퍼파라미터는 모델의 훈련 과정에 영향을 미치는 설정 값으로, 학습률, 배치 크기, 에폭 수, 레이어의 유닛 수, 활성화 함수 등을 포함합니다.
- 그리드 탐색 (Grid Search): 가능한 모든 하이퍼파라미터 조합을 시도합니다.
- 랜덤 탐색 (Random Search): 하이퍼파라미터를 무작위로 샘플링하여 시도합니다.
- 베이지안 최적화 (Bayesian Optimization): 이전 시도의 결과를 바탕으로, 가장 유망한 하이퍼파라미터 조합을 탐색합니다.
2) 과적합 방지
과적합은 모델이 훈련 데이터에 너무 맞춰져, 새로운 데이터에 대한 일반화 성능이 떨어지는 현상입니다. 과적합을 방지하기 위해 다음과 같은 기법을 사용할 수 있습니다.
- 드롭아웃 (Dropout): 훈련 과정에서 무작위로 뉴런을 비활성화합니다.
- 정규화 (Regularization): 가중치의 크기를 제한하여 모델의 복잡도를 줄입니다.
- L1 정규화: 가중치의 절대값 합을 손실 함수에 더합니다.
- L2 정규화: 가중치의 제곱 합을 손실 함수에 더합니다.
- 데이터 증강 (Data Augmentation): 훈련 데이터를 변환(회전, 이동, 확대/축소 등)하여, 데이터의 양을 늘리고 모델의 일반화 성능을 향상시킵니다.
3) 주의사항 및 트러블슈팅
- 기울기 소실 문제(vanishing gradient problem): 활성화 함수로
sigmoid나tanh를 사용하고, 레이어가 깊어질수록 기울기가 0에 가까워져 학습이 제대로 이루어지지 않는 문제입니다.ReLU활성화 함수를 사용하거나, 배치 정규화(Batch Normalization) 기법을 활용하여 해결할 수 있습니다. - 폭주하는 기울기 문제(exploding gradient problem): 기울기가 너무 커져 학습이 불안정해지는 문제입니다. 기울기 클리핑(gradient clipping)을 사용하여 기울기의 범위를 제한하거나, 학습률을 낮추는 방법을 사용할 수 있습니다.
- 모델 성능 평가: 훈련 및 검증 데이터셋에 대한 손실과 정확도를 지속적으로 모니터링하여, 모델의 성능과 과적합 여부를 파악해야 합니다.
- 데이터 전처리: 데이터 전처리는 모델의 성능에 큰 영향을 미칩니다. 데이터 정규화, 결측값 처리, 이상치 제거 등을 꼼꼼하게 수행해야 합니다.
6. 결론
MNIST 손글씨 숫자 인식 실습을 통해, 딥러닝의 기본적인 개념과 TensorFlow/Keras를 이용한 모델 구현 과정을 살펴보았습니다. 완전 연결 계층을 이용한 모델부터, CNN을 이용한 모델까지, 다양한 모델 구조를 통해 MNIST 문제를 해결할 수 있습니다. 하이퍼파라미터 튜닝, 과적합 방지, 주의사항 등을 숙지하여, 더욱 높은 성능의 딥러닝 모델을 구축할 수 있습니다. MNIST는 딥러닝 학습의 훌륭한 시작점이 되며, 여기서 얻은 경험은 다른 딥러닝 문제 해결에도 큰 도움이 될 것입니다.
비슷한 글 추천
4-2. Keras API: 딥러닝 모델 구축 및 학습 간소화
Keras API를 사용하여 딥러닝 모델을 쉽게 구축하고 학습하는 방법을 소개하고, 다양한 예제 코드를 제공합니다.
3-7. 경사 하강법의 변형: Momentum, AdamW
경사 하강법의 단점을 보완하기 위한 모멘텀, AdamW 등 다양한 최적화 알고리즘에 대해 설명하고, 각 알고리즘의 특징과 사용 사례를 비교합니다.
1-5. 딥러닝 개발 환경 설정: GPU, CUDA, cuDNN
딥러닝 연구 및 실습을 위한 GPU, CUDA, cuDNN 설치 및 설정 방법, 환경 점검 방법을 다룹니다.
4-1. TensorFlow 설치 및 기본 사용법: 텐서 연산, 자동 미분
TensorFlow 라이브러리의 설치 방법과 기본적인 사용법(텐서 연산, 자동 미분)을 소개하고, 예제 코드를 제공합니다.
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.