Showing posts with label 교차 엔트로피 손실 함수. Show all posts
Showing posts with label 교차 엔트로피 손실 함수. Show all posts

2026-10-12

엔트로피, 그대는 왜 엔트로피인가요?

파이토치로 분류 모델을 만들다 보면 손실 함수로 거의 언제나 교차 엔트로피를 고르게 된다. 그런데 이름이 묘하다. 모델의 예측이 정답과 얼마나 다른지를 잴 때 왜 물리 시간에 배운 단어가 붙은 손실 함수를 사용할까? 엔트로피의 원래 의미를 우리말로 옮기면 '엇갈린 무질서의 정도' 쯤이 되는데 도무지 어울리지 않는다.

이유를 굳이 알 필요는 없지만, 사정을 알고 나면 왜 \(-\log p\)를 손실로 쓰는지 납득되고, 학습 시작 직후의 손실이 얼마여야 정상인지를 알 수 있게 된다.

1. 열역학의 엔트로피

무질서가 아니라 경우의 수

고등학교 물리 시간에 엔트로피는 보통 '무질서한 정도'로 가르친다. 틀린 설명은 아니지만 오해하기 딱 좋다. 정확히 말하자면 '같은 겉모양을 만들어낼 수 있는 내부의 경우의 수는 몇 가지인가'다.

책상 위에 동전 100개가 있다고 하자. 전부 앞면인 상태를 만드는 방법은 한 가지뿐이다. 반면 앞면 50개, 뒷면 50개인 상태는 어느 동전이 앞면인지에 따라 경우의 수가 \(10^{29}\) 가까이 된다. 겉으로 보이는 상태는 '앞면의 개수' 하나라는 것과 비교하면 하늘과 땅 차이다.

그래서 동전 100개를 흔들어 흩뿌리면 반반에 가까운 상태가 나온다. 무질서를 추종하려는 힘이 따로 있어서가 아니라 그렇게 될 경우의 수가 압도적으로 많기 때문이다.

왜 로그인가?

이 경우의 수를 엔트로피로 정의한 사람이 루트비히 볼츠만이다.

\[ S = k \log W \]

여기서 \(W\)가 경우의 수고, \(k\)는 상수다. 그 사이에 있는 로그에 주목해 보자. 두 사건을 나란히 놓고 보면 전체 경우의 수는 더해지지 않고 곱해진다. 엔트로피를 물리량으로 정의해 사용하려면 양이 두 배가 될 때 엔트로피도 두 배가 되면 계산이 편해진다. 로그의 역할이 바로 이것이다.

\[ \log(W_1 \times W_2) = \log W_1 + \log W_2 \]

로그를 사용하면 곱을 합으로 바꿀 수 있다. 이 원리를 기억해 두자. 뒤에서 다시 등장한다.

2. 클로드 섀넌의 엔트로피

뻔한 소식과 뜻밖의 소식

1948년 클로드 섀넌은 통신을 연구하다 이런 질문을 던졌다.

이 메시지는 얼마나 많은 정보를 담고 있을까?

시작은 단순하다. 뻔한 소식은 정보가 적고 뜻밖의 소식은 정보가 많다. '내일 해가 뜬다'는 말 속에는 새로운 정보라고 할 만한 내용이 들어 있지 않다. 만약 10월에 '내일 눈이 온다'는 말을 듣는다면 매우 놀라울 것이며, 그만큼 많은 정보가 담겨 있다.

그래서 섀넌은 어떤 사건의 정보량을 그 사건이 일어날 확률의 역수로 정의했다.그런데 여기에도 로그를 사용했다.

\[ \text{정보량} = \log \frac{1}{p} = -\log p \]

이유는 볼츠만과 같다. 독립인 두 사건이 함께 일어날 확률은 곱해지지만, 정보량 역시 더하면 여러모로 편리하기 때문이다. 예를 들어 동전을 한 번 던져 얻는 정보가 1비트일 때 두 번 던져 얻는 정보는 2비트가 되면 받아 들이기도, 계산하기도 편하다. 확률은 \(\frac{1}{2}\)과 \(\frac{1}{2}\)를 곱한 \(\frac{1}{4}\)가 되지만, 로그를 씌우면 \(\log \frac{1}{2}\)와 \(\log \frac{1}{2}\)를 더한 \(2 \log \frac{1}{2}\)가 된다.

평균적으로 얼마나 놀랐을까?

이제 사건 하나 대신 분포 전체를 생각해보자. 분포 전체를 놓고 평균 정보량을 구한 것이 바로 정보 엔트로피다. 다음과 같이 정의된다.

\[ H(p) = -\sum_{i} p_i \log p_i \]

각 사건의 정보량 \(-\log p_i\)에 그 사건이 일어날 확률 \(p_i\)를 곱해 모두 더한 값이다. 말하자면 놀라움의 평균이다. 앞면만 나오는 동전은 결과가 뻔하니 엔트로피가 0이고, 평범한 동전은 가장 예측하기 어려우니 엔트로피가 최대가 된다.

3. 두 엔트로피가 만나는 지점

이제 볼츠만과 셰년의 엔트로피를 나란히 놓아 보자.

\[ S = k \log W \]

\[ H = -\sum_{i} p_i \log p_i \]

이때 경우의 수가 \(W\)가지이고 모두 똑같이 나올 법하다면 각각의 확률은 \(\frac{1}{W}\)다. 섀넌의 엔트로피에 그대로 넣어 보면 이렇게 된다.

\[ H = -\sum_{i=1}^{W} \frac{1}{W} \log \frac{1}{W} = \log W \]

볼츠만의 식에서 상수 \(k\)만 뺀 모양인데, 우연이 아니다. 둘 다 '가능한 경우가 얼마나 많은가'를 로그로 계산한다. 물리학은 그것을 분자의 배치에 적용했고 정보 공학은 메시지에 놀랄 가능성에 적용했을 뿐이다.

폰 노이만의 오지랖에 관한 풍문

섀넌이 여기에 어떤 이름을 붙일지 고민하다 존 폰 노이만에게 물었더니 이렇게 답했다고 한다.

엔트로피라고 부르게. 첫째로 자네 함수는 통계역학에서 이미 그 이름으로 쓰이고 있고, 둘째로 엔트로피가 정확히 무엇인지는 아무도 모르니 논쟁에서 늘 유리할 걸세.

널리 알려진 이야기지만 섀넌 본인의 기록이 아니다. 사실 여부는 불명확하지만, 사실이 아니라 해도 식이 이름에 걸맞았기에 나온 이야기였을 것이다.

4. 그래서 교차 엔트로피는

두 개의 분포를 가진다.

지금까지는 분포 하나를 가진 엔트로피를 이야기했다. 그런데 분류 모델의 경우 분포가 둘이다. 하나는 정답 분포 \(p\)로, 정답이 1번 클래스라면 \([0, 1, 0, \dots]\)이다. 다른 하나는 모델이 소프트맥스 함수를 통해 계산한 예측 분포 \(q\)다.

교차 엔트로피는 정답 분포를 기준으로 삼아 모델의 예측이 얼마나 놀라운 결과인지를 계산한다.

\[ H(p, q) = -\sum_{i} p_i \log q_i \]

엔트로피 식에서 로그 안쪽만 \(q\)로 바뀌었다. 이름이 '교차'인 이유가 이것 때문이다. 한쪽 분포로 가중치를 매기고 다른 쪽 분포로 놀라움 정도를 계산하는 식으로 교차한다.

정답이 원-핫 벡터라면 수식은 매우 단촐해진다. 정답 클래스 이외에는 \(p_i\)가 모두 0이기 때문이다.

\[ H(p, q) = -\log q_{\text{정답}} \]

이것이 \(-\log p\)를 손실로 사용하는 이론적 설명이다. 해설하자면 모델이 정답 클래스에 높은 확률을 준 경우 별로 놀랍지 않고(즉, 오차가 작고), 낮은 확률을 준 경우 놀랍다(즉, 오차가 크다)는 의미다.

엔트로피를 둘로 나누면

교차 엔트로피는 다시 두 조각으로 나뉜다.

\[ H(p, q) = H(p) + D_{\mathrm{KL}}(p \,\|\, q) \]

앞쪽 \(H(p)\)는 정답 자체의 엔트로피다. 데이터가 정해지는 순간 결정되므로 모델과 무관한 고정값이다. 뒤쪽 \(D_{\mathrm{KL}}(p \,\|\, q)\)가 두 분포가 얼마나 다른지를 나타낸다. 코드로 확인해 보자.

import torch

p = torch.tensor([0.7, 0.2, 0.1])      # 정답 분포
q = torch.tensor([0.5, 0.3, 0.2])      # 예측 분포

H  = -(p * p.log()).sum()              # 0.801819
KL = (p * (p.log() - q.log())).sum()   # 0.085123
CE = -(p * q.log()).sum()              # 0.886941

print(torch.allclose(H + KL, CE))      # True

학습으로 줄일 수 있는 것은 KL 발산쪽뿐이다. 그래서 "교차 엔트로피를 최소화한다"와 "예측 분포를 정답 분포에 가깝게 만든다"가 같은 말이 된다. 정답이 원-핫이면 \(H(p)\)가 0이라 교차 엔트로피가 곧 KL 발산이 되는데, 분류 모델에서 둘을 구분하지 않고 말하는 경우가 많은 이유가 이것이다.

5. 손실의 시작값

여기까지 오면 알 수 있는 것

갓 초기화한 모델은 아무것도 모르는 모델이다. 모든 클래스에 똑같은 확률을 준다는 뜻이다. 클래스가 \(k\)개면 각각 \(\frac{1}{k}\)이므로 손실은 \(-\log \frac{1}{k}\), 즉 \(\log k\)가 되어야 한다.

클래스 수 시작 손실 해당하는 데이터셋
2 0.693 이진 분류
10 2.303 MNIST, CIFAR-10, Fashion-MNIST
100 4.605 CIFAR-100

실제로 그런지 코드로 확인할 수 있다.

import torch
import torch.nn as nn

logits = torch.zeros(4096, 10)             # 아무것도 모르는 상태
y = torch.randint(0, 10, (4096,))

print(nn.CrossEntropyLoss()(logits, y))    # tensor(2.3026)

이 숫자가 꽤 쓸 만한 진단 도구가 된다. 시작 손실이 2.3 근처라면 정상이다. 7이나 20처럼 훨씬 크다면 초기 가중치가 지나치게 크거나 로짓에 이미 소프트맥스를 먹였을 가능성이 있다. 반대로 훨씬 작다면 데이터가 새고 있거나 정답 라벨이 잘못 들어갔을 수 있다. 기울기를 들여다보기 전에 첫 숫자 하나로 거를 수 있는 문제가 생각보다 많다.

다만 학습 로그의 첫 줄과 혼동하지 말자. 대개의 학습 루프는 1에포크를 다 돌고 나서 평균 손실을 찍는다. 그 값은 이미 수천 번 갱신된 뒤라 \(\log k\)보다 한참 낮게 나온다. 위 숫자를 보려면 학습 루프에 들어가기 전에 손실을 한 번 계산해 봐야 한다.

밑이 2가 아니다.

마지막으로 자주 헷갈리는 것 하나. 정보 이론에서는 로그의 밑을 2로 두고 단위를 비트라고 부른다. 반면 파이토치를 비롯한 딥러닝 라이브러리는 자연로그를 쓰고 내트(nat)라는 단위를 사용한다.

그래서 클래스가 10개일 때 시작 손실은 \(\log_2 10 = 3.32\)가 아니라 \(\ln 10 = 2.30\) 이다. 물론 어느 쪽이든 이 차이는 상수곱으로 해결되므로 최적화 결과는 달라지지 않는다.

6. 이름값을 한다

엔트로피라는 이름은 물리학에서 빌려 온 것이지만 억지로 가져다 붙은 비유가 아니다. 경우의 수를 로그로 계산한다는 기본 접근 방식이 같았고, 곱을 합으로 바꾸기 위해 로그를 사용한다는 로그의 용도도 같다. 폰 노이만의 일화가 사실이든 아니든 이름값은 하는 셈이다.

코랩 TPU에서 파이토치, 이제는 쓸 만 할까? - TorchTPU의 등장

<멀티모달까지 직접 구현하는 딥러닝 with 파이토치>의 코랩 안내 문서에는 이런 문장이 있다. "TPU는 고르지 말 것." 코랩의 런타임 유형 메뉴에서 TPU를 선택하면 GPU처럼 하드웨어 가속기의 장점을 누릴 수 있을 ...