옵티마이저概述
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이 더 효율적일 수 있습니다.