정규분포의 KL: 평균 차이를 σ로 잰다
이 장 첫머리에서 유클리드 자는 같은 9cm 이동을 두 번 다 9라고 했고, KL은 σ = 5.8cm인 성인 남성의 키에서는 1.20, σ = 30cm쯤인 모든 연령의 키에서는 0.045라고 했다. 같은 9cm인데 KL은 무엇을 보고 27배나 다르게 쟀을까?
정규분포끼리 — 닫힌꼴
KL의 정의에 나오는 합 Σ pi log(pi/qi)는 키처럼 연속인 값에서는 적분이 된다. 정규분포끼리는 그 적분이 닫힌꼴(적분 없이 평균과 표준편차만 넣으면 값이 나오는 식)로 풀린다.
두 σ가 같으면 앞의 로그와 −½이 상쇄되고 (Δμ)² / (2σ²)만 남는다. 첫머리의 두 숫자가 여기서 나온다. 81 / (2 × 5.8²) ≈ 1.20, 81 / (2 × 30²) = 0.045. 평균의 차이를 σ로 나눈다는 것, 그것이 유클리드 자에게 없던 맥락이다.
무빙워크를 확률에 깔면 — 넓은 현실, 좁은 모형
무빙워크(타고 가면 3분, 거슬러 걸으면 11분)를 확률에 깔아 보자. 넓게 퍼진 현실 p를 좁은 모형 q로 설명하려는 방향은 거슬러 걷는 쪽이다. 현실이 자주 내놓는 결과 상당수를 모형은 거의 불가능하다고 여기기 때문이다. 반대로 좁은 현실을 넓은 모형으로 설명하는 방향은 무빙워크를 탄 쪽이다. 모형이 다소 흐릿할 뿐, 현실에서 일어나는 일을 불가능하다고 하지는 않는다.
숫자로 확인하면 이렇다. p = N(0, 2²), q = N(0, 1²)이면 KL(p‖q) = 0.807이다. 둘을 바꾸면 KL(q‖p) = 0.318이다. 같은 두 분포인데 2.5배 차이다.
ML에서: VAE가 손실에 더하는 KL
VAE(변분 오토인코더. 사진을 몇 개의 숫자로 줄였다가 되살리도록 학습하는 모델)는 사진 한 장마다 그 숫자들의 분포를 정규분포 N(μ, σ²)로 내놓고, 손실에 이 분포와 표준정규분포 N(0, 1) 사이의 KL을 더한다. 킹마(Diederik Kingma)와 웰링(Max Welling)의 2013년 논문 「변분 베이즈 오토인코딩」(Auto-Encoding Variational Bayes)은 부록에서 이 항을 바로 위 닫힌꼴로, 표본 없이 계산한다. 이 항이 무엇을 싸게, 무엇을 비싸게 매기는지는 아래 문제 7에서 따져 본다.
파이썬
import numpy as np
def kl_gauss(m1, s1, m2, s2):
"""KL( N(m1, s1²) ‖ N(m2, s2²) )"""
return np.log(s2 / s1) + (s1**2 + (m1 - m2)**2) / (2 * s2**2) - 0.5
print(f"성인 남성 σ=5.8, 9cm 이동 : {kl_gauss(174, 5.8, 183, 5.8):.3f}")
print(f"전 연령 σ=30, 9cm 이동 : {kl_gauss(150, 30, 159, 30):.3f}")
print(f"넓은 p, 좁은 q : {kl_gauss(0, 2, 0, 1):.3f}")
print(f"좁은 p, 넓은 q : {kl_gauss(0, 1, 0, 2):.3f}")
# 정의대로 확인: KL(p‖q) = p 에서 뽑은 x 로 평균낸 log p(x) − log q(x)
def log_pdf(x, m, s):
return -0.5 * ((x - m) / s)**2 - np.log(s * np.sqrt(2 * np.pi))
x = np.random.default_rng(0).normal(0, 2, 1_000_000) # p = N(0, 2²) 에서 표본
print(f"표본 평균으로 잰 KL(p‖q) : {np.mean(log_pdf(x, 0, 2) - log_pdf(x, 0, 1)):.3f}")
# 성인 남성 σ=5.8, 9cm 이동 : 1.204
# 전 연령 σ=30, 9cm 이동 : 0.045
# 넓은 p, 좁은 q : 0.807
# 좁은 p, 넓은 q : 0.318
# 표본 평균으로 잰 KL(p‖q) : 0.809
마지막 줄은 닫힌꼴 값 0.807과 소수 둘째 자리까지 맞는다. 표본을 늘릴수록 더 가까워진다.
수확
“정규분포의 KL은 평균의 차이를 σ로 나눠서 잰다.” KL이 정확히 무엇을 재는지 — 로그가 왜 거기 있는지는 아직 말하지 않았다. 그 답은 "놀라움"을 세는 법에서 나온다.
문제 6. 인치로 재도 같은 KL
한국 남성의 키 N(174, 5.8²)를 현실 자리에, 네덜란드 남성의 키 N(183, 7.1²)를 모형 자리에 둔다(단위 cm). (가) 닫힌꼴로 KL을 구하라. 방향을 바꾸면 얼마인가? (나) 키를 인치(1인치 = 2.54cm)로 바꿔 다시 계산하면 어떻게 되는가? KL에 cm 같은 길이 단위가 붙는가? (다) numpy로 σ = 5.8인 정규분포 표본을 뽑아 확인할 때 주의할 점도 적어라.
함께 풀기

(가)는 항별로 했어요. log(7.1/5.8) = 0.202, 5.8²/(2 × 7.1²) = 0.334, 9²/(2 × 7.1²) = 0.803, 여기에 −½을 더하면 0.839예요. 방향을 바꾸면 1.251이고요. 두 σ가 다르니까 두 방향이 달라요.

(나)는요?

인치로 바꾸면 평균도 σ도 모두 2.54로 나뉘는데… 로그 안은 σ끼리의 비, 나머지 두 항은 cm²/cm²라서 2.54가 다 지워져요. 0.839 그대로예요. 어, 그러면 KL 1이라는 게 cm로 몇 cm인지는 말할 수 없는 거네요?

말할 수 없어요. cm 같은 길이 단위는 사라져요. 그리고 그게 장점이에요. 키를 mm로 재도, 인치로 재도 KL은 같아요. Δμ와 σ가 같은 비율로 바뀌니까요.

유클리드 거리는 단위를 바꾸면 값이 바뀌는데, 이건 안 바뀌네요. 해석학 시간에 "척도 불변인 양을 찾아라"던 게 이런 거였구나.

근데 저 numpy로 확인했더니 안 맞았어요. np.random.normal(174, 5.8**2, n)으로 뽑아서 KL을 표본 평균으로 쟀는데 값이 한참 작게 나와요.

normal의 두 번째 인수(argument)가 뭐예요?

scale… 표준편차요. 분산을 넣었네요. σ를 33.64로 뽑았으니 봉우리가 엄청 넓어져서 9cm 이동이 별거 아닌 게 된 거예요.

이 장 첫머리의 “모든 연령의 키”(σ 30cm쯤)를 우연히 다시 만든 셈이에요. 주의할 점 하나 적었네요.
문제 7. VAE의 KL 항은 무엇을 벌하나
VAE의 인코더가 사진 한 장에 잠재 숫자 하나의 분포 N(μ, σ²)를 내고, 손실에는 KL(N(μ, σ²)‖N(0, 1))을 더한다. (가) (μ, σ) = (2, 1)일 때와 (0, 0.1)일 때 이 KL을 각각 구하라. (나) μ = 0에 둔 채 σ를 0.01, 0.001로 더 줄이면 어떻게 되는가? 인코더가 사진마다 한 점을 딱 찍어 내면(σ → 0) 이 항은 어떻게 되는가? (다) 이 KL의 앞 칸과 뒤 칸에는 각각 무엇이 들어 있는가? 이 책의 약속(앞 칸이 현실, 뒤 칸이 모형)과 견주어 보라.
함께 풀기

(가) 닫힌꼴에 넣었어요. (2, 1)은 σ가 1로 같으니까 2²/2 = 2.0이고, (0, 0.1)은 log(1/0.1) + 0.01/2 − ½ = 1.808이에요. 평균을 2나 옮긴 쪽이 조금 더 비싸네요.

(나)에서 σ를 더 줄이면요?

0.01이면 4.105, 0.001이면 6.408이요. 열 배 줄일 때마다 2.3씩 늘어요.

2.3이면 log 10이네. log(1/σ) 항이 σ를 열 배 줄일 때마다 그만큼 커지는 거야. σ → 0이면 끝없이 커져요. 인코더가 사진마다 한 점을 딱 찍으면 이 항이 무한대가 되니까, 학습이 그러지 못하게 막는 셈이에요.

모형이 0이라고 우기는 결과가 현실에서 일어나면 KL이 끝없이 커지던 경우와 견주어 봐요. 여기서도 누가 0을 주고 있어요?

그게 아니에요. σ → 0인 분포가 앞 칸에 있으니까, 무게는 그 분포가 쥐고 있고 거의 한 점에만 몰려 있어요. 그 점에서 앞 칸의 밀도는 1/σ처럼 치솟고 N(0, 1)의 밀도는 그대로라서, 둘의 비의 로그가 끝없이 커져요. 뒤 칸이 0을 줘서가 아니라 앞 칸이 한 점으로 뾰족해져서 커지는 거예요. 끝없이 커지는 까닭이 달라요.

좋아요. (다)는요?

앞 칸이 인코더가 낸 분포, 뒤 칸이 N(0, 1)이에요. 둘 다 "현실"은 아니에요. 앞 칸은 모델이 낸 것이고, 뒤 칸은 사람이 정해 둔 기준이에요.

그래요. 이 책은 p를 현실, q를 모형이라 부르기로 약속했지만, 실제 손실에서 무엇을 앞 칸에 두는지는 그 손실을 만든 사람이 고른 거예요. 식을 볼 때마다 앞 칸에 누가 있는지부터 확인해요.

과제 채점에 “풀이 과정 없이 답만 쓰면 감점” 규칙이 있는 거랑 비슷하네요. 답 하나에 모든 걸 걸지 말고 조금은 퍼뜨려 두라는 거죠.