Kurzfassung:
Angenommen, Sie haben zwei Tensoren, y_hat
die berechnete Punktzahlen für jede Klasse enthalten (z. B. von y = W * x + b) und y_true
One-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_hat
als 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_hat
ein 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_true
Array, bei dem die Zeilen wiederum Trainingsinstanzen und die Spalten Klassen sind. Im Folgenden habe ich ein Beispiel für ein y_true
One-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_softmax
nahe an der Wahrscheinlichkeitsverteilung in y_true
? Wir können den Kreuzentropieverlust verwenden , um den Fehler zu messen.
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_1
und total_loss_2
erzeugen 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()
.
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, istpred=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.