Keras binaire crossentropy vs categorical crossentropy performance?

j'essaie de former un CNN pour catégoriser le texte par sujet. Quand j'utilise binary_crossentropy j'obtiens ~80% acc, avec categoric_crossentrop j'obtiens ~50% acc.

Je ne comprends pas pourquoi. C'est un problème multiclasse, ça veut dire que je dois utiliser catégorique et les résultats binaires sont insignifiants?

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'))

puis

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

ou

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
58
demandé sur desertnaut 2017-02-07 06:34:55

7 réponses

la raison de cette apparente divergence de performance entre l'entropie croisée catégorique et binaire est ce que @xtof54 a déjà rapporté dans sa réponse, i.e.:

la précision calculée avec la méthode Keras "evaluate" est juste simple faux en utilisant binary_crossentropy avec plus de 2 étiquettes

je voudrais développer plus sur ce, démontrer la question sous-jacente réelle, l'expliquer, et offrir un recours.

ce comportement n'est pas un bug; la raison sous-jacente est un problème plutôt subtil et non documenté à la façon dont Keras devine quelle précision utiliser, en fonction de la fonction de perte que vous avez sélectionnée, lorsque vous incluez simplement metrics=['accuracy'] dans votre compilation de modèle. En d'autres termes, alors que 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'])

sera ne pas produire ce que vous attendez, mais la raison n'est pas l'utilisation de l'entropie croisée binaire (qui, au moins en principe, est une fonction de perte absolument valide).

pourquoi? Si vous cochez le metrics source code , Keras ne définit pas une seule mesure de précision, mais plusieurs différentes, dont 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 votre fonction de perte et n'ont pas spécifié une précision particulière métrique, Keras (à tort...) implique que vous êtes intéressé par le binary_accuracy , et c'est ce qu'il retourne - alors qu'en fait vous êtes intéressé par le categorical_accuracy .

vérifions que c'est le cas, en utilisant L'exemple MNIST 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.-à-d. d'utiliser en effet l'entropie croisée binaire comme votre fonction de perte (comme je l'ai dit, rien de mal avec cela, au moins en principe) tout en obtenant toujours le catégorique précision exigée par le problème à la main, vous devriez demander explicitement pour categorical_accuracy dans la compilation de modèle comme suit:

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

dans l'exemple du MNIST, après l'entraînement, la notation et la prévision du test comme je le montre ci-dessus, les deux mesures sont maintenant les mêmes, comme elles devraient l'être:

# 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 billet, j'ai découvert que ce problème avait déjà été identifié dans this answer .

66
répondu desertnaut 2018-02-14 14:19:06

c'est un cas très intéressant. En fait, dans votre configuration, l'affirmation suivante est vraie:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

cela signifie que jusqu'à un facteur de multiplication constant vos pertes sont équivalentes. Le comportement étrange que vous observez pendant une phase de formation pourrait être un exemple d'un phénomène suivant:

  1. au début la classe la plus fréquente domine le réseau de perte-ainsi apprend à prédire la plupart du temps ce classe pour chaque exemple.
  2. après avoir appris le schéma le plus fréquent, il commence à discriminer parmi les classes moins fréquentes. Mais quand vous utilisez adam - le taux d'apprentissage a une valeur beaucoup plus faible qu'il avait au début de la formation (c'est en raison de la nature de cet optimiseur). Cela rend la formation plus lente et empêche votre réseau, par exemple, de laisser un mauvais minimum local moins possible.

C'est pourquoi ce facteur constant peut aider en cas de binary_crossentropy . Après de nombreuses époques , la valeur du taux d'apprentissage est plus grande que dans le cas categorical_crossentropy . J'ai l'habitude de reprendre la formation (et la phase d'apprentissage) à quelques reprises lorsque je remarque un tel comportement ou / et d'ajuster les poids d'une classe en utilisant le modèle suivant:

class_weight = 1 / class_frequency

Cela fait une perte d'une classe moins fréquente équilibrant l'influence d'une perte de classe dominante au début d'une formation et dans une partie ultérieure d'un processus d'optimisation.

EDIT:

en fait - j'ai vérifié que même si en cas de mathématiques:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

devrait tenir - dans le cas de keras ce n'est pas vrai, parce que keras normalise automatiquement toutes les sorties pour résumer à 1 . C'est la véritable raison de ce comportement étrange car, dans le cas d'une classification multiple, une telle normalisation nuit à la formation.

21
répondu Marcin Możejko 2018-06-12 21:49:22

je suis tombé sur un problème" inversé " - j'obtenais de bons résultats avec categoric_crossentropy (avec 2 classes) et pauvre avec binary_crossentropy. Il semble que le problème était avec la mauvaise fonction d'activation. Les réglages corrects étaient:

  • pour binary_crossentropy : activation sigmoïde, cible scalaire
  • pour categorical_crossentropy : activation softmax, cible encodée une fois
13
répondu Alexander Svetkin 2017-08-01 10:43:45

après avoir commenté la réponse de @Marcin, j'ai vérifié plus attentivement le code d'un de mes étudiants où j'ai trouvé le même comportement bizarre, même après seulement 2 époques ! (Donc l'explication de @Marcin n'était pas très probable dans mon cas).

et j'ai trouvé que la réponse est en fait très simple: l'exactitude calculée avec la méthode Keras" evaluate " est tout simplement faux en utilisant binary_crossentropy avec plus de 2 étiquettes. Vous pouvez vérifier cela en recalculant la précision vous-même (d'abord appeler la méthode de Keras "prédire", puis calculer le nombre de réponses correctes retournées par prédire): vous obtenez la vraie précision, qui est beaucoup plus faible que le Keras "évaluer" un.

9
répondu xtof54 2017-06-12 12:02:11

tout dépend du type de problème de classification que vous traitez. Il y a trois catégories principales:

  • binaire classification (deux classes cibles)
  • classe multiple classification (plus de deux cibles "exclusives )
  • multi-label classification (plus de deux non exclusive cibles) dans lesquelles plusieurs classes de cibles peuvent être activées en même temps

dans le premier cas, l'entropie croisée binaire doit être utilisée et les cibles doivent être encodées comme des vecteurs à une seule température.

dans le deuxième cas, il faut utiliser une entropie croisée catégorique et encoder les cibles comme des vecteurs à une chaleur.

dans le dernier cas, l'entropie croisée binaire doit être utilisée et les cibles doivent être encodées comme des vecteurs à une seule température. Chaque neurone de sortie (ou unité) est considéré comme une variable binaire aléatoire séparée, et la perte pour l'ensemble du vecteur de sorties est le produit de la perte de variables binaires simples. Par conséquent, il est le produit de binaire d'entropie croisée pour chaque unité de sortie.

entropie binaire croisée est définie comme telle: entropie binaire croisée et l'entropie croisée catégorique est définie comme telle: catégorique d'entropie croisée

8
répondu whynote 2018-03-08 14:34:48

comme il s'agit d'un problème multi-classes, vous devez utiliser la categorical_crossentropy, l'entropie binaire croisée produira des résultats bidons, très probablement ne évaluera que les deux premières classes seulement.

50% pour un problème multi-classes peut être assez bon, selon le nombre de classes. Si vous avez n classes, alors 100 / n est la performance minimale que vous pouvez obtenir en sortant une classe aléatoire.

4
répondu Matias Valdenegro 2017-02-07 15:04:53

lorsque vous utilisez la perte categorical_crossentropy , vos cibles doivent être en format catégorique (par exemple, si vous avez 10 classes, la cible pour chaque échantillon doit être un vecteur en 10 dimensions qui est de tous les zéros sauf un 1 à l'index correspondant à la classe de l'échantillon).

1
répondu Priyansh 2018-02-02 23:09:26