본문 바로가기

Deep Learning

Simple CNN 예제

아무래도 가장 간단한 딥러닝 예제가 필요할 것 같다. 

가장 간단한 딥러닝 예제로는 mnist 손글씨 데이터에 CNN 예제가 적당할 것이다. 

 

파이토치를 활용하여 바로 예제를 보자. 

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, random_split

# 1. 데이터셋 준비 (정규화)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])


full_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)

# 3. train/test 비율 설정 (8:2)
train_size = int(0.8 * len(full_dataset))  # 48000
test_size = len(full_dataset) - train_size # 12000

train_dataset, test_dataset = random_split(full_dataset, [train_size, test_size])

train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader  = DataLoader(test_dataset, batch_size=64, shuffle=False)

# 2. CNN 모델 정의
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv_layer = nn.Sequential(
            nn.Conv2d(1, 32, 3, 1),   # (입력채널 1개, 출력채널 32개, 커널 3x3, 스트라이드 1)
            nn.ReLU(),
            nn.MaxPool2d(2),          # 2x2 풀링
            nn.Conv2d(32, 64, 3, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc_layer = nn.Sequential(
            nn.Flatten(),
            nn.Linear(64*5*5, 64),
            nn.ReLU(),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.conv_layer(x)
        x = self.fc_layer(x)
        return x

model = SimpleCNN()

# 3. 손실 함수, 옵티마이저 설정
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 4. 학습 루프
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

epochs = 5
for epoch in range(epochs):
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0

    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    train_accuracy = 100 * correct / total
    print(f"Epoch [{epoch+1}/{epochs}], Loss: {running_loss/len(train_loader):.4f}, Accuracy: {train_accuracy:.2f}%")

# 5. 테스트셋 정확도 측정
model.eval()
correct = 0
total = 0

with torch.no_grad():
    for images, labels in test_loader:
        images, labels = images.to(device), labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

test_accuracy = 100 * correct / total
print(f"\n테스트 데이터 정확도: {test_accuracy:.2f}%")

 

코드를 보면... 

1. 데이터셋을 준비하고. 

  . 여기서는 mnist 데이터를 자동으로 다운로드 받아서 사용한다

  . 데이터셋을 구성하는데 train_dataset 과 test_dataset으로 구성한다. 

  . 구성한 데이터셋으로부터 train_loader, test_loader 데이터로더를 만든다. 

 

2. CNN 모델을 정의한다. 

  . 자세한 내부구조는 모르더라도 그냥 딥러닝 네트워크를 구성했다 정도로 이해하자

 

3. 손실함수와 옵티마이저를 설정하고,

 

4. epoch 만큼 돌면서 학습을 한다. 

  . 이미지 데이터(images)와 정답데이터(labels)를 가져와서 

  . 모델에 넣고 outputs를 받는다. 

  . outputs와 labels를 비교해서 어느정도 정답을 맞추는지 확인하고(오차를 계산하고)

  . loss.backward()를 통해서 오차기울기를 계산한다. 

  . optimizer.step()으로 기울기 업데이트를 수행한다. 

 

5. 학습이 epoch만큼 수행되어서 학습이 끝나면, 테스트셋에 대해 정확도를 측정한다. 

 

이정도의 순서로 진행되는 것만 기억하면 될 것 같다. 

대부분의 기초 딥러닝 학습은 이 순서로 진행된다. 

 

실제 코드를 돌려보면 아래와 같은 결과를 얻을 수 있다. 

간단한 예제인데, 너무 결과가 좋은데?

 

암튼 predict 와 정답이 다른 경우를 출력해서 보면 다음과 같은 결과를 얻을 수 있다. 

흠. 어찌보면 잘못 예상할 수도 있을 것 같다.

 

틀린 그림에 대해서 출력하는 코드는 다음과 같다. 

5. 테스트셋 정확도 측정부분의 코드를 아래 코드로 변경하면 된다. 

import matplotlib.pyplot as plt
import numpy as np

# 오답 이미지 저장용 리스트
wrong_images = []
wrong_preds = []
wrong_labels = []

model.eval()
with torch.no_grad():
    for images, labels in test_loader:
        images, labels = images.to(device), labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        
        # 오답 인덱스 찾기
        wrong_mask = (predicted != labels)
        if wrong_mask.sum() > 0:
            wrong_images.append(images[wrong_mask])
            wrong_preds.append(predicted[wrong_mask])
            wrong_labels.append(labels[wrong_mask])

# 리스트 합치기
wrong_images = torch.cat(wrong_images)
wrong_preds  = torch.cat(wrong_preds)
wrong_labels = torch.cat(wrong_labels)

# 오답 이미지 10개 출력
num_images = 10
plt.figure(figsize=(12, 5))
for i in range(num_images):
    image = wrong_images[i].cpu().squeeze().numpy()
    pred  = wrong_preds[i].item()
    label = wrong_labels[i].item()
    
    plt.subplot(2, 5, i+1)
    plt.imshow(image, cmap='gray')
    plt.title(f'Pred: {pred}, Label: {label}')
    plt.axis('off')

plt.tight_layout()
plt.show()

 

간단한 예제이지만 꽤 정확한 결과를 얻을 수 있다는 것을 알 수 있는 예제이다. 

 

그럼 오늘은 이만~

'Deep Learning' 카테고리의 다른 글

Simple Imitation Learning  (0) 2025.05.15
Simple Object Detection with DETR  (1) 2025.05.13
Multi-task learning  (0) 2025.04.30
Continual Learning(연속학습)  (0) 2025.04.30
강화학습(Reinforcement Learning) 최신 동향  (0) 2025.04.15