TensorFlow中的KL分歧

时间:2017-01-25 23:51:36

标签: python statistics tensorflow entropy

我有两个张量prob_aprob_b,形状为[None, 1000],我想计算从prob_aprob_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

如果没有内置功能,那么什么是一个好的解决方法?

7 个答案:

答案 0 :(得分:8)

假设您的输入张量prob_aprob_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)

我使用this code中的函数(来自this中函数)从正态高斯分布计算任何给定张量的KL散度,其中sd是标准偏差, mn是张量。

latent_loss = -0.5 * tf.reduce_sum(1.0 + 2.0 * sd - tf.square(mn) - tf.exp(2.0 * sd), 1)