7. 파이토치(PyTorch) 튜토리얼 - 최적화(Optimization)

Yeonghyeon·2022년 7월 30일
0
post-custom-banner

본 포스팅은 파이토치(PYTORCH) 한국어 튜토리얼을 참고하여 공부하고 정리한 글임을 밝힙니다.


모델 매개변수 최적화하기

  • 데이터에 매게변수를 최적화하여 모델 학습/검증/테스트
  • 각 epoch마다 모델은 출력을 예측하고, 예측과 정답 사이의 오류(손실;loss)를 계산
  • 매개변수에 대한 오류의 도함수를 구해 경사하강법을 사용하여 파라미터들을 최적화(optimize)

기본(Pre-requisite) 코드

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

하이퍼파라미터(Hyperparameter)

  • 서로 다른 하이퍼파라미터 값은 모델 학습과 수렴율(convergence rate)에 영향을 미칠 수 있음
  • 학습 시에 정의할 하이퍼파라미터
    • epoch 수: 데이터셋을 반복하는 횟수

    • batch size: 매개변수가 갱신되기 전 신경망을 통해 전파된 데이터 샘플의 수

    • learning rate: 각 배치/에폭에서 모델의 매개변수를 조절하는 비율

      • 값이 작을수록 학습 속도가 느려지고, 값이 크면 학습 중 예측할 수 없는 동작 발생 가능
learning_rate = 1e-3
batch_size = 64
epochs = 5

최적화 단계(Opimization Loop)

  • 최적화 단계의 각 반복을 epoch이라 함
    • 학습 단계(train_loop): 학습용 데이터셋을 반복하고 최적의 매개변수로 수렴
    • 검증/테스트 단계(validation/test loop): 모델 성능이 개선되고 있는지 확인하기 위해 테스트 데이터셋을 반복
  • 학습 단계에서 일어나는 몇 가지 개념에 대해 살펴보자

손실 함수(loss function)

  • 손실 함수: 획득한 결과와 실제 값 사이의 틀린 정도를 측정하여, 학습 중에 이 값을 최소화
  • 주어진 데이터 샘플을 입력으로 계산한 예측과 정답을 비교하여 손실을 계산
  • 회귀 문제에서 사용하는 손실 함수: nn.MSELoss(평균 제곱 오차(MSE; Mean Square Error))
  • 분류 문제에서 사용하는 손실 함수: nn.NLLLoss(음의 로그 우도(Negative Log Likelihood))
  • nn.LogSoftmaxnn.NLLLoss를 합친 nn.CrossEntroyLoss

모델의 출력 logit을 nn.CrossEntroyLoss에 전달하여 logit을 정규화하고 예측 오류를 계산

# 손실 함수 초기화
loss_fn = nn.CrossEntropyLoss()

옵티마이저(Optimizer)

  • 각 학습 단계에서 모델의 오류를 줄이기 위해 모델 매개변수에 조정하는 과정
  • 최적화 알고리즘은 이 과정이 수행되는 방식을 정의 (예제에서는 확률적 경사하강법(SGD; Stochastic Gradient Descent))
  • SGD, ADAM, RMSProp 등 다양한 옵티마이저

학습하려는 모델의 매개변수와 학습률(learning rate) 하이퍼파라매터를 등록하여 옵티마이저를 초기화

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

학습 단계에서서의 최적화 세 단계

  1. optimizer.zero_grad()를 호출하여 모델 매개변수의 변화도를 재설정 ➡️ 기본적으로 gradient는 더해지기 때문에 중복 계산 막기 위해 반복할 때마다 명시적으로 0으로 설정
  2. loss.backwards()를 호출하여 예측 손실을 역전파 (각 매개변수에 대한 손실의 변화도를 저장)
  3. 변화도 계산한 뒤에는 optimizer.step()을 호출하여 역전파 단계에서 수집한 변화도로 매개변수 조정

전체 구현

  • 최적화 코드를 반복 수행하는 train_loop, 테스트 데이터로 모델의 성능 측정하는 test_loop
def train_loop(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    for batch, (X, y) in enumerate(dataloader):
        # 예측과 손실 계산
        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")
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!")
post-custom-banner

0개의 댓글