wake-up-neo.net

Keras binary_crossentropy vs. kategoriale_crossentropy-Leistung?

Ich versuche, ein CNN zu trainieren, um Text nach Themen zu kategorisieren. Wenn ich binary_crossentropy verwende, bekomme ich ~ 80% acc, mit categorical_crossentrop bekomme ich ~ 50% acc.

Ich verstehe nicht, warum das so ist. Es ist ein Problem mit mehreren Klassen, bedeutet das, dass ich kategoriale verwenden muss und die binären Ergebnisse bedeutungslos sind?

model.add(embedding_layer)
model.add(Dropout(0.25))
# convolution layers
model.add(Conv1D(nb_filter=32,
                    filter_length=4,
                    border_mode='valid',
                    activation='relu'))
model.add(MaxPooling1D(pool_length=2))
# dense layers
model.add(Flatten())
model.add(Dense(256))
model.add(Dropout(0.25))
model.add(Activation('relu'))
# output layer
model.add(Dense(len(class_id_index)))
model.add(Activation('softmax'))

dann 

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

oder 

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
82
Daniel Messias

Der Grund für diese scheinbare Leistungsdifferenz zwischen kategorialer und binärer Kreuzentropie ist das, was @ xtof54 bereits in seiner Antwort berichtet hat, d.h.

die mit der Keras-Methode evaluate berechnete Genauigkeit ist einfach falsch bei Verwendung von binary_crossentropy mit mehr als 2 Labels

Ich möchte darauf näher eingehen, das eigentliche zugrunde liegende Problem aufzeigen, erläutern und Abhilfe schaffen.

Dieses Verhalten ist kein Fehler. Der zugrunde liegende Grund ist ein eher subtiler und undokumentierter Grund, wie Keras tatsächlich die {Vermutungen _ Genauigkeit verwendet, abhängig von der von Ihnen gewählten Verlustfunktion, wenn Sie einfach metrics=['accuracy'] in Ihre Modellkompilierung aufnehmen. Mit anderen Worten, während Ihre erste Übersetzungsoption 

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

ist gültig, dein zweiter:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

wird nicht das produzieren, was Sie erwarten, aber der Grund ist nicht die Verwendung der binären Kreuzentropie (die zumindest im Prinzip eine absolut gültige Verlustfunktion ist).

Warum das? Wenn Sie den metrics-Quellcode überprüfen, definiert Keras keine einzelne Genauigkeitsmetrik, sondern mehrere verschiedene, darunter binary_accuracy und categorical_accuracy. Was passiert unter der Haube ist, dass Keras (falsch ...), da Sie als Verlustfunktion die binäre Kreuzentropie als Verlustfunktion ausgewählt und keine bestimmte Genauigkeitsmetrik angegeben haben, an Sie und Ihr Interesse an dem binary_accuracy erinnert ist das, was er zurückgibt - während Sie tatsächlich am categorical_accuracy interessiert sind.

Stellen Sie sicher, dass dies der Fall ist, und verwenden Sie dazu das MNIST CNN-Beispiel in Keras mit der folgenden Änderung:

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])  # WRONG way

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=2,  # only 2 epochs, for demonstration purposes
          verbose=1,
          validation_data=(x_test, y_test))

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.9975801164627075

# Actual accuracy calculated manually:
import numpy as np
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98780000000000001

score[1]==acc
# False    

Um Abhilfe zu schaffen, dh um die binäre Kreuzentropie als Verlustfunktion zu verwenden (wie gesagt, dies ist zumindest im Prinzip nichts Falsches), während gleichzeitig die durch das anstehende Problem geforderte Genauigkeit von kategorical erreicht wird, sollten Sie fragen explizit für categorical_accuracy in der Modellzusammenstellung wie folgt:

from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])

Im MNIST-Beispiel sind die beiden Metriken nach dem Training, Bewerten und Vorhersagen des Test-Sets, wie ich es oben gezeigt habe, nun die gleichen, wie sie sein sollten:

# Keras reported accuracy:
score = model.evaluate(x_test, y_test, verbose=0) 
score[1]
# 0.98580000000000001

# Actual accuracy calculated manually:
y_pred = model.predict(x_test)
acc = sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000
acc
# 0.98580000000000001

score[1]==acc
# True    

Systemkonfiguration:

Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4

UPDATE: Nach meinem Beitrag habe ich festgestellt, dass dieses Problem bereits in dieser Antwort gefunden wurde.

106
desertnaut

Es ist wirklich ein interessanter Fall. Eigentlich gilt in Ihrem Setup die folgende Aussage:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

Dies bedeutet, dass Ihre Verluste bis zu einem konstanten Multiplikationsfaktor gleich sind. Das merkwürdige Verhalten, das Sie während einer Trainingsphase beobachten, kann ein Beispiel für ein folgendes Phänomen sein:

  1. Zu Beginn dominiert die häufigste Klasse den Verlust. Daher lernt das Netzwerk, diese Klasse meist für jedes Beispiel vorherzusagen.
  2. Nachdem es das häufigste Muster gelernt hat, beginnt es, zwischen weniger häufigen Klassen zu unterscheiden. Wenn Sie jedoch adam verwenden, hat die Lernrate einen viel geringeren Wert als zu Beginn des Trainings (dies liegt an der Natur dieses Optimierers). Dies macht das Training langsamer und verhindert, dass Ihr Netzwerk z. Hinterlassen eines schlechten lokalen Minimums ist weniger möglich.

Deshalb kann dieser konstante Faktor im Fall von binary_crossentropy helfen. Nach vielen Epochen - der Lernratenwert ist größer als in categorical_crossentropy. Normalerweise starte ich das Training (und die Lernphase) einige Male neu, wenn ich ein solches Verhalten bemerke oder/und die Klassengewichtung anhand des folgenden Musters anpasse:

class_weight = 1 / class_frequency

Dies führt dazu, dass der Verlust von weniger häufig auftretenden Klassen den Einfluss eines dominanten Klassenverlusts zu Beginn eines Trainings und in einem weiteren Teil eines Optimierungsprozesses ausbalanciert.

BEARBEITEN:

Eigentlich - ich habe das überprüft, auch wenn es sich um Mathematik handelt:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

sollte halten - im Fall von keras ist dies nicht wahr, da keras automatisch alle Ausgaben normalisiert, um 1 zu summieren. Dies ist der eigentliche Grund für dieses seltsame Verhalten, da bei einer Klassifizierung eine solche Normalisierung einem Training schadet.

24
Marcin Możejko

Ich bin auf ein "umgekehrtes" Problem gestoßen - ich habe gute Ergebnisse mit categorical_crossentropy (mit 2 Klassen) und schlecht mit binary_crossentropy erzielt. Es scheint, dass das Problem mit einer falschen Aktivierungsfunktion war. Die korrekten Einstellungen waren:

  • für binary_crossentropy: sigmoidale Aktivierung, skalares Ziel 
  • für categorical_crossentropy: Softmax-Aktivierung, One-Hot-codiertes Ziel
18

Es hängt alles von der Art des Klassifizierungsproblems ab, mit dem Sie sich befassen. Es gibt drei Hauptkategorien:

  • binary Klassifizierung (zwei Zielklassen)
  • multi-class Klassifizierung (mehr als zwei exclusive Ziele)
  • multi-label Klassifizierung (mehr als zwei nicht exklusive Ziele), in der mehrere Zielklassen gleichzeitig aktiviert sein können

Im ersten Fall sollte eine binäre Kreuzentropie verwendet werden, und Ziele sollten als One-Hot-Vektoren codiert werden.

Im zweiten Fall sollte kategoriale Kreuzentropie verwendet werden, und Ziele sollten als One-Hot-Vektoren kodiert werden.

Im letzten Fall sollte eine binäre Kreuzentropie verwendet werden, und Ziele sollten als One-Hot-Vektoren codiert werden. Jedes Ausgabeneuron (oder jede Einheit) wird als separate zufällige binäre Variable betrachtet, und der Verlust für den gesamten Vektor der Ausgänge ist das Produkt des Verlusts einzelner binärer Variablen. Daher ist es das Produkt der binären Kreuzentropie für jede einzelne Ausgabeeinheit.

binäre Kreuzentropie ist als solche definiert: Binäre Kreuzentropie und kategoriale Kreuzentropie ist als solche definiert: Kategoriale Kreuzentropie

14
whynote

Nachdem ich die Antwort von @Marcin kommentiert habe, habe ich einen Code meiner Schüler genauer überprüft, in dem ich selbst nach nur zwei Epochen das seltsame Verhalten fand. (Also war @ Marcins Erklärung in meinem Fall nicht sehr wahrscheinlich).

Und ich fand, dass die Antwort eigentlich sehr einfach ist: Die mit der Keras-Methode evaluate berechnete Genauigkeit ist einfach falsch, wenn Sie binary_crossentropy mit mehr als 2 Labels verwenden. Sie können dies überprüfen, indem Sie die Genauigkeit selbst neu berechnen (rufen Sie zuerst die Keras-Methode "Prediction" an und berechnen Sie dann die Anzahl der korrekten Antworten, die von Predict zurückgegeben werden).

12
xtof54

Da es sich um ein Problem mit mehreren Klassen handelt, müssen Sie categorical_crossentropy verwenden. Die binäre Kreuzentropie führt zu falschen Ergebnissen. Wahrscheinlich werden nur die ersten beiden Klassen ausgewertet.

50% für ein Problem mit mehreren Klassen können je nach Anzahl der Klassen recht gut sein. Wenn Sie n Klassen haben, ist 100/n die minimale Leistung, die Sie durch Ausgabe einer zufälligen Klasse erzielen können.

4

wenn Sie categorical_crossentropy loss verwenden, sollten Ihre Ziele in kategorialem Format sein (z. B. wenn Sie 10 Klassen haben, sollte das Ziel für jede Probe ein 10-dimensionaler Vektor sein, der aus Nullen besteht, mit Ausnahme einer 1 am Index, die der Klasse von entspricht die Probe).

1
Priyansh

ein einfaches Beispiel unter einer Multi-Class-Einstellung

angenommen, Sie haben 4 Klassen (onehot-codiert) und unten ist nur eine Vorhersage

true_label = [0,1,0,0] predicted_label = [0,0,1,0]

bei der Verwendung von categorical_crossentropy ist die Genauigkeit nur 0, es ist nur wichtig, wenn Sie die betreffende Klasse richtig einstellen.

bei der Verwendung von binary_crossentropy wird jedoch die Genauigkeit für alle Klassen berechnet. Diese Vorhersage würde 50% betragen. und das Endergebnis ist das Mittel der Einzelgenauigkeiten für beide Fälle.

es wird empfohlen, categorical_crossentropy für Probleme mit mehreren Klassen (Klassen sind sich gegenseitig ausschließend) zu verwenden, aber binary_crossentropy für Probleme mit mehreren Labels.

1
bazinga

Sie übergeben ein Ziel-Array mit einer Form (x-dim, y-dim), während Sie als Verlust categorical_crossentropy verwenden. categorical_crossentropy erwartet, dass Ziele binäre Matrizen (1s und 0s) der Form (Samples, Klassen) sind. Wenn Ihre Ziele Ganzzahlklassen sind, können Sie sie in das erwartete Format konvertieren:

from keras.utils import to_categorical
y_binary = to_categorical(y_int)

Alternativ können Sie stattdessen die Verlustfunktion sparse_categorical_crossentropy verwenden, die ganzzahlige Ziele erwartet.

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
0
susan097

Schauen Sie sich die Gleichung an, Sie können feststellen, dass binäre Kreuzentropie nicht nur die Label = 1, Predicted = 0, sondern auch Label = 0, Predicted = 1 bestraft.

Jedoch kategorische Kreuzentropie bestraft nur das Label = 1, aber vorhergesagt = 1. Deshalb gehen wir davon aus, dass nur EIN Label positiv ist.

0
Kuang Yan