[PyTorch] Lab07.1 - Tips

Yun Geonil·2021년 2월 20일
0

📌 학습 목표


  • Maximum Likelihood Estimation(MLE)
  • Overfitting
  • Training and Test Dataset
  • Learning Rate
  • Data Preprocessing

Maximum Likelihood Estimation(MLE)

  • MLE는 '최대 우도 추정'이라고도 한다.

    압정을 던졌을 때 앞, 뒤 중 어디로 떨어질 것인지 예측한다고 해보자.

    주어진 관측값은 n번 시행했을 때, k번 앞으로 떨어졌다고 한다.

    압정던지기는 베르누이 분포를 따르므로 다음과 같이 표현할 수 있다.

    KB(n,θ)K \sim B(n,\theta)

    P(K=k)=(nk)θk(1θ)nkP(K=k) = {n \choose k}\theta^k(1-\theta)^{n-k}

    여기서 (nk){n \choose k}조합(combination)기호로 n개 원소중 k개를 순서와 상관없이 조합할 수 있는 경우의 수를 뜻한다. 즉, (nk){n \choose k}n!n!(nk)!\frac{n!}{n!(n-k)!}으로 표현할 수 있다.

    P(K=k)=n!n!(nk)!θk(1θ)nkP(K=k) = \frac{n!}{n!(n-k)!}\theta^k(1-\theta)^{n-k} 로 나타내고, 관측 값을 대입하면 θ\theta에 대한 함수 f(θ)f(\theta)를 만들 수 있다. 여기서 MLE란, f(θ)f(\theta)의 값이 최대가 되는 θ\theta를 찾는 것이다.

  • 어떻게 최적의 θ\theta를 찾을 수 있을까.

    바로 f(θ)f(\theta)함수의 기울기를 이용하는 것이다.

    기울기를 이용해 최대를 구하는 과정을 gradient ascent 라고 하며 최소를 찾는 과정은 gradient descent이다.

    그럼 descent를 기준으로는 최적의 θ\theta는 어떻게 갱신될까.

    θθαθL(x;θ)\theta \leftarrow \theta - \alpha\nabla_\theta{L(x;\theta)}

    위와 같은 식을 통해 최적은 θ\theta값을 찾아가게 된다.

    α\alpha는 이후 설명하겠지만 learning rate이고, 이 learning rate에 f(θ)f(\theta)θ\theta에 대한 미분을 한 값을 곱한 후 기존 θ\theta에서 빼어준다.

Overfitting

  • Overfitting이란 주어진 데이터에 대해서만 과도하게 fitting된 상황이다.

    MLE를 이용하여 주어진 데이터를 가장 잘 설명하는 모델을 찾다보면 overfitting을 만나게 된다.

  • 그렇다면 어떻게 overfitting을 확인하고 피할 수 있을까.

    어떠한 모델을 훈련 시킬 때 우리는 데이터를 Train dataTest data로 나눈다. Train data는 모델을 훈련시킬 때만 사용을 하고, Test data로 훈련이 된 모델을 평가한다.

    하지만, 모델이 Train data에 overfitting된다면 Test data에는 모델이 제 성능을 낼 수 없다. Test data는 말 그래로 평가 하는데에만 사용해야한다. Test data를 training(학습)에 사용할 수 없다. 따라서, Validation data라는 개념이 사용된다.

    전체 dataset을 train, validation, test로 나누어 사용한다. 이때, train data는 학습하는데 사용되고, validation data는 모델의 검증에 사용, test data는 최종 모델을 평가하는데 사용한다.

뿐만아니라 더 많은 데이터, features를 줄이거나, Regularization을 사용하여 overfitting을 막을 수 있다.

  • Regularizaion은 다음과 같은 것들이 존재한다.

    1. Early stopping
    2. Reducing Network size
    3. Weight Decay
    4. Dropout
    5. Batch Normalization
  • 이러한 기법들을 적용하여 DNN을 훈련시키는 과정은 다음과 같다.

    1. 신경망의 구조를 설계한다.

    2. 모델을 훈련하고 overfitting을 확인한다.

      a. overfitting이 아니라면 모델 사이즈를 증가시킨다.(deeper and wider)

      b. overfitting이라면 Regularization을 적용한다.(Dropout, Batch Norm 등)

    3. 2를 반복한다.

Training and Test Dataset

Training set과 Test set을 나누는 실습을 한다.

  • Imports
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

torch.manual_seed(1)
  • Dataset

    아래와 같이 train, test set으로 분리한다.

x_train = torch.FloatTensor([[1, 2, 1],
                            [1, 3, 2],
                            [1, 3, 4],
                            [1, 5, 5],
                            [1, 7, 5],
                            [1, 2, 5],
                            [1, 6, 6],
                            [1, 7, 7]])
y_train = torch.LongTensor([2, 2, 2, 1, 1, 1, 0, 0])

x_test = torch.FloatTensor([[2, 1, 1], [3, 1, 2], [3, 3, 4]])
y_test = torch.LongTensor([2, 2, 2])
  • Moduel

    softmax분류기를 이용한다. nn.Module 을 상속해 사용한다.

class SoftmaxClassifierModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(3, 3)
    def forward(self, x):
        return self.linear(x)

model = SoftmaxClassifierModel()

optimizer = optim.SGD(model.parameters(), lr=0.1)
  • Training
def train(model, optimizer, x_train, y_train):
    nb_epochs = 20
    for epoch in range(nb_epochs):
        prediction = model(x_train)
        cost = F.cross_entropy(prediction, y_train)
        
        optimizer.zero_grad()
        cost.backward()
        optimizer.step()
        
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

train(model, optimizer, x_train, y_train)
'''
Epoch    0/20 Cost: 2.203667
Epoch    1/20 Cost: 1.199645
Epoch    2/20 Cost: 1.142985
Epoch    3/20 Cost: 1.117769
Epoch    4/20 Cost: 1.100901
Epoch    5/20 Cost: 1.089523
Epoch    6/20 Cost: 1.079872
Epoch    7/20 Cost: 1.071320
Epoch    8/20 Cost: 1.063325
Epoch    9/20 Cost: 1.055720
Epoch   10/20 Cost: 1.048378
Epoch   11/20 Cost: 1.041245
Epoch   12/20 Cost: 1.034285
Epoch   13/20 Cost: 1.027478
Epoch   14/20 Cost: 1.020813
Epoch   15/20 Cost: 1.014279
Epoch   16/20 Cost: 1.007872
Epoch   17/20 Cost: 1.001586
Epoch   18/20 Cost: 0.995419
Epoch   19/20 Cost: 0.989365
'''
  • Test

    아래 정확도는 0%로 overfitting 된 상황이라는 것을 짐작해볼 수 있다.

def test(model, x_test, y_test):
    prediction = model(x_test)
    predicted_classes = prediction.max(1)[1]
    correct_count = (predicted_classes == y_test).sum().item()
    cost = F.cross_entropy(prediction, y_test)
    
    print('Accuracy: {}% Cost: {:.6f}'.format(
        correct_count / len(y_test) * 100, cost.item()
    ))

test(model, x_test, y_test)
'''
Accuracy: 0.0% Cost: 1.425844
'''

Learning Rate

  • MLE는 Gradient Descent(혹은 Ascent)로 수행한다.

    Gradient Descent를 기준으로 아래식을 통해 수행하고

    θθαθL(x;θ)**\theta \leftarrow \theta - \alpha\nabla_\theta{L(x;\theta)}**

    위 최적화 과정을 통해 주어진 데이터 xx를 가장 잘 설명하는 θ\theta를 찾아간다.

    이때, α\alpha를 우리는 learning rate라고 부른다. learning rate는 최적화를 위해 이동하는 거리의 크기라고 생각하면 쉽다. 또한, learning rate는 인간이 직접 설정해주어야 하는 Hyper Parameter이다.

  • learning rate가 클 경우 발산할 수 있다.

model = SoftmaxClassifierModel()
optimizer = optim.SGD(model.parameters(), lr=1e5)
train(model, optimizer, x_train, y_train)
'''
Epoch    0/20 Cost: 3.187324
Epoch    1/20 Cost: 1100707.375000
Epoch    2/20 Cost: 2482261.000000
...
Epoch   17/20 Cost: 1265073.750000
Epoch   18/20 Cost: 1686645.000000
Epoch   19/20 Cost: 484999.625000
'''
  • 반대로 learning rate가 너무 작으면 학습이 거의 진행되지 않는다.
model = SoftmaxClassifierModel()
optimizer = optim.SGD(model.parameters(), lr=1e-10)
train(model, optimizer, x_train, y_train)
'''
Epoch    0/20 Cost: 1.341574
Epoch    1/20 Cost: 1.341574
Epoch    2/20 Cost: 1.341574
...
Epoch   17/20 Cost: 1.341574
Epoch   18/20 Cost: 1.341574
Epoch   19/20 Cost: 1.341574
'''
  • learning rate는 적절한 값을 선택해서 조정해야한다.
model = SoftmaxClassifierModel()
optimizer = optim.SGD(model.parameters(), lr=1e-1)
train(model, optimizer, x_train, y_train)
'''
Epoch    0/20 Cost: 2.939317
Epoch    1/20 Cost: 1.887239
Epoch    2/20 Cost: 1.055398
...
Epoch   17/20 Cost: 0.855000
Epoch   18/20 Cost: 0.850961
Epoch   19/20 Cost: 0.847010
'''

처음 학습 시 적당한 learning rate를 선택하여 학습하고 cost값을 확인하며 발산한다면 learning rate를 감소시키고, 학습이 더디다면 learning rate를 증가시키는 등의 방법을 이용하여 learning rate를 설정하면 된다.

Data Preprocessing

Data Preprocessing(데이터 전처리)는 학습을 더 쉽게 해주기 위한 과정이다. 아래 데이터를 살펴보면 3개의 feature를 이용해 regression시키는 task이다.

x_train = torch.FloatTensor([[73, 80, 75],
                            [93, 88, 93],
                            [89, 91, 90],
                            [96, 98, 100],
                            [73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])

이때, 데이터 전처리를 해주면 학습이 더욱 수월해진다. 여기서는 Standardization을 이용해 preprocessing 시켜본다. Standardization은 아래 식과 같다.

xj=xjμjσjx'_j = \frac{x_j - \mu_j}{\sigma_j}

여기서 σ\sigma는 표준편차, μ\mu는 평균이다. 공식을 이용해 위 데이터를 Standardization 시키면 아래와 같다.

mu = x_train.mean(dim=0)
sigma = x_train.std(dim=0)
norm_x_train = (x_train-mu)/sigma
print(norm_x_train)
'''
tensor([[-1.0674, -0.3758, -0.8398],
        [ 0.7418,  0.2778,  0.5863],
        [ 0.3799,  0.5229,  0.3486],
        [ 1.0132,  1.0948,  1.1409],
        [-1.0674, -1.5197, -1.2360]])
'''

그렇다면 전처리된 데이터를 이용해 학습해보자. nn.Module을 상속받는 MultivariateLinearRegressionModel을 설계하여 사용한다.

class MultivariateLinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(3, 1)
    
    def forward(self, x):
        return self.linear(x)

model = MultivariateLinearRegressionModel()
optimizer = optim.SGD(model.parameters(), lr=1e-1)

학습을 담당하는 train 함수를 구현해 사용한다. 이때, regression task 이므로 cost function 으로 MSE 를 사용한다.

def train(model, optimizer, x_train, y_train):
    nb_epochs = 20
    for epoch in range(nb_epochs):
        prediction = model(x_train)
        cost = F.mse_loss(prediction, y_train)
        
        optimizer.zero_grad()
        cost.backward()
        optimizer.step()
        
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

train(model, optimizer, norm_x_train, y_train)
'''
Epoch    0/20 Cost: 29474.621094
Epoch    1/20 Cost: 18722.042969
Epoch    2/20 Cost: 11941.125000
Epoch    3/20 Cost: 7630.646973
...
Epoch   16/20 Cost: 23.729731
Epoch   17/20 Cost: 15.416880
Epoch   18/20 Cost: 10.089418
Epoch   19/20 Cost: 6.672885
'''

데이터 전처리는 이외에도 여러 방법이 있다. 각 데이터와 상황에 맞게 전처리 하는 것이 가장 중요하다.

0개의 댓글