본문 바로가기

[Pytorch]- MNIST 데이터셋으로 MLP구현하기(심화편) 본문

AI/Pytorch

[Pytorch]- MNIST 데이터셋으로 MLP구현하기(심화편)

점핑노루 2021. 7. 26. 13:48

이번 글은 저번의 MNIST 데이터셋을 그대로 활용하지만, 더욱 다양한 응용을 할 것이다.

 

그전에, 간단한 MLP를 구현하는 법을 확인하고 싶으면

https://noru-jumping-in-the-mountains.tistory.com/10?category=1218749 

 

[Pytorch] MNIST 데이터셋으로 간단한 MLP구현하기

이번 글에서는 파이토치를 활용하여 MNIST dataset을 불러들인 다음, 간단한 MLP(Multi Layer Perceptron)를 생성해보도록 할 것이다. 먼저 필요한 패키지들을 불러들이고 시드 설정을 한다. import torch import.

noru-jumping-in-the-mountains.tistory.com

을 먼저 읽어 보고 오길 바란다. 

 

 

먼저 필요한 패키지들을 불러오고 시드를 설정한다.

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

device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 시드설정
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)

저번처럼 parameter도 똑같이 설정한다. 다만 learning rate을 초기에 설정하였고, dropout probability라는 것을 설정하였다. Dropout에 대한 설명은 아래에 유투브 링크를 걸어놓았으니 확인바란다.

# parameters
learning_rate = 0.001 #learning rate를 parameter에 먼저 선언하였다.
training_epochs = 15
batch_size = 100
drop_prob = 0.3 #dropout 확률 추가

 

MNIST 데이터셋을 training set, test set으로 각각 가져오고 이를 불러들인다.

# 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)
                         
# dataset loader
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

이제는 여러 개의 layer을 생성한다. linear1은 input layer인데, 784개의 input을 받아서 512개의 output을 돌려준다.

linear2의 input은 linear1의 output이 되어야 하므로 input값은 512여야만 한다. 그런 식으로 4개의 layer을 만든다. 마지막 4번째 layer은 output layer이고, 출력 가능한 숫자가 0부터 9까지 있으므로 총 10개의 output을 돌려준다.

또한 activation function 중 하나인 ReLU함수를 사용하였고, dropout은 0.3으로 설정하였다.

linear1 = torch.nn.Linear(784, 512, bias=True)
linear2 = torch.nn.Linear(512, 512, bias=True)
linear3 = torch.nn.Linear(512, 512, bias=True)
linear4 = torch.nn.Linear(512, 10, bias = True)

relu = torch.nn.ReLU() #activation function으로 ReLU 설정
dropout = torch.nn.Dropout(p=drop_prob) #dropout 설정

이 글은 위의 개념을 다 인지하고 있다는 가정 하에 진행하므로, activation function 및 dropout에 대한 사전지식이 부족하다면 아래 영상을 참고할 것을 추천한다.

 

ReLU 보충강의: [PyTorch] Lab-09-1 ReLU - YouTube

Dropout 보충강의: [PyTorch] Lab-09-3 Dropout - YouTube

다음으로 weights를 초기화 해야한다. Weights를 초기화하는 방법은 다양하지만, 여기서는 Xavier Uniform Initialization을 진행할 것이다.

#Xavier uniform initialization 하는 법
torch.nn.init.xavier_uniform_(linear1.weight)
torch.nn.init.xavier_uniform_(linear2.weight)
torch.nn.init.xavier_uniform_(linear3.weight)
torch.nn.init.xavier_uniform_(linear4.weight)


# Normal Initialization
"""
torch.nn.init.normal_(linear1.weight)
torch.nn.init.normal_(linear2.weight)
torch.nn.init.normal_(linear3.weight)
torch.nn.init.normal_(linear4.weight)
"""

추가적으로 normal initialization을 하는 법도 써놓았다. Normal Initialization이란 평균 0, 표준편차 1의 분포를 따르는 임의의 난수를 생성하여 가중치로 지정하는 초기화 방법이다. Weight Initialization 보충 강의는 아래에 영상첨부를 하였다. 

 

Weight Initializtion 보충강의: [PyTorch] Lab-09-2 Weight initialization - YouTube

드디어 본격적으로 모델을 생성할 것이다. 앞에서는 linear모델 하나로 MLP를 구현하였기 때문에 모델 생성 단계가 없었다. 그러나 우리는 이번 모델에 4개의 층이 있고, output layer을 제외한 모든 layer에 ReLU 및 dropout을 진행하고 싶다. 러기 위해서는 torch.nn.Sequential을 활용해 하나의 model을 생성한다. 그 코드는 아래와 같다.

#model 생성
model = torch.nn.Sequential(linear1, relu, dropout,
                          linear2, relu, dropout,
                          linear3, relu, dropout,
                           linear4)

Cost & Loss & Optimizer 설정도 잊지 말자.

# define cost/loss & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)    # Softmax is internally computed.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) #gradient descent할 때 adam 활용

여기까지 완료하였으면 training set에 데이터를 학습시켜보자. Training set에는 dropout이 들어가므로 dropout을 활성화시키는 코드를 넣어야 한다. 그러기 위해서 model.train()을 사용하면 된다.

total_batch = len(data_loader)
model.train()    # set the model to train mode (dropout=True)
for epoch in range(training_epochs):
    avg_cost = 0

    for X, Y in data_loader:
        X = X.view(-1, 28 * 28).to(device)
        Y = Y.to(device)

        optimizer.zero_grad()
        hypothesis = model(X)
        cost = criterion(hypothesis, Y)
        cost.backward()
        optimizer.step()

        avg_cost += cost / total_batch

    print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))

print('Learning finished')

코드 구현 결과 필자는 아래와 같은 값을 얻었다. Cost가 감소하는 것으로 보아 모델이 잘 학습되고 있음을 확인할 수 있다.

 

Epoch: 0001 cost = 0.280489981

Epoch: 0002 cost = 0.127762243

Epoch: 0003 cost = 0.097461879

Epoch: 0004 cost = 0.083512314

Epoch: 0005 cost = 0.071569972

Epoch: 0006 cost = 0.065550774

Epoch: 0007 cost = 0.056336664

Epoch: 0008 cost = 0.052665610

Epoch: 0009 cost = 0.046140146

Epoch: 0010 cost = 0.047833875

Epoch: 0011 cost = 0.040519468

Epoch: 0012 cost = 0.041156765

Epoch: 0013 cost = 0.039497864

Epoch: 0014 cost = 0.037736870

Epoch: 0015 cost = 0.034322739

Learning finished

 

이제 실제 test set에 우리의 모델을 적용시켜 보자. Test set에는 dropout을 하면 안되기에 model.eval()을 통하여 dropout의 영향을 제거한다. 또한 임의의 자료를 불러들여 예측한 숫자 값이랑 실제 숫자값이 일치하는지의 여부도 확인할 수 있다.

# Test model and check accuracy
with torch.no_grad():
    model.eval()    # set the model to evaluation mode (dropout=False)

    # Test the model using test sets
    X_test = mnist_test.test_data.view(-1, 28 * 28).float().to(device)
    Y_test = mnist_test.test_labels.to(device)

    prediction = model(X_test)
    correct_prediction = torch.argmax(prediction, 1) == Y_test
    accuracy = correct_prediction.float().mean()
    print('Accuracy:', accuracy.item())
    
    # 임의의 자료 가져와 일치여부 확인
    r = random.randint(0, len(mnist_test) - 1)
    X_single_data = mnist_test.test_data[r:r + 1].view(-1, 28 * 28).float().to(device)
    Y_single_data = mnist_test.test_labels[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())

Accuracy: 0.9810000061988831

Label: 9

Prediction: 9

 

98%의 정확도를 얻은 것으로 보아 간단한 MLP를 구현했을 때보다 10% 정도 높은 정확도를 얻을 수 있었다. 

 

Batch Normalization에 관한 것도 이 글에 써보려 했으나, 영상으로 대체하고자 한다.

 

Batch Normalization 보충강의: [PyTorch] Lab-09-4 Batch Normalization - YouTube

 

Sung Kim 교수님께서 주도하시는 모두를 위한 딥러닝이 참 자료 정리를 잘해놓았다. 위 자료들 뿐만 아니라 추가적으로 궁금한 것이 있으면 들어가서 해당 유투브 강의를 보는 것을 강력 추천한다. 

 

출처: GitHub - deeplearningzerotoall/PyTorch: Deep Learning Zero to All - Pytorch

 

GitHub - deeplearningzerotoall/PyTorch: Deep Learning Zero to All - Pytorch

Deep Learning Zero to All - Pytorch. Contribute to deeplearningzerotoall/PyTorch development by creating an account on GitHub.

github.com

 

Comments