본문 바로가기
머신러닝

MNIST Classification using SLP, MLP

by 의문의 효몽 2023. 12. 17.

Perceptron 을 이용한 MNIST 손글씨 데이터셋 분류

 

MNIST Datebase (Modified National Institute of Standards and Technology)

- 손으로 쓴 숫자들로 이루어진 대형 데이터베이스

- Train dataset 60,000개, Test dataset 10,000개로 구성됨

 

 

1. Single Layer Perceptron (SLP) 실습

 

목표 : MNIST 손글씨 데이터를 분류하는 single layer(단층) perceptron 모델 학습

입력 : 손글씨 이미지 (28x28x1)

출력 : 0~9까지 숫자들의 정답 확률

 

▼ 패키지 선언

import torch
import torch.nn as nn
import torchvision.datasets as dataset
import torchvision.transforms as transform
from torch.utils.data import DataLoader

 

▼ Dataset 다운로드

# Training dataset 다운로드
mnist_train = dataset.MNIST(root = "./",
                            train = True,
                            transform = transform.ToTensor(),
                            download = True)
# Testing dataset 다운로드
mnist_test = dataset.MNIST(root = "./",
                            train = False,
                            transform = transform.ToTensor(),
                            download = True)

 

▼ MNIST 데이터셋 형상 확인

import matplotlib.pyplot as plt
print(len(mnist_train))     # training dataset 개수 확인

first_data = mnist_train[0]
print(first_data[0].shape)  # 첫번째 data의 형상 확인
print(first_data[1])        # 첫번째 data의 정답 확인

plt.imshow(first_data[0][0,:,:], cmap='gray') # 이미지를 시각화
plt.show()
60000
torch.Size([1, 28, 28])
5

 

※ 참고 _ MNIST 데이터셋 형상

Image : 28x28 (pixels)

MNIST "train" dataset 과 MNIST "test" dataset

 

 

MNIST 데이터셋의 perceptron 입력 방법

- Perceptron의 각 노드는 한 번에 한 개의 값을 입력받을 수 있다

- 따라서 2D 형태의 이미지 전처리가 필요하다 → 평탄화

▼ 평탄화 확인

first_img = first_data[0]
print(first_img.shape)

first_img = first_img.view(-1, 28*28) # 이미지 평탄화 수행 2D -> 1D
print(first_img.shape)
torch.Size([1, 28, 28])
torch.Size([1, 784])

● MNIST 이미지는 28x28 픽셀의 2D 배열로 표현된다. (이미지 데이터는 보통 2D 형태로 표현된다.)
● 일부 신경망 모델은 1D 벡터 형태의 입력을 기대할 수 있다. 
● 따라서 원래 2D 이미지를 1D로 평탄화하는 역할을 수행한다 → view(-1, 28*28) 
● 이렇게 평탄화된 1D 벡터는 주로 이미지의 모든 픽셀 값을 포함하고 신경망의 입력으로 사용되어 이미지의 구조적 특징을 보존하면서도 효과적으로 처리될 수 있다

 

▼ Single Layer Perceptron 모델 정의

class SLP(nn.Module):

  def __init__(self):
    super(SLP, self).__init__()
    # SLP의 입력은 784개, 출력은 10개
    self.fc = nn.Linear(in_features=784, out_features=10)

  def forward(self, x):
    x = x.view(-1, 28*28) #이미지 평탄화
    y = self.fc(x)
    return y

Pytorch에서 구현하는 모델은 반드시 2가지 함수를 선언해야 한다.

__init__() 함수 에 포함해야 하는 정보

- Parameter를 가지는 layer 정보 (Fully connected layer, Convolutional layer 등)

- Activation function

- ※참고 : torch.nn.Linear = Fully connected layer

forward() 함수 에 포함해야 하는 정보

- 모델의 동작 순서

- 각 layer, 함수의 입출력 관계

 

▼ Hyper-parameters 지정

batch_size = 100 # 60,000개에 대해서 600번의 weight update
learning_rate = 0.1
training_epochs = 15 # 15번 반복
loss_function = nn.CrossEntropyLoss()
network = SLP()
optimizer = torch.optim.SGD(network.parameters(), lr = learning_rate)

data_loader = DataLoader(dataset=mnist_train,
                         batch_size=batch_size,
                         shuffle=True,
                         drop_last=True)

✓ Batch size : 100 (한번에 학습할 데이터의 개수)
✓ Learning rate : 0.1 (가중치를 얼마나 변경시킬지 정하는 상수)
✓ Epoch : 15 (1 Epoch: 전체 데이터셋에 대해 1회 학습)
✓ Loss function : Cross entropy error (학습 모델이 얼마나 잘못 예측하고 있는지는 표현하는 지표)

    ※ 참고 : torch.nn.CrossEntropyLoss()함수

        1. 예측 값들에 대해서 자동으로 softmax 적용

        2. 정답 값과 예측 값을 이용해서 cross entropy loss 측정

✓ Optimizer: SGD (Loss function을 최소로 만들기 위한 가중치, 편향을 찾는 알고리즘)

 

✓ Batch 단위의 학습을 위해서 data_loader 함수 사용

 

▼ Perceptron 학습을 위한 반복문 선언

network.train()

for epoch in range(training_epochs): # 전체 데이터에 대한 반복 : epoch
  avg_cost = 0
  total_batch = len(data_loader)

  for img, label in data_loader: # 1 epoch 내의 1 batch에 대한 반복 : iteration

    pred = network(img) → 1. 입력 이미지에 대해서 forward pass

    loss = loss_function(pred, label) → 2. 예측 값, 정답 값을 이용해 loss 계산
    optimizer.zero_grad() # gradient 초기화
    loss.backward() → 3. 모든 weight에 대해 편미분 값 계산
    optimizer.step() → 4. 파라미터 업데이트

    avg_cost += loss / total_batch # 모든 batch에 대한 평균 loss값 계산

  print('Epoch: %d Loss = %f'%(epoch+1, avg_cost))

print('Learning finished')
Epoch: 1 Loss = 0.535026
Epoch: 2 Loss = 0.358744
Epoch: 3 Loss = 0.330988
Epoch: 4 Loss = 0.316194
Epoch: 5 Loss = 0.306888
Epoch: 6 Loss = 0.300198
Epoch: 7 Loss = 0.294928
Epoch: 8 Loss = 0.290794
Epoch: 9 Loss = 0.287432
Epoch: 10 Loss = 0.284395
Epoch: 11 Loss = 0.281804
Epoch: 12 Loss = 0.279809
Epoch: 13 Loss = 0.277766
Epoch: 14 Loss = 0.275743
Epoch: 15 Loss = 0.274424
Learning finished

 

▼ 학습이 완료된 모델을 이용해 정답률 확인

network.eval()
img_test = mnist_test.data.float()
label_test = mnist_test.targets

with torch.no_grad(): # test에서는 기울기 계산 제외
  prediction = network(img_test) # 전체 test data를 한번에 계산

  correct_prediction = torch.argmax(prediction, 1) == label_test # 예측 값이 가장 높은 숫자(0~9)와 정답 데이터가 일치한지 확인
  accuracy = correct_prediction.float().mean()
  print('Accuracy:', accuracy.item())
Accuracy: 0.8894000053405762

 

▼ 예측 결과 확인

first_data = mnist_test.data[0] # Test dataset 중 첫 번째 Image에 대해 예측 값 확인

with torch.no_grad():
  prediction = network(first_data.float())

prediction_num = torch.argmax(prediction, 1)

print(prediction)
print(prediction_num)
plt.imshow(first_data, cmap="gray")
plt.show
tensor([[ 215.8501, -2486.6294, 311.1895, 1416.2732, -800.1486, -419.4375, -2076.6809, 2521.7944, 381.8009, 792.3948]])
tensor([7])
<function matplotlib.pyplot.show(close=None, block=None)>

 

 

 

 

2. Multi Layer Perceptron (MLP) 실습

목표 : MNIST 손글씨 데이터를 분류하는 multi layer(단층) perceptron 모델 학습

입력 : 손글씨 이미지 (28x28x1)

출력 : 0~9까지 숫자들의 정답 확률

 

▼ 패키지 선언 (SLP 와 동일)

import torch
import torch.nn as nn
import torchvision.datasets as dataset
import torchvision.transforms as transform
from torch.utils.data import DataLoader

 

▼ Dataset 다운로드 (SLP 와 동일)

# Training dataset 다운로드
mnist_train = dataset.MNIST(root = "./",
                            train = True,
                            transform = transform.ToTensor(),
                            download = True)
# Testing dataset 다운로드
mnist_test = dataset.MNIST(root = "./",
                            train = False,
                            transform = transform.ToTensor(),
                            download = True)

 

▼ Multi Layer Perceptron 모델 정의 (2-layer)

class MLP(nn.Module): # 2-layer

  def __init__(self):
    super(MLP, self).__init__()
    self.fc1 = nn.Linear(in_features=784, out_features=100)
    self.fc2 = nn.Linear(in_features=100, out_features=10)
    self.sigmoid = nn.Sigmoid()

  def forward(self, x):
    x = x.view(-1, 28*28)
    y = self.sigmoid(self.fc1(x))
    y = self.fc2(y)
    return y

fc1의 출력 노드와 fc2의 입력 노드가 반드시 동일해야 한다.

    self.fc1 = nn.Linear(in_features=784, out_features=100)
    self.fc2 = nn.Linear(in_features=100, out_features=10)

 

▼ Hyper-parameters 지정 (SLP 와 동일_network만 MLP()로 바꾸면 됨)

batch_size = 100 # 60,000개에 대해서 600번의 weight update
learning_rate = 0.1
training_epochs = 15 # 15번 반복
loss_function = nn.CrossEntropyLoss()
network = MLP()
optimizer = torch.optim.SGD(network.parameters(), lr = learning_rate)

data_loader = DataLoader(dataset=mnist_train,
                         batch_size=batch_size,
                         shuffle=True,
                         drop_last=True)

✓ Batch size : 100 (한번에 학습할 데이터의 개수)
✓ Learning rate : 0.1 (가중치를 얼마나 변경시킬지 정하는 상수)
✓ Epoch : 15 (1 Epoch: 전체 데이터셋에 대해 1회 학습)
✓ Loss function : Cross entropy error (학습 모델이 얼마나 잘못 예측하고 있는지는 표현하는 지표)

    ※ 참고 : torch.nn.CrossEntropyLoss()함수

        1. 예측 값들에 대해서 자동으로 softmax 적용

        2. 정답 값과 예측 값을 이용해서 cross entropy loss 측정

✓ Optimizer: SGD (Loss function을 최소로 만들기 위한 가중치, 편향을 찾는 알고리즘)

 

✓ Batch 단위의 학습을 위해서 data_loader 함수 사용

 

▼ Perceptron 학습을 위한 반복문 선언 (SLP 와 동일)

network.train()

for epoch in range(training_epochs): # 전체 데이터에 대한 반복 : epoch
  avg_cost = 0
  total_batch = len(data_loader)

  for img, label in data_loader: # 1 epoch 내의 1 batch에 대한 반복 : iteration 
    pred = network(img) → 1. 입력 이미지에 대해서 forward pass

    loss = loss_function(pred, label) → 2. 예측 값, 정답 값을 이용해 loss 계산
    optimizer.zero_grad() # gradient 초기화
    loss.backward() → 3. 모든 weight에 대해 편미분 값 계산
    optimizer.step() → 4. 파라미터 업데이트

    avg_cost += loss / total_batch # 모든 batch에 대한 평균 loss값 계산

  print('Epoch: %d Loss = %f'%(epoch+1, avg_cost))

print('Learning finished')

 

Epoch: 1 Loss = 1.154235
Epoch: 2 Loss = 0.450059
Epoch: 3 Loss = 0.360999
Epoch: 4 Loss = 0.324635
Epoch: 5 Loss = 0.302197
Epoch: 6 Loss = 0.285472
Epoch: 7 Loss = 0.271260
Epoch: 8 Loss = 0.258964
Epoch: 9 Loss = 0.247979
Epoch: 10 Loss = 0.237658
Epoch: 11 Loss = 0.228358
Epoch: 12 Loss = 0.219735
Epoch: 13 Loss = 0.211678
Epoch: 14 Loss = 0.204083
Epoch: 15 Loss = 0.196845
Learning finished

 

▼ 학습이 완료된 모델을 이용해 정답률 확인 (SLP 와 동일)

network.eval()
img_test = mnist_test.data.float()
label_test = mnist_test.targets

with torch.no_grad(): # test에서는 기울기 계산 제외
  prediction = network(img_test) # 전체 test data를 한번에 계산

  correct_prediction = torch.argmax(prediction, 1) == label_test # 예측 값이 가장 높은 숫자(0~9)와 정답 데이터가 일치한지 확인
  accuracy = correct_prediction.float().mean()
  print('Accuracy:', accuracy.item())
Accuracy: 0.9406999945640564

 

▼ 예측 결과 확인 (SLP 와 동일)

first_data = mnist_test.data[0] # Test dataset 중 첫 번째 Image에 대해 예측 값 확인

with torch.no_grad():
  prediction = network(first_data.float())

prediction_num = torch.argmax(prediction, 1)

print(prediction)
print(prediction_num)
plt.imshow(first_data, cmap="gray")
plt.show
tensor([[ 215.8501, -2486.6294, 311.1895, 1416.2732, -800.1486, -419.4375, -2076.6809, 2521.7944, 381.8009, 792.3948]])
tensor([7])
<function matplotlib.pyplot.show(close=None, block=None)>