web-dev-qa-db-fra.com

Divergence KL dans TensorFlow

J'ai deux tenseurs, prob_a et prob_b avec une forme [None, 1000], et je veux calculer la divergence KL de prob_a à prob_b. Existe-t-il une fonction intégrée pour cela dans TensorFlow? J'ai essayé d'utiliser tf.contrib.distributions.kl(prob_a, prob_b) mais cela donne:

NotImplementedError: No KL(dist_a || dist_b) registered for dist_a type Tensor and dist_b type Tensor

S'il n'y a pas de fonction intégrée, quelle solution de contournement serait la bonne?

8
Transcendental

En supposant que vos tenseurs en entrée prob_a et prob_b sont des tenseurs de probabilité dont la somme est égale à 1 le long du premier axe, procédez comme suit:

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)

Un exemple simple:

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]

Vous obtiendriez le même résultat avec

np.sum(a * np.log(a / b), axis=1) 

Cependant, cette implémentation est un peu boguée (vérifiée dans Tensorflow 1.8.0).

Si vous avez une probabilité nulle dans a, par exemple. Si vous essayez [0.8, 0.2, 0.0] au lieu de [0.8, 0.15, 0.05], vous obtiendrez nan même si, selon la définition de Kullback-Leibler, 0 * log(0 / b) devrait contribuer à zéro.

Pour atténuer cela, il convient d’ajouter une petite constante numérique. Il est également prudent d'utiliser tf.distributions.kl_divergence(X, Y, allow_nan_stats=False) pour provoquer une erreur d'exécution dans de telles situations.

De même, s'il existe des zéros dans b, vous obtiendrez des valeurs inf qui ne seront pas interceptées par l'option allow_nan_stats=False, de sorte que celles-ci doivent également être gérées.

6
meferne

Pour softmax_cross_entropy_with_logits, il n'est pas nécessaire d'optimiser 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 
6
Jiecheng Zhao

tf.contrib.distributions.kl prend des instances d'un tf.distribution et non d'une Tensor.

Exemple:

  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
2
jvdillon

J'ai utilisé la fonction de ce code (de this poste moyen) pour calculer la divergence KL d'un tensor donné à partir d'une distribution gaussienne normale, où sd est l'écart type et mn est le tenseur.

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

En supposant que vous ayez accès aux logits a et 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)
0
Sara

Je pense que cela pourrait fonctionner:

tf.reduce_sum(p * tf.log(p/q))

où p est ma distribution de probabilité réelle et q est ma distribution de probabilité approximative.

0
Akshaya Natarajan