02. 분류 손실로서의 cross-entropy — softmax · sigmoid · BCE · $p_t$ 통합
Contents
- 2.1 모델 출력을 확률로 — softmax와 sigmoid
- softmax — 여러 로짓을 상호배타 확률분포로
- sigmoid — 단일 로짓을 양성 확률로
- sigmoid = 2-클래스 softmax (특수화 증명)
- 2.2 categorical cross-entropy — 다중 클래스, 단일 정답
- one-hot 라벨과 정의
- one-hot에서 한 항으로 환원
- 수치예제 — 3클래스 로짓
- 2.3 binary cross-entropy (BCE)와 베르누이 우도
- BCE 정의
- 유도 — 베르누이 우도의 음로그
- 로 통합 — 두 경우를 한 줄로
- easy/hard 직관과 곡선
- 수치예제 — BCE 표
- 2.4 multi-class vs multi-label — softmax-CE냐 sigmoid-BCE냐
- 두 문제 유형
- multi-label 수치예제
- 2.5 프레임워크 관례 — PyTorch가 실제로 하는 일
- CrossEntropyLoss: 로짓 + 정수라벨 → 내부 log-softmax + NLL
- BCEWithLogitsLoss: 로짓 → 내부 sigmoid + BCE
- 라벨 표현 정리
- 2.6 흔한 오개념 — 하지 말 것
- 출처
01장은 cross-entropy를 정의할 때 가 이미 확률분포라고 가정했다. 그런데 실제 모델은 확률이 아니라 raw 점수(로짓 )를 낸다. 이 장은 그 빠진 고리, 곧 로짓에서 확률을 거쳐 cross-entropy 숫자까지 가는 계산 파이프라인을 끝까지 판다.
분류 한 번의 흐름은 항상 같은 4단계다.
입력에서 손실까지, 로짓과 확률을 거치는 분류 한 번의 흐름.
핵심 용어를 정해 두자(00장 §0.6 기호표의 호명).
- 로짓(logit) : 네트워크의 마지막 선형층 출력이다. softmax/sigmoid를 통과하기 전의 raw 점수다. 부호 제한도 합 제한도 없어 어떤 실수든 가능하다. "로짓"은 어원상 로지스틱의 역함수 를 뜻한다. 딥러닝에서는 "확률화 직전의 raw 점수"라는 넓은 뜻으로 쓴다.
- 확률 (이진에서는 ): 로짓을 softmax/sigmoid로 0~1 범위로 짠 값이다.
- 라벨 : 정답이다. 다중 클래스는 정수 인덱스나 one-hot 벡터, 이진은 0/1이다.
- 손실 : 그 샘플에 대한 cross-entropy 한 숫자다.
이제 "로짓 → 확률" 변환기 두 개를 차례로 본다.
2.1 모델 출력을 확률로 — softmax와 sigmoid
softmax — 여러 로짓을 상호배타 확률분포로
개 클래스의 로짓 벡터 에 대해
이 출력 벡터 는 확률분포의 두 조건을 항상 만족한다. 하나씩 풀어쓰자.
성질 1 — 모두 양수. 분자 이고 분모도 양수들의 합이다. 따라서 어떤 든 0보다 크다. 로짓이 음수여도 가 양수로 보내준다.
성질 2 — 합이 1. 분모가 모든 분자의 합이므로
성질 1과 2를 합치면 는 진짜 확률분포다. 01장의 cross-entropy에 그대로 넣을 수 있다.
성질 3 — 순서 보존(단조). . 로짓이 큰 클래스가 확률도 크다. 가장 큰 로짓이 가장 확률 높은 예측이다(argmax 일치).
성질 4 — 평행이동 불변(translation invariance). 모든 로짓에 같은 상수 를 더해도 출력이 안 바뀐다.
가 분자와 분모에서 약분된다. 실제 구현은 이 성질을 활용한다. 를 빼서 를 계산하면 큰 의 overflow를 막는다(safe softmax). 값은 같고 수치만 안전하다. 수치안정 상세는 04장 §4.1에서 다룬다.
⚠️ 불변은 평행이동에만. 모든 로짓에 같은 수를 곱하면(scaling) 결과가 바뀐다. 이게 다음 온도 이야기다.
성질 5 — 온도(temperature) . 로 쓰면 가 작을수록 가장 큰 로짓에 확률이 쏠린다(sharp, 저엔트로피). 가 클수록 고르게 퍼진다(uniform, 고엔트로피). 이 표준 softmax다. 온도는 distillation·calibration에서 중요하지만 깊은 다룸은 이 책 범위 밖이다.
왜 하필 지수 인가. 두 가지를 동시에 해결한다.
- 양수화. 로짓은 음수일 수 있지만 확률은 음수면 안 된다. 는 어떤 실수든 양수로 보낸다(단조 증가).
- 상대 강조(부드러운 max). 지수는 큰 값을 불균형하게 키워 1등 로짓에 확률을 더 몰아준다. 그래서 "soft한 argmax", 곧 soft-max다. 그냥 로 정규화하면 음수·0합 문제가 생기고 강조 효과도 없다.
더 깊은 이유 하나는 03장에서 드러난다. softmax와 CE를 합치면 로그가 지수를 상쇄해 gradient가 깔끔한 가 된다. Goodfellow et al.은 "음의 로그우도의 log가 softmax의 exp를 되돌린다(undoes)"고 표현한다.
sigmoid — 단일 로짓을 양성 확률로
이진 분류는 클래스가 둘(양성=1, 음성=0)뿐이다. 그래서 로짓 하나 만 내고 양성일 확률 를 sigmoid(로지스틱 함수)로 짠다.
여기서 는 00장 §0.6에서 정한 예측 양성확률이다. 01장의 진짜 분포 와는 다른 양이다(예측 측 대 정답 측). 이 장부터 이진의 예측 확률은 일관되게 로 쓴다.
- 면 (양성 확신), 면 (음성 확신), 이면 (반반)다.
- 라는 대칭이 곧 "음성 확률"을 준다.
sigmoid = 2-클래스 softmax (특수화 증명)
sigmoid는 새 함수가 아니라 softmax의 특수경우다. 클래스 0의 로짓을 , 클래스 1을 이라 하면 클래스 1의 softmax 확률은
분자·분모를 로 나눈다. 평행이동 불변으로 을 잡아도 같다(즉 ).
두 로짓의 차 하나면 충분하다. 그게 sigmoid의 입력이다. 그래서 이진 분류는 로짓을 1개만 둔다(2개가 아니다).
sigmoid는 클래스가 둘일 때의 softmax로 환원된다.
수치 확인: 과 이 정확히 일치한다.
2.2 categorical cross-entropy — 다중 클래스, 단일 정답
one-hot 라벨과 정의
클래스가 개이고 정답이 정확히 하나(클래스 )인 상황이다. 라벨을 one-hot 벡터 로 쓴다(§0.4). 정답 자리만 1, 나머지는 0이다.
예측은 다. categorical cross-entropy는
one-hot에서 한 항으로 환원
가 one-hot이라 이고 나머지 이다. 그래서 합에서 정답 항만 살아남는다.
01장과의 한 줄 연결. 일반 cross-entropy는 였다(01장 §1.4). 라벨 분포 가 one-hot이면(정답에 전 확률 몰빵) 로 정확히 위 식이 된다. 즉 "분류 CE = 정답 분포가 one-hot인 cross-entropy"다. 01장의 그 특수화가 여기서 softmax 출력 로 구체화됐다.
그래서 실전 categorical CE는 "정답 클래스에 모델이 준 확률의 음로그" 한 줄로 끝난다. softmax를 직접 끼워 넣으면
오른쪽 형태는 정답 로짓을 빼고 log-sum-exp를 더한 꼴이다. 바로 PyTorch가 내부에서 계산하는 모양이다(§2.5). 둘째 항 가 그 악명 높은 log-sum-exp다. 수치안정 처리는 04장 §4.1에서 본다.
softmax로 확률을 만든 뒤 정답 자리 만 골라 음로그를 취한다.
수치예제 — 3클래스 로짓
이 예제는 이 책의 주 예제(running example)다. 03장 gradient와 05장 walkthrough가 같은 숫자를 이어받는다.
1단계: softmax. overflow 방지로 을 빼고 지수를 취한다(성질 4).
| 0 | 2.0 | 0.659001 | |
| 1 | 1.0 | 0.242433 | |
| 2 | 0.1 | 0.098566 | |
| 합 | ✓ |
2단계: 정답에 따른 CE. .
| 정답 클래스 | 해석 | ||
|---|---|---|---|
| 0 (로짓 최대) | 0.659001 | 0.417030 | 잘 맞힘 → 작은 손실 (easy) |
| 1 (중간) | 0.242433 | 1.417030 | 애매 → 중간 손실 |
| 2 (로짓 최소) | 0.098566 | 2.317030 | 거의 못 맞힘 → 큰 손실 (hard) |
읽는 법은 이렇다. 정답이 모델이 자신 없어 한 클래스(2번)일수록 CE가 크다. 같은 로짓, 같은 예측이라도 정답이 무엇이냐에 따라 손실이 다르다. CE는 "정답에 준 확률"만 보기 때문이다.
🔎 우아한 패턴. 세 CE 값 0.417, 1.417, 2.317의 차이가 정확히 로짓 차이(2.0−1.0=1.0, 1.0−0.1=0.9)와 같다. 왜일까. 에서 둘째 항은 정답과 무관한 상수다(). 정답을 바꾸면 CE는 딱 만큼만 평행이동한다.
2.3 binary cross-entropy (BCE)와 베르누이 우도
BCE 정의
이진 분류에서 라벨은 , 모델의 양성 확률은 다. binary cross-entropy는
이건 사실 one-hot CE를 푼 것과 같다. one-hot이 , 확률이 이므로 가 되어 위 식 그대로다.
유도 — 베르누이 우도의 음로그
BCE는 그냥 던져진 식이 아니다. 최대우도추정(MLE)에서 자연히 떨어진다(01장 §1.6의 이진 버전). 양성 확률 인 베르누이 분포에서 라벨 를 관측할 확률(우도)은
지수 와 가 스위치 역할을 해 한 식으로 두 경우를 표현한다. 음의 로그우도를 취하면
즉 BCE를 최소화하는 일이 베르누이 우도를 최대화하는 일이다.
로 통합 — 두 경우를 한 줄로
라벨에 따라 항이 갈리는 게 거추장스럽다. 정답 클래스에 모델이 준 확률 를 정의한다(00장 §0.5의 그 ).
그러면 일 때 둘째 항이 0이라 다. 일 때 첫째 항이 0이라 다. 두 경우 모두
categorical의 와 같은 골격이다(와 둘 다 "정답에 준 확률"). 다중클래스든 이진이든 cross-entropy는 결국 "정답에 준 확률의 음로그"다.
easy/hard 직관과 곡선
를 의 함수로 보자.
정답에 확신할수록 손실이 0으로, 정답을 의심할수록 손실이 무한대로 간다.
- 이면 손실 0이다. 완벽히 맞힌 것이다.
- 면 이다. 반반(찍기)이다.
- 이면 손실이 로 간다. 정답을 강하게 부정하니 가장 큰 벌점이다.
가 클수록 easy, 작을수록 hard다. 단, easy 샘플()도 손실이 정확히 0은 아니다().
Focal Loss로 가는 다리. 위에서 본 "0이 아닌 잔여 손실"이 easy 샘플 수천 개에 쌓이면 학습을 지배할 수 있다. 이를 고치려고 CE에 변조항 를 곱한 것이 Focal Loss 다. 잘 맞히는 쉬운 샘플의 손실을 깎고 어려운 샘플에 집중하는 CE의 확장이다. 이 책은 이 다리만 놓는다(04장 §4.3에서 한 번 더). 깊은 유도는 별도 주제로 안내한다.
수치예제 — BCE 표
. 두 식이 모든 행에서 일치한다.
| 해석 | ||||
|---|---|---|---|---|
| 1 | 0.90 | 0.90 | 0.105361 | 양성을 양성으로 확신 → easy |
| 1 | 0.50 | 0.50 | 0.693147 | 반반 → 찍기 수준 |
| 1 | 0.30 | 0.30 | 1.203973 | 양성인데 음성 쪽으로 기움 → hard |
| 1 | 0.10 | 0.10 | 2.302585 | 양성을 강하게 부정 → 매우 hard |
| 0 | 0.10 | 0.90 | 0.105361 | 음성을 음성으로 확신 → easy |
| 0 | 0.20 | 0.80 | 0.223144 | 음성에 약간 confidence ↓ |
| 0 | 0.80 | 0.20 | 1.609438 | 음성인데 양성으로 오판 → hard |
대칭에 주목하자. 와 은 둘 다 라 같은 손실 0.105다. CE는 "정답에 준 확률"만 보므로 라벨이 뭐든 가 같으면 손실이 같다.
2.4 multi-class vs multi-label — softmax-CE냐 sigmoid-BCE냐
두 문제 유형
| 구분 | multi-class (단일 라벨) | multi-label (다중 라벨) |
|---|---|---|
| 질문 | "이 중 하나는 무엇?" | "각 속성이 있나/없나?" |
| 라벨 | 정확히 한 클래스가 정답 (상호배타) | 여러 클래스가 동시에 참 가능 (독립) |
| 예 | 개 vs 고양이 vs 새 (사진 1장에 1동물) | 사진 속성: {야외?, 사람있나?, 밤인가?} 동시 가능 |
| 출력층 | 로짓 개 → softmax (합=1) | 로짓 개 → 클래스마다 독립 sigmoid |
| 손실 | categorical CE | 클래스마다 BCE 합/평균 |
| 확률 제약 | (한 클래스↑면 다른 건↓) | 각 독립, 합 제약 없음 |
핵심 차이는 상호배타성이다. softmax는 분모를 공유해 클래스끼리 확률을 경쟁시킨다(하나 오르면 다른 게 내림). 정답이 하나일 때 옳다. sigmoid-per-class는 각 채널이 독립이다. 그래서 "야외이면서 동시에 밤"처럼 여러 라벨이 같이 참일 수 있다.
정답이 하나뿐인지가 softmax-CE와 sigmoid-BCE를 가르는 갈림길이다.
규칙은 한 줄이다. 정답이 정확히 하나면 softmax-CE, 여러 라벨이 동시에 가능하면 클래스별 sigmoid-BCE다.
실전 한 줄. 멀티태스크 모델(예: 운전자 모니터링)은 태스크마다 출력 형태가 다르다. 졸음 3단계(정상/경미/심각)처럼 상호배타 분류는 softmax+CE를 쓴다. "안경 착용? 마스크 착용? 흡연 중?"처럼 동시에 참일 수 있는 다중 속성은 클래스별 sigmoid+BCE를 쓴다. 한 모델이 두 손실을 태스크별로 섞어 쓰는 게 정상이다.
multi-label 수치예제
3개 독립 속성, 로짓 , 라벨 이다. 각 채널을 sigmoid에 통과시킨 뒤 BCE를 구한다.
| 채널 | |||||
|---|---|---|---|---|---|
| 0 | 2.197 | 0.9000 | 1 | 0.9000 | 0.105383 |
| 1 | −1.386 | 0.2000 | 0 | 0.8000 | 0.223202 |
| 2 | 0.847 | 0.6999 | 1 | 0.6999 | 0.356764 |
| 평균 | 0.228450 |
multi-class와 달리 로짓 사이에 분모 공유가 없다. 채널 0의 큰 로짓이 채널 1·2 확률에 전혀 영향을 주지 않는다(독립). 그래서 "둘 다 참"을 표현할 수 있다.
2.5 프레임워크 관례 — PyTorch가 실제로 하는 일
이론을 코드로 옮길 때 가장 많이 깨지는 지점이다. 그래서 왜 프레임워크가 로짓을 직접 받는지 짚고 간다. 한 줄 직관은 이렇다. 확률을 거치지 않고 로짓에서 바로 손실을 계산하면 수치적으로 안전하다(04장 §4.1).
CrossEntropyLoss: 로짓 + 정수라벨 → 내부 log-softmax + NLL
PyTorch nn.CrossEntropyLoss는 softmax를 적용하지 않은 raw 로짓과 정수 클래스 인덱스(one-hot 아님)를 받는다. 공식 문서는 "The input is expected to contain the unnormalized logits for each class (which do not need to be positive or sum to 1, in general)." 그리고 "this case is equivalent to applying LogSoftmax on an input, followed by NLLLoss."
즉 CrossEntropyLoss = LogSoftmax + NLLLoss를 한 클래스로 합친 것이다. 정수 라벨 일 때 한 샘플 손실은
§2.2의 와 같다. PyTorch는 클래스-확률 타깃(soft label)도 지원한다(). label smoothing·distillation에서 쓴다(04장).
CrossEntropyLoss는 안에서 LogSoftmax와 NLLLoss를 차례로 돌린다.
수치 확인:
F.cross_entropy([[2.0,1.0,0.1]], target=0) = 0.417030. §2.2 손계산과 정확히 일치한다.
BCEWithLogitsLoss: 로짓 → 내부 sigmoid + BCE
nn.BCEWithLogitsLoss는 로짓(sigmoid 전)을 받는다. 공식 문서는 "This loss combines a Sigmoid layer and the BCELoss in one single class. ... we take advantage of the log-sum-exp trick for numerical stability."
별도 nn.BCELoss는 확률 를 받는다. 하지만 로짓을 직접 받는 BCEWithLogitsLoss가 수치적으로 안전하다(sigmoid를 따로 하면 위험). 클래스 불균형용 pos_weight(양성 가중)로 재현율과 정밀도를 trade-off할 수 있다. weighted loss 상세는 04장 §4.3에서 본다.
라벨 표현 정리
| 표현 | 형태 | 쓰는 곳 |
|---|---|---|
| 정수 인덱스 | (스칼라) | PyTorch CrossEntropyLoss 기본 (메모리·속도 유리) |
| one-hot 벡터 | 손계산·정보이론 식·soft label | |
| multi-hot 벡터 | multi-label (BCEWithLogitsLoss) |
정수 인덱스에서 one-hot으로 가는 건 동치다(가 정수 자리 하나만 보므로). PyTorch가 정수를 받는 건 같은 계산이면서 더 싸기 때문이다.
2.6 흔한 오개념 — 하지 말 것
- softmax/sigmoid 이중 적용 (가장 흔함).
CrossEntropyLoss와BCEWithLogitsLoss는 내부에서 softmax/sigmoid를 한다. 모델 마지막에 또 softmax를 넣고 그 출력을 이 손실에 먹이면 두 번 적용된다. 로짓이 뭉개지고 학습이 망가진다. 손실 함수에는 raw 로짓을 줘라. 추론에서 확률이 필요하면 그때 softmax/sigmoid를 명시적으로 적용한다. - 확률에 다시 CE. 이미 확률인 값을
CrossEntropyLoss에 넣으면 PyTorch가 그걸 또 로짓으로 보고 log-softmax를 적용한다. 틀린다. 확률과 정수라벨로 NLL을 직접 쓰려면NLLLoss(torch.log(p), y)처럼 로그 확률을 줘야 한다. - multi-label에 softmax. 여러 라벨이 동시 참인데 softmax를 쓰면 확률이 강제로 합=1이 된다. "둘 다 참"을 표현 못 한다. 클래스별 sigmoid+BCE를 써라.
- one-hot 라벨을
CrossEntropyLoss에 정수처럼. PyTorch는 정수 인덱스 또는 클래스-확률(soft) 타깃을 받는다. 어느 쪽인지 API를 확인하라.
함정의 증상→원인→해결 체크리스트는 04장 §4.5에 단일화돼 있다.
분류 CE는 다중클래스든 이진이든 결국 "정답에 준 확률의 음로그"다(). softmax/sigmoid가 로짓을 확률로 짜고, 그 위에서 CE가 손실 한 숫자를 낸다. 다음 03장은 softmax+CE를 미분하면 왜 깔끔한 (예측−정답)가 나오는지를 유도한다. 주 예제 를 그대로 이어받는다.
출처
- PyTorch
CrossEntropyLoss·BCEWithLogitsLoss·BCELoss공식 문서 — 로짓 입력,LogSoftmax+NLLLoss/Sigmoid+BCELoss등가, log-sum-exp 수치안정,pos_weight. https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html - Wikipedia — Softmax function — 정의, 평행이동 불변, safe softmax, 2-클래스에서 sigmoid로 환원, 온도. https://en.wikipedia.org/wiki/Softmax_function
- Goodfellow, Bengio, Courville, Deep Learning (2016), Ch.6 — Bernoulli→sigmoid→BCE / Multinoulli→softmax→CE 대응, "log가 softmax의 exp를 상쇄". https://www.deeplearningbook.org/contents/mlp.html
- Glass Box Medicine — "Multi-label vs. Multi-class Classification: Sigmoid vs. Softmax" (2019) — 상호배타(softmax) vs 독립 라벨(클래스별 sigmoid). https://glassboxmedicine.com/2019/05/26/classification-sigmoid-vs-softmax/