PyTorch 최적화 기법: 옵티마이저 사용 가이드

옵티마이저概述

PyTorch의 torch.optim 모듈은 신경망 학습에 필요한 다양한 최적화 알고리즘을 제공합니다. 모든 옵티마이저는 기본 클래스 optim.Optimizer를 상속하며, 공통된 구조와 메서드를 갖습니다.

옵티마이저 인스턴스 생성

옵티마이저 객체는 다음 주요 속성을 포함합니다:

opt.parameters()      # 학습 가능한 파라미터 반복자
opt.defaults         # 기본 하이퍼파라미터 딕셔너리
opt.param_groups     # 파라미터 그룹 목록 (리스트 형태)

흔히 사용되는 최적화 알고리즘으로는 SGD, Adam, RMSProp 등이 있으며, 각각의 특성과 수렴 특성이 다릅니다.

옵티마이저 기본 사용법

모델 학습 시 옵티마이저의 전형적인 사용 흐름은 다음과 같습니다:

import torch
import torch.nn as nn
from torch import optim

# 모델 정의
model = nn.Sequential(
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 10)
)

# 옵티마이저 생성: model 파라미터와 학습률 지정
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 학습 루프
for inputs, targets in data_loader:
    # 기울기 초기화
    optimizer.zero_grad()
    
    # 순전파 계산
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    
    # 역전파 수행
    loss.backward()
    
    # 파라미터 업데이트
    optimizer.step()

주요 옵티마이저 비교 분석

각 최적화 알고리즘의 수렴 특성을 비교하기 위해 실제 학습 결과를 시각화해 봅니다.

import torch
import torch.utils.data as Data
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt

# 하이퍼파라미터 설정
learning_rate = 0.02
batch_size = 40
epochs = 15

# 데이터 생성: 2차원 입력, 1차원 출력
input_data = torch.unsqueeze(torch.linspace(-2, 2, 800), dim=1)
target_data = input_data.pow(3) + 0.15 * torch.randn(input_data.size())

dataset = Data.TensorDataset(input_data, target_data)
data_loader = Data.DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True)

# 간단한 피드포워드 네트워크
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.hidden_layer = nn.Linear(1, 32)
        self.output_layer = nn.Linear(32, 1)
    
    def forward(self, x):
        x = F.tanh(self.hidden_layer(x))
        return self.output_layer(x)

# 다양한 옵티마이저로 학습할 모델 초기화
model_sgd = SimpleModel()
model_nesterov = SimpleModel()
model_rmsprop = SimpleModel()
model_adam = SimpleModel()

models = [model_sgd, model_nesterov, model_rmsprop, model_adam]

# 각 옵티마이저 설정
opt_sgd = torch.optim.SGD(model_sgd.parameters(), lr=learning_rate)
opt_nesterov = torch.optim.SGD(model_nesterov.parameters(), lr=learning_rate, momentum=0.85, nesterov=True)
opt_rmsprop = torch.optim.RMSprop(model_rmsprop.parameters(), lr=learning_rate, alpha=0.95)
opt_adam = torch.optim.Adam(model_adam.parameters(), lr=learning_rate, betas=(0.88, 0.995))

optimizers = [opt_sgd, opt_nesterov, opt_rmsprop, opt_adam]

# 손실 함수 정의
criterion = nn.MSELoss()

# 각 모델의 손실 기록
loss_records = [[], [], [], []]

# 학습 실행
for epoch in range(epochs):
    for batch_x, batch_y in data_loader:
        for model, optimizer, loss_hist in zip(models, optimizers, loss_records):
            predictions = model(batch_x)
            loss = criterion(predictions, batch_y)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            loss_hist.append(loss.detach().item())

# 결과 시각화
optimizer_names = ["SGD", "Nesterov", "RMSProp", "Adam"]

plt.figure(figsize=(10, 6))
for idx, (name, history) in enumerate(zip(optimizer_names, loss_records)):
    plt.plot(history, label=name, linewidth=1.5)

plt.xlabel("반복 횟수", fontsize=11)
plt.ylabel("손실값", fontsize=11)
plt.title("옵티마이저별 수렴 특성 비교", fontsize=13)
plt.legend(loc="upper right")
plt.ylim(0, 0.25)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

알고리즘별 특징

  • SGD (Stochastic Gradient Descent)**: 가장 기본적인 최적화 방법으로, 배치 크기에 따라 국소 최적점에 수렴할 수 있습니다.
  • Momentum/Nesterov**: 이전 업데이트 방향을 고려하여 관성을 주고, Nesterov 버전은 미리 관성 방향으로 계산한 후修正합니다.
  • RMSProp**: 학습률을adaptive하게 조절하며,gradient의 제곱 지수 이동 평균을 사용합니다.
  • Adam**: Momentum과 RMSProp의 장점을 결합하여, 1차 모멘트(속도)와 2차 모멘트(adaptive 학습률)를 모두 활용합니다.

일반적으로Adam이 대부분의 문제에서 좋은 성능을 보이지만, 간단한 문제나 특정한 구조에서는 SGD+Momentum이 더 효율적일 수 있습니다.

태그: pyytorch optimizer SGD Adam RMSProp

7월 16일 06:25에 게시됨