SGD — Stochastic Gradient Descent

난이도: 초중급

태그: 기초수학,최적화,딥러닝기초

분류: foundations

타입: concept

선수지식: 있음 — 미분, gradient, 손실함수

딥러닝 모델 학습의 가장 기본이 되는 알고리즘. 이것을 이해하면 Adam, AdamW 같은 모든 optimizer의 기반을 이해한 것이다.

문제 설정

신경망 학습의 목표는 손실함수(loss)를 최소화하는 파라미터를 찾는 것입니다.

w ← w - η ∇wL

즉 gradient가 가리키는 상승 방향의 반대로 이동해 loss를 줄입니다.

이 수식은 매우 짧지만 의미는 세 덩어리로 나눠서 봐야 이해가 쉽습니다. w는 지금 모델이 가진 파라미터 위치, ∇L은 loss가 가장 빨리 커지는 방향, η는 한 번에 얼마나 움직일지 정하는 보폭입니다.

한 줄 요약

오차(loss)를 줄이기 위해 그래디언트 방향으로 조금씩 파라미터를 움직이는 방법이다.

이 문서를 읽고 설명할 수 있어야 하는 핵심 3가지

처음 보는 사람용 핵심 용어

1단. 왜 이런 방법이 필요한가

신경망은 이런 흐름으로 동작한다.

입력 → 신경망 → 예측 → 정답과 비교 → loss 발생

학습의 목표는 이 loss를 최소로 만드는 파라미터 w를 찾는 것이다.

# 목표
min L(w)   # w: 파라미터, L: loss function

파라미터 공간은 수십억 차원이기 때문에 전수 탐색은 불가능하다. gradient를 이용해 조금씩 내려가는 방법이 필요하다.

2단. 기본 Gradient Descent

loss가 줄어드는 방향 = gradient의 반대 방향. 이 방향으로 조금씩 이동한다.

w = w - η * ∇L(w)
# η: learning rate (보폭)
# ∇L(w): gradient (오르막 방향 → 반대로 가면 내리막)

여기서 중요한 것은 gradient가 "좋은 방향"이 아니라 loss가 커지는 방향이라는 점입니다. 그래서 업데이트 식에 항상 마이너스가 붙습니다. 마이너스가 없으면 학습이 아니라 오히려 loss를 키우는 방향으로 올라가게 됩니다.

η는 방향을 바꾸지 않고 이동량만 조절합니다. 즉 gradient가 어디로 갈지를 알려주고, learning rate가 얼마나 멀리 갈지를 정한다고 생각하면 됩니다.

그래서 learning rate는 optimizer의 성격을 바꾸는 값이 아니라, 같은 방향을 얼마나 공격적으로 따를지 정하는 값입니다. 아무리 좋은 optimizer라도 learning rate가 지나치게 크면 발산하고, 너무 작으면 거의 학습이 안 되는 것처럼 보일 수 있습니다.

문제: 전체 데이터로 gradient를 계산해야 한다. 데이터가 1조 토큰이면 1 step에 전부 읽어야 한다. 계산량이 엄청나고 GPU를 오래 점유한다.

3단. SGD 아이디어 — 일부만 쓴다

전체 데이터 대신 랜덤하게 일부만 뽑아서 gradient를 계산한다.

방식사용 데이터속도정확도
Gradient Descent전체 (1,000,000)느림정확
SGD (mini-batch)일부 (128)빠름근사

Stochastic(확률적)이라는 이름이 여기서 나온다. 매 step마다 랜덤하게 샘플을 뽑는다.

w = w - η * ∇L_i(w)
# L_i: mini-batch i로 계산한 loss (전체 loss의 근사)

즉 SGD는 "방향을 대충 보더라도 자주 움직이자"는 전략입니다. 한 번의 gradient는 덜 정확하지만 계산이 훨씬 싸기 때문에, 실제 wall-clock time 기준으로는 훨씬 빠르게 학습을 진행할 수 있습니다.

SGD는 현재 gradient만 보고 한 걸음씩 이동 step마다 noisy하지만 계산이 가볍다
SGD는 매 step마다 현재 mini-batch gradient만 보고 바로 이동한다. 방향은 다소 흔들릴 수 있지만, 계산이 빠르고 자주 업데이트할 수 있다.

4단. 실제 학습 흐름

실제로는 mini-batch SGD를 사용한다. 아래가 딥러닝 학습의 기본 루프다.

for x, y in dataloader:       # mini-batch 로드 (예: 128개)
    pred = model(x)            # 순전파: 예측
    loss = criterion(pred, y)  # loss 계산

    optimizer.zero_grad()      # 이전 gradient 초기화 (누적 방지)
    loss.backward()            # 역전파: gradient 계산
    optimizer.step()           # SGD: w = w - η * gradient

이 루프가 전체 데이터를 한 번 다 돌면 1 epoch이다. 학습은 이것을 수십~수백번 반복한다.

핵심 수식 정리

① 최적화 목표

min L(w) = min (1/N) * Σ ℓ(f(x_i; w), y_i)
# N: 전체 데이터 수
# ℓ: 개별 샘플의 loss
# f(x_i; w): 파라미터 w를 가진 모델의 예측값

직관: 모든 샘플에서의 평균 오차를 최소화하는 w를 찾는 것이 목표다.

② Gradient Descent (전체 데이터)

w = w - η * ∇L(w)   # 전체 데이터 기준. 정확하지만 느리다.

여기서 ∇L(w)는 전체 데이터 평균 loss를 기준으로 계산한 gradient입니다. 그래서 방향은 비교적 안정적이지만, 한 번 계산하는 데 비용이 매우 큽니다.

③ SGD (mini-batch)

w = w - η * ∇L_i(w)  # mini-batch 기준. 빠르고 노이즈가 있다.

∇L_i(w)는 전체 loss가 아니라 현재 mini-batch가 만들어낸 근사 gradient입니다. 즉 정확도는 조금 희생하지만, 계산량을 크게 줄여 더 자주 업데이트할 수 있게 만든 것이 SGD의 핵심입니다.

한계: learning rate η를 직접 정해야 하고, 모든 파라미터에 동일한 η를 사용한다. 이 한계를 극복하려고 Adam이 나왔다.

5단. SGD의 장단점

장점 1 — 계산이 빠르다

전체 데이터 대신 128개만 쓰기 때문에 1 step이 수천 배 빠르다. step이 많아져도 전체 학습 시간은 줄어든다.

장점 2 — 노이즈가 오히려 도움이 된다

gradient가 정확하지 않아 생기는 노이즈가 두 가지 효과를 낸다.

단점 — loss가 들쭉날쭉

noisy gradient 때문에 loss curve가 불안정하다. learning rate 조절이 중요하고, 잘못 설정하면 수렴이 느리거나 발산한다.

이때 momentum은 learning rate와 다른 역할을 합니다. learning rate가 "한 걸음 크기"를 조절한다면, momentum은 "이전 방향을 얼마나 기억할지"를 조절합니다. 그래서 둘은 서로 대체 관계가 아니라 함께 튜닝하는 값입니다.

6단. SGD와 개선된 Optimizer 비교

Optimizer핵심 아이디어주요 사용처
SGD기본. momentum 옵션 추가 가능CNN, ResNet 학습
RMSProp파라미터별 learning rate 자동 조절RNN
AdamSGD + momentum + RMSProp 결합범용
AdamWAdam + weight decay를 gradient와 분리LLM (거의 표준)

핵심: 이름이 달라도 모두 gradient를 계산하고 w를 업데이트하는 구조는 SGD와 같다. Adam은 SGD에 adaptive learning rate와 momentum을 추가한 것이다.

즉 optimizer 비교의 핵심 질문은 "gradient를 계산하느냐 마느냐"가 아니라, 계산된 gradient를 어떻게 더 안정적으로 쓰느냐입니다. Momentum은 방향 기억을 추가하고, Adam/AdamW는 파라미터별 스케일 조절까지 넣는다고 보면 됩니다.

실험 설명 섹션

예상 질문 5개와 답변

다음에 스스로 해볼 실습 2가지