손실 함수 완전 정복: 무엇을 최소화하는가
MSE·MAE·Huber·CrossEntropy·Focal Loss·KL Divergence까지 주요 손실 함수의 원리와 용도를 수식과 PyTorch 코드로 완전 정리한다.
지난 글에서 옵티마이저가 파라미터를 어떻게 업데이트하는지 살펴봤다. 옵티마이저가 최소화하려는 목표값이 바로 **손실 함수(Loss Function)**다. “무엇을 최소화하느냐”가 모델이 학습하는 것을 결정한다. 잘못된 손실 함수를 선택하면 아무리 좋은 옵티마이저를 쓰더라도 원하는 결과를 얻을 수 없다.
회귀 손실: 연속값 예측
회귀 문제는 연속적인 수치를 예측한다. 집값 예측, 기온 예측, 주식 가격 예측 등이 해당한다.
MSE (Mean Squared Error): 가장 널리 쓰이는 회귀 손실이다.
import torch
import torch.nn as nn
import torch.nn.functional as F
pred = torch.tensor([2.5, 0.0, 2.0, 8.0])
true = torch.tensor([3.0, -0.5, 2.0, 5.0])
# MSE: L = (1/n) Σ (ŷ - y)²
mse = nn.MSELoss()(pred, true)
print(f"MSE: {mse:.4f}") # 큰 오차(8→5)가 제곱으로 강조됨
# MAE: L = (1/n) Σ |ŷ - y|
mae = nn.L1Loss()(pred, true)
print(f"MAE: {mae:.4f}") # 이상치(8→5)에 덜 민감
# Huber Loss: 작으면 MSE, 크면 MAE
huber = nn.HuberLoss(delta=1.0)(pred, true)
print(f"Huber: {huber:.4f}") # MSE와 MAE의 장점 결합
| 손실함수 | 공식 | 이상치 민감도 | 미분 |
|---|---|---|---|
| MSE | Σ(ŷ-y)²/n | 높음 (제곱) | 매끄러움 |
| MAE | Σ | ŷ-y | /n |
| Huber | 조건부 MSE/MAE | 중간 | 매끄러움 |
실전 선택: 이상치가 없으면 MSE, 이상치가 많으면 MAE, 둘 다 걱정되면 Huber.
이진 분류: BCE
이진 분류(0/1 출력)에는 **Binary Cross-Entropy(BCE)**를 쓴다.
# BCEWithLogitsLoss = sigmoid + BCE (수치적으로 더 안정)
# logits: sigmoid 이전 값 (제한 없음)
logits = torch.tensor([2.0, -1.5, 0.5, -0.3])
labels = torch.tensor([1.0, 0.0, 1.0, 0.0])
bce = nn.BCEWithLogitsLoss()(logits, labels)
print(f"BCE: {bce:.4f}")
# 클래스 불균형 대응: pos_weight
# 양성:음성 = 1:10 → pos_weight=10으로 균형 보정
pos_weight = torch.tensor([10.0])
bce_balanced = nn.BCEWithLogitsLoss(pos_weight=pos_weight)(logits, labels)
# 공식: L = -[y·log(σ(x)) + (1-y)·log(1-σ(x))]
다중 분류: Cross-Entropy
3개 이상 클래스를 분류할 때 Cross-Entropy Loss를 쓴다. PyTorch의 CrossEntropyLoss는 Softmax + Log + NLL을 한 번에 처리한다.
# CrossEntropyLoss: logits → softmax → log → NLL
# 배치 4, 클래스 10
logits = torch.randn(4, 10)
targets = torch.randint(0, 10, (4,))
ce_loss = nn.CrossEntropyLoss()(logits, targets)
print(f"CE: {ce_loss:.4f}")
# 클래스 가중치: 불균형 클래스에 가중치 부여
weights = torch.ones(10)
weights[3] = 5.0 # 3번 클래스가 희귀 → 5배 가중치
ce_weighted = nn.CrossEntropyLoss(weight=weights)(logits, targets)
# 레이블 스무딩 (LLM 학습에서 중요)
# 완전한 one-hot 대신 (1-ε)를 정답에, ε/(K-1)을 나머지에 분배
ce_smooth = nn.CrossEntropyLoss(label_smoothing=0.1)(logits, targets)
LLM의 언어 모델링은 다음 토큰을 맞추는 거대한 다중 분류 문제다. 어휘 크기 50257(GPT-2)이나 128000(LLaMA-3)개 클래스 중 다음 토큰을 예측한다.
Focal Loss: 클래스 불균형의 해결사
객체 탐지에서 배경 영역이 객체보다 수십 배 많다. 쉬운 음성 샘플이 학습을 지배해 모델이 모든 것을 배경으로 예측하려는 경향이 생긴다.
def focal_loss(logits, targets, gamma=2.0, alpha=0.25):
"""Focal Loss: 쉬운 샘플 가중치 감소, 어려운 샘플 가중치 증가"""
ce = F.cross_entropy(logits, targets, reduction='none')
pt = torch.exp(-ce) # 예측 확률 (잘 맞힌 샘플은 높음)
# (1-pt)^gamma: 잘 맞히는 샘플의 기여도 감소
focal_weight = (1 - pt) ** gamma
return (alpha * focal_weight * ce).mean()
# gamma=0: 일반 Cross-Entropy
# gamma=2: 잘 분류된 샘플은 거의 영향 없음, 어려운 샘플에 집중
logits = torch.randn(8, 5)
targets = torch.randint(0, 5, (8,))
print(f"Focal Loss: {focal_loss(logits, targets):.4f}")
KL 발산: 생성 모델의 손실
VAE(Variational Autoencoder)에서 잠재 공간 분포를 정규분포에 가깝게 만드는 데 KL 발산을 사용한다.
# VAE 손실: 재구성 손실 + KL 발산
def vae_loss(recon_x, x, mu, log_var):
"""VAE 손실 함수"""
# 재구성 손실 (BCE)
recon_loss = F.binary_cross_entropy(recon_x, x, reduction='sum')
# KL 발산: q(z|x)~N(μ,σ²) vs p(z)~N(0,1)
# KL = -0.5 * Σ(1 + log(σ²) - μ² - σ²)
kl_loss = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())
return recon_loss + kl_loss
# RLHF에서도 KL: 현재 정책과 참조 정책의 차이를 제약으로 사용
# reward_loss = reward - β·KL(π_θ ‖ π_ref)
대조 손실: 임베딩 학습의 핵심
CLIP, SimCLR 같은 모델은 비슷한 데이터는 임베딩 공간에서 가깝게, 다른 데이터는 멀게 만드는 **대조 손실(Contrastive Loss)**을 사용한다.
def infonce_loss(image_emb, text_emb, temperature=0.07):
"""InfoNCE Loss (CLIP 스타일)"""
# 정규화
image_emb = F.normalize(image_emb, dim=-1)
text_emb = F.normalize(text_emb, dim=-1)
# 유사도 행렬 (배치 내 모든 이미지-텍스트 쌍)
logits = image_emb @ text_emb.T / temperature # [B, B]
# 대각선이 정답 쌍 (같은 인덱스끼리 매칭)
labels = torch.arange(logits.size(0))
loss_i = F.cross_entropy(logits, labels) # 이미지→텍스트
loss_t = F.cross_entropy(logits.T, labels) # 텍스트→이미지
return (loss_i + loss_t) / 2
손실 함수 선택 가이드
손실 함수를 고를 때 순서가 있다.
- 예측 목표: 연속값이면 회귀 손실, 클래스이면 분류 손실
- 출력 형태: sigmoid → BCE, softmax → CE, 원점 대칭 → MSE/Huber
- 데이터 특성: 이상치 많으면 MAE/Huber, 클래스 불균형이면 Focal/가중치
LLM과 생성 모델은 대부분 Cross-Entropy 또는 그 변형을 쓰지만, 생성 다양성(다음 단계에서 배울 온도), 인간 선호(RLHF reward), 안전성(KL 제약) 등을 다루기 위해 손실을 조합한다.
지난 글: 옵티마이저 완전 정복: SGD에서 AdamW까지
다음 글: 정규화: 과적합을 막는 AI의 방패
읽어주셔서 감사합니다. 😊