Cross-Entropy Loss
Cross-Entropy Loss
분류 문제의 손실 함수. 예측 확률과 실제 분포의 차이 측정.
Cross-Entropy Loss
분류 문제의 손실 함수. 예측 확률과 실제 분포의 차이 측정.
Cross-Entropy Loss는 분류 문제에서 모델의 예측 오차를 측정하는 손실 함수입니다. 모델이 출력한 확률 분포와 실제 정답(원-핫 인코딩) 간의 교차 엔트로피를 계산하여, 이 값을 최소화하는 방향으로 모델 파라미터를 업데이트합니다.
딥러닝 초기부터 분류 문제의 표준 손실 함수로 자리 잡았습니다. Softmax 활성화 함수와 결합하면 미분이 간단해지고(y_pred - y_true), 역전파 계산이 효율적입니다. 이러한 수학적 편의성 덕분에 1990년대 이후 신경망 분류기의 기본 선택이 되었습니다.
Cross-Entropy Loss는 이진 분류(Binary CE)와 다중 분류(Categorical CE)로 구분됩니다. 이진 분류에서는 L = -[y*log(p) + (1-y)*log(1-p)]로, 다중 분류에서는 L = -sum(y_i * log(p_i))로 계산됩니다. PyTorch의 CrossEntropyLoss는 내부에서 LogSoftmax와 NLLLoss를 결합하여 수치 안정성을 보장합니다.
실무에서 이미지넷 분류, BERT의 마스크 언어 모델링, GPT의 다음 토큰 예측 등 대부분의 분류 태스크에 사용됩니다. Label Smoothing(라벨 스무딩)을 적용하면 과적합을 방지하고, Focal Loss로 변형하면 클래스 불균형 문제에 대응할 수 있습니다.
import torch
import torch.nn as nn
import torch.nn.functional as F
# 기본 CrossEntropyLoss 사용
criterion = nn.CrossEntropyLoss()
# 예측 logits (softmax 적용 전)
logits = torch.tensor([
[2.0, 1.0, 0.1], # 클래스 0을 강하게 예측
[0.5, 2.5, 0.3], # 클래스 1을 강하게 예측
[0.2, 0.3, 3.0] # 클래스 2를 강하게 예측
])
# 정답 레이블 (클래스 인덱스)
targets = torch.tensor([0, 1, 2])
# Loss 계산
loss = criterion(logits, targets)
print(f"Cross-Entropy Loss: {loss.item():.4f}") # ~0.36
# 클래스 불균형 해결: 가중치 적용
# 클래스 0:1:2 비율이 1:10:100일 때
class_weights = torch.tensor([100.0, 10.0, 1.0]) # 역비율로 가중치
weighted_criterion = nn.CrossEntropyLoss(weight=class_weights)
weighted_loss = weighted_criterion(logits, targets)
print(f"Weighted CE Loss: {weighted_loss.item():.4f}")
# Label Smoothing 적용 (과적합 방지)
smooth_criterion = nn.CrossEntropyLoss(label_smoothing=0.1)
smooth_loss = smooth_criterion(logits, targets)
print(f"Label Smoothed CE Loss: {smooth_loss.item():.4f}")
# Binary Cross-Entropy (이진 분류)
bce_criterion = nn.BCEWithLogitsLoss()
binary_logits = torch.tensor([1.5, -0.5, 2.0])
binary_targets = torch.tensor([1.0, 0.0, 1.0])
bce_loss = bce_criterion(binary_logits, binary_targets)
print(f"Binary CE Loss: {bce_loss.item():.4f}")
# 실제 학습 루프에서 사용
model = nn.Linear(10, 3) # 입력 10, 출력 3클래스
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 미니배치 학습
x = torch.randn(32, 10) # 배치 크기 32
y = torch.randint(0, 3, (32,)) # 랜덤 레이블
optimizer.zero_grad()
output = model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()
print(f"Training Loss: {loss.item():.4f}")
"Training loss는 계속 줄어드는데 validation loss가 0.8에서 올라갑니다. 전형적인 과적합이에요. Label smoothing 0.1을 적용하거나, 데이터 증강을 추가해보죠. 또는 모델 크기를 줄이는 것도 방법입니다."
"CrossEntropyLoss에 logits를 넣어야 하는 이유는 수치 안정성 때문입니다. softmax의 지수 연산과 log가 서로 상쇄되는 log-sum-exp 트릭을 내부에서 사용하기 때문에 오버플로우를 방지합니다. 그래서 softmax를 직접 적용하고 넣으면 안 됩니다."
"여기서 ignore_index=-100 설정을 빠뜨리셨네요. 패딩 토큰도 loss 계산에 포함되면서 학습이 잘 안 되는 겁니다. NLP에서 시퀀스 분류할 때 패딩 인덱스는 반드시 ignore_index로 지정해야 합니다."
PyTorch의 CrossEntropyLoss는 내부에서 softmax를 적용합니다. 모델 출력에 softmax를 먼저 적용하고 CrossEntropyLoss에 넣으면 잘못된 결과가 나옵니다. logits를 직접 전달하세요.
CrossEntropyLoss는 타겟이 클래스 인덱스(Long 텐서)여야 하고, BCELoss는 확률(Float 텐서)이어야 합니다. 원-핫 인코딩된 타겟을 CrossEntropyLoss에 넣으면 에러가 발생합니다.
기본 reduction='mean'은 배치 내 평균을 반환합니다. 샘플별 loss가 필요하면 reduction='none'으로 설정해야 하며, 클래스 가중치와 함께 쓸 때 의도치 않은 스케일링이 발생할 수 있습니다.