개요
Adam(Adaptive Moment Estimation) Optimizer는 2014년에 발표된 최적화 알고리즘으로, Momentum과 RMSProp의 장점을 합친 방식입니다. 딥러닝 모델 학습에서 자주 사용되며, 학습률 조정 없이도 안정적이고 빠른 수렴을 기대할 수 있습니다.
Adam은 다음의 두 가지 아이디어를 기반으로 합니다.
1차 모멘트(평균, momentum)
2차 모멘트(분산의 제곱, adaptive learning rate)
수식 정리
Adam의 주요 업데이트 수식은 다음과 같습니다.
초기화:
$$m_0 = 0,\quad v_0 = 0,\quad t = 0$$
반복 업데이트 (매 step 마다):
시간 스텝 증가
$$t \leftarrow t + 1$$
그래디언트 계산
$$g_t = \nabla_\theta J(\theta_t)$$
1차 모멘트 추정 (모멘텀)
$$m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t$$
2차 모멘트 추정 (스케일)
$$v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2$$
편향 보정 (초기 값이 0이라서 bias correction)
$$\hat{m}_t = \frac{m_t}{1 - \beta_1^t},\quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}$$
파라미터 업데이트
$$\theta_{t+1} = \theta_t - \alpha \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}$$
파라미터 요약
파라미터 | 의미 | 기본값 |
---|---|---|
$\alpha$ | 학습률 (learning rate) | 0.001 |
$\beta_1$ | 1차 모멘텀 감쇠 계수 | 0.9 |
$\beta_2$ | 2차 모멘텀 감쇠 계수 | 0.999 |
$\epsilon$ | 0으로 나누는 것 방지 | $10^{-8}$ |
numpy 코드 구현 예시
이제 위의 수식을 바탕으로 numpy
로 구현한 간단한 Adam Optimizer를 보겠습니다.
import numpy as np
class AdamOptimizer:
def __init__(self, learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
self.lr = learning_rate
self.beta1 = beta1
self.beta2 = beta2
self.eps = epsilon
self.m = None
self.v = None
self.t = 0
def update(self, params, grads):
if self.m is None:
self.m = np.zeros_like(params)
self.v = np.zeros_like(params)
self.t += 1
# 1차, 2차 모멘텀 업데이트
self.m = self.beta1 * self.m + (1 - self.beta1) * grads
self.v = self.beta2 * self.v + (1 - self.beta2) * (grads ** 2)
# 편향 보정
m_hat = self.m / (1 - self.beta1 ** self.t)
v_hat = self.v / (1 - self.beta2 ** self.t)
# 파라미터 업데이트
params -= self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
return params
사용 예시
# 예제: x^2 함수의 최소값을 찾기
def f(x):
return x**2
def grad_f(x):
return 2 * x
x = np.array([5.0]) # 초기값
optimizer = AdamOptimizer()
for i in range(100):
grad = grad_f(x)
x = optimizer.update(x, grad)
if i % 10 == 0:
print(f"Step {i}: x = {x[0]:.6f}, f(x) = {f(x)[0]:.6f}")
마무리
Adam은 초기에 빠르게 수렴하고, 이후 안정적으로 최솟값에 접근하는 특징이 있어 대부분의 딥러닝 모델에서 기본 최적화 알고리즘으로 사용됩니다. 하지만 너무 많은 step이나 작은 learning rate에서 일찍 멈추거나 local minima에 갇히는 경우도 있어 주의가 필요합니다.