error cross compile categorical machine-learning keras neural-network deep-learning conv-neural-network

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:

  1. 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.
  2. 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.