我有两个张量prob_a
和prob_b
,形状为[None, 1000]
,我想计算从prob_a
到prob_b
的KL偏差。 TensorFlow中是否有内置功能?我尝试使用tf.contrib.distributions.kl(prob_a, prob_b)
,但它给出了:
NotImplementedError: No KL(dist_a || dist_b) registered for dist_a type Tensor and dist_b type Tensor
如果没有内置功能,那么什么是一个好的解决方法?
答案 0 :(得分:8)
假设您的输入张量prob_a
和prob_b
是沿第一轴总和为1的概率张量,则可以这样操作:
def kl(x, y):
X = tf.distributions.Categorical(probs=x)
Y = tf.distributions.Categorical(probs=y)
return tf.distributions.kl_divergence(X, Y)
result = kl(prob_a, prob_b)
一个简单的例子:
import numpy as np
import tensorflow as tf
a = np.array([[0.25, 0.1, 0.65], [0.8, 0.15, 0.05]])
b = np.array([[0.7, 0.2, 0.1], [0.15, 0.8, 0.05]])
sess = tf.Session()
print(kl(a, b).eval(session=sess)) # [0.88995184 1.08808468]
您将获得与
相同的结果np.sum(a * np.log(a / b), axis=1)
但是,此实现有点错误(在Tensorflow 1.8.0中进行了检查)。
如果您在a
中的概率为零,例如如果您尝试使用[0.8, 0.2, 0.0]
而不是[0.8, 0.15, 0.05]
,即使根据Kullback-Leibler的定义nan
应该贡献为零,也会得到0 * log(0 / b)
。
为减轻这种情况,应添加一些小的数值常数。在这种情况下,使用tf.distributions.kl_divergence(X, Y, allow_nan_stats=False)
会导致运行时错误也是谨慎的做法。
此外,如果b
中有一些零,您将获得inf
选项不会捕获的allow_nan_stats=False
值,因此也必须对其进行处理。 / p>
答案 1 :(得分:6)
因为有softmax_cross_entropy_with_logits,所以不需要在KL上进行优化。
KL(prob_a, prob_b)
= Sum(prob_a * log(prob_a/prob_b))
= Sum(prob_a * log(prob_a) - prob_a * log(prob_b))
= - Sum(prob_a * log(prob_b)) + Sum(prob_a * log(prob_a))
= - Sum(prob_a * log(prob_b)) + const
= H(prob_a, prob_b) + const
答案 2 :(得分:5)
我不确定为什么它没有实现,但也许有一种解决方法。 KL分歧定义为:
KL(prob_a, prob_b) = Sum(prob_a * log(prob_a/prob_b))
另一方面,交叉熵H定义为:
H(prob_a, prob_b) = -Sum(prob_a * log(prob_b))
因此,如果您创建变量y = prob_a/prob_b
,则可以通过调用负H(proba_a, y)
来获取KL分歧。在Tensorflow表示法中,类似于:
KL = tf.reduce_mean(-tf.nn.softmax_cross_entropy_with_logits(prob_a, y))
答案 3 :(得分:2)
tf.contrib.distributions.kl
包含tf.distribution
而不是Tensor
的实例。
示例:
ds = tf.contrib.distributions
p = ds.Normal(loc=0., scale=1.)
q = ds.Normal(loc=1., scale=2.)
kl = ds.kl_divergence(p, q)
# ==> 0.44314718
答案 4 :(得分:0)
假设您有权访问log和b:
prob_a = tf.nn.softmax(a)
cr_aa = tf.nn.softmax_cross_entropy_with_logits(prob_a, a)
cr_ab = tf.nn.softmax_cross_entropy_with_logits(prob_a, b)
kl_ab = tf.reduce_sum(cr_ab - cr_aa)
答案 5 :(得分:0)
我认为这可能有效:
tf.reduce_sum(p * tf.log(p/q))
其中p是我的实际概率分布 q是我的近似概率分布。
答案 6 :(得分:0)