심드렁하게 저장

최적화 - Adam Optimizer (Adaptive Moment Estimation) 본문

Artificial intelligence/Deep Learning

최적화 - Adam Optimizer (Adaptive Moment Estimation)

Ggoosae 2025. 3. 11. 22:45

1.  Adam Optimizer란?

Adam(Adaptive Moment Estimation) 옵티마이저는 확률적 경사 하강법의 개선된 버전으로, 모멘텀(Momentum)과 RMsprop을 결합한 최적화 알고리즘이다. Adam은 각각의 매개변수에 대해 학습률을 적응적으로 조정하여 빠르고 안정적인 학습을 가능하게 한다. SGD에 비해 빠르게 수렴하고 학습속도가 다르거나 노이즈가 있는 데이터에 대해서도 강인한 성능을 보인다.

2. Adam의 핵심 개념

Adam은 1차 모멘트(이동 평균) 와 2차 모멘트(제곱의 이동 평균)를 활용하여 학습률을 조절한다.

  • 1) 1차 모멘트 (Gradient의 이동평균)
    • 과거의 기울기 평균을 저장하여 모멘텀처럼 동작, 지금까지 계산해온 기울기의 지수 평균 저장
    • $m_{t}$: 현재까지의 기울기의 지수 가중 이동 평균
    • 최근 기울기를 더 중요하게 반영하면서 방향성을 유지
    •  

1차 모멘트

  • 2) 2차 모멘트 (Gradient 제곱의 이동 평균)
    • 기울기의 변화량(Variance)을 추적하여 적응형 학습률 적용, RMSProp과 유사하게 기울기의 제곱값에 지수 평균 저장
    • $v_{t}$: 기울기 제곱의 지수 가중 이동평균
    •  

2차 모멘트

  • 3) 편향 보정 (Bias Correction)
    • Adam 은 초반에 $m_{t}$와 $v_{t}$가 0으로 초기화되므로 편향이 발생할 수 있다. 이를 보정하기 위해 아래와 같이 보정된 ($\hat{m_{t}}$, $\hat{v_{t}}$) 을 사용한다. 보정을 통해 unbiased된 expectation을 얻을 수 있다.
    •  

편향 보정(Bias Correction)

  • 4) 학습률 업데이트
    • 최종적으로 학습률 $\alpha$를 사용하여 가중치를 업데이트 한다.
    • 학습률 업데이트 수식
    • $\alpha$ : 기본 학습률 
    • $\beta_{1}$: 1차 모멘트 계수 (default: 0.9)
    • $\beta_{2}$: 2차 모멘트 계수 (default:0.999)
    • $\epsilon$: 수치 안정성을 위한 작은 값

3.  Implementation

import torch

class AdamOptim():
    def __init__(self,params:torch.Tensor, lr=0.001,beta1=0.9,beta2=0.999,epsilon=1e-8):
        self.params = list(params)
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        self.t = 0

        # 1차, 2차 모멘트 초기화
        self.m = [torch.zeros_like(p) for p in self.params]
        self.v = [torch.zeros_like(p) for p in self.params]

    def step(self):
        '''
        가중치 업데이트 함수
        '''
        self.t += 1 # 타임 스텝
        for i, param in enumerate(self.params):
            if param.grad is None:
                continue

            g = param.grad.data # 기울기

            # 1차 모멘트
            self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * g
            # 2차 모멘트
            self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * g**2

            # 편향 보정
            m_hat = self.m[i] / (1-self.beta1**self.t)
            v_hat = self.v[i] / (1 - self.beta2 ** self.t)

            # 가중치 업데이트
            param.data -= self.lr * m_hat / (torch.sqrt(v_hat) + self.epsilon)

    def zero_grad(self):
        '''
        기울기 초기화
        '''
        for param in self.params:
            if param.grad is not None:
                param.grad.zero_()
# 직접 사용
model = torch.nn.Linear(2,1)
optim = AdamOptim(model.parameters(),lr=0.01)

# 더미 데이터
x = torch.randn(10,2)
y = torch.randn(10,1)

# 학습 루프
for epoch in range(100):
    optim.zero_grad()
    loss = ((model(x) - y) ** 2).mean() # mse loss
    loss.backward()
    optim.step()

    if (epoch + 1) % 10 == 0:
        print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
Epoch 10, Loss: 0.9769
Epoch 20, Loss: 0.8544
Epoch 30, Loss: 0.7616
Epoch 40, Loss: 0.6932
Epoch 50, Loss: 0.6439
Epoch 60, Loss: 0.6102
Epoch 70, Loss: 0.5885
Epoch 80, Loss: 0.5751
Epoch 90, Loss: 0.5674
Epoch 100, Loss: 0.5632

 

  • PyTorch의 optim.Adam 과 동일한 방식으로 동작하며, 모델을 직접 업데이트하는 방식으로 구현됨.
  • zero_grad() 를 호출하여 기울기를 초기화하고, step() 을 호출하여 Adam 최적화를 수행.

Adam Optimizer의 장점

  1. 적응형 학습률
    • 매개변수마다 개별적인 학습률을 적용하여 빠르게 수렴.
  2. 모멘텀과 RMSprop의 장점 결합
    • 빠른 수렴 속도 + 노이즈가 큰 데이터에도 강함.
  3. SGD보다 튜닝이 쉬움
    • 기본값(β1=0.9,β2=0.999\beta_1=0.9, \beta_2=0.999)이 잘 동작하여 별도 조정 없이 사용 가능.

Adam Optimizer의 단점

  1. 최적의 학습률 찾기 어려움
    • 학습률 $\alpha$ 가 너무 크거나 작으면 수렴이 잘 안 될 수 있음.
  2. 일부 문제에서 일반화 성능이 낮음
    • Adam이 항상 최적의 결과를 내는 것은 아니므로 AdamW 또는 SGD로 전환하는 것이 필요할 수도 있음.