Solución:
desde las métricas f1 de Keras 2.0, se han eliminado la precisión y la recuperación. La solución es utilizar una función métrica personalizada:
from keras import backend as K
def f1(y_true, y_pred):
def recall(y_true, y_pred):
"""Recall metric.
Only computes a batch-wise average of recall.
Computes the recall, a metric for multi-label classification of
how many relevant items are selected.
"""
true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
recall = true_positives / (possible_positives + K.epsilon())
return recall
def precision(y_true, y_pred):
"""Precision metric.
Only computes a batch-wise average of precision.
Computes the precision, a metric for multi-label classification of
how many selected items are relevant.
"""
true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
precision = true_positives / (predicted_positives + K.epsilon())
return precision
precision = precision(y_true, y_pred)
recall = recall(y_true, y_pred)
return 2*((precision*recall)/(precision+recall+K.epsilon()))
model.compile(loss="binary_crossentropy",
optimizer= "adam",
metrics=[f1])
La línea de retorno de esta función
return 2*((precision*recall)/(precision+recall+K.epsilon()))
se modificó agregando la constante épsilon, para evitar la división entre 0. Por lo tanto, NaN no se calculará.
Usar una función métrica de Keras no es la forma correcta de calcular F1 o AUC o algo así.
La razón de esto es que la función métrica se llama en cada paso del lote durante la validación. De esa forma, el sistema Keras calcula un promedio de los resultados del lote. Y esa no es la puntuación correcta de F1.
Esa es la razón por la que la puntuación F1 se eliminó de las funciones métricas en keras. Mira aquí:
- https://github.com/keras-team/keras/commit/a56b1a55182acf061b1eb2e2c86b48193a0e88f7
- https://github.com/keras-team/keras/issues/5794
La forma correcta de hacer esto es usar una función de devolución de llamada personalizada de una manera como esta:
- https://github.com/PhilipMay/mltb#module-keras
- https://medium.com/@thongonary/how-to-compute-f1-score-for-each-epoch-in-keras-a1acd17715a2
También sugiero esta solución
- instalar el paquete keras_metrics por ybubnov
- llama
model.fit(nb_epoch=1, ...)
dentro de un bucle for aprovechando las métricas de precisión / recuperación generadas después de cada época
Algo como esto:
for mini_batch in range(epochs):
model_hist = model.fit(X_train, Y_train, batch_size=batch_size, epochs=1,
verbose=2, validation_data=(X_val, Y_val))
precision = model_hist.history['val_precision'][0]
recall = model_hist.history['val_recall'][0]
f_score = (2.0 * precision * recall) / (precision + recall)
print 'F1-SCORE {}'.format(f_score)