47 votes

Sigmoïde à flux tensoriel et entropie croisée vs sigmoid_cross_entropy_with_logits

Lorsque vous essayez d'obtenir une entropie croisée avec la fonction d'activation sigmoïde, il y a une différence entre

  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)

Mais ils sont les mêmes avec la fonction d'activation de softmax.

Voici l'exemple de code:

 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)
 

72voto

Maxim Points 28843

Vous êtes à la confusion de l'entropie croisée pour les binaires et multi-classe de problèmes.

Multi-classe d'entropie croisée

La formule que vous utilisez est correct et qu'il correspond directement à l' tf.nn.softmax_cross_entropy_with_logits:

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

p et q sont censés être des distributions de probabilité sur N classes. En particulier, N 2, comme dans l'exemple suivant:

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]

Notez que q calcul tf.nn.softmax, c'est à dire des sorties d'une distribution de probabilité. Il est donc encore multi-classe d'entropie croisée de la formule, uniquement pour N = 2.

Binaire d'entropie croisée

Cette fois, la formule correcte est

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

Bien que mathématiquement c'est une partielle cas de la multi-cas de la classe, le sens de l' p et q est différent. Dans le cas le plus simple, chaque p et q est un nombre, correspondant à une probabilité de la classe A.

Important: Ne soyez pas confus par la commune p * -tf.log(q) de la partie et de la somme. Précédente p a été un "one-hot" vecteur, maintenant, il est un certain nombre, zéro ou un. De même pour q - c'était une distribution de probabilité, maintenant, c'est un nombre (de probabilité).

Si p est un vecteur, chaque composant est considéré comme un indépendant de classification binaire. Voir cette réponse qui décrit la différence entre softmax et sigmoïde fonctions dans tensorflow. Ainsi, la définition p = [0, 0, 0, 1, 0] ne signifie pas un "one-hot" vecteur, mais 5 différentes fonctions, 4 sont à l'extérieur et 1 est en marche. La définition q = [0.2, 0.2, 0.2, 0.2, 0.2] signifie que chacun des 5 caractéristiques est sur avec 20% de probabilité.

C'est ce qui explique l'utilisation de l' sigmoid de la fonction avant de l'entropie croisée: son but est d'écraser le logit de [0, 1] intervalle.

La formule ci-dessus tient toujours pour de multiples fonctionnalités indépendantes, et c'est exactement ce qu' tf.nn.sigmoid_cross_entropy_with_logits calcule:

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))

Vous devriez voir que les trois dernières tenseurs sont égaux, alors que l' prob1 n'est qu'une partie de l'entropie croisée, si elle contient de la valeur correcte uniquement lorsqu' p est 1:

[[ 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]]

Maintenant, il devrait être clair que la prise d'une somme de -p * tf.log(q) long axis=1 n'a pas de sens dans ce cadre, bien que ce ne serait pas valide formule multi-cas de la classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X