optimizer는 loss를 줄이기 위해 가중치를 어떻게 업데이트 할것인가를 결정하는 알고리즘
| SGD | 가장 기본 | 낮음 |
| NAG | ||
| Momentum | SGD 개선 | 보통 |
| Adagrad | 희소 데이터에 강함 | 낮음 |
| RMSprop | RNN 학습에 사용 | 보통 |
| Adam | 범용적으로 강력 | 높음 |
| AdamW | Adam 개선판 | 매우 높음 |
Optimizer, 가중치를 어떻게 수정할 것인지 결정하는 알고리즘
Optimizer - SGD Stochastic Gradient Descent loss 줄어드는 방향으로 조금 이동한다. 단순하고 계산이 안정적인대신 느리고 흔들림이 크다. loss가 지그재그로 내려가며 learning rate 설정에 매우 민감하다.
import torch
import torch.nn as nn
import torch.optim as optim
x = torch.tensor([[1.0], [2.0], [3.0]])
y = torch.tensor([[2.0], [4.0], [6.0]])
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
for epoch in range(100):
pred = model(x)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("SGD 학습 완료")
Optimizer - SGD + Momentum, 관성을 추가한다. 이전 gradient 방향을 기억하는것. 경사면 굴러가는 공처럼 더 빠르게 내려가고 흔들림이 줄어든다. SGD보다 안정적이고 local noice가 감소된다.
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.SGD(
model.parameters(),
lr=0.01,
momentum=0.9
)
for epoch in range(100):
pred = model(x)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("Momentum SGD 완료")
Optimizer - NAG Nesterov Accelerated Gradient, Momentum 개선판. Momentum이 현재 위치에서 기울기를 계산한다면, NAG는 앞으로 갈 위치를 예측해 그 위치에서 기울기를 계산한다. Momentum보다 빠르지만 Adam 등장 후 사용빈도가 감소했다.
torch.optim.SGD(
model.parameters(),
lr=0.01,
momentum=0.9,
nesterov=True
)
Optimizer - RMSProp, gradient크기에 따라서 step이 자동조절된다 .gradient가 큰 방향으로 작게이동하고 gradient가 작은 방향으로 크게 이동하는 등 RNN 시절에 많이 사용했다. 비정상적인 graient를 안정화하기 좋다.
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.RMSprop(
model.parameters(),
lr=0.001
)
for epoch in range(100):
pred = model(x)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("RMSProp 완료")
Optimizer - Adam. 가장 많이 쓴다. momentum + RSAProp를 합친 것으로 방향도 기억하고 스케일도 자동 조절한다. 거이 항상 잘되고 튜닝이 거의 필요없는 빠른방법.
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)
for epoch in range(100):
pred = model(x)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("Adam 완료")
Optimizer - AdamW 기존 Adam에서는 L2 regularization이 이상하게 섞일수있는데 AdamW에서는 weight decay를 진짜 weight decay로 처리해 일반화성능이좋아져 transformer에서 필수적이다.
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.AdamW(
model.parameters(),
lr=0.001,
weight_decay=0.01
)
for epoch in range(100):
pred = model(x)
loss = criterion(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("AdamW 완료")
실무기준으로는 Adam, AdamW를 기본적으로 90%, 연구 및 cnn 일부에서는 sgd + momentum을 쓴다.
튜닝이필요없다는 것이 가장 큰 장점. 초기학습도 빨라 초반 loss가 빠르게 감소하며 자동 scaling 덕에 noisy data에 강하고 매우 깊고 gradient noisy가 있는 transformer에 adamw가 아주 안정적이다 .
반대로 sgd + momentum가 아직도 쓰이는 이유는 놀랍게도 SGD가 더 좋은 최종 성능이 나오는 경우가 있기 때문인데 noise가 있고 흔들림이 있는 SGD가 오히려 좋은 일반화를 찾는 경우가 있는것. CNN 에서는 아직강하고 연구논문 기준비교 공정성으로 채택되어있으며 adam은 너무 빨리 맞춰버려 overfit이 가능하나 SGD는 느리지만 일반화가 더 잘되 overfitting이 적은 경우가 있기 때문이다. 실무에서는 결과를 빨리 뽑아야하기때문에 adam이 더 인기가 많음.