web-dev-qa-db-fra.com

Pourquoi le binary_crossentropy est-il plus précis que categorical_crossentropy pour la classification multiclasse dans Keras?

J'apprends à créer des réseaux de neurones convolutifs en utilisant Keras. J'essaie d'obtenir une grande précision pour l'ensemble de données MNIST.

Apparemment categorical_crossentropy est pour plus de 2 classes et binary_crossentropy est pour 2 classes. Puisqu'il y a 10 chiffres, je devrais utiliser categorical_crossentropy. Cependant, après avoir formé et testé des dizaines de modèles, binary_crossentropy surpasse systématiquement categorical_crossentropy significativement.

Sur Kaggle, j'ai obtenu une précision de 99 +% en utilisant binary_crossentropy et 10 époques. Pendant ce temps, je ne peux pas dépasser 97% en utilisant categorical_crossentropy, même en utilisant 30 époques (ce qui n'est pas beaucoup, mais je n'ai pas de GPU, donc la formation prend une éternité).

Voici à quoi ressemble mon modèle maintenant:

model = Sequential()
model.add(Convolution2D(100, 5, 5, border_mode='valid', input_shape=(28, 28, 1), init='glorot_uniform', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(100, 3, 3, init='glorot_uniform', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.3))
model.add(Flatten())
model.add(Dense(100, init='glorot_uniform', activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(100, init='glorot_uniform', activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(10, init='glorot_uniform', activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='adamax', metrics=['accuracy'])
17
Leo Jiang

Réponse courte: c'est pas.

Pour voir cela, essayez simplement de calculer la précision "à la main", et vous verrez qu'elle est différente de celle rapportée par Keras avec le model.evaluate méthode:

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

# 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.98999999999999999

La raison pour laquelle semble être ainsi est un problème assez subtil sur la façon dont Keras suppose quelle précision utiliser, selon la fonction de perte que vous avez sélectionnée, quand vous incluez simplement metrics=['accuracy'] dans votre compilation de modèles.

Si vous cochez code source , Keras ne définit pas une seule métrique de précision, mais plusieurs différentes, parmi lesquelles binary_accuracy et categorical_accuracy. Ce qui se passe sous le capot est que, puisque vous avez sélectionné l'entropie croisée binaire comme fonction de perte et que vous n'avez pas spécifié de métrique de précision particulière, Keras (à tort ...) en déduit que vous êtes intéressé par le binary_accuracy, et c'est ce qu'il renvoie.

Pour éviter cela, c'est-à-dire utiliser en effet l'entropie croisée binaire comme fonction de perte (rien de mal à cela, en principe) tout en obtenant la précision catégorique requise par le problème en question (c'est-à-dire la classification MNIST), vous devrait demander explicitement categorical_accuracy dans la compilation du modèle comme suit:

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

Et après l'entraînement, la notation et la prévision de l'ensemble de tests comme je le montre ci-dessus, les deux mesures sont maintenant les mêmes, comme elles devraient l'être:

sum([np.argmax(y_test[i])==np.argmax(y_pred[i]) for i in range(10000)])/10000 == score[1]
# True

(HT à cette excellente réponse à un problème similaire, ce qui m'a aidé à comprendre le problème ...)

UPDATE : Après mon message, j'ai découvert que ce problème avait déjà été identifié dans cette réponse .

14
desertnaut

Tout d'abord, binary_crossentropy n'est pas lorsqu'il y a deux classes.

Le nom "binaire" est dû au fait qu'il est adapté pour la sortie binaire et que chaque numéro du softmax est destiné à être 0 ou 1. Ici, il vérifie chaque numéro de la sortie.

Cela n'explique pas votre résultat, car categorical_entropy exploite le fait qu'il s'agit d'un problème de classification.

Êtes-vous sûr que lorsque vous lisez vos données, il y a une et une seule classe par échantillon? C'est la seule explication que je puisse donner.

2
Labo