Solución:
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 de Keras
evaluate
es simplemente incorrecto cuando se usa binary_crossentropy con más de 2 etiquetas
Me gustaría desarrollar más sobre esto, demostrar el problema subyacente real, explicarlo y ofrecer una solución.
Este comportamiento no es un error; La razón subyacente es una cuestión bastante sutil e indocumentada sobre cómo Keras realmente suposiciones qué precisión usar, dependiendo de la función de pérdida que haya seleccionado, cuando incluye simplemente metrics=['accuracy']
en su compilación de modelos. En otras palabras, mientras que su primera opción de compilación
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=['accuracy'])
es válido, el segundo:
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
no producirá lo que espera, pero la razón no es el uso de la entropía cruzada binaria (que, al menos en principio, es una función de pérdida absolutamente válida).
¿Porqué es eso? Si comprueba el código fuente de las métricas, Keras no define una única métrica de precisión, sino varias diferentes, entre ellas binary_accuracy
y categorical_accuracy
. Lo que sucede bajo el capó es que, dado que ha seleccionado la entropía cruzada binaria como su función de pérdida y no ha especificado una métrica de precisión en particular, Keras (erróneamente …) infiere que está interesado en la binary_accuracy
, y esto es lo que devuelve, mientras que de hecho está interesado en el categorical_accuracy
.
Verifiquemos que este es el caso, usando 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, usar de hecho la entropía cruzada binaria como función de pérdida (como dije, no hay nada de malo en esto, al menos en principio) sin dejar de obtener la categórico precisión requerida por el problema en cuestión, debe solicitar explícitamente categorical_accuracy
en la 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 de MNIST, después de entrenar, puntuar y predecir el conjunto de pruebas como se muestra 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
ACTUALIZAR: Después de mi publicación, descubrí que este problema ya se había identificado en esta respuesta.
Todo depende del tipo de problema de clasificación con el que esté lidiando. Hay tres categorías principales
- binario clasificación (dos clases de destino),
- multiclase clasificación (más de dos exclusivo objetivos),
- multi-etiqueta clasificación (más de dos no exclusivo objetivos), en el que pueden estar activadas varias clases de objetivos al mismo tiempo.
En el primer caso, se debe utilizar la entropía cruzada binaria y los objetivos se deben codificar como vectores one-hot.
En el segundo caso, se debe utilizar la entropía cruzada categórica y los objetivos se deben codificar como vectores one-hot.
En el último caso, se debe utilizar la entropía cruzada binaria y los objetivos se deben codificar como vectores one-hot. Cada neurona de salida (o unidad) se considera una variable binaria aleatoria separada, y la pérdida para todo el vector de salidas es el producto de la pérdida de variables binarias individuales. Por lo tanto, es el producto de la entropía cruzada binaria para cada unidad de salida.
La entropía cruzada binaria se define como
y la entropía cruzada categórica se define como
dónde c
es el índice que se ejecuta sobre el número de clases C
.
Me encontré con un problema “invertido”: obtenía buenos resultados con categorical_crossentropy (con 2 clases) y malos con binary_crossentropy. Parece que el problema estaba en una función de activación incorrecta. Los ajustes correctos fueron:
- por
binary_crossentropy
: activación sigmoidea, objetivo escalar - por
categorical_crossentropy
: activación softmax, objetivo codificado en caliente