4-5. MNIST 손글씨 숫자 인식: PyTorch 실습
1. MNIST 손글씨 숫자 인식 문제 소개
MNIST (Modified National Institute of Standards and Technology) 손글씨 숫자 인식 문제는 기계 학습 분야에서 널리 사용되는 벤치마크 데이터셋입니다. 0부터 9까지의 손으로 쓴 숫자 이미지를 분류하는 문제로, 딥러닝 모델의 성능을 평가하고 새로운 기법을 개발하는 데 활용됩니다. MNIST는 단순해 보이지만, 다양한 딥러닝 알고리즘의 효과를 검증하고, 기본적인 딥러닝 개념을 이해하는 데 매우 유용합니다.
1) MNIST 데이터셋 구성
MNIST 데이터셋은 28x28 픽셀의 흑백 이미지로 구성되어 있으며, 각 이미지는 0에서 9까지의 숫자 중 하나를 나타냅니다. 데이터셋은 60,000개의 학습 이미지와 10,000개의 테스트 이미지로 나뉘어 있습니다. 각 이미지에는 해당 숫자에 대한 레이블(정답)이 함께 제공됩니다.
2) 왜 MNIST가 중요할까?
MNIST는 다음과 같은 이유로 중요합니다.
- 단순성: 이미지 크기가 작고, 데이터의 양이 적어 모델 학습 및 실험이 용이합니다.
- 가시성: 결과를 시각적으로 쉽게 확인할 수 있어, 모델의 성능을 직관적으로 이해할 수 있습니다.
- 표준화: 다양한 딥러닝 모델의 성능을 비교하는 데 사용되는 표준 벤치마크입니다.
- 입문: 딥러닝을 처음 배우는 사람들에게 기본적인 개념을 익히고 실습할 수 있는 좋은 예제입니다.
2. PyTorch를 이용한 MNIST 손글씨 숫자 인식
PyTorch는 딥러닝 모델을 구축하고 학습시키는 데 사용되는 오픈 소스 딥러닝 프레임워크입니다. 유연하고 사용하기 쉬운 인터페이스를 제공하며, 연구 및 개발 환경에서 널리 사용됩니다. PyTorch를 사용하여 MNIST 손글씨 숫자 인식 문제를 해결하는 과정을 살펴보겠습니다.
1) PyTorch 환경 설정
PyTorch를 사용하기 위해서는 먼저 PyTorch를 설치해야 합니다. 다음 명령어를 사용하여 PyTorch를 설치할 수 있습니다.
pip install torch torchvision
2) 데이터 로딩 및 전처리
PyTorch는 torchvision 라이브러리를 통해 MNIST 데이터셋을 쉽게 다운로드하고 로드할 수 있습니다. 다음 코드는 MNIST 데이터셋을 다운로드하고, 이미지 데이터를 텐서로 변환하며, 정규화를 수행하는 과정을 보여줍니다.
import torch
import torchvision
import torchvision.transforms as transforms
# 데이터셋 로드
transform = transforms.Compose([
transforms.ToTensor(), # 이미지를 텐서로 변환
transforms.Normalize((0.5,), (0.5,)) # 픽셀 값 정규화
])
trainset <mark class="highlight"><strong><u> torchvision.datasets.MNIST(root</u></strong></mark>'./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset <mark class="highlight"><strong><u> torchvision.datasets.MNIST(root</u></strong></mark>'./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
위 코드에서 transforms.ToTensor()는 이미지를 [0, 1] 범위의 텐서로 변환하고, transforms.Normalize((0.5,), (0.5,))는 이미지의 픽셀 값을 정규화하여 학습의 효율성을 높입니다.
3) 모델 정의
MNIST 손글씨 숫자 인식을 위한 딥러닝 모델을 정의합니다. 여기서는 간단한 2개의 선형 레이어(Fully Connected Layer)를 가진 모델을 사용합니다.
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128) # 입력: 28x28, 출력: 128
self.fc2 = nn.Linear(128, 10) # 입력: 128, 출력: 10 (0~9)
def forward(self, x):
x = x.view(-1, 28 * 28) # 이미지를 1차원 벡터로 변환
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
net = Net()
모델은 nn.Module을 상속받아 정의됩니다. __init__ 함수에서 레이어를 정의하고, forward 함수에서 입력 데이터를 처리하는 순서를 정의합니다. F.relu는 ReLU 활성화 함수를 사용합니다.

Source: Medium
4) 손실 함수 및 옵티마이저 정의
모델 학습에 필요한 손실 함수와 옵티마이저를 정의합니다. 손실 함수는 모델의 예측과 실제 값 사이의 차이를 계산하고, 옵티마이저는 이 손실을 최소화하도록 모델의 가중치를 업데이트합니다.
import torch.optim as optim
criterion = nn.CrossEntropyLoss() # 손실 함수: 교차 엔트로피
optimizer = optim.Adam(net.parameters(), lr=0.001) # 옵티마이저: Adam
여기서는 nn.CrossEntropyLoss를 손실 함수로 사용하고, Adam 옵티마이저를 사용하여 모델의 가중치를 업데이트합니다.
5) 모델 학습
정의된 모델을 학습 데이터셋을 사용하여 학습시킵니다. 학습 과정은 다음과 같습니다.
- 데이터 로드: 미니 배치 단위로 데이터를 로드합니다.
- 순전파 (Forward pass): 모델에 데이터를 입력하여 예측값을 계산합니다.
- 손실 계산: 예측값과 실제 값 사이의 손실을 계산합니다.
- 역전파 (Backward pass): 손실을 기반으로 기울기를 계산합니다.
- 가중치 업데이트: 옵티마이저를 사용하여 모델의 가중치를 업데이트합니다.
for epoch in range(2): # 데이터셋을 두 번 반복 학습
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# 입력 데이터 가져오기
inputs, labels = data
# 기울기 초기화
optimizer.zero_grad()
# 순전파 + 역전파 + 최적화
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 통계 출력
running_loss += loss.item()
if i % 2000 == 1999: # 각 2000 미니 배치마다 출력
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
6) 모델 평가
학습된 모델의 성능을 테스트 데이터셋을 사용하여 평가합니다.
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
3. 핵심 원리 상세 설명
1) 텐서 (Tensor)
PyTorch에서 텐서는 딥러닝 모델의 기본 데이터 구조입니다. 텐서는 다차원 배열로, 스칼라, 벡터, 행렬 등 다양한 형태의 데이터를 표현할 수 있습니다. 텐서는 CPU 또는 GPU에서 연산을 수행할 수 있으며, 자동 미분 기능을 제공하여 딥러닝 모델 학습을 용이하게 합니다.
2) 신경망 구조
MNIST 손글씨 숫자 인식 문제에서 사용되는 신경망 구조는 다음과 같습니다.
- 입력 계층 (Input Layer): 28x28 픽셀의 흑백 이미지 데이터를 받습니다.
- 은닉 계층 (Hidden Layer): 입력 데이터를 처리하고, 특징을 추출합니다. ReLU 활성화 함수를 사용하여 비선형성을 추가합니다.
- 출력 계층 (Output Layer): 0에서 9까지의 숫자 각각에 대한 확률을 출력합니다.
3) 활성화 함수
활성화 함수는 신경망에 비선형성을 추가하여 모델의 표현력을 높입니다. ReLU (Rectified Linear Unit)는 가장 널리 사용되는 활성화 함수 중 하나입니다. ReLU는 입력값이 0보다 크면 입력을 그대로 출력하고, 0 이하면 0을 출력합니다.
$f(x) = max(0, x)$
4) 손실 함수
손실 함수는 모델의 예측과 실제 값 사이의 차이를 측정합니다. 교차 엔트로피 손실 함수는 분류 문제에서 널리 사용되며, 모델의 예측 확률과 실제 레이블 간의 차이를 계산합니다.
5) 옵티마이저
옵티마이저는 손실 함수를 최소화하도록 모델의 가중치를 업데이트합니다. Adam은 널리 사용되는 옵티마이저 중 하나로, 학습률을 적응적으로 조절하여 학습 속도를 향상시킵니다.
6) 순전파와 역전파
- 순전파 (Forward pass): 입력 데이터를 모델에 통과시켜 예측값을 계산하는 과정입니다.
- 역전파 (Backward pass): 손실 함수를 기반으로 기울기를 계산하고, 이 기울기를 사용하여 모델의 가중치를 업데이트하는 과정입니다.

Source: GeeksforGeeks
4. 응용 및 활용 사례
MNIST 손글씨 숫자 인식 문제는 다음과 같은 다양한 분야에 응용될 수 있습니다.
- OCR (Optical Character Recognition) 시스템: 손으로 쓴 문자를 인식하여 텍스트로 변환하는 시스템.
- 우편 번호 인식: 우편물 분류 자동화에 사용됩니다.
- 수표 인식: 은행에서 수표의 금액을 자동으로 인식하는 데 활용됩니다.
- 필기 인식: 태블릿 PC나 스마트폰에서 사용자가 쓴 글씨를 인식하는 데 활용됩니다.
5. 주의사항과 트러블슈팅
1) 과적합 (Overfitting)
모델이 훈련 데이터에 너무 맞춰져 새로운 데이터에 대한 일반화 성능이 떨어지는 현상입니다. 과적합을 방지하기 위해 다음과 같은 방법을 사용할 수 있습니다.
- 드롭아웃 (Dropout): 훈련 중에 무작위로 일부 뉴런을 비활성화하여 모델의 복잡성을 줄입니다.
- 정규화 (Regularization): 모델의 가중치에 페널티를 부과하여 과도한 가중치를 방지합니다.
- 데이터 증강 (Data augmentation): 훈련 데이터를 변형하여 데이터셋을 늘립니다 (예: 회전, 이동, 노이즈 추가).
2) 학습률 (Learning rate)
학습률은 모델의 가중치를 업데이트하는 속도를 결정합니다. 학습률이 너무 크면 학습이 불안정해지고, 너무 작으면 학습 속도가 느려집니다. 적절한 학습률을 찾는 것이 중요하며, 일반적으로 0.001 또는 0.0001과 같은 작은 값을 사용합니다.
3) 배치 크기 (Batch size)
배치 크기는 한 번의 학습에 사용되는 데이터의 양을 결정합니다. 배치 크기가 너무 작으면 학습이 불안정해지고, 너무 크면 메모리 사용량이 증가합니다. 일반적으로 32, 64, 128과 같은 값을 사용합니다.
4) 기울기 소실 (Vanishing gradients) 및 기울기 폭발 (Exploding gradients)
깊은 신경망에서 기울기가 0에 가깝거나 매우 커지는 현상입니다. 기울기 소실은 모델의 학습을 어렵게 만들고, 기울기 폭발은 학습을 불안정하게 만듭니다.
- ReLU 활성화 함수: 기울기 소실 문제를 완화하는 데 도움을 줍니다.
- 배치 정규화 (Batch normalization): 학습 속도를 높이고 기울기 소실/폭발 문제를 완화합니다.
- 기울기 클리핑 (Gradient clipping): 기울기 폭발을 방지합니다.
6. 결론
PyTorch를 사용하여 MNIST 손글씨 숫자 인식 문제를 해결하는 과정을 살펴보았습니다. 딥러닝 모델의 기본적인 구조, 학습 과정, 그리고 주의사항에 대해 이해할 수 있었습니다. MNIST는 딥러닝을 시작하는 데 좋은 예제이며, PyTorch를 사용하여 다양한 딥러닝 모델을 구축하고 실험해 볼 수 있습니다.
비슷한 글 추천
8-6. 이미지 생성 실습: GAN 모델 구현 및 학습
GAN 모델을 직접 구현하고, 간단한 이미지 데이터셋(MNIST, CIFAR-10)을 이용하여 이미지를 생성하는 실습 과정을 상세히 설명합니다.
4-3. PyTorch 설치 및 기본 사용법: 텐서 연산, 자동 미분
PyTorch 라이브러리의 설치 방법과 기본적인 사용법(텐서 연산, 자동 미분)을 소개하고, 예제 코드를 제공합니다.
3-1. PyTorch 소개: 텐서
PyTorch 소개, 텐서 생성, 텐서 자료형
3-2. PyTorch: 텐서 연산
텐서 연산(덧셈, 뺄셈, 곱셈, 나눗셈), 차원 변환
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.