[Pytorch]- MNIST 데이터셋으로 MLP구현하기(심화편) 본문
이번 글은 저번의 MNIST 데이터셋을 그대로 활용하지만, 더욱 다양한 응용을 할 것이다.
그전에, 간단한 MLP를 구현하는 법을 확인하고 싶으면
https://noru-jumping-in-the-mountains.tistory.com/10?category=1218749
을 먼저 읽어 보고 오길 바란다.
먼저 필요한 패키지들을 불러오고 시드를 설정한다.
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
'AI > Pytorch' 카테고리의 다른 글
[Pytorch] MNIST 데이터셋으로 간단한 CNN 구현하기 (0) | 2021.07.27 |
---|---|
[Pytorch] MNIST 데이터셋으로 간단한 MLP구현하기 (0) | 2021.07.26 |
[Pytorch] 간단한 Linear Regression 모형 만들기 (0) | 2021.07.24 |