我有两个张量,prob_a
并prob_b
与形状[None, 1000]
,我想从计算KL散prob_a
到prob_b
.TensorFlow中是否有内置功能?我尝试过使用tf.contrib.distributions.kl(prob_a, prob_b)
但它给出了:
prob_a
如果没有内置功能,那么什么是好的解决方法?
假设您的输入张量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]
,则nan
即使Kullback-Leibler定义0 * log(0 / b)
应该归零,您也会得到.
为了缓解这个问题,我们应该添加一些小的数值常数.tf.distributions.kl_divergence(X, Y, allow_nan_stats=False)
在这种情况下使用导致运行时错误也是谨慎的.
此外,如果有一些零b
,您将获得inf
该allow_nan_stats=False
选项不会捕获的值,因此必须处理这些值.
因为有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
我不确定为什么它没有实现,但也许有一个解决方法.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
,您可以通过调用负数来获得KL分歧H(proba_a, y)
.在Tensorflow表示法中,类似于:
KL = tf.reduce_mean(-tf.nn.softmax_cross_entropy_with_logits(prob_a, y))