Skip to content

11장. 깊이의 대가

이 장의 질문: 왜 깊은 신경망은 그냥은 학습되지 않으며, 무엇이 그것을 가능하게 만들었는가? 소실·폭발과의 전쟁에서 나온 네 가지 무기 — 초기화, 정규화 층, 잔차 연결, 현대적 옵티마이저 — 를 원리로 이해한다.

전제: 10장(역전파, 민감도의 곱).

전장의 지도

10장 끝에서 본 재앙을 다시 보자. 깊은 망의 기울기는 층별 민감도 수십 개의 이다. 곱은 폭군이다 — 인수들이 평균 1에서 조금만 벗어나도 결과는 지수적으로 소실되거나 폭발한다. 그러니 깊은 망 학습의 대전략은 한 문장이다.

신호(순전파의 활성값)와 민감도(역전파의 기울기)가 층을 지나도 크기가 대략 보존되도록, 망의 모든 요소를 설계하라.

이 장의 네 무기는 전부 이 한 문장의 실행이다.

무기 1: 출발선을 맞추는 초기화

학습 전 가중치는 무작위로 시작한다(전부 0이면 모든 뉴런이 똑같이 움직여 영원히 같은 것만 배운다 — 대칭을 깨야 한다). 문제는 무작위의 크기다. 층 하나의 출력은 입력 여러 개의 가중합이므로, 가중치가 크면 층을 지날 때마다 값이 불어나고 작으면 쪼그라든다 — 100층이면 지수적으로.

해법은 통계적이다. 입력이 n개 들어오는 층에서, 출력의 분산이 입력의 분산과 같아지려면 가중치의 분산을 1/n 규모로 맞추면 된다(합쳐지는 항이 n개니 각 항을 그만큼 작게). ReLU는 음수 절반을 0으로 죽여 분산을 반토막 내므로 2배 보정한 2/n을 쓴다 — 이것이 He 초기화이고, ReLU 망의 기본값이다. 프레임워크가 자동으로 해 주지만, 원리를 알아야 하는 이유가 있다: 커스텀 층을 만들거나 학습이 첫 스텝부터 발산/정체할 때, 첫 용의자 목록에 초기화를 올릴 수 있게 된다. 2장 끝의 점검 문제 — 입력 크기를 정규화하면 학습이 편해지는 이유 — 도 같은 원리다: 크기가 관리되는 곳에서 학습이 산다.

무기 2: 매 층에서 다시 맞추는 정규화 층

초기화는 출발선만 맞춘다. 학습이 진행되며 가중치가 변하면 활성값 분포는 다시 표류한다. 그렇다면 아예 망 안에 "분포 재정렬 장치"를 끼워 넣자 — 층의 출력을 그 자리에서 평균 0, 분산 1로 표준화해 버리는 것이다. 표준화가 표현력을 깎지 않도록, 학습 가능한 배율(γ)과 이동(β)을 붙여 망이 원하면 되돌릴 수 있게 한다.

무엇을 기준으로 평균·분산을 내느냐에 따라 두 유파가 있다. 배치 정규화(BatchNorm)는 미니배치 방향으로 — 같은 뉴런의 값들을 배치 내 여러 샘플에 걸쳐 — 표준화한다. CNN 시대의 주력이지만 배치 크기에 의존하고, 학습 때(배치 통계)와 추론 때(누적 이동평균) 동작이 달라지는 미묘함이 있다(모델을 평가 모드로 안 바꿔 성능이 이상해지는 사고의 주범). 층 정규화(LayerNorm)는 샘플 하나 안에서 특징 방향으로 표준화한다 — 배치와 무관하고 언제나 같은 동작이라, 시퀀스를 다루는 Transformer의 표준이 되었다(18장에서 재회한다). 어느 쪽이든 효과는 같다: 활성값의 크기가 층마다 리셋되어, 신호가 표류하거나 포화되는 것을 막고 훨씬 큰 학습률을 허용한다.

무기 3: 지름길을 뚫는 잔차 연결

2015년경, 기묘한 실험 결과가 나왔다. 56층 망이 20층 망보다 훈련 오차조차 높았던 것이다. 과적합이 아니다 — 훈련 성적 자체가 나쁘니, 이것은 최적화의 실패다. 이론상 56층 망은 "20층 + 아무것도 안 하는 36층"을 표현할 수 있으니 최소한 동급이어야 하는데, 경사하강이 그 답을 못 찾는 것이다. 알고 보니 "아무것도 안 하기(항등 함수)"는 일반 층에게 의외로 배우기 어려운 과제였다.

해법은 민망할 만큼 단순하다. 층이 출력 전체를 만들게 하지 말고, 입력에 더할 수정분만 만들게 하라.

출력=x+F(x)

이것이 잔차 연결(residual connection)이다. 이제 "아무것도 안 하기"는 F(x)=0 — 가중치를 0 근처에 두면 되는, 세상에서 가장 쉬운 과제가 된다. 층은 백지에서 출력을 그리는 대신 "입력에서 무엇을 고칠까"만 고민한다.

역전파 관점의 효과가 더 극적이다. x+F(x)x로 미분하면 1+F(x) — 민감도에 항상 1이 더해진 채로 뒤로 전달된다. 곱의 사슬 옆에 덧셈의 고속도로가 나란히 뚫린 셈이라, F쪽 민감도가 아무리 작아도 기울기는 1의 통로로 끝까지 살아 돌아온다. 소실 문제의 구조적 해결이다. 잔차 연결의 등장으로 152층, 1000층 망이 학습 가능해졌고, 이후 등장한 거의 모든 대형 구조 — ResNet(13장), Transformer(18장), GPT — 는 예외 없이 잔차 블록의 탑이다.

무기 4: 더 영리하게 걷는 옵티마이저

마지막 무기는 걸음걸이 자체다. 그 전에 실전 전제 하나 — 데이터가 수백만 개면 한 걸음마다 전체 손실을 계산할 수 없다. 무작위로 뽑은 미니배치(수십~수천 개)로 기울기를 근사해 걷는다. 이것이 확률적 경사하강법(SGD)이다. 배치가 작을수록 걸음은 값싸지되 방향에 노이즈가 낀다 — 그런데 이 노이즈는 순전한 악이 아니어서, 얕고 좁은 나쁜 골짜기를 튕겨 나오게 해 주는 공짜 탐색이기도 하다.

순수 SGD의 두 가지 고질을 처방한다.

관성(모멘텀) — 손실 지형에는 좁고 긴 협곡이 흔하다. 순수 SGD는 협곡의 가파른 벽 사이를 지그재그로 튕기며 정작 완만한 진행 방향으로는 굼뜨다. 처방: 기울기를 그대로 쓰지 말고 지수이동평균을 내서 쓰라. 좌우로 튕기는 성분은 평균에서 상쇄되고, 꾸준한 진행 성분은 누적되어 가속된다 — 공이 관성을 갖고 구르는 그림 그대로다.

좌표별 보폭(적응적 학습률) — 파라미터마다 기울기의 스케일이 천차만별이다(어떤 임베딩은 드물게만 갱신 신호를 받는다). 하나의 학습률로는 누군가에겐 너무 크고 누군가에겐 너무 작다. 처방: 각 파라미터의 최근 기울기 크기의 이동평균으로 보폭을 나눠, 기울기가 늘 큰 좌표는 조심스럽게, 작은 좌표는 과감하게 걷게 하라.

이 둘을 합친 것이 Adam이다(가중치 감쇠를 올바르게 분리한 개량형 AdamW가 현재의 사실상 표준). 튜닝에 관대하고 웬만하면 잘 걸어서, "일단 AdamW, 학습률 3e-4 근처에서 시작"이 실무의 안전한 출발점이다. 학습률은 고정하지 않고 스케줄을 태우는 것이 정석이다 — 초반 잠깐은 0에서 서서히 올리고(웜업: 초기화 직후의 불안정한 시기에 큰 걸음을 삼가는 것), 이후 코사인 곡선 등으로 서서히 줄여 마지막엔 골짜기 바닥을 잔걸음으로 더듬는다.

과적합 무기의 신경망 버전: 드롭아웃

4장에서 예고한 무기를 회수하자. 드롭아웃 — 학습 중 매 스텝, 뉴런들을 무작위로(예: 20%) 꺼 버린다. 특정 뉴런 조합에 기댄 암기가 불가능해지고, 매 스텝 조금씩 다른 부분망을 학습시키는 셈이라 암묵적인 앙상블(6장!) 효과까지 얻는다. 추론 때는 모두 켜되 기대값이 맞도록 보정한다(프레임워크가 처리하지만, 그래서 학습/평가 모드 전환을 잊으면 안 된다 — BatchNorm과 함께 model.eval() 깜빡함 사고의 양대 주범이다).

조립: 현대적 학습의 표준 레시피

네 무기를 다 얹은 학습 코드의 뼈대는 이렇다. 이 20줄이 이후 모든 장의 공통 배경이다.

python
model = MyDeepNet()                     # 내부: He 초기화 + 정규화 층 + 잔차 블록
opt = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
sched = torch.optim.lr_scheduler.OneCycleLR(opt, max_lr=3e-4,
                                            total_steps=EPOCHS * len(loader))
for epoch in range(EPOCHS):
    model.train()                                    # 드롭아웃/BN을 학습 모드로
    for x, y in loader:                              # 미니배치 SGD
        opt.zero_grad()                              # 기울기 누적 방지 (10장)
        loss = criterion(model(x), y)
        loss.backward()                              # 역전파 (10장)
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)  # 폭발 보험
        opt.step(); sched.step()                     # AdamW 한 걸음 + 스케줄
    model.eval()                                     # 평가는 반드시 eval 모드로
    validate(model)                                  # 검증 성적으로 조기 종료 판단 (4장)

clip_grad_norm_ 한 줄만 처음 보일 것이다 — 기울기 벡터가 임계값보다 크면 방향은 유지한 채 크기를 잘라내는 기울기 클리핑, 폭발에 대한 값싼 보험이다. 이 레시피를 실제 데이터로 완주하는 것이 코드랩 02 — PyTorch 학습 파이프라인이다. 지금 하라.

핵심 요약

  • 대전략: 층을 지나도 신호와 기울기의 크기가 보존되게 하라. 깊은 망의 모든 표준 부품이 이 원칙의 구현이다.
  • He 초기화는 출발선의 분산을, 정규화 층(BatchNorm/LayerNorm)은 학습 내내의 분산을 관리한다. 잔차 연결 x+F(x)는 기울기에 "1의 고속도로"를 뚫어 소실을 구조적으로 해결한다 — 현대 대형 모델의 공통 골격.
  • 미니배치 SGD에 관성(모멘텀)과 좌표별 보폭(적응 학습률)을 더한 AdamW + 웜업·감쇠 스케줄이 표준 걸음걸이. 클리핑은 폭발 보험.
  • 드롭아웃은 무작위로 뉴런을 꺼 암기를 방해하는 신경망식 정규화(암묵적 앙상블). 학습/평가 모드 전환을 잊지 말 것.

스스로 점검

  1. "가중치 분산을 1/n로"의 n은 무엇이며, ReLU에서 2/n로 키우는 이유는?
  2. 잔차 연결의 역전파 민감도 1+F(x)에서, "1"이 왜 소실 방지의 핵심인지 설명해 보라.
  3. BatchNorm 모델을 model.eval() 없이 평가하면 왜 결과가 이상해질 수 있는가?
  4. 모멘텀이 "협곡의 지그재그"를 완화하는 원리를 지수이동평균의 성질로 설명해 보라.
  5. (실험) 코드랩 02에서 정규화 층을 제거하고 학습률을 그대로 두면 무슨 일이 생기는지 직접 확인해 보라.

다음 장에서

무기를 다 갖췄는데도 현실의 학습은 여전히 자주 무너진다 — 손실이 NaN이 되고, 내려가다 멈추고, 훈련만 좋고 검증은 나쁘고. 다음 장은 짧고 실전적이다: 병든 학습의 증상별 진단 순서, 즉 십수 년치 삽질을 압축한 체크리스트다.

12장. 병든 학습 고치기 →