AI 학습의 숨은 심판관, 손실함수 완전 정복: MSE·Cross-Entropy부터 Focal·Dice·LLM 손실까지
같은 데이터와 같은 모델 구조를 사용해도 손실함수(Loss Function)를 어떻게 정의하느냐에 따라 모델이 배우는 방향은 달라집니다.
예를 들어 실제값과 예측값의 오차가 다음과 같다고 가정해봅시다.
- 모델 A의 오차:
1, 1, 1, 10 - 모델 B의 오차:
4, 4, 4, 4
모델 A는 대부분 정확하지만 한 번 크게 틀렸고, 모델 B는 모든 예측에서 비슷하게 틀렸습니다.
- 모델 A: MAE = 3.25, MSE = 25.75
- 모델 B: MAE = 4.00, MSE = 16.00
MAE는 모델 A를 더 좋게 평가하지만, 큰 오차를 강하게 벌점 주는 MSE는 모델 B를 더 좋게 평가합니다. 어느 쪽이 옳은지는 수학 공식이 아니라 실제 문제에서 큰 오차가 얼마나 위험한가에 달려 있습니다.
손실함수는 단순히 오차를 재는 공식이 아니라, 모델이 어떤 실수를 우선적으로 줄여야 하는지 정의하는 학습 정책이다.
이 글에서는 다음 내용을 다룹니다.
- 손실함수·비용함수·목적함수·평가지표의 차이
- MSE, MAE, Huber, Quantile Loss 등 회귀 손실
- Binary·Categorical Cross-Entropy, 가중 손실, Focal Loss
- Dice, Tversky, IoU 계열 손실과 객체 탐지의 복합 손실
- Triplet, Contrastive, KL Divergence, VAE·LLM·DPO 손실
- 로짓(Logit), Sigmoid, Softmax를 손실함수와 올바르게 조합하는 법
- PyTorch와 TensorFlow/Keras 구현 예제
- 손실은 내려가는데 성능이 오르지 않을 때의 진단법
1. 손실함수란 무엇인가
1.1 한 샘플의 오차를 학습 가능한 숫자로 바꾸는 함수
입력 $x_i$, 정답 $y_i$, 모델 $f_\theta$가 있을 때 한 샘플의 손실은 다음처럼 표현할 수 있습니다.
$$
\ell_i = \ell\left(f_\theta(x_i), y_i\right)
$$
- $\theta$: 모델의 가중치와 편향 등 학습 파라미터
- $f_\theta(x_i)$: 모델의 예측
- $y_i$: 실제 정답
- $\ell$: 예측과 정답의 차이를 수치화하는 손실함수
미니배치 또는 전체 학습 데이터에서는 개별 손실을 평균하거나 합산합니다.
$$
J_{data}(\theta)=\frac{1}{N}\sum_{i=1}^{N} w_i\ell_i
$$
여기에 가중치 감쇠 같은 정규화 항을 더하면 실제 최적화 목표가 됩니다.
$$
J(\theta)=J_{data}(\theta)+\lambda R(\theta)
$$
즉, 학습 로그에 표시되는 loss는 순수 예측 오차뿐 아니라 다음 요소를 포함할 수 있습니다.
- 샘플별 손실의 평균 또는 합
- 클래스·샘플 가중치
- L1·L2 정규화
- 여러 태스크의 손실 합
- 보조 출력에 적용한 Auxiliary Loss
따라서 서로 다른 코드나 논문의 손실값을 숫자만 보고 직접 비교하면 안 됩니다.
1.2 손실함수, 비용함수, 목적함수, 평가지표의 차이
| 용어 | 핵심 질문 | 예시 |
|---|---|---|
| 손실함수(Loss) | 한 예측이 얼마나 잘못됐는가? | 한 샘플의 BCE, 절대오차 |
| 비용함수(Cost) | 데이터 전체에서 평균적으로 얼마나 잘못됐는가? | 미니배치 평균 MSE |
| 목적함수(Objective) | 최적화 알고리즘이 최종적으로 무엇을 최소화·최대화하는가? | 데이터 손실 + 정규화 |
| 평가지표(Metric) | 모델을 어떤 기준으로 평가·선택할 것인가? | F1, AUROC, RMSE, mAP |
| 비즈니스 KPI | 실제 서비스에서 어떤 가치가 생겼는가? | 불량 유출률, 사고 감소, 매출 |
실무에서는 loss와 cost를 엄격히 구분하지 않는 경우가 많습니다. 그러나 손실함수와 평가지표는 반드시 구분해야 합니다.
예를 들어 희귀 질환 분류 모델은 다음처럼 설계할 수 있습니다.
- 학습 손실: 가중 Binary Cross-Entropy
- 검증 지표: AUPRC, Recall, Precision
- 운영 기준: Recall 95% 이상에서 Precision 최대화
- 비즈니스 KPI: 미탐 환자 수와 추가 검사 비용
F1이나 Accuracy는 임계값을 기준으로 예측을 잘라 계산하기 때문에 대부분 구간별로 값이 일정하고 미분하기 어렵습니다. 그래서 학습할 때는 Cross-Entropy처럼 연속적인 대리 손실(Surrogate Loss)을 사용하고, 검증할 때는 실제 목적에 맞는 지표를 봅니다.
1.3 좋은 손실함수는 반드시 매끄럽고 볼록해야 할까
반드시 그렇지는 않습니다.
- MAE는 오차가 0인 지점에서 고전적인 의미의 미분값이 하나로 정해지지 않습니다.
- ReLU도 0에서 미분 가능하지 않지만 자동미분 프레임워크가 정한 서브그래디언트로 학습합니다.
- 딥러닝 모델의 전체 목적함수는 일반적으로 비볼록(Non-convex)입니다.
- Dice·IoU 계열 손실은 복잡한 비선형 구조를 가집니다.
중요한 것은 “모든 지점에서 완벽히 미분 가능한가”가 아니라 다음 질문입니다.
- 모델 파라미터를 개선할 수 있는 유용한 기울기를 제공하는가?
- 이상치·노이즈·불균형에 지나치게 끌려가지 않는가?
- 수치적으로 안정적인가?
- 실제 평가 목적과 충분히 정렬되어 있는가?
2. 손실함수가 모델의 학습 방향을 바꾸는 원리
2.1 손실값보다 기울기가 중요하다
경사하강법은 손실값 자체가 아니라 파라미터에 대한 손실의 기울기를 이용합니다.
$$
\theta \leftarrow \theta-\eta\nabla_\theta J(\theta)
$$
여기서 $\eta$는 학습률입니다.
잔차를 $e=\hat{y}-y$라고 하면 대표적인 회귀 손실의 기울기는 다음처럼 달라집니다.
| 손실 | 손실 형태 | 잔차에 대한 기울기 | 학습 효과 |
|---|---|---|---|
| MSE | $e^2$ | $2e$ | 큰 오차에 큰 기울기 |
| MAE | $ | e | $ |
| Huber | 작은 오차는 제곱, 큰 오차는 선형 | 작은 오차는 $e$, 큰 오차는 $\delta\operatorname{sign}(e)$ | 큰 오차의 영향 상한 설정 |
MSE가 이상치에 민감한 이유는 단순히 값을 제곱하기 때문만이 아닙니다. 큰 잔차일수록 기울기도 선형으로 커져서 한두 개의 샘플이 파라미터 업데이트를 지배할 수 있기 때문입니다.
2.2 손실함수는 데이터 분포에 대한 가정을 담고 있다
많은 손실함수는 최대우도추정(Maximum Likelihood Estimation) 관점에서 해석할 수 있습니다.
| 데이터·오차 가정 | 대응 손실 | 학습되는 대표값 |
|---|---|---|
| 오차가 가우시안 분포 | MSE 또는 Gaussian NLL | 조건부 평균 |
| 오차가 라플라스 분포 | MAE | 조건부 중앙값 |
| 정답이 베르누이 분포 | Binary Cross-Entropy | 양성 확률 |
| 정답이 범주형 분포 | Categorical Cross-Entropy | 클래스 확률 분포 |
| 정답이 포아송 분포 | Poisson NLL | 사건 발생률 |
| 특정 분위수 예측 | Quantile/Pinball Loss | 조건부 분위수 |
이 관점은 손실 선택을 훨씬 명확하게 만듭니다. 단순히 “회귀니까 MSE”가 아니라, 어떤 확률 분포와 어떤 통계량을 예측하려는가를 묻게 됩니다.
2.3 mean, sum, none은 결과가 같지 않다
대부분의 딥러닝 프레임워크는 reduction 옵션을 제공합니다.
none: 샘플·픽셀별 손실을 그대로 반환mean: 모든 원소의 평균sum: 모든 원소의 합
sum을 사용하면 배치 크기나 이미지 해상도가 커질수록 기울기 규모도 커질 수 있습니다. 반대로 mean은 배치 크기가 달라도 평균 기울기 규모를 비교적 일정하게 유지합니다.
마스킹, 샘플 가중치, 클래스별 가중치를 적용하려면 보통 reduction="none"으로 손실을 얻은 뒤 원하는 방식으로 직접 집계하는 것이 안전합니다.
3. 회귀 손실함수
3.1 MSE: 큰 오차를 강하게 줄이고 싶을 때
평균 제곱 오차(Mean Squared Error)는 다음과 같습니다.
$$
MSE=\frac{1}{N}\sum_{i=1}^{N}(y_i-\hat{y}_i)^2
$$
장점
- 큰 오차에 강한 벌점을 줍니다.
- 모든 지점에서 매끄러운 기울기를 제공합니다.
- 가우시안 오차를 가정한 최대우도추정과 연결됩니다.
- 선형회귀와 일반적인 회귀 신경망의 강력한 기준선입니다.
한계
- 극단값과 잘못된 라벨에 매우 민감합니다.
- 타깃 단위가 커지면 손실값과 기울기 규모도 급격히 커질 수 있습니다.
- “평균적으로 몇 단위 틀렸는가”를 손실값 자체로 해석하기 어렵습니다.
적합한 상황
- 큰 오차가 작은 오차보다 훨씬 위험한 문제
- 라벨 노이즈와 이상치가 적은 문제
- 오차가 대체로 대칭적이고 가우시안에 가까운 문제
주의할 점
주가나 부동산 가격처럼 이상치가 많다는 이유만으로 MAE가 항상 더 좋은 것은 아닙니다. 중요한 것은 이상치가 측정 오류인지, 실제로 반드시 맞혀야 하는 희귀 사건인지입니다. 실제 위험 사건이라면 MSE의 큰 벌점이 오히려 필요할 수 있습니다.
3.2 MAE: 이상치의 영향과 큰 기울기를 제한하고 싶을 때
평균 절대 오차(Mean Absolute Error)는 다음과 같습니다.
$$
MAE=\frac{1}{N}\sum_{i=1}^{N}|y_i-\hat{y}_i|
$$
장점
- 큰 오차의 영향이 MSE보다 제한적입니다.
- 손실값을 원래 타깃 단위로 해석할 수 있습니다.
- 기대 MAE를 최소화하면 조건부 중앙값을 추정합니다.
한계
- 오차가 0인 지점에서 미분값이 하나로 정해지지 않지만, 실무 프레임워크는 서브그래디언트로 처리합니다.
- 오차가 매우 작아져도 기울기 크기가 거의 일정해 최적점 근처에서 미세 조정이 MSE보다 느릴 수 있습니다.
- 큰 오차와 작은 오차를 기울기 크기로 구분하지 않습니다.
적합한 상황
- 일부 큰 잔차가 전체 학습을 지배하지 않게 하고 싶을 때
- 조건부 평균보다 중앙값 예측이 목적일 때
- 라벨 분포의 꼬리가 두껍거나 이상치가 존재할 때
3.3 Huber Loss: 작은 오차는 MSE처럼, 큰 오차는 MAE처럼
Huber Loss는 잔차의 절댓값이 $\delta$ 이하일 때 제곱 손실, 그보다 클 때 선형 손실을 사용합니다.
$$
L_\delta(e)=
\begin{cases}
\frac{1}{2}e^2, & |e|\le\delta \
\delta\left(|e|-\frac{1}{2}\delta\right), & |e|>\delta
\end{cases}
$$
핵심 해석
- 작은 잔차: MSE처럼 정밀하게 줄임
- 큰 잔차: 기울기를 $\pm\delta$로 제한
- $\delta$가 작을수록 더 빨리 선형 구간으로 들어가므로 일반적으로 이상치에 더 강건
- $\delta$가 클수록 더 넓은 범위에서 MSE처럼 동작
기존 설명에서 자주 나오는 “이상치가 많을수록 $\delta$를 크게 한다”는 기준은 반대로 이해될 수 있습니다. 이상치의 영향력을 더 일찍 제한하려면 보통 더 작은 $\delta$가 MAE에 가까운 동작을 만듭니다.
다만 $\delta$는 타깃의 단위에 직접 영향을 받습니다. 매출이 원 단위인지 백만 원 단위인지에 따라 같은 delta=1.0의 의미가 완전히 달라집니다. 다음 순서가 안전합니다.
- 타깃을 표준화하거나 견고한 스케일로 변환
- 표준화된 공간에서
delta=1.0을 기준선으로 시작 - 검증 지표와 잔차 분포를 보며 조정
PyTorch의
HuberLoss와SmoothL1Loss는 형태가 유사하지만 일반적인 $\delta$에서 스케일 정의가 완전히 동일하지 않습니다. 라이브러리를 바꿀 때 파라미터 이름만 맞추지 말고 공식 문서를 확인해야 합니다.
3.4 Quantile Loss: 과소 예측과 과대 예측의 비용이 다를 때
Pinball Loss라고도 부르는 분위수 손실은 다음과 같습니다.
$$
L_\tau(y,\hat{y})=
\begin{cases}
\tau(y-\hat{y}), & y\ge\hat{y} \
(1-\tau)(\hat{y}-y), & y<\hat{y}
\end{cases}
$$
- $\tau=0.5$: 중앙값 예측, MAE와 연결
- $\tau=0.9$: 실제값이 예측보다 큰 과소 예측에 더 큰 벌점
- $\tau=0.1$: 과대 예측에 상대적으로 더 큰 벌점
실전 예시
전력 수요를 과소 예측하면 정전 위험이 커지고, 과대 예측하면 예비전력 비용이 늘어납니다. 두 비용이 같지 않다면 대칭적인 MSE보다 Quantile Loss가 실제 운영 목적에 더 잘 맞을 수 있습니다.
여러 분위수, 예를 들어 0.1·0.5·0.9를 동시에 예측하면 점예측뿐 아니라 예측구간도 만들 수 있습니다. 단, 분위수 곡선이 서로 교차하는 Quantile Crossing 문제를 확인해야 합니다.
3.5 Poisson NLL과 Gaussian NLL: 값뿐 아니라 분포를 예측할 때
Poisson Negative Log-Likelihood
콜 수, 고장 건수, 클릭 수처럼 일정 구간의 사건 횟수를 예측할 때 사용할 수 있습니다.
$$
y\sim\operatorname{Poisson}(\lambda)
$$
모델은 음수가 될 수 없는 발생률 $\lambda$ 또는 $\log\lambda$를 예측합니다. 평균보다 분산이 훨씬 큰 과산포 데이터에는 단순 Poisson 가정이 부족할 수 있어 Negative Binomial 같은 대안을 고려합니다.
Gaussian Negative Log-Likelihood
평균뿐 아니라 샘플별 분산도 예측할 수 있습니다.
$$
y\sim\mathcal{N}(\mu(x),\sigma^2(x))
$$
모델이 불확실한 샘플에는 큰 분산을, 확실한 샘플에는 작은 분산을 예측하는 이분산 회귀(Heteroscedastic Regression)에 유용합니다. 다만 분산을 무작정 크게 만들어 오차를 회피하지 못하도록 로그 분산 항이 함께 작동하며, 수치 안정성을 위해 분산 하한값이 필요합니다.
3.6 회귀 손실 선택표
| 상황 | 우선 시도할 손실 | 함께 확인할 지표·주의점 |
|---|---|---|
| 일반적인 연속값 예측 | MSE | MAE, RMSE, 잔차 분포 |
| 큰 오차가 특히 위험 | MSE | 상위 분위수 오차, 최대 오차 |
| 이상치·라벨 노이즈가 있음 | Huber | MAE, 이상치 슬라이스 |
| 중앙값이 목적 | MAE | Median AE |
| 과소·과대 예측 비용이 다름 | Quantile Loss | 분위수별 Coverage |
| 건수·빈도 예측 | Poisson NLL | 과산포 여부 |
| 샘플별 불확실성까지 예측 | Gaussian NLL | NLL, Coverage, 구간 폭 |
4. 분류 손실함수
4.1 로짓과 확률부터 구분하자
분류 모델의 마지막 선형층이 출력하는 값은 보통 확률이 아니라 로짓(Logit)입니다.
이진 분류에서 로짓 $z$를 확률로 바꾸려면 Sigmoid를 사용합니다.
$$
p=\sigma(z)=\frac{1}{1+e^{-z}}
$$
다중 클래스 분류에서는 Softmax를 사용합니다.
$$
p_k=\frac{e^{z_k}}{\sum_j e^{z_j}}
$$
그러나 학습 코드에서 Sigmoid나 Softmax를 직접 적용한 뒤 로그를 계산하면 매우 큰 양수·음수 로짓에서 오버플로 또는 log(0) 문제가 생길 수 있습니다. 그래서 프레임워크는 활성화와 로그 손실을 하나로 결합한 안정적인 함수를 제공합니다.
- PyTorch 이진·다중 레이블:
BCEWithLogitsLoss - PyTorch 다중 클래스:
CrossEntropyLoss - TensorFlow/Keras:
BinaryCrossentropy(from_logits=True) - TensorFlow/Keras:
CategoricalCrossentropy(from_logits=True)또는SparseCategoricalCrossentropy(from_logits=True)
결합 손실을 사용할 때 모델 출력에 Sigmoid나 Softmax를 한 번 더 적용하면 안 됩니다.
4.2 Binary Cross-Entropy: 이진 분류와 다중 레이블 분류
정답 $y\in{0,1}$, 양성 확률 $p$일 때 BCE는 다음과 같습니다.
$$
BCE=-\left[y\log p+(1-y)\log(1-p)\right]
$$
정답이 1일 때 예측 확률별 손실을 보면 확신의 정도가 반영됩니다.
| 양성 확률 $p$ | 손실 $-\log p$ |
|---|---|
| 0.90 | 약 0.105 |
| 0.60 | 약 0.511 |
| 0.10 | 약 2.303 |
| 0.01 | 약 4.605 |
Accuracy는 0.5 임계값만 넘으면 0.6과 0.9를 모두 정답으로 처리하지만, BCE는 더 정확하고 자신 있는 확률에 더 낮은 손실을 줍니다.
사용 유형
- 이진 분류: 출력 로짓 1개
- 다중 레이블 분류: 클래스마다 독립적인 로짓 1개씩
- 이진 세그멘테이션: 픽셀마다 로짓 1개
다중 레이블 문제에서는 여러 클래스가 동시에 참일 수 있으므로 Softmax가 아니라 각 클래스에 독립적인 Sigmoid+BCE를 사용합니다.
4.3 Categorical Cross-Entropy: 서로 배타적인 다중 클래스 분류
정답 분포 $y_k$, 예측 확률 $p_k$에 대해 다음과 같습니다.
$$
CE=-\sum_{k=1}^{C} y_k\log p_k
$$
원-핫 정답이면 실제 정답 클래스의 음의 로그 확률만 남습니다.
PyTorch에서 주의할 점
nn.CrossEntropyLoss는 내부적으로 LogSoftmax + NLLLoss를 결합합니다.
- 입력: Softmax를 거치지 않은 로짓
[batch, classes, ...] - 정수 정답: 보통
torch.long, 형태[batch, ...] - 정답 값:
0부터C-1
Soft target이나 확률 분포 형태의 정답도 지원할 수 있지만, 정수 클래스 인덱스와 요구 shape가 다르므로 공식 문서를 확인해야 합니다.
Keras에서 주의할 점
- 원-핫 정답:
CategoricalCrossentropy - 정수 클래스 정답:
SparseCategoricalCrossentropy
4.4 클래스 가중치와 pos_weight
클래스 불균형이 있다고 해서 무조건 Focal Loss로 바꿀 필요는 없습니다. 먼저 가중 Cross-Entropy를 기준선으로 시도할 수 있습니다.
이진 분류의 단순한 가중 BCE는 다음처럼 표현할 수 있습니다.
$$
L=-\left[w_+y\log p+w_-(1-y)\log(1-p)\right]
$$
PyTorch BCEWithLogitsLoss(pos_weight=...)의 pos_weight는 양성 항의 기여도를 조절합니다. 음성 수 / 양성 수는 흔한 시작값이지만 최적값을 보장하지는 않습니다.
가중치를 정할 때는 다음을 함께 봐야 합니다.
- 실제 클래스 비율
- FP와 FN의 업무 비용
- 필요한 Recall 또는 Precision 수준
- 확률 보정 상태
- 샘플 중복과 라벨 노이즈
가중치를 크게 주면 소수 클래스 Recall이 오를 수 있지만 FP도 증가할 수 있습니다. 최종 결정은 검증 데이터의 운영 임계값에서 내려야 합니다.
4.5 Focal Loss: 쉬운 샘플의 영향은 줄이고 어려운 샘플에 집중
Focal Loss는 RetinaNet 논문에서 밀집 객체 탐지의 극단적인 전경·배경 불균형을 다루기 위해 제안되었습니다.
$$
FL(p_t)=-\alpha_t(1-p_t)^\gamma\log(p_t)
$$
- $p_t$: 정답 클래스에 할당한 확률
- $\gamma$: 쉬운 샘플을 얼마나 강하게 낮출지 결정하는 focusing parameter
- $\alpha_t$: 클래스 가중치
$\gamma=2$라고 하면 다음과 같습니다.
- 잘 맞힌 샘플 $p_t=0.9$: 조절 계수 $(1-0.9)^2=0.01$
- 어려운 샘플 $p_t=0.2$: 조절 계수 $(1-0.2)^2=0.64$
장점
- 매우 많은 쉬운 음성 샘플이 학습을 지배하는 상황에서 유용합니다.
- 어려운 샘플과 오분류 샘플에 더 큰 비중을 둡니다.
- 밀집 객체 탐지와 일부 희소 양성 분류 문제에서 효과적일 수 있습니다.
한계
- 어려운 샘플이 실제 정보가 아니라 잘못된 라벨이라면 노이즈에도 집중할 수 있습니다.
- $\alpha$와 $\gamma$ 튜닝이 필요합니다.
- 가중 BCE보다 확률 보정이 나빠질 수 있으므로 Calibration을 별도로 확인해야 합니다.
- 모든 객체 탐지 모델이나 모든 YOLO 구현이 동일한 Focal Loss를 사용하는 것은 아닙니다.
고정 비율 기준은 없다
“1:10이면 가중 CE, 1:100이면 Focal Loss” 같은 보편적인 경계는 없습니다. 같은 1:100 데이터라도 쉬운 음성이 대부분인지, 양성 라벨이 깨끗한지, 평가 지표가 무엇인지에 따라 결과가 달라집니다.
안전한 비교 순서는 다음과 같습니다.
- 일반 BCE/CE 기준선
- 클래스·샘플 가중치 적용
- 리샘플링 또는 Hard Negative Mining
- Focal Loss
- 선택한 운영 임계값에서 Precision·Recall·AUPRC와 Calibration 비교
4.6 Label Smoothing: 정답을 100% 확신하지 않게 만들기
원-핫 정답을 완전히 0과 1로 두지 않고 일부 확률을 다른 클래스에 나눕니다.
$$
y’_k=(1-\varepsilon)y_k+\frac{\varepsilon}{C}
$$
기대 효과
- 모델의 과도한 확신을 완화
- 일부 데이터에서 일반화 성능 개선
- 로짓이 무한히 벌어지는 경향 완화
주의점
- 라벨이 실제로 확실한 문제에서 지나치게 큰 smoothing은 클래스 구분력을 떨어뜨릴 수 있습니다.
- 예측 확률의 의미를 바꾸므로 보정 품질을 별도로 확인해야 합니다.
- 지식 증류나 거리 기반 표현 학습처럼 클래스 간 구조가 중요한 경우 목적에 맞는 soft target이 단순 균등 smoothing보다 나을 수 있습니다.
4.7 KL Divergence와 지식 증류
두 확률 분포 $P$와 $Q$의 차이를 나타내는 KL Divergence는 다음과 같습니다.
$$
D_{KL}(P|Q)=\sum_x P(x)\log\frac{P(x)}{Q(x)}
$$
KL은 대칭이 아닙니다.
$$
D_{KL}(P|Q)\neq D_{KL}(Q|P)
$$
다음과 같은 곳에서 사용됩니다.
- VAE의 잠재분포 정규화
- 교사 모델과 학생 모델의 분포 일치
- 정책 최적화에서 기준 정책과의 거리 제한
- 확률 분포 예측
PyTorch KLDivLoss는 입력을 로그 확률로 받는 방식과 reduction 정의에 주의해야 합니다. 수학적인 배치 평균 KL을 원하면 공식 문서가 권장하는 batchmean을 검토해야 합니다.
4.8 분류 손실 선택표
| 문제 | 출력 | 기본 손실 | 추가 검토 |
|---|---|---|---|
| 이진 분류 | 로짓 1개 | BCEWithLogits | pos_weight, Focal |
| 다중 클래스 | 클래스별 로짓 C개 | Cross-Entropy | class weight, label smoothing |
| 다중 레이블 | 클래스별 독립 로짓 C개 | BCEWithLogits | 클래스별 pos_weight |
| 소수 양성·쉬운 음성 다수 | 로짓 | Weighted BCE/CE | Focal, hard negative mining |
| 확률 분포 모사 | 분포 또는 로그 분포 | CE 또는 KL | temperature, reduction |
5. 세그멘테이션과 객체 탐지 손실
5.1 픽셀별 BCE·Cross-Entropy
세그멘테이션을 픽셀 단위 분류로 보면 기본 손실은 다음과 같습니다.
- 이진 세그멘테이션:
BCEWithLogitsLoss - 다중 클래스 세그멘테이션:
CrossEntropyLoss - 다중 레이블 세그멘테이션: 채널별 BCE
픽셀 손실은 지역적인 분류 신호가 강하고 학습이 안정적이지만, 배경이 대부분인 데이터에서는 작은 객체의 기여가 묻힐 수 있습니다.
5.2 Dice Loss: 영역의 겹침을 직접 최적화
Soft Dice Coefficient는 다음처럼 정의할 수 있습니다.
$$
Dice=\frac{2\sum_i p_i y_i+\epsilon}{\sum_i p_i+\sum_i y_i+\epsilon}
$$
$$
DiceLoss=1-Dice
$$
장점
- 전경과 배경의 크기 차이를 어느 정도 정규화합니다.
- 픽셀 정확도보다 영역 겹침을 직접 반영합니다.
- 의료 영상처럼 전경이 작은 세그멘테이션에서 널리 사용됩니다.
실전 주의점
- 빈 마스크: 정답과 예측에 전경이 모두 없는 샘플을 어떻게 처리할지 정해야 합니다.
- 평활화 상수 $\epsilon$: 0으로 나누는 문제와 빈 마스크의 점수에 영향을 줍니다.
- 집계 축: 이미지별 Dice, 배치 전체 Dice, 클래스별 Dice는 서로 다른 최적화 목표입니다.
- 작은 객체: 몇 픽셀 변화가 점수와 기울기를 크게 바꿀 수 있습니다.
- 확률 보정: Dice만 사용하면 픽셀 확률 자체의 보정이 좋지 않을 수 있습니다.
그래서 실무에서는 다음 조합이 흔합니다.
$$
L=\lambda_{BCE}L_{BCE}+\lambda_{Dice}L_{Dice}
$$
BCE는 픽셀별 안정적인 신호를, Dice는 영역 단위 겹침 신호를 제공합니다.
5.3 Tversky Loss: FP와 FN을 다르게 벌점
Tversky Index의 한 형태는 다음과 같습니다.
$$
TI=\frac{TP+\epsilon}{TP+\alpha FP+\beta FN+\epsilon}
$$
$$
TverskyLoss=1-TI
$$
- $\beta>\alpha$: FN을 더 강하게 벌점, Recall 중심
- $\alpha>\beta$: FP를 더 강하게 벌점, Precision 중심
의료 영상에서 종양을 놓치는 FN 비용이 큰 경우처럼 오류 비용이 비대칭일 때 유용합니다. 단, 논문과 라이브러리마다 $\alpha$, $\beta$ 표기 관례가 다를 수 있으므로 구현식을 직접 확인해야 합니다.
5.4 IoU·Lovász 계열 손실
세그멘테이션의 평가 지표가 IoU라면 Cross-Entropy 감소가 반드시 mIoU 증가로 바로 이어지지는 않습니다. Lovász-Softmax는 Jaccard/IoU의 미분 가능한 대리 손실을 구성해 이 간극을 줄이려는 방법입니다.
다만 metric-aligned loss가 항상 더 안정적인 것은 아닙니다. 학습 초반에는 픽셀 CE가 더 강한 신호를 줄 수 있어 CE+Lovász 같은 조합을 검토합니다.
5.5 객체 탐지는 하나의 손실로 끝나지 않는다
객체 탐지는 보통 다음 손실을 결합합니다.
$$
L_{total}=\lambda_{cls}L_{cls}+\lambda_{box}L_{box}+\lambda_{obj}L_{obj}+\cdots
$$
- 분류 손실: CE, BCE, Focal, Varifocal 등
- 객체 존재 여부: Objectness BCE 계열
- 박스 회귀: L1, Smooth L1, IoU, GIoU, DIoU, CIoU 등
- 분포 회귀: 일부 탐지기의 Distribution Focal Loss
IoU 손실은 예측 박스와 정답 박스가 겹치지 않으면 유용한 기울기가 제한될 수 있습니다. GIoU는 두 박스를 감싸는 최소 영역을 이용해 비중첩 상태에서도 학습 신호를 제공하도록 제안되었습니다.
“객체 탐지는 Focal Loss를 쓴다”처럼 하나로 일반화하지 말고 사용 중인 모델 버전의 실제 학습 코드와 논문을 확인해야 합니다.
6. 임베딩·생성 모델·LLM의 손실함수
6.1 Hinge Loss: 정답이 경계 밖에 있도록 만들기
이진 분류의 Hinge Loss는 다음과 같습니다.
$$
L=\max(0,1-yf(x)),\quad y\in{-1,+1}
$$
정답을 맞히는 것뿐 아니라 결정 경계에서 일정 마진 이상 떨어지게 합니다. 전통적인 SVM의 대표 손실이며, 신경망에서도 랭킹·마진 기반 목적에 변형해 사용할 수 있습니다.
6.2 Triplet Loss: Anchor가 Positive보다 Negative에 더 가깝지 않게
Anchor $a$, Positive $p$, Negative $n$에 대해 다음과 같습니다.
$$
L=\max\left(d(a,p)-d(a,n)+m,0\right)
$$
- 같은 클래스의 Anchor와 Positive는 가깝게
- 다른 클래스의 Negative는 멀게
- $m$: 최소 거리 차이인 마진
얼굴 인식, 이미지 검색, 상품 검색, 유사 문장 검색에 사용할 수 있습니다.
Triplet Loss의 성능은 손실 공식보다 어떤 triplet을 선택하는가에 크게 좌우됩니다. 너무 쉬운 Negative는 손실이 0이라 학습 신호가 없고, 지나치게 어려운 Negative는 라벨 오류나 초기 학습 불안정을 키울 수 있습니다. FaceNet은 semi-hard negative mining을 중요한 구성 요소로 다뤘습니다.
6.3 Contrastive Loss와 InfoNCE
대조학습은 같은 의미의 표현은 가깝게, 다른 표현은 멀게 학습합니다. InfoNCE는 한 Positive와 여러 Negative 사이에서 올바른 Positive를 구분하는 Cross-Entropy 형태로 볼 수 있습니다.
성능에 영향을 주는 핵심 요소는 다음과 같습니다.
- Positive pair를 만드는 데이터 증강
- Negative의 수와 품질
- 배치 크기 또는 메모리 뱅크
- Temperature
- false negative 문제
6.4 VAE: 재구성 손실과 KL 손실의 균형
VAE의 대표 목적은 다음 두 항으로 구성됩니다.
$$
L=L_{recon}+\beta D_{KL}\left(q_\phi(z|x)|p(z)\right)
$$
- 재구성 손실: 입력을 얼마나 잘 복원하는가
- KL 항: 잠재분포가 사전분포와 얼마나 가까운가
KL 비중이 너무 크면 잠재변수를 거의 사용하지 않는 Posterior Collapse가 생길 수 있고, 너무 작으면 잠재공간이 정돈되지 않을 수 있습니다. KL annealing, free bits, $\beta$-VAE 같은 방법은 이 균형을 조절합니다.
6.5 언어모델의 기본 손실: 다음 토큰 Cross-Entropy
자기회귀 언어모델은 앞 토큰이 주어졌을 때 다음 토큰의 음의 로그우도를 최소화합니다.
$$
L=-\frac{1}{T}\sum_{t=1}^{T}\log p_\theta(x_t|x_{
Perplexity는 평균 토큰 Cross-Entropy에 지수를 취한 값입니다.
$$
PPL=\exp(L)
$$
실전 주의점
- Padding 토큰은
ignore_index또는 attention mask로 손실에서 제외 - SFT에서 프롬프트 토큰까지 학습할지, 응답 토큰만 학습할지 명확히 결정
- 토크나이저가 다르면 Perplexity 직접 비교가 어려움
- 낮은 토큰 손실이 사실성·안전성·지시 이행을 보장하지 않음
6.6 DPO: 선호 답변과 비선호 답변의 상대 확률을 학습
Direct Preference Optimization은 동일한 프롬프트에 대한 선호 응답 $y_w$와 비선호 응답 $y_l$을 이용합니다. 정책 모델이 기준 모델보다 선호 응답의 상대 로그확률을 더 높이도록 로지스틱 분류 형태의 손실을 최적화합니다.
DPO는 별도 보상모델과 온라인 강화학습 없이 선호 데이터를 직접 사용할 수 있다는 장점이 있지만 다음에 민감합니다.
- 선호 데이터의 품질과 일관성
- 응답 길이 편향
- 기준 모델 선택
- $\beta$와 학습률
- 선호 기준의 다양성
LLM 학습에서 “손실이 낮다”는 말은 사전학습 CE, SFT CE, 보상모델 손실, DPO 손실 중 무엇을 뜻하는지 먼저 구분해야 합니다.
7. 출력층과 손실함수의 올바른 조합
| 문제 | 모델의 마지막 출력 | 정답 형태 | PyTorch 권장 손실 |
|---|---|---|---|
| 단일값 회귀 | 활성화 없는 실수 | float, 예측과 같은 shape | MSELoss, L1Loss, HuberLoss |
| 양수 회귀 | 로짓 후 softplus 등 | 양수 float | MSE 또는 NLL |
| 이진 분류 | 로짓 1개 | 0/1 float | BCEWithLogitsLoss |
| 다중 클래스 | 로짓 C개 | 클래스 인덱스 long | CrossEntropyLoss |
| 다중 레이블 | 독립 로짓 C개 | 0/1 벡터 float | BCEWithLogitsLoss |
| 이진 세그멘테이션 | [B,1,H,W] 로짓 | 같은 shape의 0/1 float | BCEWithLogits + Dice |
| 다중 클래스 세그멘테이션 | [B,C,H,W] 로짓 | [B,H,W] long | CrossEntropy + Dice/Lovász |
| 확률 분포 모사 | 로그 확률 또는 로짓 | 확률 분포 | CE 또는 KLDivLoss |
| 토큰 예측 | [B,T,V] 로짓 | [B,T] 토큰 ID long | CrossEntropy + mask |
가장 흔한 shape 오류
- 이진 분류 예측
[B,1], 정답[B] - 다중 클래스 CE에 정답을
float로 전달 - 다중 클래스 CE 전에 Softmax 적용
- BCEWithLogitsLoss 전에 Sigmoid 적용
- 세그멘테이션에서 채널 축과 클래스 축 혼동
- 브로드캐스팅으로 코드가 실행되지만 엉뚱한 손실 계산
손실을 계산하기 전에 logits.shape, targets.shape, targets.dtype, 값 범위를 출력하는 습관이 중요합니다.
8. PyTorch 실전 구현
8.1 회귀: MSE, Huber, Quantile Loss
from __future__ import annotations
import torch
from torch import Tensor, nn
def pinball_loss(
prediction: Tensor,
target: Tensor,
quantile: float,
) -> Tensor:
"""분위수 회귀를 위한 Pinball Loss."""
if not 0.0 < quantile < 1.0:
raise ValueError("quantile은 0과 1 사이여야 합니다.")
if prediction.shape != target.shape:
raise ValueError("prediction과 target의 shape가 같아야 합니다.")
error = target - prediction
loss = torch.maximum(quantile * error, (quantile - 1.0) * error)
return loss.mean()
y_pred = torch.tensor([2.5, 3.0, 1.8], dtype=torch.float32)
y_true = torch.tensor([3.0, 2.8, 2.1], dtype=torch.float32)
mse = nn.MSELoss()(y_pred, y_true)
huber = nn.HuberLoss(delta=1.0)(y_pred, y_true)
q90 = pinball_loss(y_pred, y_true, quantile=0.9)
print(f"MSE: {mse.item():.4f}")
print(f"Huber: {huber.item():.4f}")
print(f"Q90 Pinball: {q90.item():.4f}")실제 프로젝트에서는 타깃을 표준화한 뒤 Huber의 delta를 조정하고, 원래 단위의 MAE·RMSE를 별도로 계산하는 것이 좋습니다.
8.2 이진 분류: 로짓 기반 BCE와 pos_weight
from __future__ import annotations
import torch
from torch import nn
# Sigmoid를 적용하지 않은 모델 출력
logits = torch.tensor([2.2, -0.7, 0.4, -1.5], dtype=torch.float32)
targets = torch.tensor([1.0, 0.0, 1.0, 0.0], dtype=torch.float32)
# 예: 양성 샘플의 손실 기여도를 3배로 시작해 검증 데이터에서 조정
criterion = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([3.0]))
loss = criterion(logits, targets)
probabilities = torch.sigmoid(logits) # 추론·지표 계산 시에만 확률 변환
predictions = (probabilities >= 0.5).to(torch.int64)
print(f"Loss: {loss.item():.4f}")
print("Probabilities:", probabilities)
print("Predictions:", predictions)pos_weight로 학습한 뒤에도 운영 임계값을 무조건 0.5로 고정할 필요는 없습니다. 임계값은 검증 세트에서 실제 비용과 Precision·Recall 조건에 맞춰 선택합니다.
8.3 다중 클래스: CrossEntropyLoss
from __future__ import annotations
import torch
from torch import nn
# 4개 샘플, 3개 클래스의 로짓
logits = torch.tensor(
[
[2.1, 0.4, -1.0],
[0.2, 1.7, 0.3],
[-0.3, 0.1, 2.0],
[1.0, 0.9, 0.8],
],
dtype=torch.float32,
)
# 클래스 인덱스는 Long 타입
classes = torch.tensor([0, 1, 2, 1], dtype=torch.long)
criterion = nn.CrossEntropyLoss(
weight=torch.tensor([1.0, 2.0, 1.5]),
label_smoothing=0.05,
)
loss = criterion(logits, classes)
probabilities = torch.softmax(logits, dim=1)
predictions = probabilities.argmax(dim=1)
print(f"Loss: {loss.item():.4f}")
print("Predictions:", predictions)CrossEntropyLoss에 전달하기 전 softmax를 적용하지 않습니다.
8.4 수치적으로 안정적인 Binary Focal Loss
from __future__ import annotations
from typing import Literal
import torch
import torch.nn.functional as F
from torch import Tensor
Reduction = Literal["none", "mean", "sum"]
def binary_focal_loss_with_logits(
logits: Tensor,
targets: Tensor,
*,
alpha: float | None = 0.25,
gamma: float = 2.0,
reduction: Reduction = "mean",
) -> Tensor:
"""Sigmoid를 내부에서 처리하는 이진 Focal Loss."""
if logits.shape != targets.shape:
raise ValueError("logits와 targets의 shape가 같아야 합니다.")
if gamma < 0:
raise ValueError("gamma는 0 이상이어야 합니다.")
if alpha is not None and not 0.0 <= alpha <= 1.0:
raise ValueError("alpha는 0과 1 사이이거나 None이어야 합니다.")
targets = targets.to(dtype=logits.dtype)
bce = F.binary_cross_entropy_with_logits(
logits,
targets,
reduction="none",
)
probabilities = torch.sigmoid(logits)
p_t = probabilities * targets + (1.0 - probabilities) * (1.0 - targets)
modulating_factor = (1.0 - p_t).pow(gamma)
loss = modulating_factor * bce
if alpha is not None:
alpha_t = alpha * targets + (1.0 - alpha) * (1.0 - targets)
loss = alpha_t * loss
if reduction == "mean":
return loss.mean()
if reduction == "sum":
return loss.sum()
if reduction == "none":
return loss
raise ValueError(f"지원하지 않는 reduction: {reduction}")직접 구현하기 전에 torchvision.ops.sigmoid_focal_loss처럼 검증된 구현이 현재 환경에 있는지 확인하는 것이 좋습니다.
8.5 BCE와 Dice를 결합한 이진 세그멘테이션 손실
from __future__ import annotations
import torch
import torch.nn.functional as F
from torch import Tensor
def soft_dice_loss(
logits: Tensor,
targets: Tensor,
*,
epsilon: float = 1e-6,
) -> Tensor:
if logits.shape != targets.shape:
raise ValueError("logits와 targets의 shape가 같아야 합니다.")
targets = targets.to(dtype=logits.dtype)
probabilities = torch.sigmoid(logits)
# 배치 축을 제외한 모든 축을 합산: [B, 1, H, W] -> 샘플별 Dice
reduce_dims = tuple(range(1, logits.ndim))
intersection = (probabilities * targets).sum(dim=reduce_dims)
denominator = probabilities.sum(dim=reduce_dims) + targets.sum(dim=reduce_dims)
dice = (2.0 * intersection + epsilon) / (denominator + epsilon)
return 1.0 - dice.mean()
def bce_dice_loss(
logits: Tensor,
targets: Tensor,
*,
bce_weight: float = 0.5,
dice_weight: float = 0.5,
) -> Tensor:
if bce_weight < 0 or dice_weight < 0:
raise ValueError("손실 가중치는 0 이상이어야 합니다.")
if bce_weight + dice_weight == 0:
raise ValueError("손실 가중치 합은 0보다 커야 합니다.")
targets = targets.to(dtype=logits.dtype)
bce = F.binary_cross_entropy_with_logits(logits, targets)
dice = soft_dice_loss(logits, targets)
return bce_weight * bce + dice_weight * dice빈 마스크를 포함하는 데이터셋에서는 빈 정답 샘플을 별도로 집계할지, 배경 정확도를 어떤 방식으로 반영할지 검증해야 합니다.
9. TensorFlow/Keras 구현 시 핵심
TensorFlow/Keras에서도 가장 중요한 원칙은 모델 출력이 로짓인지 확률인지와 from_logits를 일치시키는 것입니다.
import tensorflow as tf
# 이진 분류: 마지막 Dense에 activation을 두지 않은 경우
binary_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)
# 다중 클래스, 원-핫 정답
categorical_loss = tf.keras.losses.CategoricalCrossentropy(
from_logits=True,
label_smoothing=0.05,
)
# 다중 클래스, 정수 클래스 정답
sparse_loss = tf.keras.losses.SparseCategoricalCrossentropy(
from_logits=True,
)
# 회귀
huber_loss = tf.keras.losses.Huber(delta=1.0)반대로 마지막 층에 activation="sigmoid" 또는 activation="softmax"를 넣었다면 from_logits=False를 사용합니다. 두 방식을 섞으면 손실값과 기울기가 잘못됩니다.
커스텀 손실에서는 다음을 점검합니다.
tf.clip_by_value로 로그 입력 안정화- 배치·픽셀 축의 reduction 확인
sample_weight와 mask의 적용 순서- mixed precision에서 작은 상수의 dtype
- 분산 학습 시 전역 배치 기준 평균 방식
10. 여러 손실을 조합할 때 생기는 문제
멀티태스크 모델과 객체 탐지·세그멘테이션 모델은 여러 손실을 합칩니다.
$$
L=\lambda_1L_1+\lambda_2L_2+\cdots+\lambda_kL_k
$$
단순히 모두 1로 두면 한 손실이 숫자 규모나 기울기 규모 때문에 전체 학습을 지배할 수 있습니다.
예를 들어:
- 분류 CE: 약 0.5
- 박스 L1 합: 약 30
- 정규화 손실: 약 0.001
이 경우 숫자가 큰 박스 손실이 반드시 더 중요한 것은 아닙니다. 중요한 것은 각 항이 공유 파라미터에 만드는 기울기입니다.
실전 점검법
- 각 손실 항을 따로 로그로 기록
- 손실의 평균뿐 아니라 분산과 최대값 확인
- 가중치 변경 시 주요 평가지표의 trade-off 관찰
- 특정 항이 0에 고정되거나 폭발하는지 확인
- 가능하면 태스크별 gradient norm 비교
가중치 조정 방법으로는 수동 튜닝, 불확실성 기반 가중, GradNorm 같은 방법이 있지만 먼저 단순한 고정 가중치와 명확한 검증 지표로 기준선을 만드는 것이 좋습니다.
11. 손실 곡선으로 학습 상태 진단하기
11.1 Train Loss는 내려가고 Validation Loss는 오른다
과적합 가능성이 큽니다.
확인할 항목:
- 데이터 누수 없이 분리되었는가
- 증강이 학습 데이터에만 적용되는가
- 모델 용량이 지나치게 큰가
- 정규화·가중치 감쇠·Dropout이 필요한가
- Early Stopping 시점이 적절한가
- 학습·검증 분포가 다른가
11.2 Train과 Validation Loss가 모두 거의 내려가지 않는다
단순히 “과소적합이므로 모델을 키운다”로 결론 내리면 안 됩니다.
가능한 원인:
- 학습률이 너무 작거나 너무 큼
- 입력·정답 shape 오류
- 이진 CE에 Softmax 사용 등 손실 조합 오류
- 라벨 인덱스 범위 오류
- 모델 출력이 상수로 붕괴
- 정규화가 지나치게 강함
- 데이터 자체에 예측 신호가 부족
- 잘못된 mask로 모든 손실이 제외됨
11.3 Loss가 NaN 또는 Inf가 된다
다음을 순서대로 확인합니다.
- 입력과 라벨에 NaN·Inf가 있는가
- 직접 구현한
log(p)에서 $p=0$이 되는가 - 분모가 0이 되는 Dice·IoU 계산이 있는가
- 학습률이 너무 큰가
- 기울기 폭발이 있는가
- mixed precision overflow가 있는가
- 분산·표준편차·정규화 계산에 하한값이 있는가
로짓 기반 공식 손실, gradient clipping, 안정적인 logsumexp, 적절한 epsilon을 우선 사용합니다.
11.4 Loss는 내려가는데 F1·mAP가 오르지 않는다
손실과 평가지표의 불일치일 수 있습니다.
- CE는 확률 분포 전체를 개선하지만 현재 임계값의 F1은 변하지 않을 수 있음
- 박스 L1은 줄지만 IoU 임계값을 넘지 못할 수 있음
- 토큰 CE는 줄지만 생성 품질·사실성은 개선되지 않을 수 있음
- 다수 클래스 손실 감소가 소수 클래스 실패를 가릴 수 있음
해결 방법:
- 임계값을 검증 데이터에서 재선택
- 클래스·구간별 지표 확인
- metric-aligned surrogate loss 검토
- 손실의 샘플·클래스별 분포 확인
- 실제 실패 사례를 직접 검토
12. 손실함수 선택 절차
1단계. 모델이 무엇을 출력해야 하는지 정의한다
- 평균값인가
- 중앙값인가
- 특정 분위수인가
- 클래스 확률인가
- 여러 독립 레이블인가
- 영역이나 박스인가
- 임베딩 거리인가
- 전체 확률 분포인가
2단계. 가장 단순한 기준 손실로 시작한다
- 일반 회귀: MSE 또는 Huber
- 이진·다중 레이블: BCEWithLogits
- 다중 클래스: Cross-Entropy
- 이진 세그멘테이션: BCE
- 언어모델: Token Cross-Entropy
3단계. 오류 비용과 데이터 문제를 파악한다
- 큰 오차가 특히 위험한가
- 과소 예측과 과대 예측 비용이 다른가
- 클래스 불균형이 있는가
- 라벨 노이즈가 있는가
- 작은 객체가 중요한가
- 빈 마스크가 많은가
4단계. 손실과 출력층 조합을 검증한다
로짓·확률, dtype, shape, reduction, mask를 확인합니다.
5단계. 손실이 아닌 실제 지표로 모델을 비교한다
- 회귀: MAE, RMSE, MASE, Coverage
- 분류: AUPRC, Recall, Precision, MCC, Calibration
- 세그멘테이션: Dice, IoU, 클래스별 성능
- 탐지: AP, AR, 크기별 AP
- LLM: 태스크 성공률, 사실성, 선호도, 안전성
6단계. 실패 사례별로 손실을 바꾼다
- 이상치가 업데이트를 지배: Huber 또는 MAE
- FN 비용이 큼: 가중 BCE, Tversky, 임계값 조정
- 쉬운 음성이 너무 많음: Focal 또는 hard negative mining
- IoU와 CE의 간극: Dice·Lovász·IoU 계열 조합
- 불확실성 필요: Quantile 또는 NLL
7단계. Ablation으로 효과를 확인한다
손실만 바꾸고 다른 조건을 최대한 고정한 비교가 필요합니다.
- 동일 데이터 분할
- 동일 초기화 또는 여러 seed
- 동일 학습 예산
- 동일 임계값 선택 절차
- 평균과 분산 또는 신뢰구간 보고
13. 자주 발생하는 실수 15가지
실수 1. BCEWithLogitsLoss 전에 Sigmoid를 적용한다
Sigmoid가 두 번 적용되어 기울기와 손실이 왜곡됩니다.
실수 2. CrossEntropyLoss 전에 Softmax를 적용한다
CrossEntropyLoss는 내부에서 LogSoftmax를 처리합니다.
실수 3. 다중 클래스와 다중 레이블을 혼동한다
서로 배타적인 클래스는 Softmax+CE, 동시에 여러 클래스가 가능한 문제는 Sigmoid+BCE가 기본입니다.
실수 4. 정답 dtype과 shape를 확인하지 않는다
PyTorch 다중 클래스 CE의 정수 라벨은 일반적으로 long이어야 합니다.
실수 5. 불균형 비율만 보고 Focal Loss를 선택한다
양성 난이도, 라벨 노이즈, 평가 지표, 운영 임계값을 함께 봐야 합니다.
실수 6. Huber의 δ 방향을 반대로 이해한다
작은 δ는 더 빨리 선형 구간으로 들어가 큰 잔차의 기울기를 더 강하게 제한합니다.
실수 7. 타깃 스케일 없이 Huber δ를 복사한다
delta=1은 타깃 단위에 따라 전혀 다른 의미입니다.
실수 8. 손실값 크기로 모델을 직접 비교한다
reduction, 가중치, 정규화, 배치 크기가 다르면 숫자 크기는 비교 불가능합니다.
실수 9. sum과 mean 차이를 무시한다
배치 크기와 해상도 변화가 기울기 크기를 바꿀 수 있습니다.
실수 10. Dice Loss 하나면 불균형이 해결된다고 믿는다
빈 마스크, 작은 객체, 클래스별 집계 방식과 라벨 노이즈를 따로 확인해야 합니다.
실수 11. 학습 손실만 보고 모델을 선택한다
검증 지표와 실제 운영 비용이 최종 기준입니다.
실수 12. 검증 데이터에서 손실 가중치와 임계값을 무한 반복 튜닝한다
검증 세트에도 과적합할 수 있습니다. 최종 테스트 세트는 마지막에 고정된 절차로 평가합니다.
실수 13. 여러 손실을 합하면서 각 항의 규모를 기록하지 않는다
한 항이 전체 학습을 지배하거나 사실상 무시될 수 있습니다.
실수 14. 패딩·미정 라벨을 손실에 포함한다
NLP의 padding, 세그멘테이션의 ignore class, 부분 라벨을 mask로 제외해야 합니다.
실수 15. 학습 데이터의 실제 실패 비용을 반영하지 않는다
FP와 FN 비용이 다르다면 가중치·임계값·평가 지표를 함께 설계해야 합니다.
14. 자주 묻는 질문
Q1. 회귀 문제에서 Cross-Entropy를 사용하면 안 되나요?
일반적인 연속값 하나를 그대로 예측하는 회귀에는 MSE, MAE, Huber, Quantile, NLL이 더 자연스럽습니다. 그러나 “절대 사용할 수 없다”는 표현은 과도합니다.
예외적으로 다음 방식이 가능합니다.
- 연속값을 구간으로 나눈 분류형 회귀
- 순서형 회귀(Ordinal Regression)
- 연속분포를 여러 bin의 확률분포로 예측
- Distributional Regression
이 경우 Cross-Entropy는 숫자 자체가 아니라 구간 또는 확률분포를 학습합니다.
Q2. 가중 Cross-Entropy와 Focal Loss 중 무엇이 더 좋나요?
보편적인 정답이나 고정 불균형 비율 기준은 없습니다.
- 소수 클래스 전체를 일정하게 강조: 가중 CE/BCE
- 쉬운 샘플의 영향은 줄이고 어려운 샘플에 집중: Focal
- 라벨 노이즈가 많음: Focal이 오히려 노이즈에 집중할 수 있음
- 확률이 중요함: 보정 지표까지 비교
동일한 데이터 분할과 학습 예산으로 두 방식을 비교해야 합니다.
Q3. Huber Loss의 δ는 어떻게 정하나요?
타깃을 먼저 스케일링한 뒤 1.0을 기준선으로 시작할 수 있습니다.
- 더 작은 δ: MAE에 가까운 구간이 넓어져 큰 오차 영향 제한
- 더 큰 δ: MSE처럼 동작하는 구간 확대
검증 MAE·RMSE뿐 아니라 잔차 히스토그램과 극단값 성능을 함께 확인합니다.
Q4. 손실함수를 학습 중간에 바꿔도 되나요?
가능하며 목적이 명확하면 유용할 수 있습니다.
- 학습 초반 CE, 후반 metric-aligned loss 추가
- KL warm-up 또는 annealing
- 멀티태스크 손실 가중치 스케줄
- 커리큘럼 학습
다만 바꾸는 시점과 이유를 실험 설정에 기록해야 하며, 단순히 손실 곡선이 마음에 들지 않는다는 이유로 임의 변경하면 비교가 어려워집니다.
Q5. 여러 손실함수를 동시에 사용해도 되나요?
가능합니다. 객체 탐지, 세그멘테이션, VAE, 멀티태스크 모델에서는 일반적입니다. 다만 가중치와 기울기 규모를 모니터링해야 합니다.
Q6. Validation Loss가 가장 낮은 모델이 항상 가장 좋은 모델인가요?
아닙니다. Validation Loss는 학습 목적에 대한 성능이고, 실제 선택 기준은 F1, mAP, Recall, Calibration, 비용 등일 수 있습니다.
예를 들어 CE가 더 낮은 모델이 확률 분포는 더 좋지만 0.5 임계값의 F1은 낮을 수 있습니다. 임계값 선택과 목표 지표를 함께 봐야 합니다.
Q7. 손실함수는 항상 0 이상이어야 하나요?
MSE, BCE, CE, KL처럼 흔한 손실은 보통 0 이상이지만 모든 최적화 목적이 반드시 그렇지는 않습니다. 로그우도, ELBO, 보상 최대화 목적을 부호 반전하거나 상수를 더한 구현에서는 음수가 나올 수 있습니다. 중요한 것은 절댓값보다 정의와 감소 방향입니다.
Q8. 학습 손실이 0에 가까우면 완벽한 모델인가요?
아닙니다. 학습 데이터 암기, 데이터 누수, 잘못된 mask, 쉬운 데이터만 포함된 경우에도 학습 손실은 매우 낮을 수 있습니다. 독립된 검증·테스트 데이터와 실제 실패 사례로 확인해야 합니다.
15. 결론: 손실함수는 문제의 실패 비용을 수학으로 번역한 것이다
손실함수에 만능 정답은 없습니다.
- MSE는 큰 오차에 강한 벌점을 줍니다.
- MAE는 큰 잔차의 영향력을 제한합니다.
- Huber는 두 방식의 전환점을 조절합니다.
- Quantile Loss는 과소·과대 예측 비용의 비대칭을 반영합니다.
- BCE와 Cross-Entropy는 확률적 분류의 기본 손실입니다.
- 가중 손실은 특정 클래스의 오류 비용을 높입니다.
- Focal Loss는 쉬운 샘플보다 어려운 샘플에 집중합니다.
- Dice와 IoU 계열은 영역 겹침과 평가 지표의 간극을 줄입니다.
- Triplet과 InfoNCE는 표현 공간의 거리를 학습합니다.
- KL, VAE, Token CE, DPO는 생성 모델과 LLM의 서로 다른 학습 목표를 정의합니다.
손실함수를 고를 때 가장 먼저 물어야 할 질문은 “어떤 함수가 유명한가?”가 아닙니다.
우리 모델이 어떤 실수를 했을 때 가장 큰 비용이 발생하는가?
이 질문을 데이터 분포, 출력 형태, 평가지표, 운영 제약과 함께 수학적으로 표현한 것이 좋은 손실함수입니다.
참고 자료
공식 문서
- PyTorch, Loss Functions
- PyTorch,
BCEWithLogitsLoss - PyTorch,
CrossEntropyLoss - PyTorch,
HuberLoss - PyTorch,
KLDivLoss - PyTorch,
GaussianNLLLoss - PyTorch,
PoissonNLLLoss - TensorFlow/Keras Losses
- TensorFlow,
BinaryCrossentropy - TensorFlow,
CategoricalCrossentropy - TensorFlow,
SparseCategoricalCrossentropy
주요 논문
- Huber, P. J. (1964), Robust Estimation of a Location Parameter
- Lin et al. (2017), Focal Loss for Dense Object Detection
- Milletari et al. (2016), V-Net: Fully Convolutional Neural Networks for Volumetric Medical Image Segmentation
- Szegedy et al. (2015), Rethinking the Inception Architecture for Computer Vision
- Schroff et al. (2015), FaceNet: A Unified Embedding for Face Recognition and Clustering
- van den Oord et al. (2018), Representation Learning with Contrastive Predictive Coding
- Berman et al. (2017), The Lovász-Softmax Loss
- Rezatofighi et al. (2019), Generalized Intersection over Union
- Rafailov et al. (2023), Direct Preference Optimization

2 Comments