「KLダイバージェンスって、分布の距離みたいなものですよね?」
この言い方、直感としてはかなり近いのですが、数学的には正確ではありません。
この記事では、ダミーデータを使って KLダイバージェンスは何を測っていて、なぜ“距離”ではないのか を、Google Colab で追試できる形で整理します。
TL;DR
-
KLダイバージェンスは、分布
Pを分布Qで近似したときの余分な驚き(または余分な情報量)を表します。 - 数式は
$$
D_{\mathrm{KL}}(P|Q)=\sum_i p_i \log \frac{p_i}{q_i}
$$
です。 - KLダイバージェンスは 0以上 で、
P=Qのときは 0 になります。 - でも、対称ではありません。つまり
$$
D_{\mathrm{KL}}(P|Q) \neq D_{\mathrm{KL}}(Q|P)
$$
です。 - さらに、三角不等式も満たしません。だから 距離(metric)ではありません。
まず最小で動かす
import numpy as np
import matplotlib.pyplot as plt
def kl_div(p, q, eps=1e-12):
"""
KL divergence D_KL(P || Q) for discrete distributions.
eps は数値安定性のため。今回の例では 0 が出てこないので値にはほぼ影響しません。
"""
p = np.asarray(p, dtype=float)
q = np.asarray(q, dtype=float)
p = p / p.sum()
q = q / q.sum()
p = np.clip(p, eps, 1.0)
q = np.clip(q, eps, 1.0)
return float(np.sum(p * np.log(p / q)))
# -----------------------------
# 例1: 対称ではないことを確認する
# 「天気の分布」だと思ってください
# P: 真実の分布(ほぼ晴れ)
# Q: モデルの分布(晴れ/曇り/雨に広め)
# -----------------------------
labels1 = ["sunny", "cloudy", "rainy"]
P = np.array([0.90, 0.09, 0.01])
Q = np.array([0.40, 0.30, 0.30])
d_pq = kl_div(P, Q)
d_qp = kl_div(Q, P)
d_pp = kl_div(P, P)
print("=== asymmetry check ===")
print(f"KL(P||Q) = {d_pq:.3f}")
print(f"KL(Q||P) = {d_qp:.3f}")
print(f"KL(P||P) = {d_pp:.3f}")
# -----------------------------
# 例2: 三角不等式が成り立たないことを確認する
# -----------------------------
labels2 = ["A", "B", "C"]
A = np.array([0.70, 0.20, 0.10])
B = np.array([0.40, 0.40, 0.20])
C = np.array([0.10, 0.20, 0.70])
d_ab = kl_div(A, B)
d_bc = kl_div(B, C)
d_ac = kl_div(A, C)
print("\n=== triangle inequality check ===")
print(f"KL(A||B) = {d_ab:.3f}")
print(f"KL(B||C) = {d_bc:.3f}")
print(f"KL(A||C) = {d_ac:.3f}")
print(f"KL(A||B) + KL(B||C) = {d_ab + d_bc:.3f}")
# -----------------------------
# 可視化
# -----------------------------
plt.figure(figsize=(12, 4))
w = 0.35
# 左: 非対称性
ax1 = plt.subplot(1, 2, 1)
x1 = np.arange(len(labels1))
ax1.bar(x1 - w/2, P, width=w, label="P")
ax1.bar(x1 + w/2, Q, width=w, label="Q")
ax1.set_xticks(x1)
ax1.set_xticklabels(labels1)
ax1.set_ylim(0, 1.0)
ax1.set_title("Asymmetry: KL(P||Q) != KL(Q||P)")
ax1.legend()
ax1.text(
0.03, 0.95,
f"KL(P||Q) = {d_pq:.3f}\nKL(Q||P) = {d_qp:.3f}",
transform=ax1.transAxes,
va="top",
bbox=dict(boxstyle="round", facecolor="white", alpha=0.8)
)
# 右: 三角不等式の失敗
ax2 = plt.subplot(1, 2, 2)
x2 = np.arange(len(labels2))
ax2.bar(x2 - w, A, width=w, label="A")
ax2.bar(x2, B, width=w, label="B")
ax2.bar(x2 + w, C, width=w, label="C")
ax2.set_xticks(x2)
ax2.set_xticklabels(labels2)
ax2.set_ylim(0, 1.0)
ax2.set_title("Triangle inequality fails")
ax2.legend()
ax2.text(
0.03, 0.95,
f"KL(A||C) = {d_ac:.3f}\nKL(A||B)+KL(B||C) = {d_ab + d_bc:.3f}",
transform=ax2.transAxes,
va="top",
bbox=dict(boxstyle="round", facecolor="white", alpha=0.8)
)
plt.tight_layout()
plt.savefig("fig1_kl_not_distance.png", dpi=200, bbox_inches="tight")
plt.show()
実行すると、次のような出力がでます。
=== asymmetry check ===
KL(P||Q) = 0.587
KL(Q||P) = 1.057
KL(P||P) = 0.000
=== triangle inequality check ===
KL(A||B) = 0.184
KL(B||C) = 0.581
KL(A||C) = 1.168
KL(A||B) + KL(B||C) = 0.765
そもそもKLダイバージェンスとは何か
ここでは 離散分布 だけに絞って説明します。
確率分布 P と Q があるとき、KLダイバージェンスは
$$
D_{\mathrm{KL}}(P|Q)=\sum_i p_i \log \frac{p_i}{q_i}
$$
で定義されます。
直感的には何を表しているのか
一番初心者向けに言うなら、
本当は P に従ってデータが出てくるのに、それを Q だと思って扱うと、どれだけ余分に損するか
です。
もう少し情報理論っぽく書くと、KLダイバージェンスは
$$
D_{\mathrm{KL}}(P|Q)=H(P,Q)-H(P)
$$
という形でも書けます。
- $H(P)$ : 真の分布
Pのエントロピー - $H(P,Q)$ :
PをQで見たときの交差エントロピー
つまり、KLダイバージェンスは「余分な驚き」です。
距離なら満たしてほしい性質
数学でいう「距離(metric)」には、典型的には次の性質が必要です。
-
非負性
$$
d(x,y)\ge 0
$$ -
同一性
$$
d(x,y)=0 \iff x=y
$$ -
対称性
$$
d(x,y)=d(y,x)
$$ -
三角不等式
$$
d(x,z)\le d(x,y)+d(y,z)
$$
では、KLダイバージェンスはどうでしょうか。
| 性質 | KLダイバージェンス |
|---|---|
| 非負性 | 満たす |
| 同一性 | 満たす |
| 対称性 | 満たさない |
| 三角不等式 | 満たさない |
つまり、2つも落第しているので、KLダイバージェンスは距離ではありません。
なぜ対称ではないのか
図1の左側で見たように、
- $D_{\mathrm{KL}}(P|Q)=0.587$
- $D_{\mathrm{KL}}(Q|P)=1.057$
となって、値が違いました。
ここが本質
KLダイバージェンスの式をもう一度見ると、
$$
D_{\mathrm{KL}}(P|Q)=\sum_i p_i \log \frac{p_i}{q_i}
$$
です。
この式では、重みとして p_i が掛かっています。
つまり、「どのズレを重く見るか」は P 側が決めるのです。
P と Q を入れ替えると、
$$
D_{\mathrm{KL}}(Q|P)=\sum_i q_i \log \frac{q_i}{p_i}
$$
になって、重みが q_i に変わります。
だから、同じ2つの分布でも、向きを変えると意味が変わります。
今回の例を言葉で読むと
今回の P は
- 晴れ: 0.90
- 曇り: 0.09
- 雨: 0.01
で、ほとんど晴れです。
一方 Q は
- 晴れ: 0.40
- 曇り: 0.30
- 雨: 0.30
で、かなり広がっています。
$D_{\mathrm{KL}}(P|Q)$ の読み方
「本当はほぼ晴れなのに、モデル Q は曇りや雨にもかなり確率を振っている」
→ ズレてはいるけれど、そこまで致命的ではありません。
$D_{\mathrm{KL}}(Q|P)$ の読み方
「本当は曇りや雨もそこそこ起こるのに、モデル P はそれらをほぼ無視している」
→ 本来ありえる出来事にほぼ確率を置いていないので、強く罰されます。
この違いが、非対称性の正体です。
なぜ三角不等式を満たさないのか
図1の右側では、
- $D_{\mathrm{KL}}(A|C)=1.168$
- $D_{\mathrm{KL}}(A|B)+D_{\mathrm{KL}}(B|C)=0.765$
でした。
つまり、
$$
D_{\mathrm{KL}}(A|C) > D_{\mathrm{KL}}(A|B)+D_{\mathrm{KL}}(B|C)
$$
となって、三角不等式が破れています。
なぜこうなるのか
距離は「空間の中を移動する長さ」のようなものなので、
A → B → C と回り道した長さは、A → C の直行より短くなれません。
でもKLダイバージェンスは、そういう幾何学的な長さを表しているわけではありません。
KLダイバージェンスは、あくまで
真の分布を、別の分布で見たときのズレ
です。
そのため、A と B のズレ、B と C のズレを足したからといって、
A と C のズレを上から押さえられるとは限りません。
「じゃあKLダイバージェンスは何に使うの?」という疑問へ
距離ではないからといって、KLダイバージェンスがダメなわけではありません。
むしろ、機械学習ではとても重要です。
例えば次のような場面で出てきます。
-
分類の損失関数
交差エントロピーと深く関係します -
変分推論 / VAE
近似分布と真の分布のズレを測ります -
知識蒸留
教師モデルと生徒モデルの出力分布を合わせるときに使われます -
分布の比較
「予測分布がどれくらい違うか」を見たいときに出てきます
つまりKLダイバージェンスは、距離というより“方向つきのズレ”として使うのが自然です。
最小実験の見どころまとめ
この1本の図で、次の3点を確認できました。
1. 0以上である
KL(P||P)=0.000 でした。
また、他の値もすべて正です。
2. 向きを変えると値が変わる
KL(P||Q) と KL(Q||P) が違いました。
これで 対称性がない ことが分かります。
3. 三角不等式が壊れる
KL(A||C) のほうが、KL(A||B)+KL(B||C) より大きくなりました。
これで 距離とは言えない ことが分かります。
実務での読み替え
実務で KL ダイバージェンスを見たときは、まず
- どちらが真の分布(または基準)なのか
- どちらが近似分布なのか
を確認すると、かなり混乱が減ります。
覚え方
- $D_{\mathrm{KL}}(P|Q)$
→ 「P を Q で近似したときの損」 - 左側が基準、右側が近似
と読むと理解しやすいです。
チェックリスト
-
KLダイバージェンスの式を見て、
p_iが重みになっていると説明できる - $D_{\mathrm{KL}}(P|Q)$ と $D_{\mathrm{KL}}(Q|P)$ が違ってよいと説明できる
- KLダイバージェンスが距離でない理由を「対称性」と「三角不等式」で説明できる
-
交差エントロピーとの関係
$D_{\mathrm{KL}}(P|Q)=H(P,Q)-H(P)$ を説明できる - 実務で見たときに「左が基準、右が近似」と読める
次にやると理解が深まること
Colabで次の3つを試してみてください。
-
PとQを入れ替える
非対称性がもっと腹落ちします -
Qのどれかの確率を極端に小さくする
KLが大きく跳ねる様子が分かります -
Jensen-Shannon divergence を実装して比較する
「対称にしたい」という気持ちがよく分かります
よくある落とし穴
1. 「分布の距離」と雑に言ってしまう
会話としては通じることもありますが、数学的には正確ではありません。
距離ではなく、方向つきのズレです。
2. 0 を含む分布でそのまま計算する
もし p_i > 0 なのに q_i = 0 なら、本来
$$
D_{\mathrm{KL}}(P|Q)=\infty
$$
になります。
今回のコードでは数値安定性のため eps を入れています。
3. log の底を意識しない
自然対数なら単位は nats、底2なら bits です。
論文やライブラリによって単位が変わるので注意です。
まとめ
KLダイバージェンスは、分布のズレを測るとても重要な量ですが、距離ではありません。
理由はシンプルで、
- 対称でない
- 三角不等式を満たさない
からです。
一方で、
- 交差エントロピー
- 知識蒸留
- 変分推論
- 分布比較
など、機械学習ではとてもよく出てきます。
なので、KLダイバージェンスは
「距離」ではなく、「基準分布から見た方向つきのズレ」
として理解しておくと、かなり腹落ちしやすいです。
