본문 바로가기
C.W.K.
Stream
Lesson 07 of 10 · published

기울기 제한: 폭발하는 기울기 길들이기

~10 min · clipping, stability, norm

Level 0텐서 탐구자
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

기울기가 너무 커지면 제한해

일부 학습 구성에서는 기울기 노름이 아주 커질 수 있어. 긴 시퀀스를 다루는 RNN, 적절한 정규화가 없는 매우 깊은 신경망, GAN, 워밍업 없이 학습하는 Transformer가 대표적이야. 거대한 기울기에 학습률을 곱하면 갱신 폭도 지나치게 커져서 손실이 NaN이 되거나 학습이 갑자기 발산할 수 있어.

기울기 제한은 옵티마이저가 매개변수를 갱신하기 전에 기울기 크기를 제한하는 기법이야. 흔한 방식은 두 가지야:

  • 전체 노름으로 제한: 모든 기울기를 합친 L2 노름을 계산하고, 임곗값을 넘으면 전체를 같은 비율로 줄여. Transformer나 LLM 미세 조정 같은 현대적인 학습에서 가장 흔해.
  • 값으로 제한: 각 기울기 원소를 [-c, c] 범위로 잘라. 더 거친 방식이지만 전체 노름보다 일부 이상치 원소가 문제일 때 유용해.

반복문 안에서의 위치

항상 backward()optimizer.step() 사이에 둬. 역전파 전에는 아직 기울기가 없으니 제한할 수 없고, 매개변수를 갱신한 뒤에는 이미 늦어.

max_norm은 Transformer 학습에서 흔히 1.0, RNN에서는 5.0을 쓰기도 해. 다만 알맞은 값은 경험적으로 정해야 해. 학습 중 실제 기울기 노름을 기록하면 임곗값에 얼마나 자주 걸리는지 볼 수 있어.

Code

전체 노름 제한: 표준 구성법·python
import torch
import torch.nn as nn

model = nn.Sequential(nn.Linear(100, 50), nn.ReLU(), nn.Linear(50, 10))
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()

x = torch.randn(32, 100)
y = torch.randint(0, 10, (32,))

optimizer.zero_grad()
loss = loss_fn(model(x), y)
loss.backward()

# Clip before step — returns the original (pre-clip) total norm
total_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
print(f"pre-clip norm: {total_norm:.4f}")

optimizer.step()
값으로 제한: 더 거칠고, 가끔 유용·python
import torch
import torch.nn as nn

model = nn.Linear(10, 2)
loss = nn.functional.mse_loss(model(torch.randn(4, 10)), torch.randn(4, 2))
loss.backward()

# Clamps each element of every gradient tensor to [-0.5, 0.5]
torch.nn.utils.clip_grad_value_(model.parameters(), clip_value=0.5)
기울기 노름 기록: 진단용, 상한 적용 없이·python
import torch
import torch.nn as nn

model = nn.Linear(10, 2)
loss = nn.functional.mse_loss(model(torch.randn(4, 10)), torch.randn(4, 2))
loss.backward()

# Compute the global norm WITHOUT clipping (pass max_norm=inf)
norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=float('inf'))
print(f"global grad norm: {norm:.4f}")

# In a training loop, log this every N steps. If it consistently exceeds
# your max_norm, your clip threshold is doing real work — that's a signal
# to investigate (lr too high? warmup needed? mixed-precision underflow?).

External links

Exercise

간단한 시퀀스 과제로 작은 RNN을 기울기 제한 없이 5에포크 학습해 봐. 매 배치에서 전체 기울기 노름을 기록하면 보통 급증하는 구간이 보일 거야. 이번에는 clip_grad_norm_(model.parameters(), 1.0)을 적용해 다시 학습해. 손실 곡선이 눈에 띄게 부드러워지는지 비교해 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.