То же значение для метрик Keras 2.3.0: точность, точность и отзывчивость

Я пытаюсь получить метрики keras для точности, точности и отзывчивости, но все три из них показывают одно и то же значение, которое на самом деле является точностью.

Я использую список показателей, приведенный в примере документации TensorFlow:

metrics = [keras.metrics.TruePositives(name='tp'),
           keras.metrics.FalsePositives(name='fp'),
           keras.metrics.TrueNegatives(name='tn'),
           keras.metrics.FalseNegatives(name='fn'),
           keras.metrics.BinaryAccuracy(name='accuracy'),
           keras.metrics.Precision(name='precision'),
           keras.metrics.Recall(name='recall'),
           keras.metrics.AUC(name='auc')]

Модель - это довольно простая CNN для классификации изображений:

model = Sequential()

model.add(Convolution2D(32, 
                      (7, 7), 
                      padding ="same", 
                      input_shape=(255, 255, 3), 
                      activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Convolution2D(64, 
                      (3, 3), 
                      padding ="same"))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(256, 
              activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(n_classes, 
              activation='softmax'))

Компиляция со списком показателей, показанным выше:

model.compile(loss=loss,
            optimizer=optimizer,
            metrics=metrics)

Это пример проблемы, с которой я постоянно сталкиваюсь во время тренировок:

Epoch 1/15
160/160 [==============================] - 6s 37ms/step - loss: 0.6402 - tp: 215.0000 - fp: 105.0000 - tn: 215.0000 - fn: 105.0000 - accuracy: 0.6719 - precision: 0.6719 - recall: 0.6719 - auc: 0.7315 - val_loss: 0.6891 - val_tp: 38.0000 - val_fp: 42.0000 - val_tn: 38.0000 - val_fn: 42.0000 - val_accuracy: 0.4750 - val_precision: 0.4750 - val_recall: 0.4750 - val_auc: 0.7102
Epoch 2/15
160/160 [==============================] - 5s 30ms/step - loss: 0.6929 - tp: 197.0000 - fp: 123.0000 - tn: 197.0000 - fn: 123.0000 - accuracy: 0.6156 - precision: 0.6156 - recall: 0.6156 - auc: 0.6941 - val_loss: 0.6906 - val_tp: 38.0000 - val_fp: 42.0000 - val_tn: 38.0000 - val_fn: 42.0000 - val_accuracy: 0.4750 - val_precision: 0.4750 - val_recall: 0.4750 - val_auc: 0.6759

Показателей на раз, с одинаковыми значениями точности, точности и повторяемости каждый раз:

['loss', 'tp', 'fp', 'tn', 'fn', 'accuracy', 'precision', 'recall', 'auc']
[[ 0.351 70.    10.    70.    10.     0.875  0.875  0.875  0.945]
 [ 0.091 78.     2.    78.     2.     0.975  0.975  0.975  0.995]
 [ 0.253 72.     8.    72.     8.     0.9    0.9    0.9    0.974]
 [ 0.04  78.     2.    78.     2.     0.975  0.975  0.975  0.999]
 [ 0.021 80.     0.    80.     0.     1.     1.     1.     1.   ]]

sklearn.metrics.classification_report показывает правильную точность и отзыв

================ Fold 1 =====================
Accuracy: 0.8875
              precision    recall  f1-score   support

      normal       0.84      0.95      0.89        38
          pm       0.95      0.83      0.89        42

    accuracy                           0.89        80
   macro avg       0.89      0.89      0.89        80
weighted avg       0.89      0.89      0.89        80

================ Fold 2 =====================
Accuracy: 0.9375
              precision    recall  f1-score   support

      normal       1.00      0.87      0.93        38
          pm       0.89      1.00      0.94        42

    accuracy                           0.94        80
   macro avg       0.95      0.93      0.94        80
weighted avg       0.94      0.94      0.94        80

================ Fold 3 =====================
Accuracy: 0.925
              precision    recall  f1-score   support

      normal       0.88      0.97      0.92        37
          pm       0.97      0.88      0.93        43

    accuracy                           0.93        80
   macro avg       0.93      0.93      0.92        80
weighted avg       0.93      0.93      0.93        80

================ Fold 4 =====================
Accuracy: 0.925
              precision    recall  f1-score   support

      normal       0.97      0.86      0.91        37
          pm       0.89      0.98      0.93        43

    accuracy                           0.93        80
   macro avg       0.93      0.92      0.92        80
weighted avg       0.93      0.93      0.92        80

================ Fold 5 =====================
Accuracy: 1.0
              precision    recall  f1-score   support

      normal       1.00      1.00      1.00        37
          pm       1.00      1.00      1.00        43

    accuracy                           1.00        80
   macro avg       1.00      1.00      1.00        80
weighted avg       1.00      1.00      1.00        80

person Daniel López    schedule 16.05.2020    source источник


Ответы (3)


Когда я разместил свой вопрос, я не осознавал, что истинные положительные и ложные положительные результаты также имеют такое же значение, как истинные отрицательные и ложно отрицательные. В моем наборе проверки 80 наблюдений, поэтому эти показатели для tp, fp, tn и fn фактически означали, что 70 наблюдений были предсказаны правильно, а 10 - ошибочными, независимо от класса каждого наблюдения:

      1. 10.

Я не мог понять, почему все эти показатели были перепутаны, возможно, это просто проблема, о которой любезно упомянул Забир Аль Наци . Однако мне удалось получить правильные показатели благодаря некоторым небольшим изменениям:

  • Функция потери: binary_crossentropy вместо category_crossentropy.
  • Верхний слой: 1 сигмоид нейрона вместо n_classes нейронов softmax.
  • Форма меток: массив 1D numpy вместо горячего кодирования.

Надеюсь, это поможет кому-то другому.

person Daniel López    schedule 19.05.2020

Уже есть некоторая проблема с точностью и отзывом.

Взгляните на эту проблему: https://github.com/keras-team/keras/issues/5400

Вместо этого вы можете попробовать tensorflow.keras. Проблема должна исчезнуть.

Или вы можете использовать настраиваемую реализацию и передать ее в функции компиляции.

from keras import backend as K

def check_units(y_true, y_pred):
    if y_pred.shape[1] != 1:
      y_pred = y_pred[:,1:2]
      y_true = y_true[:,1:2]
    return y_true, y_pred

def precision(y_true, y_pred):
    y_true, y_pred = check_units(y_true, y_pred)
    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

def recall(y_true, y_pred):
    y_true, y_pred = check_units(y_true, y_pred)
    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
metrics = [keras.metrics.TruePositives(name='tp'),
           keras.metrics.FalsePositives(name='fp'),
           keras.metrics.TrueNegatives(name='tn'),
           keras.metrics.FalseNegatives(name='fn'),
           keras.metrics.BinaryAccuracy(name='accuracy'),
           precision,
           recall,
           keras.metrics.AUC(name='auc')]
person Zabir Al Nazi    schedule 16.05.2020

Проблема равных TP и TN заключается в использовании меток, отформатированных как векторы с горячим кодированием для двоичной классификации. Метки в векторе с горячим кодированием выражаются как: [[0,1], [0,1], [1,0], [1,0], [0,1], [1,0],… ., [0,1], [1,0]], поэтому всякий раз, когда алгоритм предсказывает правильность, класс A выражается как [1,0] в метке; метрики получают как правильные значения TP для A и TN для класса B. Таким образом, в выборке из 80 наблюдений получается 70 TP и 70 TN.

Решение, описанное в вашем обновлении с более подробной информацией:

  1. Преобразуйте выходные данные плотного слоя, чтобы получить 1 выходной класс: model.add(Dense(1, activation='sigmoid'))

  2. Измените формат y на 1d массив, имеющий [1,1,0,0,1,0…., 1,0] вместо одного горячего вектора [[0,1], [0,1], [1, 0], [1,0], [0,1], [1,0],…., [0,1], [1,0]] и

  3. Измените функцию потерь на BinaryCrossentropy, например: model.compile(loss="BinaryCrossentropy", optimizer=optimizer, metrics=metrics)

Keras не предлагает автоматического перехода от задачи классификации с несколькими метками к двоичной.

person Tasos Lytos    schedule 09.02.2021
comment
Вы допустили опечатку, model.add(Dense(1, activation='softmax')) неверно, должно быть sigmoid. - person Frightera; 10.02.2021
comment
Спасибо за ваш комментарий, я обновил для соображений согласованности, однако я без проблем выполнил обновленный код с sigmoid, relu и softmax в качестве функций активации. Сталкивались ли вы с проблемами с функцией softmax после изменений? - person Tasos Lytos; 10.02.2021
comment
Если вы используете softmax как активацию с 1 нейроном, вы будете получать предсказание [1] каждый раз, потому что сумма выходов softmax равна единице. - person Frightera; 10.02.2021