Cross-Entropy
교차 엔트로피
분류 문제의 손실 함수. 예측 확률과 실제 분포의 차이 측정.
교차 엔트로피
분류 문제의 손실 함수. 예측 확률과 실제 분포의 차이 측정.
Cross-Entropy(교차 엔트로피)는 두 확률 분포 사이의 차이를 측정하는 정보 이론의 개념입니다. 머신러닝에서는 모델이 예측한 확률 분포와 실제 정답 분포 간의 차이를 정량화하는 데 사용되며, 분류 문제에서 가장 널리 사용되는 손실 함수의 기반이 됩니다.
정보 이론의 창시자 Claude Shannon이 1948년 엔트로피 개념을 정립했고, 교차 엔트로피는 이후 두 분포 간의 "정보 차이"를 측정하는 방법으로 발전했습니다. 1990년대 이후 신경망 학습에 널리 적용되면서 딥러닝의 핵심 도구가 되었습니다.
수학적으로 교차 엔트로피 H(p,q)는 -sum(p(x) * log(q(x)))로 정의됩니다. 여기서 p는 실제 분포(정답), q는 예측 분포입니다. 예측이 정답과 일치할수록 값이 작아지고, 틀릴수록 커집니다. 로그 함수 특성상 확신 있게 틀린 예측(0.99 확률로 오답)에 큰 페널티를 부여합니다.
실무에서 교차 엔트로피는 이미지 분류, 자연어 처리의 다음 토큰 예측, 추천 시스템 등 거의 모든 분류 태스크에 사용됩니다. GPT 같은 언어 모델은 다음 토큰 예측의 교차 엔트로피를 최소화하는 방식으로 학습됩니다. 평균 교차 엔트로피를 perplexity(혼란도)로 변환하여 모델 성능을 비교하기도 합니다.
import numpy as np
import torch
import torch.nn.functional as F
# NumPy로 직접 구현
def cross_entropy_numpy(y_true, y_pred, epsilon=1e-15):
"""
y_true: 원-핫 인코딩된 실제 레이블 (batch_size, num_classes)
y_pred: 예측 확률 분포 (batch_size, num_classes)
"""
# 수치 안정성을 위해 클리핑
y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
# 교차 엔트로피 계산
ce = -np.sum(y_true * np.log(y_pred), axis=1)
return np.mean(ce)
# 예제: 3개 클래스 분류
y_true = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # 정답
y_pred_good = np.array([[0.9, 0.05, 0.05], [0.1, 0.8, 0.1], [0.1, 0.1, 0.8]]) # 좋은 예측
y_pred_bad = np.array([[0.3, 0.4, 0.3], [0.4, 0.3, 0.3], [0.3, 0.3, 0.4]]) # 나쁜 예측
print(f"좋은 예측의 CE: {cross_entropy_numpy(y_true, y_pred_good):.4f}") # ~0.18
print(f"나쁜 예측의 CE: {cross_entropy_numpy(y_true, y_pred_bad):.4f}") # ~1.10
# PyTorch에서 사용
logits = torch.tensor([[2.0, 0.5, 0.3], [0.2, 2.5, 0.3], [0.1, 0.2, 2.8]])
targets = torch.tensor([0, 1, 2]) # 클래스 인덱스
# CrossEntropyLoss는 softmax + NLL을 결합
loss = F.cross_entropy(logits, targets)
print(f"\nPyTorch CE Loss: {loss.item():.4f}")
# Perplexity 변환 (언어 모델 평가 시 사용)
perplexity = torch.exp(loss)
print(f"Perplexity: {perplexity.item():.4f}")
"학습 loss가 0.5에서 안 내려가는데, cross-entropy가 0.5면 perplexity가 약 1.65입니다. 3개 클래스 분류에서 랜덤 추측의 perplexity가 3이니까 학습은 되고 있는 거예요. 다만 클래스 불균형 문제가 있으면 weighted cross-entropy를 적용해보세요."
"분류에서 MSE 대신 cross-entropy를 쓰는 이유는 기울기 소실 문제 때문입니다. MSE의 미분값은 예측이 0이나 1에 가까우면 매우 작아지지만, cross-entropy는 틀린 정도에 비례하는 기울기를 유지합니다. 그래서 학습이 훨씬 빠르고 안정적입니다."
"여기서 softmax 먼저 적용하고 cross_entropy_loss에 넣으셨는데, PyTorch의 CrossEntropyLoss는 내부에서 log_softmax를 적용합니다. 두 번 softmax가 적용되면서 수치 불안정이 생길 수 있어요. logits를 직접 넣으세요."
예측 확률이 0에 가까우면 log(0)으로 인해 -inf가 발생합니다. PyTorch의 내장 함수는 자동 처리하지만, 직접 구현 시 epsilon(예: 1e-15)을 더하거나 클리핑이 필수입니다.
1:100 비율의 불균형 데이터에서 기본 cross-entropy를 쓰면 다수 클래스만 예측하는 모델이 만들어집니다. class_weight 파라미터로 소수 클래스에 높은 가중치를 부여하거나 Focal Loss를 사용하세요.
이진 분류에서 BCELoss(Binary Cross-Entropy)와 CrossEntropyLoss를 혼용하면 차원 오류가 발생합니다. 2개 클래스면 BCEWithLogitsLoss, 3개 이상이면 CrossEntropyLoss를 사용하세요.