개념
정보량(Information Content), 즉 놀라움(Surprise)
일어날 가능성이 낮은 일이 일어나면 더 많은 정보(information)를 담습니다. 동전이 앞면(heads)이 되는 것은 놀랍지 않습니다. 복권 당첨(lottery win)은 매우 놀랍습니다.
확률(probability)이 p인 사건(event)의 정보량(information content)은 아래와 같습니다.
I(x) = -log(p(x))
밑이 2인 로그(log base 2)를 쓰면 비트(bit)입니다. 자연로그(natural log)를 쓰면 nat입니다. 단위(unit)만 다르고 같은 아이디어입니다.
Event Probability Surprise (bits)
Fair coin heads 0.5 1.0
Rolling a 6 0.167 2.58
1-in-1000 event 0.001 9.97
Certain event 1.0 0.0
확실한 사건(certain event)은 정보를 0만큼 담습니다. 이미 일어날 것을 알고 있었기 때문입니다.
엔트로피(Entropy): 평균 놀라움(Average Surprise)
엔트로피(entropy)는 분포(distribution)의 모든 가능한 결과(possible outcome)에 대한 기대 놀라움(expected surprise)입니다.
H(P) = -sum( p(x) * log(p(x)) ) for all x
공정한 동전(fair coin)은 이진 변수(binary variable)에서 최대 엔트로피(maximum entropy)인 1 bit를 가집니다. 99%가 앞면(heads)인 편향된 동전(biased coin)은 엔트로피가 낮아 0.08 bits입니다. 거의 무엇이 일어날지 알고 있으므로 각 던짐(flip)이 거의 알려 주는 것이 없습니다.
Fair coin: H = -(0.5 * log2(0.5) + 0.5 * log2(0.5)) = 1.0 bit
Biased coin: H = -(0.99 * log2(0.99) + 0.01 * log2(0.01)) = 0.08 bits
엔트로피는 분포 안의 줄일 수 없는 불확실성(irreducible uncertainty)을 측정합니다. 그 아래로는 압축할 수 없습니다.
교차 엔트로피(Cross-entropy): 매일 쓰는 손실 함수(loss function)
교차 엔트로피(cross-entropy)는 실제로 분포(distribution) P에서 나온 사건(event)을 분포 Q로 인코딩(encode)할 때의 평균 놀라움(average surprise)입니다.
H(P, Q) = -sum( p(x) * log(q(x)) ) for all x
P는 참 분포(true distribution), 즉 레이블(label)입니다. Q는 모델 예측(model prediction)입니다. Q가 P와 완전히 맞으면 교차 엔트로피는 엔트로피와 같습니다. 불일치가 있으면 더 커집니다.
분류(classification)에서 P는 원-핫 벡터(one-hot vector)입니다. 정답 클래스(true class)의 확률(probability)은 1이고 나머지는 0입니다. 그래서 교차 엔트로피는 아래처럼 단순해집니다.
H(P, Q) = -log(q(true_class))
이것이 분류의 교차 엔트로피 손실 공식(cross-entropy loss formula) 전체입니다. 정답 클래스(correct class)의 예측 확률(predicted probability)을 최대화하면 됩니다.
KL 발산(KL divergence): 분포(distribution) 사이의 차이
KL 발산(KL Divergence)은 P 대신 Q를 사용할 때 얼마나 추가적인 놀라움(extra surprise)이 생기는지 측정합니다.
D_KL(P || Q) = sum( p(x) * log(p(x) / q(x)) ) for all x
= H(P, Q) - H(P)
교차 엔트로피(cross-entropy)는 엔트로피(entropy)에 KL 발산(KL divergence)을 더한 것입니다. 학습(training) 중 참 분포(true distribution)의 엔트로피는 상수(constant)이므로 교차 엔트로피를 최소화하는 것은 KL 발산을 최소화하는 것과 같습니다. 모델 분포(model distribution)를 참 분포 쪽으로 밀어 가는 것입니다.
KL 발산은 대칭(symmetric)이 아닙니다. D_KL(P || Q) != D_KL(Q || P)입니다. 따라서 진짜 거리 척도(distance metric)는 아닙니다.
상호정보량(mutual information)은 한 변수(variable)를 알면 다른 변수에 대해 얼마나 알게 되는지 측정합니다.
I(X; Y) = H(X) - H(X|Y)
= H(X) + H(Y) - H(X, Y)
X와 Y가 독립(independent)이면 상호정보량은 0입니다. 하나를 알아도 다른 하나에 대해 아무것도 알려 주지 않습니다. 둘이 완전히 상관(perfectly correlated)되어 있으면 상호정보량은 어느 한 변수(variable)의 엔트로피와 같습니다.
특징 선택(feature selection)에서 특징(feature)과 목표(target) 사이의 상호정보량이 높으면 해당 특징이 유용(useful)하다는 뜻입니다. 낮으면 잡음(noise)일 가능성이 큽니다.
조건부 엔트로피(Conditional Entropy)
조건부 엔트로피(Conditional Entropy) H(Y|X)는 X를 관찰한 뒤에도 Y에 대해 남아 있는 불확실성(uncertainty)입니다.
H(Y|X) = H(X,Y) - H(X)
두 가지 극단(extreme)을 살펴봅니다.
X가 Y를 완전히 결정하면 H(Y|X) = 0입니다. X를 알면 Y의 불확실성이 모두 사라집니다. 예: X가 섭씨 온도(Celsius temperature), Y가 화씨 온도(Fahrenheit temperature).
X가 Y에 대해 아무것도 알려 주지 않으면 H(Y|X) = H(Y)입니다. 예: X가 동전 던지기(coin flip), Y가 내일 날씨(tomorrow's weather).
조건부 엔트로피는 항상 음이 아니며(non-negative) H(Y)보다 크지 않습니다.
0 <= H(Y|X) <= H(Y)
머신러닝(machine learning)에서는 결정 트리(decision tree)에 나타납니다. 각 분기(split)에서 알고리즘(algorithm)은 H(Y|X)를 최소화하는 특징(feature) X, 즉 레이블(label) Y에 대한 불확실성을 가장 많이 제거하는 특징을 고릅니다.
결합 엔트로피(Joint Entropy)
결합 엔트로피(Joint Entropy) H(X,Y)는 X와 Y를 함께 본 결합 분포(joint distribution)의 엔트로피입니다.
H(X,Y) = -sum sum p(x,y) * log(p(x,y)) for all x, y
중요한 성질(property)은 다음과 같습니다.
H(X,Y) <= H(X) + H(Y)
등호(equality)는 X와 Y가 독립(independent)일 때 성립합니다. 둘이 정보를 공유하면 결합 엔트로피는 개별 엔트로피(individual entropy)의 합(sum)보다 작아집니다. 그 "빠진" 엔트로피가 정확히 상호정보량(mutual information)입니다.
graph TD
subgraph "Information Venn Diagram"
direction LR
HX["H(X)"]
HY["H(Y)"]
MI["I(X;Y)<br/>Mutual<br/>Information"]
HXgY["H(X|Y)<br/>= H(X) - I(X;Y)"]
HYgX["H(Y|X)<br/>= H(Y) - I(X;Y)"]
HXY["H(X,Y) = H(X) + H(Y) - I(X;Y)"]
end
HXgY --- MI
MI --- HYgX
HX -.- HXgY
HX -.- MI
HY -.- MI
HY -.- HYgX
HXY -.- HXgY
HXY -.- MI
HXY -.- HYgX
관계식은 아래와 같습니다.
H(X,Y) = H(X) + H(Y|X) = H(Y) + H(X|Y)
I(X;Y) = H(X) - H(X|Y) = H(Y) - H(Y|X)
H(X,Y) = H(X) + H(Y) - I(X;Y)
상호정보량(mutual information) I(X;Y)는 한 변수(variable)를 알 때 다른 변수의 불확실성(uncertainty)이 얼마나 줄어드는지 정량화합니다.
I(X;Y) = H(X) - H(X|Y)
= H(Y) - H(Y|X)
= H(X) + H(Y) - H(X,Y)
= sum sum p(x,y) * log(p(x,y) / (p(x) * p(y)))
성질(Properties):
I(X;Y) >= 0입니다. 어떤 것을 관찰해서 정보(information)를 잃지는 않습니다.
I(X;Y) = 0은 X와 Y가 독립(independent)일 때, 그리고 그때만 성립합니다.
I(X;Y) = I(Y;X)입니다. KL 발산(KL divergence)과 달리 대칭(symmetric)입니다.
I(X;X) = H(X)입니다. 변수(variable)는 자기 자신과 모든 정보를 공유합니다.
특징 선택(feature selection)을 위한 상호정보량(mutual information). ML에서는 목표(target)에 대해 정보량이 큰(informative) 특징(feature)이 필요합니다. 상호정보량은 특징을 순위화(rank)하는 원칙적인 방법(principled way)을 제공합니다.
- 각 특징
X_i에 대해 목표 변수(target variable) Y와의 I(X_i; Y)를 계산합니다.
- 상호정보량(MI) 점수로 특징을 순위화합니다.
- 상위 k개 특징(top k feature)을 유지합니다.
이 방법은 특징(feature)과 목표(target) 사이의 관계가 선형(linear), 비선형(nonlinear), 단조(monotonic)인지 여부와 무관하게 작동합니다. 상관관계(correlation)는 선형 관계(linear relationship)만 잡습니다. MI는 모든 통계적 의존성(statistical dependency)을 잡습니다.
| 방법 | 감지 대상 | 계산 비용 | 범주형 처리 |
|---|
| 피어슨 상관(Pearson correlation) | 선형 관계 | O(n) | 아니요 |
| 스피어만 상관(Spearman correlation) | 단조 관계 | O(n log n) | 아니요 |
| 상호정보량(Mutual information) | 임의의 통계적 의존성 | 구간화(binning) 사용 시 O(n log n) | 예 |
레이블 스무딩(Label smoothing)과 교차 엔트로피(cross-entropy)
표준 분류(standard classification)는 정답 클래스(true class)에 확률 1, 나머지에 0을 부여한 하드 타깃(hard target) [0, 0, 1, 0]을 사용합니다. 레이블 스무딩(label smoothing)은 이를 소프트 타깃(soft target)으로 바꿉니다.
soft_target = (1 - epsilon) * hard_target + epsilon / num_classes
epsilon = 0.1이고 클래스(class)가 4개이면 다음과 같습니다.
- 하드 타깃:
[0, 0, 1, 0]
- 소프트 타깃:
[0.025, 0.025, 0.925, 0.025]
정보이론(information theory) 관점에서 레이블 스무딩은 타깃 분포(target distribution)의 엔트로피를 높입니다. 하드 원-핫 타깃의 엔트로피는 0입니다. 불확실성이 없습니다. 소프트 타깃은 양의 엔트로피(positive entropy)를 가집니다.
도움이 되는 이유는 다음과 같습니다.
- 모델이 로짓(logit)을 극단값(extreme value)으로 밀어붙이지 못하게 합니다. 원-핫 타깃을 교차 엔트로피 기준으로 완벽히 맞추려면 무한대 로짓(infinite logit)이 필요합니다.
- 정규화(regularization)처럼 작동합니다. 모델이 100% 확신(confident)할 수 없습니다.
- 보정(calibration)을 개선합니다. 예측 확률(predicted probability)이 참 불확실성(true uncertainty)을 더 잘 반영합니다.
- 학습 동작(training behavior)과 추론 동작(inference behavior) 사이의 차이(gap)를 줄입니다.
레이블 스무딩을 사용한 교차 엔트로피 손실은 아래와 같습니다.
L = (1 - epsilon) * CE(hard_target, prediction) + epsilon * H_uniform(prediction)
두 번째 항(term)은 균등분포(uniform)에서 멀어진 예측을 벌점화(penalize)합니다. 확신도(confidence)에 대한 직접 정규화(direct regularization)입니다.
교차 엔트로피(Cross-entropy)가 분류 손실(classification loss)인 이유
세 관점이 같은 결론을 줍니다.
정보이론 관점(Information theory view). 교차 엔트로피(cross-entropy)는 참 분포(true distribution) 대신 모델 분포(model distribution)를 사용할 때 낭비하는 비트(bit) 수를 측정합니다. 이를 최소화(minimize)하면 모델은 현실(reality)을 가장 효율적으로 인코딩(encode)합니다.
최대가능도 관점(Maximum likelihood view). 정답 클래스(true class)가 y_i인 학습 샘플(training sample) N개에 대해:
Likelihood = product( q(y_i) )
Log-likelihood = sum( log(q(y_i)) )
Negative log-likelihood = -sum( log(q(y_i)) )
마지막 줄이 교차 엔트로피 손실입니다. 교차 엔트로피를 최소화하는 것은 학습 데이터(training data)의 가능도(likelihood)를 모델 아래에서 최대화하는 것과 같습니다.
기울기 관점(Gradient view). 로짓(logit)에 대한 교차 엔트로피의 기울기(gradient)는 단순히 (predicted - true)입니다. 깔끔하고 안정적이며 빠르게 계산됩니다. 그래서 소프트맥스(softmax)와 완벽히 맞습니다.
비트(Bits)와 nats
차이는 로그의 밑(log base)뿐입니다.
log base 2 -> bits (information theory tradition)
log base e -> nats (machine learning convention)
log base 10 -> hartleys (rarely used)
1 nat = 1/ln(2) bits = 1.4427 bits입니다. PyTorch와 TensorFlow는 기본적으로 자연로그(natural log), 즉 nats를 사용합니다.
퍼플렉서티(Perplexity)
퍼플렉서티(perplexity)는 교차 엔트로피(cross-entropy)의 지수(exponential)입니다. 모델(model)이 사실상 몇 개의 동일확률 선택지(equally likely choice) 사이에서 헷갈리고 있는지 알려 줍니다.
Perplexity = 2^H(P,Q) (bits를 사용할 때)
Perplexity = e^H(P,Q) (nats를 사용할 때)
퍼플렉서티(perplexity)가 50인 언어 모델(language model)은 평균적으로 다음 토큰(next token)을 50개 동일확률 선택지(equally likely option) 중에서 균등하게(uniformly) 고르는 것만큼 헷갈린다(confused)는 뜻입니다. 낮을수록 좋습니다.
GPT-2는 일반적인 벤치마크(benchmark)에서 퍼플렉서티 약 30을 달성했습니다. 최신 모델은 잘 대표되는 도메인(domain)에서는 한 자리 수(single digit)까지 내려갑니다.
직접 만들기
Step 1: 정보량(Information content)과 엔트로피(entropy)
import math
def information_content(p, base=2):
if p <= 0 or p > 1:
return float('inf') if p <= 0 else 0.0
return -math.log(p) / math.log(base)
def entropy(probs, base=2):
return sum(
p * information_content(p, base)
for p in probs if p > 0
)
fair_coin = [0.5, 0.5]
biased_coin = [0.99, 0.01]
fair_die = [1/6] * 6
print(f"Fair coin entropy: {entropy(fair_coin):.4f} bits")
print(f"Biased coin entropy: {entropy(biased_coin):.4f} bits")
print(f"Fair die entropy: {entropy(fair_die):.4f} bits")
Step 2: 교차 엔트로피(Cross-entropy)와 KL 발산(KL divergence)
def cross_entropy(p, q, base=2):
total = 0.0
for pi, qi in zip(p, q):
if pi > 0:
if qi <= 0:
return float('inf')
total += pi * (-math.log(qi) / math.log(base))
return total
def kl_divergence(p, q, base=2):
return cross_entropy(p, q, base) - entropy(p, base)
true_dist = [0.7, 0.2, 0.1]
good_model = [0.6, 0.25, 0.15]
bad_model = [0.1, 0.1, 0.8]
print(f"Entropy of true dist: {entropy(true_dist):.4f} bits")
print(f"CE (good model): {cross_entropy(true_dist, good_model):.4f} bits")
print(f"CE (bad model): {cross_entropy(true_dist, bad_model):.4f} bits")
print(f"KL divergence (good): {kl_divergence(true_dist, good_model):.4f} bits")
print(f"KL divergence (bad): {kl_divergence(true_dist, bad_model):.4f} bits")
Step 3: 분류 손실(Classification loss)로서의 교차 엔트로피(cross-entropy)
def softmax(logits):
max_logit = max(logits)
exps = [math.exp(z - max_logit) for z in logits]
total = sum(exps)
return [e / total for e in exps]
def cross_entropy_loss(true_class, logits):
probs = softmax(logits)
return -math.log(probs[true_class])
logits = [2.0, 1.0, 0.1]
true_class = 0
probs = softmax(logits)
loss = cross_entropy_loss(true_class, logits)
print(f"Logits: {logits}")
print(f"Softmax: {[f'{p:.4f}' for p in probs]}")
print(f"True class: {true_class}")
print(f"Loss: {loss:.4f} nats")
print(f"Perplexity: {math.exp(loss):.2f}")
Step 4: 교차 엔트로피(Cross-entropy)는 음의 로그가능도(negative log-likelihood)와 같다
import random
random.seed(42)
n_samples = 1000
n_classes = 3
true_labels = [random.randint(0, n_classes - 1) for _ in range(n_samples)]
model_logits = [[random.gauss(0, 1) for _ in range(n_classes)] for _ in range(n_samples)]
ce_loss = sum(
cross_entropy_loss(label, logits)
for label, logits in zip(true_labels, model_logits)
) / n_samples
nll = -sum(
math.log(softmax(logits)[label])
for label, logits in zip(true_labels, model_logits)
) / n_samples
print(f"Cross-entropy loss: {ce_loss:.6f}")
print(f"Negative log-likelihood: {nll:.6f}")
print(f"Difference: {abs(ce_loss - nll):.2e}")
def mutual_information(joint_probs, base=2):
rows = len(joint_probs)
cols = len(joint_probs[0])
margin_x = [sum(joint_probs[i][j] for j in range(cols)) for i in range(rows)]
margin_y = [sum(joint_probs[i][j] for i in range(rows)) for j in range(cols)]
mi = 0.0
for i in range(rows):
for j in range(cols):
pxy = joint_probs[i][j]
if pxy > 0:
mi += pxy * math.log(pxy / (margin_x[i] * margin_y[j])) / math.log(base)
return mi
independent = [[0.25, 0.25], [0.25, 0.25]]
dependent = [[0.45, 0.05], [0.05, 0.45]]
print(f"MI (independent): {mutual_information(independent):.4f} bits")
print(f"MI (dependent): {mutual_information(dependent):.4f} bits")
사용해보기
실무에서는 NumPy를 사용해 같은 개념을 아래처럼 다룹니다.
import numpy as np
def np_entropy(p):
p = np.asarray(p, dtype=float)
mask = p > 0
result = np.zeros_like(p)
result[mask] = p[mask] * np.log(p[mask])
return -result.sum()
def np_cross_entropy(p, q):
p, q = np.asarray(p, dtype=float), np.asarray(q, dtype=float)
mask = p > 0
return -(p[mask] * np.log(q[mask])).sum()
def np_kl_divergence(p, q):
return np_cross_entropy(p, q) - np_entropy(p)
true = np.array([0.7, 0.2, 0.1])
pred = np.array([0.6, 0.25, 0.15])
print(f"Entropy: {np_entropy(true):.4f} nats")
print(f"Cross-ent: {np_cross_entropy(true, pred):.4f} nats")
print(f"KL div: {np_kl_divergence(true, pred):.4f} nats")
직접 만든 것은 torch.nn.CrossEntropyLoss()가 내부에서 하는 일입니다. 이제 학습(training) 중 손실(loss)이 내려간다는 말이 무엇인지 알 수 있습니다. 모델의 예측 분포(model's predicted distribution)가 낭비된 정보(wasted information)의 nat 단위 측정에서 참 분포(true distribution)에 가까워지고 있다는 뜻입니다.
산출물 만들기
이 lesson의 검수 대상은 아래 두 가지입니다.
code/information_theory.py: 엔트로피(entropy), 교차 엔트로피(cross-entropy), KL 발산(KL divergence), 상호정보량(mutual information), 퍼플렉서티(perplexity)를 계산하는 실행 가능한 예제
outputs/skill-information-theory.md: ML 손실 함수(loss function), 모델 평가(model evaluation), 특징 선택(feature selection)에 정보이론 개념을 적용하기 위한 skill
연습문제
- 영어 알파벳(English alphabet)이 균등분포(uniform distribution)라고 가정해 엔트로피(entropy)를 계산합니다. 그런 다음 실제 글자 빈도(letter frequency)로 엔트로피를 추정합니다. 어느 쪽이 더 높고, 왜 그런가요?
- 정답 클래스(true class)가 1인 샘플(sample)에 대해 모델이 로짓
[5.0, 2.0, 0.5]를 출력했습니다. 교차 엔트로피 손실(cross-entropy loss)을 손으로 계산하고 cross_entropy_loss 함수로 검증합니다. 손실을 0으로 만들려면 어떤 로짓이 필요할까요?
- KL 발산(KL divergence)이 대칭(symmetric)이 아님을 보입니다. 분포
P와 Q를 골라 D_KL(P || Q)와 D_KL(Q || P)를 계산하고 왜 다른지 설명합니다.
- 토큰 예측 시퀀스(token prediction sequence)의 퍼플렉서티(perplexity)를 계산하는 함수를 만듭니다.
(true_token_index, predicted_logits) 쌍의 리스트가 주어졌을 때 시퀀스의 퍼플렉서티를 반환합니다.
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 정보량(Information content) | "놀라움(surprise)" | 사건을 인코딩(encode)하는 데 필요한 비트(bit) 또는 nat의 수. -log(p) |
| 엔트로피(Entropy) | "무작위성(randomness)" | 분포의 모든 결과(outcome)에 대한 평균 놀라움(average surprise). 줄일 수 없는 불확실성(irreducible uncertainty)을 측정한다 |
| 교차 엔트로피(Cross-entropy) | "손실 함수(loss function)" | 참 분포 P에서 온 사건을 모델 분포(model distribution) Q로 인코딩할 때의 평균 놀라움 |
| KL 발산(KL divergence) | "분포 사이의 거리" | P 대신 Q를 써서 낭비되는 추가 비트(extra bit). 교차 엔트로피에서 엔트로피를 뺀 값이며 대칭이 아니다 |
| 상호정보량(Mutual information) | "X와 Y가 얼마나 관련 있는가" | Y를 알 때 X의 불확실성이 줄어드는 양. 0이면 독립(independent)이라는 뜻 |
| 소프트맥스(Softmax) | "로짓(logit)을 확률로 바꾸기" | 지수를 취해 정규화(normalize)함으로써 실수 벡터(real-valued vector)를 유효한 확률 분포로 매핑(mapping)한다 |
| 퍼플렉서티(Perplexity) | "모델이 얼마나 헷갈리는가" | 교차 엔트로피의 지수(exponential). 각 단계(step)에서 모델이 고르는 유효 어휘 크기(effective vocabulary size) |
| 비트(Bits) | "섀넌(Shannon)의 단위" | 로그의 밑이 2인 정보 측정 단위. 1비트는 공정한 동전 던지기(fair coin flip) 한 번을 해결한다 |
| Nats | "ML의 단위" | 자연로그(natural log)로 측정한 정보. PyTorch와 TensorFlow가 기본으로 사용한다 |
| 음의 로그가능도(Negative log-likelihood) | "NLL 손실(loss)" | 원-핫 레이블에서는 교차 엔트로피 손실과 동일하다. 이를 최소화하면 정답 예측 확률(correct prediction probability)을 최대화한다 |
더 읽을거리