Was ist logits, softmax und softmax_cross_entropy_with_logits?

350

Ich wurde durch die tensorflow API - Dokumentation geht hier . In der Tensorflow-Dokumentation wurde ein Schlüsselwort namens verwendet logits. Was ist es? In vielen Methoden in den API-Dokumenten ist es so geschrieben

tf.nn.softmax(logits, name=None)

Wenn das, was geschrieben wird , ist jene logitssind nur Tensors, warum , wie einen anderen Namen zu halten logits?

Eine andere Sache ist, dass es zwei Methoden gibt, die ich nicht unterscheiden konnte. Sie sind

tf.nn.softmax(logits, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)

Was sind die Unterschiede zwischen ihnen? Die Dokumente sind mir nicht klar. Ich weiß was tf.nn.softmaxmacht. Aber nicht der andere. Ein Beispiel wird sehr hilfreich sein.

Shubhashis
quelle

Antworten:

426

Logits bedeutet einfach, dass die Funktion mit der nicht skalierten Ausgabe früherer Ebenen arbeitet und dass die relative Skalierung zum Verständnis der Einheiten linear ist. Dies bedeutet insbesondere, dass die Summe der Eingaben möglicherweise nicht gleich 1 ist und die Werte keine Wahrscheinlichkeiten sind (möglicherweise haben Sie eine Eingabe von 5).

tf.nn.softmaxerzeugt nur das Ergebnis der Anwendung der Softmax-Funktion auf einen Eingangstensor. Der Softmax "quetscht" die Eingaben so, dass sum(input) = 1: es eine Art der Normalisierung ist. Die Form der Ausgabe eines Softmax entspricht der Eingabe: Es werden nur die Werte normalisiert. Die Ausgaben von Softmax können als Wahrscheinlichkeiten interpretiert werden.

a = tf.constant(np.array([[.1, .3, .5, .9]]))
print s.run(tf.nn.softmax(a))
[[ 0.16838508  0.205666    0.25120102  0.37474789]]

Im Gegensatz dazu wird tf.nn.softmax_cross_entropy_with_logitsdie Kreuzentropie des Ergebnisses nach Anwendung der Softmax-Funktion berechnet (dies geschieht jedoch mathematisch sorgfältiger). Es ähnelt dem Ergebnis von:

sm = tf.nn.softmax(x)
ce = cross_entropy(sm)

Die Kreuzentropie ist eine zusammenfassende Metrik: Sie summiert sich über die Elemente. Die Ausgabe tf.nn.softmax_cross_entropy_with_logitseines [2,5]Formtensors hat eine Form [2,1](die erste Dimension wird als Charge behandelt).

Wenn Sie eine Optimierung durchführen möchten, um die Kreuzentropie zu minimieren, UND Sie nach Ihrer letzten Ebene Softmaxing durchführen, sollten Sie diese verwenden, tf.nn.softmax_cross_entropy_with_logitsanstatt sie selbst auszuführen , da sie numerisch instabile Eckfälle auf mathematisch richtige Weise abdeckt. Andernfalls hacken Sie es am Ende, indem Sie hier und da kleine Epsilons hinzufügen.

Bearbeitet am 07.02.2016: Wenn Sie Beschriftungen für eine Klasse haben, bei denen ein Objekt nur zu einer Klasse gehören kann, sollten Sie jetzt die Verwendung in Betracht ziehen, tf.nn.sparse_softmax_cross_entropy_with_logitsdamit Sie Ihre Beschriftungen nicht in ein dichtes One-Hot-Array konvertieren müssen. Diese Funktion wurde nach Release 0.6.0 hinzugefügt.

dga
quelle
1
Über die softmax_cross_entropy_with_logits weiß ich nicht, ob ich sie richtig verwende. Das Ergebnis ist in meinem Code nicht so stabil. Der gleiche Code wird zweimal ausgeführt, die Gesamtgenauigkeit ändert sich von 0,6 auf 0,8. cross_entropy = tf.nn.softmax_cross_entropy_with_logits(tf.nn.softmax(tf.add(tf.matmul(x,W),b)),y) cost=tf.reduce_mean(cross_entropy). Aber wenn ich einen anderen Weg benutze, ist pred=tf.nn.softmax(tf.add(tf.matmul(x,W),b)) cost =tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))das Ergebnis stabil und besser.
Rida
15
Du bist Double-Softmaxing in deiner ersten Zeile. softmax_cross_entropy_with_logits erwartet nicht skalierte Protokolle, nicht die Ausgabe von tf.nn.softmax. Sie wollen nur tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W, b))in Ihrem Fall.
dga
7
@dga Ich denke, Sie haben einen Tippfehler in Ihrem Code, die baußerhalb der Klammer sein muss,tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W), b)
jrieke
1
Was bedeutet "dass die relative Skala zum Verständnis der Einheiten linear ist". Teil deines ersten Satzes bedeuten?
Charlie Parker
5
Upvoted - aber Ihre Antwort ist etwas falsch, wenn Sie sagen, dass "die Form der Ausgabe eines Softmax die gleiche ist wie die Eingabe - sie normalisiert nur die Werte". Softmax "quetscht" die Werte nicht nur so, dass ihre Summe gleich 1 ist. Es verteilt sie auch neu, und das ist möglicherweise der Hauptgrund, warum es verwendet wird. Siehe stackoverflow.com/questions/17187507/… , insbesondere die Antwort von Piotr Czapla.
Paolo Perrotta
282

Kurzfassung:

Angenommen, Sie haben zwei Tensoren, y_hatdie berechnete Punktzahlen für jede Klasse enthalten (z. B. von y = W * x + b) und y_trueOne-Hot-codierte True-Labels enthalten.

y_hat  = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded

Wenn Sie die Ergebnisse y_hatals nicht normalisierte Protokollwahrscheinlichkeiten interpretieren , handelt es sich um Protokolle .

Zusätzlich wird der gesamte Kreuzentropieverlust auf diese Weise berechnet:

y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))

ist im Wesentlichen äquivalent zu dem mit der Funktion berechneten Gesamt-Kreuzentropieverlust softmax_cross_entropy_with_logits():

total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))

Lange Version:

In der Ausgabeschicht Ihres neuronalen Netzwerks berechnen Sie wahrscheinlich ein Array, das die Klassenwerte für jede Ihrer Trainingsinstanzen enthält, z. B. aus einer Berechnung y_hat = W*x + b. Als Beispiel habe ich unten y_hatein 2 x 3-Array erstellt, in dem die Zeilen den Trainingsinstanzen und die Spalten den Klassen entsprechen. Hier gibt es also 2 Trainingsinstanzen und 3 Klassen.

import tensorflow as tf
import numpy as np

sess = tf.Session()

# Create example y_hat.
y_hat = tf.convert_to_tensor(np.array([[0.5, 1.5, 0.1],[2.2, 1.3, 1.7]]))
sess.run(y_hat)
# array([[ 0.5,  1.5,  0.1],
#        [ 2.2,  1.3,  1.7]])

Beachten Sie, dass die Werte nicht normalisiert sind (dh die Zeilen addieren sich nicht zu 1). Um sie zu normalisieren, können wir die Softmax-Funktion anwenden, die die Eingabe als nicht normalisierte Protokollwahrscheinlichkeiten (auch als Logits bezeichnet ) interpretiert und normalisierte lineare Wahrscheinlichkeiten ausgibt.

y_hat_softmax = tf.nn.softmax(y_hat)
sess.run(y_hat_softmax)
# array([[ 0.227863  ,  0.61939586,  0.15274114],
#        [ 0.49674623,  0.20196195,  0.30129182]])

Es ist wichtig zu verstehen, was die Softmax-Ausgabe sagt. Unten habe ich eine Tabelle gezeigt, die die Ausgabe oben deutlicher darstellt. Es ist ersichtlich, dass beispielsweise die Wahrscheinlichkeit, dass die Trainingsinstanz 1 "Klasse 2" ist, 0,619 beträgt. Die Klassenwahrscheinlichkeiten für jede Trainingsinstanz werden normalisiert, sodass die Summe jeder Zeile 1,0 beträgt.

                      Pr(Class 1)  Pr(Class 2)  Pr(Class 3)
                    ,--------------------------------------
Training instance 1 | 0.227863   | 0.61939586 | 0.15274114
Training instance 2 | 0.49674623 | 0.20196195 | 0.30129182

Jetzt haben wir Klassenwahrscheinlichkeiten für jede Trainingsinstanz, wobei wir den argmax () jeder Zeile verwenden können, um eine endgültige Klassifizierung zu generieren. Von oben können wir erzeugen, dass die Trainingsinstanz 1 zu "Klasse 2" und die Trainingsinstanz 2 zu "Klasse 1" gehört.

Sind diese Klassifikationen korrekt? Wir müssen uns an den wahren Bezeichnungen aus dem Trainingssatz messen. Sie benötigen ein One-Hot-codiertes y_trueArray, bei dem die Zeilen wiederum Trainingsinstanzen und die Spalten Klassen sind. Im Folgenden habe ich ein Beispiel für ein y_trueOne-Hot-Array erstellt, bei dem die wahre Bezeichnung für Trainingsinstanz 1 "Klasse 2" und die wahre Bezeichnung für Trainingsinstanz 2 "Klasse 3" lautet.

y_true = tf.convert_to_tensor(np.array([[0.0, 1.0, 0.0],[0.0, 0.0, 1.0]]))
sess.run(y_true)
# array([[ 0.,  1.,  0.],
#        [ 0.,  0.,  1.]])

Liegt die Wahrscheinlichkeitsverteilung y_hat_softmaxnahe an der Wahrscheinlichkeitsverteilung in y_true? Wir können den Kreuzentropieverlust verwenden , um den Fehler zu messen.

Formel für Kreuzentropieverlust

Wir können den Kreuzentropieverlust zeilenweise berechnen und die Ergebnisse sehen. Unten sehen wir, dass Trainingsinstanz 1 einen Verlust von 0,479 hat, während Trainingsinstanz 2 einen höheren Verlust von 1,200 hat. Dieses Ergebnis ist sinnvoll, da in unserem obigen Beispiel gezeigt wurde y_hat_softmax, dass die höchste Wahrscheinlichkeit für Trainingsinstanz 1 für "Klasse 2" war, die mit Trainingsinstanz 1 in übereinstimmt y_true. Die Vorhersage für Trainingsinstanz 2 zeigte jedoch eine höchste Wahrscheinlichkeit für "Klasse 1", die nicht mit der wahren Klasse "Klasse 3" übereinstimmt.

loss_per_instance_1 = -tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1])
sess.run(loss_per_instance_1)
# array([ 0.4790107 ,  1.19967598])

Was wir wirklich wollen, ist der Totalverlust über alle Trainingsinstanzen. So können wir berechnen:

total_loss_1 = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1]))
sess.run(total_loss_1)
# 0.83934333897877944

Verwenden von softmax_cross_entropy_with_logits ()

Wir können stattdessen den gesamten Kreuzentropieverlust mit der tf.nn.softmax_cross_entropy_with_logits()unten gezeigten Funktion berechnen .

loss_per_instance_2 = tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true)
sess.run(loss_per_instance_2)
# array([ 0.4790107 ,  1.19967598])

total_loss_2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
sess.run(total_loss_2)
# 0.83934333897877922

Beachten Sie dies total_loss_1und total_loss_2erzeugen Sie im Wesentlichen äquivalente Ergebnisse mit einigen kleinen Unterschieden in den letzten Ziffern. Sie können jedoch auch den zweiten Ansatz verwenden: Es wird eine Codezeile weniger benötigt und es werden weniger numerische Fehler akkumuliert, da der Softmax für Sie innerhalb von ausgeführt wird softmax_cross_entropy_with_logits().

stackoverflowuser2010
quelle
Ich bestätige alle oben genannten. Der einfache Code: M = tf.random.uniform([100, 10], minval=-1.0, maxval=1.0); labels = tf.one_hot(tf.random.uniform([100], minval=0, maxval=10 , dtype='int32'), 10); tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=M) - tf.reduce_sum(-tf.nn.log_softmax(M)*tf.one_hot(labels, 10), -1)Gibt überall nahe Null zurück
Sami A. Haija
51

tf.nn.softmaxberechnet die Vorwärtsausbreitung durch eine Softmax-Schicht. Sie verwenden es während der Auswertung des Modells, wenn Sie die vom Modell ausgegebenen Wahrscheinlichkeiten berechnen.

tf.nn.softmax_cross_entropy_with_logitsberechnet die Kosten für eine Softmax-Schicht. Es wird nur während des Trainings verwendet .

Die Protokolle sind die nicht normalisierten Protokollwahrscheinlichkeiten, die das Modell ausgeben (die Werte, die ausgegeben werden, bevor die Softmax-Normalisierung auf sie angewendet wird).

Ian Goodfellow
quelle
2
Ich verstehe es. Warum nicht die Funktion tf.nn.softmax_cross_entropy_sans_normalization aufrufen?
Euro
8
@auro, weil es die Werte (intern) während der Kreuzentropieberechnung normalisiert. Es tf.nn.softmax_cross_entropy_with_logitsgeht darum zu bewerten, wie stark das Modell von den Goldetiketten abweicht, und nicht um eine normalisierte Ausgabe zu erzielen.
Erickrf
1
Bei Verwendung von tf.nn.sparse_softmax_cross_entropy_with_logits () werden die Kosten einer spärlichen Softmax-Schicht berechnet und sollten daher nur während des Trainings verwendet werden. Was wäre die Alternative, wenn das Modell mit neuen Daten ausgeführt wird, ist es möglich, daraus Wahrscheinlichkeiten zu erhalten einer.
SerialDev
2
@SerialDev, es ist nicht möglich, Wahrscheinlichkeiten von zu erhalten tf.nn.sparse_softmax_cross_entropy_with_logits. Um Wahrscheinlichkeiten zu erhalten, verwenden Sie tf.nn.softmax.
Nandeesh
4

Die obigen Antworten enthalten genügend Beschreibungen für die gestellte Frage.

Darüber hinaus hat Tensorflow den Vorgang der Anwendung der Aktivierungsfunktion optimiert und anschließend die Kosten mithilfe einer eigenen Aktivierung berechnet, gefolgt von Kostenfunktionen. Daher ist es eine gute Praxis zu verwenden: tf.nn.softmax_cross_entropy()vorbeitf.nn.softmax(); tf.nn.cross_entropy()

In einem ressourcenintensiven Modell können Sie einen deutlichen Unterschied zwischen ihnen feststellen.

Abish
quelle
1
Die Antwort oben hat die Frage eindeutig nicht gelesen. Sie sagen alle die gleichen Dinge, die bekannt sind, aber beantworten die Frage selbst nicht
Euler_Salter
@abhish Meinten Sie, tf.nn.softmaxgefolgt von tf.losses.softmax_cross_entropy?
ankurrc
4

Was immer softmaxpassiert , ist logit, das wiederholt J. Hinton die ganze Zeit in Coursera-Videos.

Prosti
quelle
1

Tensorflow 2.0 kompatibel Antwort : Die Erklärungen dgaund stackoverflowuser2010werden über Logits und die damit verbundenen Funktionen sehr detailliert.

Alle diese Funktionen funktionieren bei Verwendung in Tensorflow 1.xeinwandfrei. Wenn Sie jedoch Ihren Code von 1.x (1.14, 1.15, etc)nach migrieren 2.x (2.0, 2.1, etc..), führt die Verwendung dieser Funktionen zu Fehlern.

Daher haben wir die oben beschriebenen 2.0-kompatiblen Aufrufe für alle Funktionen angegeben, wenn wir 1.x to 2.xzum Nutzen der Community von migrieren .

Funktionen in 1.x :

  1. tf.nn.softmax
  2. tf.nn.softmax_cross_entropy_with_logits
  3. tf.nn.sparse_softmax_cross_entropy_with_logits

Entsprechende Funktionen bei der Migration von 1.x auf 2.x :

  1. tf.compat.v2.nn.softmax
  2. tf.compat.v2.nn.softmax_cross_entropy_with_logits
  3. tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits

Weitere Informationen zur Migration von 1.x auf 2.x finden Sie in diesem Migrationshandbuch .

Tensorflow-Unterstützung
quelle
0

Eine weitere Sache, die ich definitiv als logit hervorheben möchte, ist nur eine Rohausgabe, im Allgemeinen die Ausgabe der letzten Ebene. Dies kann auch ein negativer Wert sein. Wenn wir es wie unten erwähnt für die "Kreuzentropie" -Bewertung verwenden:

-tf.reduce_sum(y_true * tf.log(logits))

dann wird es nicht funktionieren. Als Protokoll von -ve ist nicht definiert. Wenn Sie also die Softmax-Aktivierung verwenden, wird dieses Problem behoben.

Dies ist mein Verständnis, bitte korrigieren Sie mich, wenn ich falsch liege.

Vipin Bansal
quelle