KL 散度又叫 相對熵,是衡量 兩個概率分布 匹配程度的指標,KL 散度越大,分布差異越大,匹配度越低
計算公式如下
或者
其中 p是 目標分布,或者叫被匹配的分布,或者叫模板分布,q 是去匹配的分布;
試想,p 是真實值,q 是預測值,豈不是 個 loss function;
性質
如果 兩個分布 完全匹配,Dkl=0;
KL 散度是非對稱的,即 D(p||q) 不一定等於 D(q||p);
KL 散度 取值范圍 大於等於 0; 【參考資料2有證明,有個 傑森不等式】
直觀解釋
KL 散度左邊是個 概率,右邊是個 log(p/q);
先看下右邊的 log,如果 p > q,log 為正,如果 p < q,log 為負,如果 p = q,log 為 0;
為了使 KL 是個期望值,加入了權重 p,也就是說,p 使得 高概率的匹配區域 比 低概率的匹配區域 更加重要;
p(xi) 大,說明 xi 對應的 占比大,占比大的 是不是該 重視一下呢,而 乘以 p(xi) 剛好可以使得其 權重增大,代表 重視了;
直觀而言,優先正確匹配近似分布中真正高可能性的事件是有實際價值的。
從數學上講,這能讓你自動忽略落在真實分布的支集(支集(support)是指分布使用的 X 軸的全長度)之外的分布區域。
另外,這還能避免計算 log(0) 的情況——如果你試圖計算落在真實分布的支集之外的任意區域的這個對數項,就可能出現這種情況。
Python 實現
import numpy as np import scipy.stats # 不能只 import scipy # 隨機生成兩個離散型分布 x = [np.random.randint(1, 11) for i in range(10)] px = x / np.sum(x) print(px) y = [np.random.randint(1, 11) for i in range(10)] py = y / np.sum(y) print(py) ##### scipy API進行計算 # scipy計算函數可以處理非歸一化情況,因此這里使用 # scipy.stats.entropy(x, y)或scipy.stats.entropy(px, py)均可 KL = scipy.stats.entropy(x, y) print(KL) # 0.14931583282835742 ##### 手動實現 KL = 0.0 for i in range(10): KL += px[i] * np.log(px[i] / py[i]) print(KL) # 0.14931583282835742
Pytorch 中 KL 計算出現負值
需加個 log
import torch KL_criterion = torch.nn.KLDivLoss(size_average=False) a = torch.tensor([0.2, 0.1, 0.3, 0.4]) b = torch.tensor([0.1, 0.2, 0.3, 0.4]) loss1 = KL_criterion(a.log(), b) print(loss1) # tensor(0.0693) 加 log 正確 loss2 = KL_criterion(a, b) print(loss2) # tensor(-1.5699) 不加 log 為 負數,錯誤
注意:分布的結果相加需要為1
參考資料:
https://www.jianshu.com/p/7b7c0777f74d 直觀解讀KL散度的數學概念 講得比較好,主要參考,里面還有其他內容,可以看看
https://zhuanlan.zhihu.com/p/39682125 KL散度理解
https://www.cnblogs.com/hxsyl/p/4910218.html 淺談KL散度
https://www.zhihu.com/question/384982085/answer/1856014994 pytorch KL散度為負數?