Adam에 L2를 추가해도 weight decay가 되지 않는 이유 | 기울기 크기에 따라 수축 방식이 달라지는 실측
요약
본 기사는 PyTorch의 `Adam`과 `AdamW` 옵티마이저를 비교하며, 가중치 감쇠(weight decay)가 실제로 어떻게 작동하는지 심층적으로 분석합니다. 특히 Adam + L2 방식은 기울기 크기에 따라 수축 정도가 달라지는 반면, AdamW는 기울기와 무관하게 일정한 방식으로 가중치를 수축시키는 'decoupled weight decay' 방식을 사용함을 실험을 통해 입증했습니다.
핵심 포인트
- Adam(L2)는 기울기가 작을수록 강하게 수축하는 경향이 있다.
- AdamW는 기울기 크기에 관계없이 일정한 감쇠율을 유지한다 (Decoupled Weight Decay).
- `weight_decay` 인자 이름은 같으나, 내부 작동 방식에 큰 차이가 있다.
- PyTorch의 `AdamW` 사용법과 기본 동작 방식을 정확히 이해해야 한다.
TL;DR
torch.optim.Adam(..., weight_decay=λ)
은 L2 정규화입니다. $\lambda\theta$를 기울기에 더한 후, Adam의 정규화($\sqrt{\hat{v}}$로 나누는 것)에 적용합니다. AdamW
은 정규화와 별개로 가중치를 수축시킵니다 (decoupled weight decay) - 평균 0인 노이즈 기울기로, 동일한 $\lambda=0.1$과 2000 스텝을 사용했습니다. AdamW는 기울기 크기에 관계없이 가중치가 0.82배로 수축합니다. Adam + L2는 기울기가 작은 파라미터일수록 강하게 수축하고(0.02배), 큰 파라미터는 거의 수축하지 않습니다(0.998배) - 손실의 기울기가 0인 파라미터에서는, Adam + L2의 수축 방식은 $\lambda$에 의존하지 않았습니다. $\lambda=0.0001$일 때나 $\lambda=1$일 때나, 1000 스텝 후 값은 0.2577이었습니다 - PyTorch의
AdamW
는 매 스텝마다 가중치를 $(1 - lr\cdot weight_decay)$배로 만듭니다. $lr$을 변경하면 감쇠 강도도 달라집니다
먼저 확인하기: 당신의 코드는 어느 쪽인가요
torch.optim.Adam(params, weight_decay=1e-2) # L2 (기울기에 더함)
torch.optim.AdamW(params, weight_decay=1e-2) # decoupled
torch.optim.Adam(params, weight_decay=1e-2, decoupled_weight_decay=True) # decoupled (AdamW와 동일)
인자 이름은 모두 weight_decay이지만, 첫 번째 줄만 내용이 다릅니다. 세 번째 줄의 decoupled_weight_decay는 제가 사용하는 PyTorch 2.14.1에는 있지만, 구 버전에는 없을 수 있습니다. 사용하기 전에 inspect.signature(torch.optim.Adam)으로 확인하세요.
기본값도 다릅니다. Adam의 weight_decay는 0이고, AdamW은
| 비교 | 최대 오차 |
|---|---|
np_adam(mode="l2") vs torch.optim.Adam(weight_decay=0.1) | |
| 0.0 | |
np_adam(mode="w") vs torch.optim.AdamW(weight_decay=0.1) | |
| 0.0 | |
Adam(weight_decay=0.1, decoupled_weight_decay=True) vs AdamW(weight_decay=0.1) | |
| 0.0 |
비트 단위로 일치했습니다. 다음 실험은 이 np_adam
으로 진행합니다.
실험 1: 기울기 크기에 따라 수축 방식이 달라짐
1만 개의 파라미터를 1.0으로 시작합니다. 손실의 기울기 대신, 평균 0, 표준편차 s인 노이즈를 부여합니다. $\lambda=0.1$로 2000 스텝을 진행한 후, 파라미터의 평균을 확인했습니다. 노이즈의 평균은 0이므로, 평균이 감소한 부분이 '감쇠로 수축된 양'입니다.
for s in [0.01, 0.1, 1, 10, 100]:
rs = np.random.default_rng(1)
noise = lambda th, t: rs.normal(scale=s, size=th.shape)
...
| 기울기 크기 s | Adam + L2 | AdamW |
|---|---|
| 0.01 | 0.0231 | 0.8185 |
| 0.1 | 0.1905 | 0.8185 |
| 1 | 0.8193 | 0.8185 |
| 10 | 0.9800 | 0.8185 |
| 100 | 0.9977 | 0.8185 |
AdamW는 어떤 s 값에서도 0.8185였습니다. 이론값인 $(1 - 0.001 imes 0.1)^{2000} = 0.8187$과 거의 같습니다.
Adam + L2는 $s=1$일 때만 AdamW와 같아졌습니다. $\sqrt{\hat{v}}$가 s와 거의 같으므로, 수축되는 양은 $\lambda\theta/s$가 됩니다. $s=1$이면 나눗셈의 영향이 없습니다.
- s가 작을 때 (0.01): $\lambda\theta/s$가 커져 0.02배까지 줄어듭니다.
- s가 클 때 (100): $\lambda\theta/s$가 작아져 거의 수축되지 않습니다.
| lr | 1000ステップ後の重み(AdamW, weight_decay=0.1) |
|---|---|
| 1e-4 | 0.9900 |
| ... | |
논문의 12번째 줄에서는 감쇠가 $\eta_t \cdot \lambda$ 이고, 학습률 $\alpha$ 는 곱해져 있지 않습니다. $\eta_t$는 스케줄의 배율입니다. 논문의 $\lambda$와 PyTorch의 weight_decay는 같은 숫자라도 같은 의미가 아닙니다. |
곤란한 것은 다음 2가지 상황입니다.
lr을 탐색할 때: lr을 10배로 하면, 감쇠도 10배가 됩니다. weight_decay를 고정하고 lr만 움직여도, 실제로는 양쪽 모두를 움직이고 있는 것입니다 -
논문이나 다른 라이브러리의 값을 가져올 때: 그 $\lambda$에 lr이 곱해질 전제인지 아닌지를 미리 확인해야 합니다.
체크리스트
: Adam인지 AdamW인지 확인하기. Adam(weight_decay=...)라면 L2, AdamW나 decoupled_weight_decay=True라면 decoupled- 입니다. 왜냐하면 인자 이름이 같은 weight_decay이기 때문에, 코드를 본 것만으로는 구분하기 어렵기 때문입니다. 실험 1과 같이 효과가 근본적으로 다릅니다.
- 왜냐하면: 인자 이름이 같음
Adam에서 AdamW로 바꿀 때, weight_decay 값을 그대로 사용하지 않기. 왜냐하면: Adam + L2의 $\lambda$는 기울기의 크기로 나누어지지만, AdamW의 $\lambda$는 나누어지지 않습니다. 같은 0.01이라도, 효과를 내는 강도가 다릅니다. 재조정(튜닝)을 전제로 생각해야 합니다.
lr을 변경했다면, 실제 감쇠($\text{lr} \times \text{weight}_decay$)도 변했다고 생각하기. 왜냐하면: PyTorch의 AdamW는 1 - lr * weight_decay로 수축합니다. lr 스케줄러로 lr이 낮아지면, 감쇠도 함께 약해집니다.
- 왜냐하면: PyTorch의 AdamW는 -
기본값을 확인하기: Adam은 0, AdamW는 0.01 -
왜냐하면: Adam을 AdamW로 대체하는 것만으로도, weight_decay=0.01의 감쇠가 새롭게 추가되기 때문입니다.
- 왜냐하면:
편향(bias)이나 LayerNorm의 가중치를 감쇠 대상에 포함할지 결정하기: param groups로 분리합니다. 왜냐하면: AdamW는 모든 파라미터를 같은 비율로 수축시킵니다. 무엇을 수축시킬지는 옵티마이저가 아니라 사용자가 스스로 결정해야 합니다.
요약
Adam(weight_decay=λ)는 L2 정규화입니다. $\lambda\theta$가 $\sqrt{\hat{v}}$로 나누어지기 때문에, 기울기가 작은 가중치는 강하게, 큰 가중치는 약하게만 수축됩니다 (실측으로 0.02배~0.998배) -
AdamW는 기울기의 크기와 관계없이 매 스텝 같은 비율로 수축합니다 (실측으로 0.8185, 이론값 0.8187). PyTorch의weight_decay는 lr에 곱해집니다. 논문의 $\lambda$와는, 같은 숫자라도 의미가 다릅니다.
이번에 측정한 것은 업데이트 규칙의 동작일 뿐, 일반화 성능은 측정하지 않았습니다. 논문에서는 이미지 분류의 테스트 오차로 AdamW가 Adam + L2를 능가했고, lr과 $\lambda$의 최적값이 독립적으로 가까워진 것이 보고되었습니다.
E자격 범위에 대해서는, 논문과 공식 문서를 출처로 삼아 노트에 한 장씩 정리했습니다. Adam・AdamW의 수식과 시험에서 질문되는 방식은 여기에 모았습니다.
👉 Adam 계열 최적화 | E자격 노트
👉 L1과 L2 페널티 | E자격 노트
pandas 3로 마이그레이션하면서 대입(assignment)이 조용히 작동하지 않게 되는 이야기는 여기에 적었습니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn ML의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기