← Day 5 Phase 0 · Week 1 · Day 6 Day 7 →

Day 6 — 최적화, 초기화, 손실 지형

엔진으로 진짜 학습을 한다 — 그런데 "loss가 줄었다"에서 멈추지 않는다. 초기화 이론(분산 보존, Xavier/He)으로 왜 시작점이 학습을 좌우하는지, SGD·모멘텀·Adam을 직접 구현해 각 옵티마이저가 손실 지형을 어떻게 항해하는지, 결정경계와 loss landscape를 시각화해 비볼록 최적화의 실제 모습을 본다. two-moons 같은 비선형 문제로 MLP의 표현력을 눈으로 확인한다.

🎯 오늘의 목표

📖 개념 (수업)

1. 초기화 이론 — 분산 보존

랜덤 초기화의 스케일이 왜 중요한가? 신호가 층을 통과하며 분산이 폭발하거나 소실되면, 깊은 망은 처음부터 학습 불능이다. 선형층 $y = Wx$($W\in\mathbb{R}^{d_\text{out}\times d_\text{in}}$, 원소 i.i.d. 평균0 분산$\sigma_W^2$)에서, 입력이 분산 $\sigma_x^2$로 독립이라 가정하면 출력 원소의 분산은

$$\mathrm{Var}(y_i) = d_\text{in}\,\sigma_W^2\,\sigma_x^2$$

forward에서 분산을 보존하려면 $\sigma_W^2 = 1/d_\text{in}$. backward에서 gradient 분산을 보존하려면 $\sigma_W^2 = 1/d_\text{out}$. 둘을 절충한 게 Xavier/Glorot: $\sigma_W^2 = 2/(d_\text{in}+d_\text{out})$. ReLU는 음수 절반을 죽여 분산을 반토막내므로 보정 계수 2를 곱한 He 초기화 $\sigma_W^2 = 2/d_\text{in}$를 쓴다. 이게 "왜 kaiming_normal_인가"의 답이다.

심화 이 분산 논증의 현대적 일반화가 신호전파 이론(Poole et al. 2016)과 NTK(Jacot et al. 2018)다. 초기화 스케일이 "혼돈/질서 상전이"의 경계(edge of chaos)에 있을 때 깊은 신호가 가장 잘 전파된다. 트랜스포머의 residual·LN도 이 분산 가계부를 맞추는 장치로 읽을 수 있다.

2. 경사하강과 그 친척들

비볼록 $\hat R(\theta)$를 1차 방법으로 내려간다. 세 갱신식을 정확히:

옵티마이저갱신식직관
SGD$\theta \leftarrow \theta - \eta\, g$가장 가파른 방향 한 걸음
Momentum$v \leftarrow \mu v + g;\ \ \theta \leftarrow \theta - \eta v$관성으로 협곡 진동 억제·가속
Adam$m\leftarrow\beta_1 m+(1{-}\beta_1)g;\ v\leftarrow\beta_2 v+(1{-}\beta_2)g^2;$
$\hat m=\tfrac{m}{1-\beta_1^t};\ \hat v=\tfrac{v}{1-\beta_2^t};\ \theta\leftarrow\theta-\eta\tfrac{\hat m}{\sqrt{\hat v}+\epsilon}$
좌표별 적응 스텝(2차 모멘트로 정규화)

Adam의 $\hat v$로 나누는 항이 핵심: gradient가 큰 좌표는 스텝을 줄이고 작은 좌표는 키워, 조건수가 나쁜 지형에서도 잘 간다. 바이어스 보정 $\hat m, \hat v$는 초기 $m,v=0$ 편향을 상쇄한다. 트랜스포머 학습은 거의 항상 AdamW (weight decay를 gradient가 아닌 파라미터에 직접 — Loshchilov & Hutter 2019)다. Phase 1에서 그대로 쓴다.

3. 옵티마이저를 추상화 — PyTorch처럼

Neuron/Layer/MLP는 Day 1 구조 그대로(이제 ReLU/He 초기화 적용). 새로 만들 것은 옵티마이저 객체다. 파라미터 리스트를 받아 step()zero_grad()를 제공한다 — PyTorch optim의 미니 버전.

class SGD:
    def __init__(self, params, lr, momentum=0.0):
        self.params, self.lr, self.mu = params, lr, momentum
        self.v = [0.0 for _ in params]
    def step(self):
        # TODO: v ← mu*v + p.grad ;  p.data -= lr * v
        ...
    def zero_grad(self):
        for p in self.params: p.grad = 0.0

class Adam:
    # TODO: m, v 버퍼 + 바이어스 보정 + 좌표별 갱신 (위 표)
    ...

4. 손실 지형 — 비볼록의 실제 모습

학습을 "loss 숫자"가 아니라 지형 위의 궤적으로 본다. 고차원 $\theta$를 직접 못 보니 단면을 뜬다:

여기서 안장점·평탄골·날카로운/평평한 최소값을 눈으로 본다. "평평한 최소값이 더 잘 일반화한다"는 가설(Hochreiter–Schmidhuber, Keskar et al.)도 이 시각화로 직관화된다. Phase 3에서 큰 모델의 일반화를 논할 때 다시 등장.

5. 진단 습관 — 학습이 안 될 때 보는 것

최고수준이라면 "loss가 안 줄어요"에서 멈추지 않는다. 항상 보는 계기판:

✍️ 직접 해보기 (강도 ↑)

과제 1 — 초기화 분산 실험. 깊이 20 ReLU MLP에서 초기화 스케일을 $\sigma_W^2 \in \{1/d, 2/d, 1\}$로 바꿔 층별 활성값 분산을 측정·플롯해라. He($2/d$)에서 분산이 보존되고, $1$에서 폭발, $1/d$에서 ReLU 때문에 서서히 소실됨을 보여라. forward 분산 식 $\mathrm{Var}(y)=d\sigma_W^2\sigma_x^2$ 와 정량 일치 확인.
과제 2 — 옵티마이저 3종 구현 + 비교. SGD/Momentum/Adam을 구현하고, Rosenbrock 또는 조건수 나쁜 2차함수에서 수렴 궤적을 등고선 위에 그려라. Adam이 협곡에서 SGD보다 빠른 이유를 좌표별 스텝으로 설명.
과제 3 — two-moons 분류. sklearn.datasets.make_moons로 비선형 데이터 생성, micrograd MLP(예: 2-16-16-1, tanh/ReLU)로 학습. 결정경계를 등고선으로 시각화하고, 은닉 너비/깊이를 바꿀 때 경계 복잡도가 어떻게 변하는지 관찰(Day 1 선형영역과 연결).
과제 4 — 손실 단면 시각화. 학습된 모델의 1D 보간 단면과 2D 필터정규화 단면(Li et al. 2018)을 그려라. 평평/날카로운 최소값을 식별하고, 배치 크기를 키웠을 때 단면이 더 날카로워지는지(Keskar 가설) 실험으로 점검.
과제 5 — zero_grad 함정 + lr×init. zero_grad를 빼면 학습이 어떻게 망가지는지 grad norm 폭발로 확인. 그리고 (초기화, 학습률) 격자를 훑어 학습 성공/발산 상도(phase diagram)를 그려라 — 좋은 초기화가 허용 lr 범위를 넓힘을 보여라.
도전 학습률 탐색기. lr을 지수적으로 증가시키며 한 배치씩 돌려 loss를 기록하는 LR range test(Smith 2017)를 구현하고, "loss가 최소 기울기로 감소하는 lr"을 자동 추정해 과제 3에 적용하라.

✅ 스스로 확인

📝 오늘의 기록

docs/00_day06.md:
이제 학습 루프 전체를 처음부터 통제한다. forward·loss·backward·step의 네 단계는 GPT 학습에서도 토씨 하나 안 바뀐다. 다만 차이는 규모와 디테일(AdamW, LR 스케줄, mixed precision) — Phase 1 Week 6에서 그대로 확장한다. 오늘 만든 진단 습관이 그때 디버깅의 무기가 된다.
다음 (Day 7): 한 주를 통합한다. micrograd ↔ PyTorch autograd 내부(grad_fn/tape) 대응을 정밀히 짚고, 스칼라 AD의 한계(벡터화 부재)를 정량화해 Week 2(텐서)의 동기를 못박는다. 그리고 "reverse-mode AD를 처음부터" 기술 글을 완성한다 — 포트폴리오의 첫 글.

← Day 5 Day 6 끝 Day 7 — 통합 & 글쓰기 →