KL散度与JS散度的公式与代码的简要实现

        KL散度(Kullback-Leibler Divergence),是两个概率分布(probability distribution)间差异的非对称性度量,通俗来说就是计算两个分布之间的不同。也有人叫做KL距离,其实是错误的叫法,因为距离的话是不分起始点与结束点的对吧,而KL散度是不对称的,所以交换值的结果是不一样的。

离散事件:定义事件A和B的差别
连续事件:把求和改为求积分即可

离散与连续分布的公式如下:

JS散度(Jensen–Shannon Divergence)是为了解决KL散度不对称性问题而出现的,我们看下它的公式有什么变化:

可以看出P1和P2明显是对称的,而且由于是两个KL叠加,故JS具有对称性和非负性。JS散度的值域范围是[0,1],相同则是0,相反为1 

它们的代码如下:

import numpy as np
import scipy.stats as ss

X=np.array([np.random.randint(2,12) for i in range(10)])
PX=X/np.sum(X)#X的概率分布
print(X,PX)
'''
[9 9 5 2 7 4 6 9 6 7]
[0.140625 0.140625 0.078125 0.03125  0.109375 0.0625 0.09375  0.140625 0.09375  0.109375]
'''
Y=np.array([np.random.randint(2,12) for i in range(10)])
PY=Y/np.sum(Y)#Y的概率分布

#KL散度:数学公式
def kld1(PX,QY):
    return np.sum(PX*np.log(PX/QY))

#KL散度:scipy接口
def kld2(P,Q):
    return ss.entropy(P,Q)

#JS散度:数学公式
def jsd1(P,Q):
    M=(P+Q)/2
    return 0.5*np.sum(P*np.log(P/M))+0.5*np.sum(Q*np.log(Q/M))

#JS散度:scipy接口提供
def jsd2(P,Q):
    M=(P+Q)/2
    return 0.5*ss.entropy(P,M)+0.5*ss.entropy(Q,M)

print('KL散度:',kld1(PX,PY),kld2(PX,PY))
#KL散度: 0.22021432361687981 0.22021432361687981

print('JS散度:',jsd1(PX,PY),jsd2(PX,PY))
#JS散度: 0.05152137849545689 0.05152137849545689


print('KL散度不对称:',kld1(PY,PX))#0.21788452702103164
print('JS散度对称:',jsd1(PY,PX))#0.05152137849545689

#可以直接使用X,Y的输入,不必须使用概率分布
print('JS散度的scipy接口:',kld2(X,Y))#0.22021432361687981

可以看出JS散度交换P,Q的值是一样的,是对称的。
KL散度在P,Q分布完全重叠时,其值显得没有意义;当P,Q完全不重叠时,JS散度是一个常数,这样梯度就为0,导致无法更新下去。比如说KL散度如果两个分布一样的话,了解GAN生成对抗神经网络的伙伴们来说就容易理解,因为辨别器太完美导致生成器的更新困难,一般都是辨别器跟生成器要旗鼓相当是最好的,互相进步。
P,Q完全不重叠的情况,那么p(x)=0或q(x)=0,公式推导如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅恪光潜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值