prob_a
とprob_b
の2つのテンソルがあり、形状は[None, 1000]
で、prob_a
からprob_b
へのKLダイバージェンスを計算します。 TensorFlowにはこのための組み込み関数はありますか? tf.contrib.distributions.kl(prob_a, prob_b)
を使用してみましたが、次のようになります。
NotImplementedError:dist_aタイプのTensorおよびdist_bタイプのTensorに登録されているKL(dist_a || dist_b)がありません
組み込み関数がない場合、良い回避策は何ですか?
入力テンソル_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]
_を試すと、Kullback-Leiblerの定義により0 * log(0 / b)
はゼロとして貢献するはずですが、nan
を取得します。
これを緩和するには、いくつかの小さな数値定数を追加する必要があります。そのような状況でランタイムエラーを発生させるためにtf.distributions.kl_divergence(X, Y, allow_nan_stats=False)
を使用することも賢明です。
また、b
にゼロがある場合、_allow_nan_stats=False
_オプションでキャッチされないinf
値が取得されるため、それらも処理する必要があります。
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
Prob_aがconstでない場合。 2つのエントロピーのサブに書き換えることができます。
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))
= H(prob_a, prob_b) - H(prob_a, prob_a)
実装されていない理由はわかりませんが、回避策があるかもしれません。 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))
tf.contrib.distributions.kl
はTensor
ではなくtf.distribution
のインスタンスを取ります。
例:
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
ロジットaおよび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)
私はこれがうまくいくと思います:
tf.reduce_sum(p * tf.log(p/q))
ここで、pは実際の確率分布、qはおおよその確率分布です。