web-dev-qa-db-ja.com

Tensorflowシグモイドとクロスエントロピーvs sigmoid_cross_entropy_with_logits

シグモイド活性化関数でクロスエントロピーを取得しようとすると、次の違いがあります

  1. loss1 = -tf.reduce_sum(p*tf.log(q), 1)
  2. loss2 = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q),1)

ただし、softmaxアクティベーション機能を使用する場合は同じです。

サンプルコードは次のとおりです。

import tensorflow as tf

sess2 = tf.InteractiveSession()
p = tf.placeholder(tf.float32, shape=[None, 5])
logit_q = tf.placeholder(tf.float32, shape=[None, 5])
q = tf.nn.sigmoid(logit_q)
sess.run(tf.global_variables_initializer())

feed_dict = {p: [[0, 0, 0, 1, 0], [1,0,0,0,0]], logit_q: [[0.2, 0.2, 0.2, 0.2, 0.2], [0.3, 0.3, 0.2, 0.1, 0.1]]}
loss1 = -tf.reduce_sum(p*tf.log(q),1).eval(feed_dict)
loss2 = tf.reduce_sum(tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q),1).eval(feed_dict)

print(p.eval(feed_dict), "\n", q.eval(feed_dict))
print("\n",loss1, "\n", loss2)
43
D.S.H.J

binaryおよびmulti-class問題のクロスエントロピーを混同しています。

マルチクラスのクロスエントロピー

使用する式は正確であり、 tf.nn.softmax_cross_entropy_with_logits に直接対応しています。

-tf.reduce_sum(p * tf.log(q), axis=1)

pおよびqは、Nクラスにわたる確率分布であると予想されます。特に、次の例のように、Nは2になります。

p = tf.placeholder(tf.float32, shape=[None, 2])
logit_q = tf.placeholder(tf.float32, shape=[None, 2])
q = tf.nn.softmax(logit_q)

feed_dict = {
  p: [[0, 1],
      [1, 0],
      [1, 0]],
  logit_q: [[0.2, 0.8],
            [0.7, 0.3],
            [0.5, 0.5]]
}

prob1 = -tf.reduce_sum(p * tf.log(q), axis=1)
prob2 = tf.nn.softmax_cross_entropy_with_logits(labels=p, logits=logit_q)
print(prob1.eval(feed_dict))  # [ 0.43748799  0.51301527  0.69314718]
print(prob2.eval(feed_dict))  # [ 0.43748799  0.51301527  0.69314718]

qtf.nn.softmax を計算していることに注意してください。つまり、確率分布を出力します。したがって、N = 2の場合のみ、マルチクラスのクロスエントロピーの式です。

バイナリクロスエントロピー

今回は正しい式は

p * -tf.log(q) + (1 - p) * -tf.log(1 - q)

数学的にはマルチクラスケースの部分的なケースですが、pqmeaningは異なります。最も単純なケースでは、pqはそれぞれ、クラスAの確率に対応する数値です。

重要:一般的なp * -tf.log(q)の部分と合計に混同しないでください。前のpはワンホットベクトルでしたが、現在は0または1の数字です。 qについても同じです。これは確率分布でしたが、現在は数値(確率)です。

pがベクトルの場合、個々のコンポーネントはそれぞれ独立したバイナリ分類と見なされます。 この回答 を参照してください。これは、テンソルフローのsoftmax関数とシグモイド関数の違いを示しています。したがって、定義p = [0, 0, 0, 1, 0]はワンホットベクトルを意味するのではなく、4つの機能がオフで1つがオンの5つの異なる機能を意味します。定義q = [0.2, 0.2, 0.2, 0.2, 0.2]は、5つの機能がそれぞれ20%の確率でオンになっていることを意味します。

これは、クロスエントロピーの前にsigmoid関数を使用することを説明します。その目的は、ロジットを[0, 1]間隔に縮小することです。

上記の式は、複数の独立した機能を保持し、それがまさに tf.nn.sigmoid_cross_entropy_with_logits の計算です:

p = tf.placeholder(tf.float32, shape=[None, 5])
logit_q = tf.placeholder(tf.float32, shape=[None, 5])
q = tf.nn.sigmoid(logit_q)

feed_dict = {
  p: [[0, 0, 0, 1, 0],
      [1, 0, 0, 0, 0]],
  logit_q: [[0.2, 0.2, 0.2, 0.2, 0.2],
            [0.3, 0.3, 0.2, 0.1, 0.1]]
}

prob1 = -p * tf.log(q)
prob2 = p * -tf.log(q) + (1 - p) * -tf.log(1 - q)
prob3 = p * -tf.log(tf.sigmoid(logit_q)) + (1-p) * -tf.log(1-tf.sigmoid(logit_q))
prob4 = tf.nn.sigmoid_cross_entropy_with_logits(labels=p, logits=logit_q)
print(prob1.eval(feed_dict))
print(prob2.eval(feed_dict))
print(prob3.eval(feed_dict))
print(prob4.eval(feed_dict))

最後の3つのテンソルが等しいことがわかりますが、prob1はクロスエントロピーの一部にすぎないため、p1である場合にのみ正しい値が含まれます。

[[ 0.          0.          0.          0.59813893  0.        ]
 [ 0.55435514  0.          0.          0.          0.        ]]
[[ 0.79813886  0.79813886  0.79813886  0.59813887  0.79813886]
 [ 0.5543552   0.85435522  0.79813886  0.74439669  0.74439669]]
[[ 0.7981388   0.7981388   0.7981388   0.59813893  0.7981388 ]
 [ 0.55435514  0.85435534  0.7981388   0.74439663  0.74439663]]
[[ 0.7981388   0.7981388   0.7981388   0.59813893  0.7981388 ]
 [ 0.55435514  0.85435534  0.7981388   0.74439663  0.74439663]]

これで、axis=1に沿って-p * tf.log(q)の合計を取得することは、この設定では意味がありませんが、マルチクラスの場合には有効な式になることは明らかです。

67
Maxim