Keras crossentropy binario vs rendimiento de crossentropy categórica?


Estoy tratando de entrenar a una CNN para categorizar 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'])
Author: desertnaut, 2017-02-07

7 answers

La razón de esta aparente discrepancia de rendimiento entre entropía cruzada categórica y binaria es lo que @xtof54 ya ha informado en su respuesta, es decir:

La precisión calculada con el método Keras "evaluar" es simple incorrecto al usar binary_crossentropy con más de 2 etiquetas

Me gustaría desarrollar más sobre esto, demostrar el problema subyacente real, explicarlo y ofrecer un remedio.

Este comportamiento no es un error; el 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 incluya 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 pérdida absolutamente válida función).

¿Por qué es eso? Si comprueba el código fuente de las métricas , Keras no define una métrica de precisión única, sino varias métricas diferentes, entre ellas binary_accuracy y categorical_accuracy. Lo que sucede bajo el capó es que, ya 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 usted está interesado en el binary_accuracy, y esto es lo que devuelve - mientras que en realidad usted está interesado en el categorical_accuracy.

Vamos a verificar 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 la entropía cruzada binaria de hecho como su función de pérdida (como dije, no hay nada de malo en esto, al menos en principio) mientras sigue obteniendo la categórica precisión requerida por el problema en cuestión, debe pedir 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 MNIST por ejemplo, después de entrenar, puntuar y predecir el conjunto de pruebas como mostré anteriormente, 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 post, descubrí que este problema ya había sido identificado en esta respuesta.

 66
Author: desertnaut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 14:19:06

Es un caso realmente interesante. En realidad, en su configuración, la siguiente declaració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 está observando durante una fase de entrenamiento podría ser un ejemplo de un fenómeno siguiente:

  1. Al principio, la clase más frecuente está dominando la pérdida, por lo que network está aprendiendo a predecir principalmente esta clase para cada ejemplo.
  2. Después de que aprendió la patrón más frecuente comienza a discriminar entre clases menos frecuentes. Pero cuando se utiliza adam - la tasa de aprendizaje tiene un valor mucho menor de lo que tenía al principio de la formación (es debido a 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 el caso de binary_crossentropy. Después de muchas épocas - el valor de la tasa de aprendizaje es mayor que en el caso categorical_crossentropy. Por lo general, reinicio el entrenamiento (y la fase de aprendizaje) algunas veces cuando noto tal comportamiento o / y ajusto los pesos de una clase utilizando el siguiente patrón:

class_weight = 1 / class_frequency

Esto hace que la pérdida de una clase menos frecuente equilibre la influencia de una pérdida de clase dominante al comienzo de un entrenamiento y en una parte posterior de un proceso de optimización.

EDITAR:

En realidad - he comprobado que a pesar de que en el caso de las matemáticas:

binary_crossentropy = len(class_id_index) * categorical_crossentropy

Debe mantenerse-en caso de keras es 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 el caso de la multiclasificación, tal normalización daña un entrenamiento.

 21
Author: Marcin Możejko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-12 21:49:22

Me encontré con un problema "invertido": estaba obteniendo buenos resultados con categorical_crossentropy (con 2 clases) y pobres con binary_crossentropy. Parece que el problema fue con la función de activación incorrecta. Los ajustes correctos fueron:

  • para binary_crossentropy: activación sigmoide, objetivo escalar
  • para categorical_crossentropy: activación softmax, un objetivo codificado en caliente
 13
Author: Alexander Svetkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-01 10:43:45

Después de comentar la respuesta de @Marcin, he revisado más cuidadosamente uno de mis códigos de estudiantes donde encontré el mismo comportamiento extraño, ¡incluso después de solo 2 épocas ! (Así que 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 el método Keras "evaluar" es simplemente incorrecta cuando se usa binary_crossentropy con más de 2 etiquetas. Puede comprobarlo recomponiendo la precisión usted mismo (primero llame al método Keras "predecir" y luego calcular el número de respuestas correctas devueltas por predict) : se obtiene la verdadera precisión, que es mucho menor que el Keras "evaluar" uno.

 9
Author: xtof54,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 12:02:11

Todo depende del tipo de problema de clasificación que esté tratando. Hay tres categorías principales;

  • binario clasificación (dos clases de destino)
  • clasificación multiclase (más de dos objetivos exclusivos)
  • clasificación de etiquetas múltiples (más de dos destinos no exclusivos) en los que pueden estar activas varias clases de destino al mismo tiempo

En el primer caso, la entropía cruzada binaria debería ser utilizado y los objetivos deben ser codificados como vectores uno-caliente.

En el segundo caso, se debe usar entropía cruzada categórica y los objetivos deben codificarse como vectores de un solo hot.

En el último caso, se debe usar entropía cruzada binaria y los objetivos deben codificarse como vectores de un solo hot. 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 única.

La entropía cruzada binaria se define como tal: entropía cruzada binaria y la entropía cruzada categórica se define como tal: entropía cruzada categórica

 8
Author: whynote,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-08 14:34:48

Como es un problema multi-clase, tienes que 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.

50% para un problema multi-clase 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.

 4
Author: Matias Valdenegro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 15:04:53

Cuando se utiliza la pérdida 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).

 1
Author: Priyansh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-02 23:09:26