관리 메뉴

TEAM EDA

[파이토치로 시작하는 딥러닝 기초] 2.5 Dropout 본문

EDA Study/PyTorch

[파이토치로 시작하는 딥러닝 기초] 2.5 Dropout

김현우 2020. 3. 20. 22:54

이번 글에서는 Overfitting과 Dropout에 대해서 배워보도록 하겠습니다. 이번 글은 EDWITH에서 진행하는 파이토치로 시작하는 딥러닝 기초를 토대로 하였고 같이 스터디하는 팀원분들의 자료를 바탕으로 작성하였습니다. 

목차 

  • Overfitting 
  • Regularization 
  • Dropout
  • Code : mnist_nn_dropout

1. Overfitting 

  • 과도하게 현재 데이터에 대해 모델을 learning을 한 경우. 즉, Training data에 대해 acc는 높지만 Test data에 대해 acc는 낮은 현상 
  • 해결 
    1. training data를 늘린다. 
    2. features의 수를 줄인다. (차원의 저주를 피하기 위함)
    3. Regularization 
    4. Dropout 

출처 : https://sigmoidal.io/machine-learning-terminology-explained-top-8-must-know-concepts/

2. Regularization 

  • 데이터에 모델이 너무 오버피팅되어서, 이후 새로운 데이터에 일반적으로 들어맞도록 하는 방법 
  • 기존 Cost function 뒤에 Regularization Term을 추가해줌으로써 파라미터의 영향을 덜 받게 함 
  • 방법으로는 L1, L2 Regularization이 있다. 

L1 Regularization (Lasso)

  • Feature selection : 파라미터의 값을 0으로 보내기에 변수 제거의 효과가 있음 
  • 영향을 크게 미치는 핵심적인 피처들만 반영

L2 Regularization (Ridge)

  • 전체적으로 파라미터의 값이 작아지도록 함 

출처 : https://dailyheumsi.tistory.com/57

3. Dropout 

  • 일부 파라미터를 학습에 반영하지 않음으로써 모델을 일반화하는 방법 
  • 주의 : Train시에는 Dropout을 적용해야 하지만 Validation, Test에는 적용하면 안됨 

4. Code : mnist_nn_dropout

dropout = torch.nn.Dropout(p=drop_prob)
# Lab 10 MNIST and softmax
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import random

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

# for reproducibility
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)
    
# parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
drop_prob = 0.3

# 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
# drop_last=True : 불완전한 마지막 셔플을 학습에 참여하지 않게 하는 것 
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

# nn layers
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, 512, bias=True)
linear5 = torch.nn.Linear(512, 10, bias=True)
relu = torch.nn.ReLU()
dropout = torch.nn.Dropout(p=drop_prob)

# xavier 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)
torch.nn.init.xavier_uniform_(linear5.weight)

# model
model = torch.nn.Sequential(linear1, relu, dropout,
                            linear2, relu, dropout,
                            linear3, relu, dropout,
                            linear4, relu, dropout,
                            linear5).to(device)
                            
# define cost/loss & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)    # Softmax is internally computed.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

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:
        # reshape input image into [batch_size by 784]
        # label is not one-hot encoded
        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')

# 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())

    # Get one and predict
    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())