machine learning - compile - Keras binary_crossentropy vs categorical_crossentropy performance?
error keras (11)
Estoy tratando de entrenar a una CNN para clasificar el texto por tema. Cuando uso binary_crossentropy obtengo ~ 80% acc, con categorical_crossentrop obtengo ~ 50% acc.
No entiendo por qué es esto. Es un problema multiclase, ¿eso significa que tengo que usar categórico y los resultados binarios no tienen sentido?
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''))
entonces
model.compile(loss=''categorical_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])
o
model.compile(loss=''binary_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])
Como es un problema de varias clases, debe usar la categorical_crossentropy, la entropía cruzada binaria producirá resultados falsos, lo más probable es que solo evalúe las dos primeras clases.
El 50% para un problema de varias clases puede ser bastante bueno, dependiendo del número de clases. Si tiene n clases, entonces 100 / n es el rendimiento mínimo que puede obtener al generar una clase aleatoria.
Después de comentar la respuesta de @Marcin, he revisado con más cuidado el código de uno de mis estudiantes donde encontré el mismo comportamiento extraño, ¡incluso después de solo 2 épocas! (Entonces, la explicación de @ Marcin no era muy probable en mi caso).
Y descubrí que la respuesta es realmente muy simple: la precisión calculada con la
evaluate
método Keras es simplemente incorrecta cuando se usa binary_crossentropy con más de 2 etiquetas.
Puede verificarlo volviendo a calcular la precisión usted mismo (primero llame al método de Keras "predecir" y luego calcule el número de respuestas correctas devueltas por predecir): obtiene la verdadera precisión, que es mucho menor que la de "evaluar" Keras.
Eche un vistazo a la ecuación y descubra que la entropía cruzada binaria no solo castiga esas etiquetas = 1, predichas = 0, sino también etiqueta = 0, predichas = 1.
Sin embargo, la entropía cruzada categórica solo castiga a esas etiquetas = 1 pero predice = 1. Por eso suponemos que solo hay UNA etiqueta positiva.
Es un caso realmente interesante. En realidad, en su configuración, la siguiente afirmación es verdadera:
binary_crossentropy = len(class_id_index) * categorical_crossentropy
Esto significa que hasta un factor de multiplicación constante sus pérdidas son equivalentes. El comportamiento extraño que observa durante una fase de entrenamiento podría ser un ejemplo de un fenómeno siguiente:
- Al principio, la clase más frecuente domina la pérdida, por lo que la red está aprendiendo a predecir principalmente esta clase para cada ejemplo.
-
Después de aprender el patrón más frecuente, comienza a discriminar entre las clases menos frecuentes.
Pero cuando usa
adam
, la tasa de aprendizaje tiene un valor mucho menor que al principio del entrenamiento (es por la naturaleza de este optimizador). Hace que el entrenamiento sea más lento y evita que su red, por ejemplo, deje un mínimo local pobre menos posible.
Es por eso que este factor constante podría ayudar en caso de
binary_crossentropy
.
Después de muchas épocas, el valor de la tasa de aprendizaje es mayor que en el caso de
categorical_crossentropy
.
Por lo general, reinicio el entrenamiento (y la fase de aprendizaje) algunas veces cuando noto tal comportamiento y / o ajusto los pesos de una clase usando el siguiente patrón:
class_weight = 1 / class_frequency
Esto hace que la pérdida de clases menos frecuentes equilibre la influencia de una pérdida de clase dominante al comienzo de un entrenamiento y en otra parte de un proceso de optimización.
EDITAR:
En realidad, lo comprobé aunque en el caso de las matemáticas:
binary_crossentropy = len(class_id_index) * categorical_crossentropy
debería mantenerse, en el caso de
keras
no es cierto, porque
keras
está normalizando automáticamente todas las salidas para sumar
1
.
Esta es la razón real detrás de este comportamiento extraño, ya que en caso de multiclasificación, tal normalización daña un entrenamiento.
Está pasando una matriz de forma objetivo (x-dim, y-dim) mientras usa como pérdida
categorical_crossentropy
.
categorical_crossentropy
espera que los objetivos sean matrices binarias (1s y 0s) de forma (muestras, clases).
Si sus objetivos son clases enteras, puede convertirlas al formato esperado a través de:
from keras.utils import to_categorical
y_binary = to_categorical(y_int)
Alternativamente, puede usar la función de pérdida
sparse_categorical_crossentropy
en
sparse_categorical_crossentropy
lugar, que espera objetivos enteros.
model.compile(loss=''sparse_categorical_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])
La binary_crossentropy (y_target, y_predict) no necesita aplicarse en un problema de clasificación binaria. .
En el código fuente de
binary_crossentropy()
, se usó realmente la función TensorFlow
nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)
.
Y, en la
documentation
, dice que:
Mide el error de probabilidad en tareas de clasificación discretas en las que cada clase es independiente y no se excluye mutuamente. Por ejemplo, uno podría realizar una clasificación de múltiples etiquetas donde una imagen puede contener un elefante y un perro al mismo tiempo.
La razón de esta aparente discrepancia de rendimiento entre la entropía cruzada categórica y binaria es lo que @ xtof54 ya ha informado en su respuesta, es decir:
la precisión calculada con la
evaluate
método Keras 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 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 verifica 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 ha seleccionado la entropía cruzada binaria como su función de pérdida y no ha especificado una métrica de precisión particular, Keras (erróneamente ...) infiere que está interesado en la
binary_accuracy
, y esto es lo que devuelve - Si bien, de hecho, está interesado en la
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, 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 sigue obteniendo la precisión
categórica
requerida por el problema en cuestión, debe solicitar explícitamente la precisión
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 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 .
Me encontré con un problema "invertido": estaba obteniendo buenos resultados con categorical_crossentropy (con 2 clases) y pobre con binary_crossentropy. Parece que el problema fue con la función de activación incorrecta. Las configuraciones correctas fueron:
-
para
binary_crossentropy
: activación sigmoidea, objetivo escalar -
para
categorical_crossentropy
: activación de softmax, objetivo codificado en caliente
Todo depende del tipo de problema de clasificación con el que esté lidiando. Hay tres categorías principales;
- clasificación binaria (dos clases objetivo)
- clasificación de varias clases (más de dos objetivos exclusivos )
- clasificación de etiquetas múltiples (más de dos objetivos no exclusivos ) en la que pueden estar disponibles múltiples clases de objetivos al mismo tiempo
En el primer caso, se debe utilizar la entropía cruzada binaria y los objetivos deben codificarse como vectores de un solo calor.
En el segundo caso, se debe utilizar la entropía cruzada categórica y los objetivos deben codificarse como vectores de un solo calor.
En el último caso, se debe utilizar la entropía cruzada binaria y los objetivos deben codificarse como vectores de un solo calor. Cada neurona de salida (o unidad) se considera como 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 individual.
la entropía cruzada binaria se define como tal: la entropía cruzada binaria y la entropía cruzada categórica se define como tal: entropía cruzada categórica
cuando use la pérdida de
categorical_crossentropy
, sus objetivos deben estar en formato categórico (por ejemplo, si tiene 10 clases, el objetivo para cada muestra debe ser un vector de 10 dimensiones que es todo ceros, excepto un 1 en el índice correspondiente a la clase de la muestra).
un ejemplo simple en un entorno de varias clases para ilustrar
supongamos que tiene 4 clases (codificadas con un solo disparo) y a continuación se muestra solo una predicción
true_label = [0,1,0,0] predicted_label = [0,0,1,0]
cuando se utiliza categorical_crossentropy, la precisión es solo 0, solo le importa si obtiene la clase correcta.
sin embargo, cuando se usa binary_crossentropy, la precisión se calcula para todas las clases, sería del 50% para esta predicción. y el resultado final será la media de las precisiones individuales para ambos casos.
se recomienda utilizar categorical_crossentropy para el problema de varias clases (las clases se excluyen mutuamente) pero binary_crossentropy para el problema de múltiples etiquetas.