
1. MNIST 손글씨
MNIST 손글씨 데이터셋은 딥러닝 이미지 분류를 처음 실습할 때 자주 사용되는 대표적인 데이터셋이다. 숫자 이미지를 보고 0부터 9까지 어떤 숫자인지 맞히는 문제이기 때문에, 딥러닝 모델이 데이터를 어떻게 학습하고 예측하는지 이해하기에 적합하다. 특히 텐서플로와 케라스를 사용하면 데이터 로딩부터 모델 생성, 학습, 평가까지의 과정을 비교적 간단한 코드로 확인할 수 있다.
MNIST 데이터셋은 손으로 쓴 숫자 이미지로 구성되어 있다. 훈련 데이터는 60,000개, 테스트 데이터는 10,000개이며, 각 이미지는 28x28 크기의 그레이스케일 이미지이다. 여기서 그레이스케일은 색상이 없는 흑백 이미지라고 이해하면 된다. 숫자의 모양은 사람마다 다르기 때문에, 모델은 단순히 하나의 정답 이미지를 외우는 것이 아니라 여러 손글씨 패턴에서 공통적인 특징을 찾아야 한다.

참고로 아래는 CIFAR-10 데이터셋으로 합성곱 신경망(CNN)을 구현에 관한 글이다.
2026.06.10 - [✨ 딥러닝·머신러닝] - 합성곱 신경망(CNN) - 합성곱 신경망을 구현해 보자 (CIFAR-10)
2. 딥너링 프로세스
딥러닝 모델을 만들기 전에 가장 먼저 해야 할 일은 데이터를 학습에 적합한 형태로 바꾸는 것이다. 코드에서는 tf.keras.datasets.mnist를 사용해 MNIST 데이터셋을 불러온 뒤, 이미지 데이터를 합성곱 신경망에 맞게 변환한다. 기존 이미지는 28x28 형태이지만, CNN 모델에서는 채널 정보가 필요하기 때문에 28x28x1 형태로 바꾼다. 여기서 마지막 1은 흑백 이미지의 채널 수를 의미한다.
이후에는 데이터 정규화 과정이 진행된다. MNIST 이미지의 픽셀 값은 0부터 255 사이의 값을 갖는다. 이 값을 그대로 사용하면 학습 과정에서 계산이 불안정해질 수 있으므로, 모든 픽셀 값을 255로 나누어 0과 1 사이의 값으로 변환한다. 데이터 정규화는 딥러닝 모델 학습에서 자주 사용되는 기본 전처리 방법이며, 모델이 더 안정적으로 학습하도록 돕는다.
라벨 데이터도 모델이 이해할 수 있는 형태로 변환한다. 입력 코드에서는 tf.one_hot을 사용해 숫자 라벨을 원-핫 인코딩한다. 예를 들어 정답이 숫자 3이라면, 10개의 클래스 중 3에 해당하는 위치만 1이 되고 나머지는 0이 되는 방식이다. 이렇게 변환하면 모델은 최종 출력층에서 0부터 9까지 각 숫자일 확률을 계산할 수 있다.

모델 구조는 합성곱 신경망, 즉 CNN을 기반으로 구성되어 있다. CNN은 이미지 인식 분야에서 많이 사용되는 딥러닝 구조로, 이미지 안에 있는 선, 곡선, 모양 같은 특징을 단계적으로 추출하는 데 적합하다. 코드에서는 Conv2D 층을 여러 번 사용해 이미지의 특징을 추출하고, MaxPool2D를 통해 중요한 정보는 남기면서 데이터 크기를 줄인다. 여기에 Dropout을 적용해 모델이 훈련 데이터에 지나치게 맞춰지는 현상을 줄이도록 설계했다.
합성곱 층을 거친 데이터는 Flatten을 통해 1차원 형태로 펼쳐지고, 이후 Dense 층을 통과한다. 마지막 출력층은 10개의 뉴런으로 구성되어 있으며, softmax 활성화 함수를 사용한다. 이는 입력 이미지가 0부터 9까지의 숫자 중 어느 클래스에 속할 가능성이 높은지를 확률 형태로 출력하기 위한 구조이다.
모델을 만들었다고 바로 학습할 수 있는 것은 아니다. 컴파일 단계에서 어떤 방식으로 학습할지 지정해야 한다. 입력 코드에서는 최적화 알고리즘으로 RMSprop을 사용하고, 손실 함수로 categorical_crossentropy를 사용한다. 손실 함수는 모델의 예측값과 실제 정답이 얼마나 다른지 계산하는 기준이며, 모델은 이 손실 값을 줄이는 방향으로 학습한다.
학습 과정에서는 훈련 데이터를 사용해 모델의 가중치가 조정된다. 코드에서는 배치 크기를 64로 설정하고, 전체 데이터를 한 번 학습하는 epochs=1로 실행했다. 또한 훈련 데이터 중 일부를 검증 데이터로 사용하기 위해 validation_split=0.1을 적용했다. 이 과정을 통해 모델은 학습 중에도 검증 성능을 함께 확인할 수 있다.
import tensorflow as tf
import numpy as np
# MNIST 데이터셋 로드
mnist = tf.keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 데이터 변환
train_images = train_images.reshape(
train_images.shape[0], train_images.shape[1], train_images.shape[2], 1)
test_images = test_images.reshape(
test_images.shape[0], test_images.shape[1], test_images.shape[2], 1)
# 데이터 정규화
train_images = train_images / 255.0
test_images = test_images / 255.0
train_labels = tf.one_hot(train_labels.astype(np.int32), depth=10)
test_labels = tf.one_hot(test_labels.astype(np.int32), depth=10)
# 모델 생성 (합성곱 층 만들기)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (5, 5), padding='same',
activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.Conv2D(32, (5, 5), padding='same', activation='relu'),
tf.keras.layers.MaxPool2D(),
tf.keras.layers.Dropout(0.25),
tf.keras.layers.Conv2D(64, (3, 3), padding='same', activation='relu'),
tf.keras.layers.MaxPool2D(strides=(2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), padding='same', activation='relu'),
tf.keras.layers.Dropout(0.25),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(10, activation='softmax')
])
# 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.RMSprop(epsilon=1e-08),
loss='categorical_crossentropy', metrics=['acc'])
# 모델 요약
model.summary()
# 모델 학습
history = model.fit(train_images, train_labels,
batch_size=64,
epochs=1,
validation_split=0.1)
# 모델 평가
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_loss, test_acc)
실행 결과
실행 결과 훈련 정확도는 93.55%로 나타났고, 테스트 데이터 평가에서는 97.59%의 정확도를 기록했다. 이는 모델이 훈련 데이터뿐 아니라 처음 보는 테스트 이미지에 대해서도 비교적 높은 성능을 보였다는 의미이다. 물론 에포크 수, 모델 구조, 배치 크기, 최적화 방식 등을 조정하면 결과는 달라질 수 있다.
MNIST 손글씨 분류 실습의 핵심은 단순히 높은 정확도를 얻는 데 있지 않다. 데이터를 불러오고, 전처리하고, CNN 모델을 설계한 뒤, 학습과 평가를 거치는 전체 딥러닝 프로세스를 직접 확인하는 데 의미가 있다. 이 흐름을 이해하면 이후 CIFAR-10 같은 컬러 이미지 데이터셋이나 더 복잡한 이미지 인식 문제로 확장할 때도 기본 구조를 잡기 쉬워진다. 텐서플로 MNIST 예제는 딥러닝 모델 구현 방법을 익히는 출발점으로 충분히 활용할 수 있는 실습이다.
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 28, 28, 32) 832
conv2d_1 (Conv2D) (None, 28, 28, 32) 25632
max_pooling2d (MaxPooling2 (None, 14, 14, 32) 0
D)
dropout (Dropout) (None, 14, 14, 32) 0
conv2d_2 (Conv2D) (None, 14, 14, 64) 18496
max_pooling2d_1 (MaxPoolin (None, 7, 7, 64) 0
g2D)
conv2d_3 (Conv2D) (None, 14, 14, 64) 36928
dropout_1 (Dropout) (None, 7, 7, 64) 0
flatten (Flatten) (None, 3136) 0
dense (Dense) (None, 128) 401536
dropout_2 (Dropout) (None, 128) 0
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 484714 (1.85 MB)
Trainable params: 484714 (1.85 MB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
844/844 [==============================] - 149s 175ms/step - loss: 0.2093 - acc: 0.9355 - val_loss: 0.0691 - val_acc: 0.9812
313/313 [==============================] - 6s 19ms/step - loss: 0.0688 - acc: 0.9759
0.0687982365489006 0.9758999943733215

'✨ 딥러닝·머신러닝' 카테고리의 다른 글
| TensorFlow - 도커 컨테이너에서 텐서플로를 실행 (0) | 2026.06.15 |
|---|---|
| 신경망의 발견 - 신경망에서 단순 퍼셉트론, 다중 퍼셉트론, 딥러닝까지 (0) | 2026.06.15 |
| Tensorflow - 텐서플로를 사용해 MNIST를 학습 (0) | 2026.06.13 |
| Fashion MNIST - 이미지를 학습하여 자동으로 분류 (0) | 2026.06.13 |
| 케라스 데이터셋 - 케라스(Keras)에서 제공하는 데이터셋 (0) | 2026.06.13 |
댓글