Предполагая, что ваши входные тензоры 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
, хотя по определению Кульбака-Лейблера 0 * log(0 / b)
должен давать нулевой вклад.
Чтобы смягчить это, нужно добавить небольшую числовую константу. Также разумно использовать tf.distributions.kl_divergence(X, Y, allow_nan_stats=False)
, чтобы вызвать ошибку времени выполнения в таких ситуациях.
Кроме того, если в b
есть несколько нулей, вы получите inf
значений, которые не будут улавливаться опцией allow_nan_stats=False
, поэтому их тоже нужно обработать.
person
meferne
schedule
25.06.2018