본문 바로가기

[Pytorch] MLP(Multi-layer)를 사용하여 MNIST 분류하기

Derrick 발행일 : 2022-05-15
728x90
반응형

 

# Multi-Layer Perceptron(MLP)MNIST data 분류하기 
MNIST : 숫자 0~9까지의 이미지로 구성된 손글씨 Dataset
→ 60,000개의 Training data, label 와 10,000개의 Test data, label로 구성됨
→ 각각의 이미지는 28 x 28 size이며, 해당 이미지가 어떤 숫자인지 분류하는 실습

 

import torch
import torchvision
import torchvision.datasets as dsets
import torchvision.transforms as transforms

# GPU & random seed 설정
device = 'cuda' if torch.cuda.is_available() else 'cpu'

torch.manual_seed(1)
if device == 'cuda':
  torch.cuda.manual_seed_all(1)

# Hyper-parameter 설정
learning_rate = 0.001
training_epochs = 15
batch_size = 100

 

- Hyperparameter (하이퍼파라미터)
  : 개발자가 직접 정해줄 수 있는 변수. ex) 각종 rate, layer의 수
- parameter (매개변수) : 모델이 학습하면서 얻어지는 값. ex) weight(가중치), bias

 

# MNIST dataset
mnist_train = dsets.MNIST(root='MNIST_data/',
                          train=True,
                          transform=transforms.ToTensor(),
                          download=True)
mnist_test = dsets.MNIST(root='MNIST_data/',
                         train=False,
                         transform=transforms.ToTensor(),
                         download=True)

# Data Loader (데이터 로드하기)
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

 

# drop_last 하는 이유
: 마지막 batch 에서 남은 데이터를 버리기 위해서 사용됨 (drop_last = True)
 → batch size보다 작은 mini-batch가 마지막에 남아서 상대적 과대 평가되는 현상을 방지한다.

 

# 임의의 MNIST 이미지 출력 - 테스트용
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

images, label = mnist_train[0]
print(images.shape, label)                  # size = 28 x 28, label = 5

plt.imshow(images.reshape(28,28), cmap='gray')        # image에 Grey color channel을 갖도록

 

 

for images, labels in data_loader:
  break

print('Labels:', labels[:10].numpy())
image = torchvision.utils.make_grid(images[:10],nrow=10)    # 10개의 임의의 images와 Label 값 출력
plt.imshow(np.transpose(image.numpy(),(1,2,0)))             # ( color, width, height )

 

 

# 모델 생성 (fc layer는 3개. 각각 relu 함수 적용)
import torch.nn as nn
import torch.nn.functional as F

class Multilayer(nn.Module):
  def __init__(self):
    super(Multilayer, self).__init__()

    # input image = 28 x 28 x 1
    self.fc1 = nn.Linear(28*28*1, 100)
    self.fc2 = nn.Linear(100, 100)
    self.fc3 = nn.Linear(100, 10)

  def forward(self, x):
    out = F.relu(self.fc1(x))
    out = F.relu(self.fc2(out))
    out = self.fc3(out)

    out = F.log_softmax(out, dim=1)

    return out

model = Multilayer().to(device)
print(model)

 

>>
Multilayer(
  (fc1): Linear(in_features=784, out_features=100, bias=True)
  (fc2): Linear(in_features=100, out_features=100, bias=True)
  (fc3): Linear(in_features=100, out_features=10, bias=True)
)

 

- nn.ReLU와 F.relu는 각각 객체로 선언하는지 or 함수로 사용하는지의 차이가 있다.
- ReLU 가 별도 학습이 필요없다면, 객체가 아닌 함수로 사용해서 적용할 수 있다.

 

# define loss function & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)                    # Softmax computed
# Adam optimizer 사용(weight 학습을 위한 최적화)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)    

 

# Training (모델 훈련)
total_batch = len(data_loader)

for epoch in range(training_epochs):        # epoch = 15회 반복
  avg_cost = 0.0

  # Dataloader에서 mini-batch를 하나씩 꺼내서 학습 진행
  for data, targets in data_loader:           # (images, label)
    # Reshape : 입력 이미지 -> [batch_size x 784]
    # 호출된 data는 (batch_size x 1 x 28 x 28)의 크기지만, view를 통해서 (batch_size x 784)의 크기로 변환
    data = data.view(-1, 28*28).to(device)   
    targets = targets.to(device)

    # Gradient 매개변수를 0으로 초기화 (실행 전)
    optimizer.zero_grad()

    # 모델 계산 후 output 저장
    output = model(data)

    # cost/loss율 계산
    cost = criterion(output, targets)

    # 가중치(weight) 개선
    cost.backward()
    optimizer.step()

    # loss율 계산 ()
    avg_cost += cost / total_batch

  # 통계치 출력
  print('Epoch: {:2d}/{}  Cost = {:.6f}'.format(
      epoch+1, training_epochs, avg_cost
  ))
print('Learning Finished!')

 

>>
Epoch:  1/15  Cost = 0.385415
Epoch:  2/15  Cost = 0.161993
Epoch:  3/15  Cost = 0.112978
Epoch:  4/15  Cost = 0.085963
Epoch:  5/15  Cost = 0.068826
Epoch:  6/15  Cost = 0.057245
Epoch:  7/15  Cost = 0.045883
Epoch:  8/15  Cost = 0.039197
Epoch:  9/15  Cost = 0.031401
Epoch: 10/15  Cost = 0.028373
Epoch: 11/15  Cost = 0.022344
Epoch: 12/15  Cost = 0.019178
Epoch: 13/15  Cost = 0.017155
Epoch: 14/15  Cost = 0.015110
Epoch: 15/15  Cost = 0.016110                        # cost값 감소 확인. 학습 잘 진행됨
Learning Finished!

 

# Model Testing & 예상한 이미지 출력
import random

with torch.no_grad():
  X_test = mnist_test.data.view(-1, 28*28).float().to(device)         # data = test_data
  Y_test = mnist_test.targets.to(device)                              # targets = test_labels

  prediction = model(X_test)
  correct_prediction = torch.argmax(prediction, 1) == Y_test
  accuracy = correct_prediction.float().mean()
  print('Accuracy:', accuracy.item())

  # 임의의 이미지 하나를 추출하고 Prediction
  r = random.randint(0, len(mnist_test) - 1)
  X_single_data = mnist_test.data[r:r + 1].view(-1, 28*28).float().to(device)
  Y_single_data = mnist_test.targets[r:r + 1].to(device)

  print('Label: ', Y_single_data.item())
  single_prediction = model(X_single_data)
  print('Prediction: ', torch.argmax(single_prediction, 1).item())

  plt.imshow(mnist_test.data[r:r + 1].view(28, 28), cmap='Greys', interpolation='nearest')
  plt.show()

 

 

- Accuracy(정확도)는 97.5%. 정답 Label과 예측한 Prediction이 동일한 값 출력 확인.
  
# Interpolation (보간법) : 이미지의 크기가 바뀌는 과정에서 생길 수 있는 문제를 해결
 : image가 커지면 새로운 pixel값 결정, 줄어든다면 작은 pixel로 표현하므로 정보를 잃을 수 있다.
 → interpolation = 'nearest' : 인접한 pixel들의 정보를 이용



 

댓글