🤖 AI/ML

KL Divergence

Kullback-Leibler Divergence

두 확률 분포의 차이를 측정. VAE, 증류 등에서 활용.

📖 상세 설명

KL Divergence(Kullback-Leibler Divergence)는 두 확률 분포 P와 Q 사이의 차이를 측정하는 정보 이론 기반 지표입니다. "P를 Q로 근사할 때 얼마나 정보가 손실되는가"를 정량화하며, 값이 0이면 두 분포가 동일함을 의미합니다.

1951년 Solomon Kullback과 Richard Leibler가 제안한 KL Divergence는 상대 엔트로피(relative entropy)라고도 불립니다. Cross-Entropy에서 엔트로피 H(P)를 빼면 KL Divergence가 되며, 분류 문제의 손실 함수와 깊은 연관이 있습니다.

수학적으로 D_KL(P||Q) = sum(P(x) * log(P(x)/Q(x)))입니다. 비대칭적이라 D_KL(P||Q) != D_KL(Q||P)이며, 이 특성이 VAE의 정규화, Knowledge Distillation 등에서 중요하게 활용됩니다.

실무에서 VAE의 latent space 정규화, 모델 증류(student가 teacher를 모방), 강화학습의 PPO(정책 변화 제한), Adversarial Training 등에 핵심적으로 사용됩니다. 2025년 연구에서는 GKL(Generalized KL) Divergence가 RobustBench에서 SOTA를 달성했습니다.

💻 코드 예제

import torch
import torch.nn.functional as F
import numpy as np
from scipy.special import kl_div as scipy_kl

# NumPy로 KL Divergence 직접 구현
def kl_divergence_numpy(p, q, epsilon=1e-10):
    """KL(P || Q): P가 실제 분포, Q가 근사 분포"""
    p = np.array(p) + epsilon
    q = np.array(q) + epsilon
    return np.sum(p * np.log(p / q))

# 예시: 실제 분포 vs 예측 분포
p_true = [0.1, 0.2, 0.3, 0.4]      # 실제 분포
q_approx = [0.25, 0.25, 0.25, 0.25]  # 균등 분포 (나쁜 근사)
q_good = [0.12, 0.22, 0.28, 0.38]    # 좋은 근사

print(f"KL(P || Q_bad): {kl_divergence_numpy(p_true, q_approx):.4f}")
print(f"KL(P || Q_good): {kl_divergence_numpy(p_true, q_good):.4f}")

# PyTorch KLDivLoss (Knowledge Distillation 예시)
# 주의: PyTorch는 입력이 log_softmax여야 함
teacher_logits = torch.tensor([[2.0, 1.0, 0.5, 0.1]])
student_logits = torch.tensor([[1.8, 1.1, 0.4, 0.2]])

temperature = 2.0  # soft label을 위한 온도
teacher_soft = F.softmax(teacher_logits / temperature, dim=-1)
student_log_soft = F.log_softmax(student_logits / temperature, dim=-1)

# reduction='batchmean'이 수학적 정의와 일치
kl_loss = F.kl_div(student_log_soft, teacher_soft, reduction='batchmean')
print(f"Knowledge Distillation KL Loss: {kl_loss.item():.4f}")

# VAE에서의 KL Divergence (잠재 공간 정규화)
def vae_kl_loss(mu, log_var):
    """q(z|x) ~ N(mu, sigma^2)와 p(z) ~ N(0, 1) 사이의 KL"""
    return -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())

mu = torch.randn(32, 64)       # 배치 32, 잠재 차원 64
log_var = torch.randn(32, 64)
print(f"VAE KL Loss: {vae_kl_loss(mu, log_var).item():.2f}")

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"Knowledge Distillation에서 student 모델이 teacher의 soft label을 얼마나 잘 모방하는지 KL Divergence로 측정합니다. temperature 2~4 정도로 설정하면 soft label이 더 부드러워져서 학습이 안정적이에요."
💬 면접에서
"KL Divergence는 비대칭이라 D_KL(P||Q)와 D_KL(Q||P)가 다릅니다. VAE에서는 근사 분포 q(z|x)를 사전 분포 p(z)=N(0,1)에 가깝게 만들기 위해 KL 항을 loss에 포함시킵니다. 이게 latent space를 정규화하는 역할을 해요."
💬 기술 토론에서
"PPO에서 KL penalty를 쓰는 이유는 정책이 급격히 변하면 학습이 불안정해지기 때문이에요. 이전 정책과의 KL Divergence를 제한해서 안정적인 업데이트를 보장합니다."

⚠️ 흔한 실수 & 주의사항

PyTorch KLDivLoss에 reduction='mean' 사용

수학적 정의와 맞지 않습니다. reduction='batchmean'을 사용해야 올바른 KL Divergence 값이 계산됩니다.

P와 Q 순서 혼동

D_KL(P||Q)에서 P는 실제(target) 분포, Q는 근사(prediction) 분포입니다. 순서가 바뀌면 전혀 다른 값이 나옵니다.

0 확률에 epsilon 추가

Q(x)=0인 곳에서 P(x)>0이면 KL이 무한대가 됩니다. 1e-10 정도의 작은 값을 더해 수치 안정성을 확보하세요.

🔗 관련 용어

📚 더 배우기