webentwicklung-frage-antwort-db.com.de

Tensorflow Sigmoid und Kreuzentropie vs Sigmoid_Kreuzentropie_mit_Logits

Beim Versuch, mit der Sigmoid-Aktivierungsfunktion eine Kreuzentropie zu erhalten, gibt es einen Unterschied zwischen

  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)

Sie sind jedoch dieselben wie bei der Softmax-Aktivierungsfunktion.

Es folgt der Beispielcode:

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

Sie verwechseln die Kreuzentropie für binär und mehrklassig Probleme.

Klassenübergreifende Kreuzentropie

Die von Ihnen verwendete Formel ist korrekt und entspricht direkt tf.nn.softmax_cross_entropy_with_logits :

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

Es wird erwartet, dass p und q Wahrscheinlichkeitsverteilungen über N Klassen sind. Insbesondere kann N wie im folgenden Beispiel 2 sein:

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]

Es ist zu beachten, dass q berechnet tf.nn.softmax , d. H. Eine Wahrscheinlichkeitsverteilung ausgibt. Es handelt sich also immer noch um eine Kreuzentropieformel für mehrere Klassen, nur für N = 2.

Binäre Kreuzentropie

Diesmal ist die richtige Formel

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

Obwohl es sich mathematisch gesehen um einen Teilfall des Mehrklassenfalls handelt, ist die Bedeutung von p und q unterschiedlich. Im einfachsten Fall ist jedes p und q eine Zahl, die einer Wahrscheinlichkeit der Klasse A entspricht.

Wichtig : Lassen Sie sich nicht durch den gemeinsamen Teil p * -tf.log(q) und die Summe verwirren. Vorherige p war ein One-Hot-Vektor, jetzt ist es eine Zahl, Null oder Eins. Dasselbe gilt für q - es war eine Wahrscheinlichkeitsverteilung, jetzt ist es eine Zahl (Wahrscheinlichkeit).

Wenn p ein Vektor ist, wird jede einzelne Komponente als unabhängige binäre Klassifikation betrachtet. Siehe diese Antwort , das den Unterschied zwischen Softmax- und Sigmoid-Funktionen im Tensorflow umreißt. Die Definition p = [0, 0, 0, 1, 0] Bedeutet also nicht einen One-Hot-Vektor, sondern 5 verschiedene Funktionen, von denen 4 deaktiviert und 1 aktiviert sind. Die Definition q = [0.2, 0.2, 0.2, 0.2, 0.2] Bedeutet, dass jedes der 5 Features mit einer Wahrscheinlichkeit von 20% aktiviert ist.

Dies erklärt die Verwendung der Funktion sigmoid vor der Kreuzentropie: Ihr Ziel ist es, das Logit auf das Intervall [0, 1] Zu zerquetschen.

Die obige Formel gilt immer noch für mehrere unabhängige Funktionen, und genau das berechnet 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))

Sie sollten sehen, dass die letzten drei Tensoren gleich sind, während prob1 Nur ein Teil der Kreuzentropie ist. Daher enthält es nur dann den korrekten Wert, wenn p1 Ist:

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

Jetzt sollte klar sein, dass die Summe von -p * tf.log(q) mit axis=1 In dieser Einstellung keinen Sinn ergibt, obwohl es sich um eine gültige Formel in Fällen mit mehreren Klassen handelt.

67
Maxim