La razón de esta aparente discrepancia de rendimiento entre la entropía cruzada categórica y binaria es lo que el usuario xtof54 ya ha informado en su respuesta a continuación , es decir:
la precisión calculada con el método Keras evaluate
es simplemente incorrecta cuando se usa binary_crossentropy con más de 2 etiquetas
Me gustaría dar más detalles sobre esto, demostrar el problema subyacente real, explicarlo y ofrecer un remedio.
Este comportamiento no es un error; La razón subyacente es un problema bastante sutil e indocumentado sobre cómo Keras realmente adivina qué precisión usar, dependiendo de la función de pérdida que haya seleccionado, cuando se incluye simplemente metrics=['accuracy']
en la compilación de su modelo. En otras palabras, mientras tu primera opción de compilación
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
es válido, tu segundo:
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
no producirá lo que espera, pero la razón no es el uso de entropía cruzada binaria (que, al menos en principio, es una función de pérdida absolutamente válida).
¿Porqué es eso? Si marca el código fuente de las métricas , Keras no define una sola métrica de precisión, sino varias, entre ellas binary_accuracy
y categorical_accuracy
. Lo que sucede debajo del capó es que, dado que seleccionó la entropía cruzada binaria como su función de pérdida y no especificó una métrica de precisión particular, Keras (erróneamente ...) infiere que le interesa binary_accuracy
, y esto es lo que devuelve: mientras que de hecho estás interesado en el categorical_accuracy
.
Verifiquemos que este sea el caso, utilizando el ejemplo MNIST CNN en Keras, con la siguiente modificación:
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
Para remediar esto, es decir, para utilizar la entropía cruzada binaria como su función de pérdida (como dije, no hay nada de malo en esto, al menos en principio) mientras obtiene la precisión categórica requerida por el problema en cuestión, debe solicitarlo explícitamente categorical_accuracy
en el compilación del modelo de la siguiente manera:
from keras.metrics import categorical_accuracy
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=[categorical_accuracy])
En el ejemplo MNIST, después de entrenar, puntuar y predecir el conjunto de pruebas como muestro arriba, las dos métricas ahora son las mismas, como deberían ser:
# 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
Configuración del sistema:
Python version 3.5.3
Tensorflow version 1.2.1
Keras version 2.0.4
ACTUALIZACIÓN : Después de mi publicación, descubrí que este problema ya se había identificado en esta respuesta .
categorical_crossentropy
. También las etiquetas deben convertirse al formato categórico. Mirato_categorical
para hacer esto. También vea las definiciones de las crossentropías categóricas y binarias aquí .