[CS300 #267] 과적합과 정규화 — 외우는 모델, 이해하는 모델
컴퓨터공학 300 주제 시리즈의 267번째 글이다. 전체 지도는 여기.
한 줄 요약
과적합은 모델이 학습 데이터의 잡음까지 외워 새 데이터에서 성능이 떨어지는 현상이고, 정규화는 가중치에 벌점을 주거나 학습을 일찍 멈추는 식으로 모델의 자유도를 제한해 일반화를 돕는 기법이다.
왜 필요한가
머신러닝의 목표는 학습 데이터를 맞히는 것이 아니다. 아직 보지 못한 데이터를 맞히는 것이다. 그런데 학습 알고리즘이 직접 줄일 수 있는 것은 학습 데이터의 오차뿐이다. 이 간극이 모든 문제의 근원이다.
시험 기출문제의 답을 통째로 외운 학생은 기출 점수는 만점이지만 새 문제 앞에서는 무너진다. 모델도 같다. 학습 데이터에서는 거의 완벽했던 모델이 실서비스에서 눈에 띄게 떨어지는 일은 흔하다. 과적합을 알아보고 막는 법은 모델 종류와 상관없이 모든 머신러닝 작업의 기본기다.
핵심 개념
과소적합과 과적합
오차
│ \ ____ 검증 오차
│ \ ___/
│ \___ ____/
│ \______________/
│ ‾‾‾‾‾‾‾\_____
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 학습 오차
└─────────────────────────────────▶ 모델 복잡도
과소적합 적당 과적합
- 과소적합: 모델이 너무 단순해 학습 데이터조차 못 맞힌다. 학습 오차와 검증 오차가 둘 다 높다.
- 과적합: 학습 오차는 계속 내려가는데 검증 오차는 어느 순간부터 올라간다. 둘 사이 간격이 벌어진다.
편향-분산 분해
제곱 오차 기준으로, 새 점에서의 기대 오차는 세 조각으로 나뉜다.
기대 오차 = 편향² + 분산 + 줄일 수 없는 잡음
- 편향: 모델이 평균적으로 정답에서 얼마나 빗나가는가. 너무 단순한 가정에서 온다.
- 분산: 학습 데이터가 바뀌면 모델이 얼마나 흔들리는가. 너무 유연한 모델에서 온다.
- 잡음: 데이터 자체의 무작위성. 어떤 모델로도 못 줄인다.
복잡도를 올리면 편향은 줄고 분산은 는다. 정규화는 편향을 조금 늘리는 대가로 분산을 크게 줄이는 거래다.
정규화 기법
| 기법 | 방법 | 효과 |
|---|---|---|
| L2 (릿지) | 손실 + λ·Σw² | 가중치를 고르게 작게. 해가 안정됨 |
| L1 (라쏘) | 손실 + λ·Σ|w| | 일부 가중치를 정확히 0 으로. 특징 선택 효과 |
| 엘라스틱넷 | L1 + L2 | 상관된 특징 묶음을 함께 다룸 |
| 조기 종료 | 검증 오차가 오르기 시작하면 멈춤 | 반복 수를 사실상 제한 |
| 드롭아웃 | 학습 중 뉴런을 무작위로 끔 | 신경망의 공적응(co-adaptation) 억제 |
| 데이터 증강 | 회전·자르기 등으로 데이터를 불림 | 불변성을 데이터로 주입 |
릿지의 닫힌 해는 정규방정식에 대각 항 하나만 더한 꼴이다.
w = (XᵀX + λI)⁻¹ Xᵀy
λI 가 더해지면 XᵀX 가 특이 행렬에 가까워도 역행렬이 안정된다. 정규화는 수치 안정성 장치이기도 하다.
L1 이 가중치를 정확히 0 으로 만드는 이유는 벌점의 모양 때문이다. 절댓값 함수는 0 에서 뾰족해서, 작은 가중치를 0 으로 밀어 넣는 힘이 크기에 상관없이 일정하다. L2 는 0 근처에서 힘이 같이 작아져 0 에 가까워질 뿐 정확히 0 이 되지는 않는다.
검증 데이터와 교차 검증
λ 같은 하이퍼파라미터는 학습 데이터로 고르면 안 된다. 언제나 λ=0 이 학습 오차를 가장 작게 하니까. 그래서 데이터를 셋으로 나눈다.
[ 학습 (모델 적합) | 검증 (하이퍼파라미터 선택) | 테스트 (마지막 한 번만) ]
데이터가 적으면 k-겹 교차 검증을 쓴다. k 등분해 한 조각씩 돌아가며 검증용으로 쓰고 평균 낸다. 테스트 세트는 모든 선택이 끝난 뒤 한 번만 열어 본다. 테스트 점수를 보고 다시 고치기 시작하면, 테스트 세트에도 과적합된다.
직접 해 보기
sin 곡선에 잡음을 섞은 점 12개에 1·3·9차 다항식을 맞추고, 9차에는 릿지 벌점을 걸어 본다.
import numpy as np
rng = np.random.default_rng(3)
f = lambda x: np.sin(2 * np.pi * x)
xtr = np.sort(rng.uniform(0, 1, 12)); ytr = f(xtr) + rng.normal(0, .2, 12)
xte = np.linspace(0, 1, 200); yte = f(xte) + rng.normal(0, .2, 200)
def design(x, d): return np.vander(x, d + 1, increasing=True)
def fit(d, lam=0.0):
X = design(xtr, d)
I = np.eye(d + 1); I[0, 0] = 0 # 절편은 벌점에서 제외
return np.linalg.solve(X.T @ X + lam * I, X.T @ ytr)
def mse(w, x, y): return np.mean((design(x, len(w)-1) @ w - y) ** 2)
print("차수 람다 train_MSE test_MSE |w|max")
for d, lam in [(1,0),(3,0),(9,0),(9,1e-3),(9,1e-1)]:
w = fit(d, lam)
print(f"{d:>3} {lam:<7g} {mse(w,xtr,ytr):9.4f} {mse(w,xte,yte):8.4f} {np.abs(w).max():8.1f}")
실행 결과:
차수 람다 train_MSE test_MSE |w|max
1 0 0.1183 0.2303 2.2
3 0 0.0100 0.0639 36.3
9 0 0.0017 103154.1504 2704259.9
9 0.001 0.0210 0.1796 7.0
9 0.1 0.0587 0.6622 0.9
교과서 그대로의 그림이다.
- 1차: 학습·테스트 오차가 둘 다 높다. 과소적합.
- 3차: 둘 다 낮다. sin 한 주기를 그리기에 충분한 복잡도.
- 9차, 벌점 없음: 학습 오차는 가장 낮지만 테스트 오차가 폭발했다. 가중치 크기가 수백만이다. 점 12개를 지나가려고 곡선이 점 사이에서 미친 듯이 출렁인다는 뜻이다.
- 9차, λ=0.001: 같은 9차인데 테스트 오차가 10만 단위에서 0.18 로 돌아왔다. 3차만큼은 아니지만 1차보다 낫고, 가중치도 한 자리 수로 줄었다. 참고로 테스트 데이터에 넣은 잡음의 분산이 0.04 이므로, 어떤 모델도 그 아래로는 내려갈 수 없다.
- 9차, λ=0.1: 벌점이 너무 세서 곡선이 펴졌다. 다시 과소적합 쪽으로 넘어갔다.
λ 가 너무 작아도, 너무 커도 나쁘다. 그 사이 값을 검증 데이터로 고르는 것이 정규화 실무의 전부다.
현업에서는
- 학습 곡선을 늘 같이 본다. 에폭마다 학습·검증 손실을 기록하고, 간격이 벌어지는 지점을 확인한다. MLflow, TensorBoard 같은 도구가 이 기록을 남기는 용도다.
- 데이터 누수가 과적합보다 무섭다. 미래 정보가 특징에 섞이거나, 같은 사용자의 데이터가 학습·검증 양쪽에 들어가면 검증 점수가 부풀어 과적합을 숨긴다. 시계열은 시간 순서로, 사용자 데이터는 사용자 단위로 나눠야 한다.
- 대형 모델도 예외가 아니다. 파인튜닝할 때 데이터가 작으면 몇 에폭 만에 학습 데이터를 외운다. 학습률을 낮추고, 에폭을 줄이고, 검증 손실로 조기 종료한다.
확인 문제
- 학습 오차 2%, 검증 오차 25% 이다. 무엇을 의심하고, 어떤 대책을 쓸 수 있는가?
- 학습 오차 20%, 검증 오차 21% 이다. 정규화를 더 거는 것이 도움이 되는가?
- L1 과 L2 정규화 중 특징 선택 효과가 있는 것은?
- 하이퍼파라미터를 테스트 세트 점수로 고르면 안 되는 이유는?
- 예제에서 9차 다항식의 가중치 크기가 정규화로 줄어든 것이 왜 일반화와 관련이 있는가?
풀이
- 과적합. 정규화 강화, 모델 단순화, 데이터 추가·증강, 조기 종료.
- 아니다. 과소적합(편향이 큼)이므로 오히려 모델을 더 복잡하게 하거나 특징을 늘려야 한다.
- L1. 가중치를 정확히 0 으로 만든다.
- 테스트 세트에 맞춰 선택이 이뤄지므로 테스트 점수가 더 이상 처음 보는 데이터의 성능을 대표하지 못한다.
- 큰 가중치는 입력이 조금만 변해도 출력이 크게 변하는 곡선을 만든다. 가중치를 작게 하면 함수가 매끄러워져 학습 점 사이에서 덜 출렁인다.
더 읽을거리 (References)
- scikit-learn User Guide, Linear Models — Ridge, Lasso, Cross-validation
- N. Srivastava 외, “Dropout: A Simple Way to Prevent Neural Networks from Overfitting”, JMLR 15, 2014. 링크
- T. Hastie 외, The Elements of Statistical Learning, 2nd ed., 3·7장. 저자 사이트