webentwicklung-frage-antwort-db.com.de

KL Divergenz in TensorFlow

Ich habe zwei Tensoren, prob_a und prob_b mit Shape [None, 1000], und ich möchte die KL-Divergenz von prob_a zu prob_b berechnen. Gibt es dafür in TensorFlow eine integrierte Funktion? Ich habe es mit tf.contrib.distributions.kl(prob_a, prob_b) versucht, aber es ergibt:

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

Was wäre eine gute Lösung, wenn keine integrierte Funktion vorhanden ist?

8
Transcendental

Angenommen, Ihre Eingabe-Tensoren prob_a und prob_b sind Wahrscheinlichkeits-Tensoren, die sich entlang der ersten Achse zu 1 summieren, Sie könnten dies folgendermaßen tun:

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)

Ein einfaches Beispiel:

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]

Sie würden das gleiche Ergebnis mit bekommen

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

Diese Implementierung ist jedoch ein wenig fehlerhaft (in Tensorflow 1.8.0 geprüft).

Wenn Sie in a null Wahrscheinlichkeiten haben, z. Wenn Sie [0.8, 0.2, 0.0] anstelle von [0.8, 0.15, 0.05] versuchen, erhalten Sie nan, auch wenn die Kullback-Leibler-Definition 0 * log(0 / b) als Null beitragen soll.

Um dies zu mildern, sollte man eine kleine numerische Konstante hinzufügen. Es ist auch ratsam, tf.distributions.kl_divergence(X, Y, allow_nan_stats=False) zu verwenden, um in solchen Situationen einen Laufzeitfehler zu verursachen.

Wenn in b einige Nullen vorhanden sind, werden inf-Werte angezeigt, die nicht von der allow_nan_stats=False-Option erfasst werden. Diese Werte müssen ebenfalls behandelt werden.

6
meferne

Für softmax_cross_entropy_with_logits gibt es keine Notwendigkeit, auf KL zu optimieren.

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

Ich bin nicht sicher, warum es nicht implementiert wird, aber möglicherweise gibt es eine Problemumgehung. Die KL-Divergenz ist definiert als:

KL(prob_a, prob_b) = Sum(prob_a * log(prob_a/prob_b))

Die Kreuzentropie H dagegen ist definiert als:

H(prob_a, prob_b) = -Sum(prob_a * log(prob_b))

Wenn Sie also eine Variable y = prob_a/prob_b erstellen, können Sie die KL-Divergenz erhalten, indem Sie negative H(proba_a, y) aufrufen. In der Tensorflow-Notation etwa:

KL = tf.reduce_mean(-tf.nn.softmax_cross_entropy_with_logits(prob_a, y))

5
E.J. White

tf.contrib.distributions.kl nimmt Instanzen eines tf.distributions und keine Tensor.

Beispiel:

  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

Ich habe die Funktion aus diesem Code (aus this Medium post) verwendet, um die KL-Divergenz eines bestimmten Tensors aus einer normalen Gaußschen Verteilung zu berechnen, wobei sd die Standardabweichung und mn der Tensor ist.

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

Angenommen, Sie haben Zugriff auf die Logits a und 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

Ich denke das könnte funktionieren:

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

dabei ist p meine tatsächliche Wahrscheinlichkeitsverteilung und q meine ungefähre Wahrscheinlichkeitsverteilung.

0