La raison de cette apparente divergence de performance entre l'entropie croisée catégorielle et binaire est ce que l'utilisateur xtof54 a déjà signalé dans sa réponse ci-dessous c'est-à-dire :
la précision calculée avec la méthode Keras evaluate
est tout simplement erronée lorsqu'on utilise l'algorithme binary_crossentropy avec plus de 2 étiquettes.
J'aimerais m'étendre davantage sur ce sujet, montrer le véritable problème sous-jacent, l'expliquer et proposer un remède.
Ce comportement n'est pas un bogue ; la raison sous-jacente est un problème plutôt subtil et non documenté dans la manière dont Keras utilise les techniques d'analyse des données. suppositions quelle précision utiliser, en fonction de la fonction de perte que vous avez choisie, lorsque vous incluez simplement metrics=['accuracy']
dans la compilation de votre modèle. En d'autres termes, si votre première option de compilation
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
est valable, votre deuxième :
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
ne produira pas ce que vous attendez, mais la raison n'en est pas l'utilisation de l'entropie croisée binaire (qui, au moins en principe, est une fonction de perte absolument valide).
Pourquoi cela ? Si vous vérifiez le code source métrique Keras ne définit pas une seule mesure de précision, mais plusieurs, parmi lesquelles binary_accuracy
y categorical_accuracy
. Ce qui se passe sous le capot est que, puisque vous avez choisi l'entropie croisée binaire comme fonction de perte et que vous n'avez pas spécifié de mesure de précision particulière, Keras en déduit (à tort...) que vous vous intéressez à l'entropie croisée binaire. binary_accuracy
et c'est ce qu'elle renvoie - alors qu'en fait, vous êtes intéressé par l'option categorical_accuracy
.
Vérifions que c'est bien le cas, en utilisant la fonction MNIST exemple CNN dans Keras, avec la modification suivante :
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
Pour remédier à cela, c'est-à-dire pour utiliser effectivement l'entropie croisée binaire comme fonction de perte (comme je l'ai dit, il n'y a rien de mal à cela, du moins en principe) tout en obtenant la catégorique précision requise par le problème en question, vous devez demander explicitement categorical_accuracy
dans la compilation du modèle comme suit :
from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
Dans l'exemple de MNIST, après l'entraînement, la notation et la prédiction de l'ensemble de test comme je l'ai montré ci-dessus, les deux métriques sont maintenant identiques, comme il se doit :
# 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
Configuration du système :
Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4
UPDATE : Après mon post, j'ai découvert que cette question avait déjà été identifiée dans cette réponse .
24 votes
Si c'est un problème multi-classes, vous devez utiliser
categorical_crossentropy
. Les étiquettes doivent également être converties au format catégoriel. Voirto_categorical
pour ce faire. Voir également les définitions des entropies croisées catégorielles et binaires. aquí .0 votes
Mes étiquettes sont catégoriques, créées à l'aide de to_categorical (un vecteur chaud pour chaque classe). Cela signifie-t-il que la précision de ~80% de la crossentropie binaire est juste un chiffre bidon ?
0 votes
Je pense que oui. Si vous utilisez des étiquettes catégoriques, c'est-à-dire des vecteurs à une chaleur, alors vous voulez
categorical_crossentropy
. Si vous avez deux classes, elles seront représentées comme suit0, 1
en étiquettes binaires et10, 01
sous forme d'étiquettes catégoriques.0 votes
Intuitivement, il est logique que je veuille utiliser categorical_crossentropy, mais je ne comprends pas pourquoi j'obtiens de bons résultats avec binaire, et de mauvais résultats avec catégorique.
2 votes
Je pense qu'il compare juste au premier nombre du vecteur et ignore le reste.
0 votes
J'observe une situation similaire, si j'utilise binary_crossentropy j'obtiens de meilleurs résultats (également en termes de perte), très intéressant.
0 votes
Mes données sont déséquilibrées (l'une des classes est plus dense), avez-vous également une structure similaire dans vos données de formation ?
0 votes
Je l'ai fait, il est possible que cela ait été un facteur contributif, bien que je me sois éloigné depuis d'un réseau neuronal pour ces données (pour d'autres raisons) et que je n'aie pas cherché à approfondir la question.
0 votes
@ParagS.Chandakkar . La représentation sera 0, 1 pour une classification binaire et [[0, 0], [0, 1]] pour une classification catégorielle. Cela dépend aussi fortement de la façon dont vous concevez la couche finale de softmax. Dense(1, activation='softmax') devrait permettre 0,1. Dense(2, activation='softmax') nécessite [[0,0], [0,1]].
7 votes
@NilavBaranGhosh La représentation sera [[1, 0], [0, 1]] pour une classification catégorielle impliquant deux classes (et non [[0, 0], [0, 1]] comme vous le mentionnez).
Dense(1, activation='softmax')
pour la classification binaire est tout simplement faux. Rappelez-vous que la sortie de softmax est une distribution de probabilité dont la somme est égale à un. Si vous voulez avoir un seul neurone de sortie avec une classification binaire, utilisez une sigmoïde avec une entropie croisée binaire.