본문 바로가기
AI

[파이토치]최적화

by Reodreamer 2022. 10. 6.
반응형

이번 포스트에선 모델의 파라미터들을 최적화하는법에 대해 알아보고자 한다. 


 모델을 학습하는 과정은 주어진 epoch 수만큼 반복을 하며 출력값을 추정하고 loss 값을 계산한다. 그리고 경사하강법을 통해 모델이 최적의 성능을 내도록 파라미터를 최적화한다.

 

1. 신경망 구성하기 

파라미터를 최적화할 기초적인 수준의 신경망을 만든다.

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)

test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28*28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10),
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork()

 

2. 하이퍼 파라미터

하이퍼 파라미터는 직접 조절 가능한 파라미터를 의미한다. 하이퍼 파라미터의 값에 따라 모델 학습결과가 달라진다.  

모델 학습 시 기본적으로 설정하는 하이퍼 파라미터는 다음과 같다.

 

  • epoch(에폭) 수 : 데이터 셋을 반복하는 횟수
  • batch size(배치 크기) : 파라미터를 업데이트하기 전에 신경망에 전달되는 데이터 샘플수 
  • learning rate (학습률) : 파라미터를 조절하는 힘, 값이 작으면 학습 속도가 느려지고, 값이 크면 학습이 제대로 안될 수 있다. 

 

3. 최적화

하이퍼 파라미터를 설정하고 나서, 최적화 loop을 통해 모델을 학습하고 최적화할 수 있다. 여기서 최적화 loop의 각각의 반복을 epoch라고 한다. 각각의 epoch은 두 단계로 구성된다. 

  • 학습 단계 : 학습 셋을 반복하면서 최적의 파라미터로 수렴하게끔 하는 단계
  • 검증/테스트 단계 : 테스트 셋을 반복하면서 모델의 성능이 개선되는지 아닌지 확인하는 단계

 

4. 손실 함수

학습이 충분히 되지 않은 신경망은 잘못된 답을 반환할 가능성이 높다. 손실 함수는 출력값과 정답 간의 차이를 계산하는데, 우리는 학습 단계에서 이 차이를 최소로 하는 파라미터의 값을 찾는 것이 목표다. 

손실 함수의 종류는 다양하다. 회귀 문제에서는 nn.MSELoss를 사용하고 분류 문제는 주로 nn.NLLLoss나 nn,CrossEntropyLoss를 사용한다. 손실 함수는 주어진 문제의 종류에 따라 달라지는 것을 기억하자.

 

5. 옵티마이저 

옵티마이저는 최적화 단계에서, 사용하는 최적화 방식을 의미한다. 최적화와 관련된 모든 과정은 optimizer 객체에 저장하여 사용한다. 

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

학습 단계는 3 단계로 구성된다. 이 단계를 이해하지 않고 코딩을 하게 되면, 많이 혼란스러울 가능성이 있으니 꼭 이 부분은 이해를 하고 넘어가는 것을 추천한다. 

 

  • 기울기 초기화 :
    파라미터를 초기화하는 단계라고 생각하면 된다. 기울기는 계속해서 더해지기 때문에 새로운 에폭마다, optimizer.zero_grad()를 이용하여  이전 에폭의 영향을 받지 않도록 기울기를 0으로 초기화하는 단계이다. 
  • 역전파 :
    loss.backward() 를 이용하여 출력단의 prediction loss를 입력 방향으로 역전파 한다. 
  • 파라미터 조정 :
    optimizer.step()을 이용하여 역전파 단계에서 수집한 기울기로 파라미터를 조정한다.  

 

6. 전체구현

학습 단계(train_loop)와 테스트 단계(test_loop)를 각각 구현한다. 

def train_loop(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    for batch, (X, y) in enumerate(dataloader):
        # 예측(prediction)과 손실(loss) 계산
        pred = model(X)
        loss = loss_fn(pred, y)

        # 역전파
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")


def test_loop(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    test_loss, correct = 0, 0

    with torch.no_grad():
        for X, y in dataloader:
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()

    test_loss /= num_batches
    correct /= size
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

손실함수와 옵티마이저를 초기화하고 train_loop과 test_loop에 적용한다.

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

epochs = 10
for t in range(epochs):
    print(f"Epoch {t+1}\n-------------------------------")
    train_loop(train_dataloader, model, loss_fn, optimizer)
    test_loop(test_dataloader, model, loss_fn)
print("Done!")

이번 포스트에선 파라미터 최적화에 무게를 두고 신경망을 학습시키는 방법에 대해 알아봤다. 이는 매우 핵심적인 내용이기 때문에 꼭 잘 이해하고, 헷갈리면 여러 번 보면서 신경망 학습의 순서별 목적과 기능을 기억하면 좋을 것 같다. 

반응형

댓글