Skip to main content

손실 함수

학습 목표

  • 손실 함수(Loss Function)의 역할과 학습 과정에서의 위치를 이해한다
  • 회귀와 분류 태스크에 적합한 손실 함수를 선택할 수 있다
  • Cross-Entropy Loss의 수학적 원리를 이해한다
  • Focal Loss 등 특수 목적 손실 함수의 동작 방식을 이해한다

왜 중요한가

손실 함수는 모델의 예측이 정답과 얼마나 다른지를 수치화하는 함수입니다. 역전파(Backpropagation)는 이 손실 값의 기울기를 계산하여 가중치를 업데이트합니다. 올바른 손실 함수를 선택하지 않으면 모델은 잘못된 방향으로 학습합니다.

회귀용 손실 함수

MSE (Mean Squared Error)

LMSE=1ni=1n(yiy^i)2\mathcal{L}_{\text{MSE}} = \frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}_i)^2 예측값과 정답의 차이를 제곱하여 평균합니다. 큰 오차에 높은 페널티를 부여합니다.
import torch
import torch.nn as nn

criterion = nn.MSELoss()

y_pred = torch.tensor([2.5, 0.0, 2.1, 7.8])
y_true = torch.tensor([3.0, -0.5, 2.0, 7.5])

loss = criterion(y_pred, y_true)
print(f"MSE Loss: {loss.item():.4f}")

MAE (Mean Absolute Error, L1 Loss)

LMAE=1ni=1nyiy^i\mathcal{L}_{\text{MAE}} = \frac{1}{n}\sum_{i=1}^{n}|y_i - \hat{y}_i| 절대값을 사용하므로 이상치(Outlier)에 MSE보다 강건합니다.
criterion = nn.L1Loss()
loss = criterion(y_pred, y_true)
print(f"MAE Loss: {loss.item():.4f}")

Huber Loss (Smooth L1)

Lδ(a)={12a2if aδδ(a12δ)otherwise\mathcal{L}_{\delta}(a) = \begin{cases} \frac{1}{2}a^2 & \text{if } |a| \leq \delta \\ \delta(|a| - \frac{1}{2}\delta) & \text{otherwise} \end{cases} MSE와 MAE의 장점을 결합합니다. 작은 오차에는 MSE처럼, 큰 오차에는 MAE처럼 동작합니다.
criterion = nn.SmoothL1Loss()  # delta=1.0 기본값
loss = criterion(y_pred, y_true)
print(f"Huber Loss: {loss.item():.4f}")
손실 함수이상치 민감도기울기 특성사용 사례
MSE높음오차에 비례일반 회귀
MAE낮음상수 (±1)이상치가 많은 경우
Huber중간혼합균형 잡힌 회귀

분류용 손실 함수

Binary Cross-Entropy (BCE)

이진 분류에 사용됩니다. 모델 출력에 Sigmoid를 적용한 확률값과 정답 레이블의 차이를 측정합니다. LBCE=1ni=1n[yilog(y^i)+(1yi)log(1y^i)]\mathcal{L}_{\text{BCE}} = -\frac{1}{n}\sum_{i=1}^{n}\left[y_i \log(\hat{y}_i) + (1-y_i)\log(1-\hat{y}_i)\right]
# 방법 1: Sigmoid를 직접 적용한 후 BCELoss 사용
criterion = nn.BCELoss()
y_pred = torch.sigmoid(torch.tensor([0.8, -0.5, 1.2]))  # Sigmoid 적용
y_true = torch.tensor([1.0, 0.0, 1.0])
loss = criterion(y_pred, y_true)

# 방법 2: BCEWithLogitsLoss (Sigmoid 내장, 수치적으로 더 안정)
criterion = nn.BCEWithLogitsLoss()
logits = torch.tensor([0.8, -0.5, 1.2])  # Sigmoid 적용 전 (raw logits)
loss = criterion(logits, y_true)
print(f"BCE Loss: {loss.item():.4f}")
nn.BCEWithLogitsLoss는 Sigmoid와 BCE를 하나로 합쳐 수치적 안정성이 높습니다. 실무에서는 이 방법을 권장합니다.

Cross-Entropy Loss (다중 분류)

다중 클래스 분류의 표준 손실 함수입니다. Softmax + Negative Log-Likelihood를 결합한 것입니다. LCE=c=1Cyclog(y^c)=log(y^true)\mathcal{L}_{\text{CE}} = -\sum_{c=1}^{C} y_c \log(\hat{y}_c) = -\log(\hat{y}_{true}) 원-핫 인코딩에서는 정답 클래스의 확률에 대한 음의 로그값만 남습니다.
criterion = nn.CrossEntropyLoss()

# logits: Softmax 적용 전의 raw 값 (배치 크기 2, 클래스 5)
logits = torch.tensor([[2.0, 1.0, 0.1, -1.0, 0.5],
                        [0.5, 2.5, 0.3, 0.1, -0.2]])
# 정답 레이블 (클래스 인덱스)
labels = torch.tensor([0, 1])

loss = criterion(logits, labels)
print(f"Cross-Entropy Loss: {loss.item():.4f}")

# Softmax 확률 확인
probs = torch.softmax(logits, dim=1)
print(f"예측 확률:\n{probs}")
PyTorch의 nn.CrossEntropyLoss는 내부적으로 Softmax를 포함합니다. 모델 출력에 Softmax를 적용한 후 이 함수를 사용하면 이중 적용이 되어 잘못된 학습이 됩니다. 반드시 raw logits을 입력하세요.

Focal Loss

클래스 불균형(Class Imbalance) 문제를 해결하기 위해 쉬운 샘플의 가중치를 줄이고, 어려운 샘플에 집중합니다. LFL=αt(1pt)γlog(pt)\mathcal{L}_{\text{FL}} = -\alpha_t (1 - p_t)^{\gamma} \log(p_t)
  • γ\gamma (focusing parameter): 쉬운 샘플의 손실을 얼마나 줄일지 조절 (보통 2)
  • αt\alpha_t: 클래스별 가중치
class FocalLoss(nn.Module):
    """클래스 불균형 문제를 위한 Focal Loss"""
    def __init__(self, alpha=1.0, gamma=2.0):
        super().__init__()
        self.alpha = alpha
        self.gamma = gamma

    def forward(self, logits, targets):
        ce_loss = nn.functional.cross_entropy(logits, targets, reduction='none')
        pt = torch.exp(-ce_loss)  # 정답 클래스의 예측 확률
        focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss
        return focal_loss.mean()

# 사용 예시
criterion = FocalLoss(gamma=2.0)
loss = criterion(logits, labels)
print(f"Focal Loss: {loss.item():.4f}")

태스크별 손실 함수 선택

태스크손실 함수PyTorch 클래스
회귀MSEnn.MSELoss()
회귀 (이상치 강건)Hubernn.SmoothL1Loss()
이진 분류BCEnn.BCEWithLogitsLoss()
다중 분류Cross-Entropynn.CrossEntropyLoss()
다중 레이블 분류BCE (각 레이블)nn.BCEWithLogitsLoss()
불균형 분류Focal Loss커스텀 구현
객체 탐지Focal + Smooth L1복합 손실
Cross-Entropy는 두 확률 분포 사이의 차이를 측정합니다. H(p,q)=H(p)+DKL(pq)H(p, q) = H(p) + D_{KL}(p \| q)에서 정답 분포 pp의 엔트로피 H(p)H(p)는 상수이므로, Cross-Entropy를 최소화하는 것은 KL Divergence를 최소화하는 것과 동일합니다. VAE에서 KL Divergence가 별도로 사용되는 이유는 VAE 문서에서 다룹니다.
원-핫 레이블 [0, 0, 1, 0]을 [0.025, 0.025, 0.925, 0.025]로 부드럽게 만드는 기법입니다. 모델이 지나치게 확신하는 것을 방지하여 일반화 성능을 개선합니다. PyTorch에서는 nn.CrossEntropyLoss(label_smoothing=0.1)로 간단히 적용할 수 있습니다.

체크리스트

  • MSE와 Cross-Entropy의 차이와 사용 시점을 구분할 수 있다
  • nn.CrossEntropyLoss에 Softmax가 내장되어 있음을 이해한다
  • Focal Loss가 클래스 불균형 문제를 어떻게 해결하는지 설명할 수 있다
  • 주어진 태스크에 적합한 손실 함수를 선택할 수 있다

다음 문서