Keras 2.3.0 指标准确度、精确度和召回率的值相同

Posted

技术标签:

【中文标题】Keras 2.3.0 指标准确度、精确度和召回率的值相同【英文标题】:Same value for Keras 2.3.0 metrics accuracy, precision and recall 【发布时间】:2020-09-02 06:04:52 【问题描述】:

我正在尝试获取准确度、精确度和召回率的 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

【问题讨论】:

【参考方案1】:

精度和召回率已经存在一些问题。

看这个问题: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')]

【讨论】:

【参考方案2】:

当我发布我的问题时,我没有意识到真阳性和假阳性也与真阴性和假阴性具有相同的价值。我的验证集有 80 个观察值,因此 tp、fp、tn 和 fn 的这些指标实际上意味着正确预测了 70 个观察值,而预测了 10 个错误,无论每个观察值的类别如何:

        10.

我无法弄清楚为什么所有这些指标都搞砸了,也许这只是Zabir Al Nazi kindly mentioned 的问题。但是,由于一些小的更改,我能够获得正确的指标:

损失函数:binary_crossentropy 而不是 categorical_crossentropy。 顶层:1 个神经元 sigmoid,而不是 n_classes 个神经元 softmax。 标签形状:一维 numpy 数组而不是 one-hot 编码。

我希望这可以帮助其他人。

【讨论】:

这是一个二元分类问题吗?你会为多类分类做什么?我认为我处于多类情况,但我遇到的问题与我的指标输出不起作用的问题相同。我正在使用 sklearn.metrics(准确度、精度、召回率、f1)【参考方案3】:

TP 和 TN 相等的问题在于使用格式化为 one-hot 编码向量的标签进行二进制分类。 one-hot 编码向量中的标签表示为:[[0,1], [0,1], [1,0],[1,0],[0,1],[1,0],… .,[0,1],[1,0]],因此,每当算法预测正确时,标签中表示为 [1,0] 的 A 类;度量标准将 A 的 TP 和 B 类的 TN 都视为正确。因此,在 80 个观察的样本中,它最终具有 70 TP 和 70 TN。

更新中描述的解决方案有更多详细信息:

    将密集层的输出转换为具有 1 个输出类: model.add(Dense(1, activation='sigmoid'))

    将 y 的格式更改为具有 [1,1,0,0,1,0….,1,0] 的一维数组,而不是单热向量 [[0,1], [0,1], [1,0],[1,0],[0,1],[1,0],….,[0,1],[1,0]] 和

    将损失函数更改为 BinaryCrossentropy 比如:model.compile(loss="BinaryCrossentropy", optimizer=optimizer, metrics=metrics)

Keras 不提供从多标签分类问题到二元分类问题的“自动转换”。

【讨论】:

你打错了,model.add(Dense(1, activation='softmax'))不正确,应该是sigmoid 感谢您的评论,出于一致性原因我进行了更新,但是我使用 sigmoid、relu 和 softmax 作为激活函数执行了更新后的代码,没有任何问题。更改后您是否遇到过 softmax 函数的问题? 如果你使用softmax作为激活1个神经元,你最终会得到预测[1],因为softmax输出的总和等于1。 这是一个二元分类问题吗?你会为多类分类做什么?我认为我处于多类情况,但我遇到的问题与我的指标输出不起作用的问题相同。我正在使用 sklearn.metrics(准确度、精度、召回率、f1) 这是一个二分类问题。在多类分类问题中,您将激活函数更改为使用您拥有的 n 个类的 softmax。这些指标始终有效,您需要检查您的深度学习管道。

以上是关于Keras 2.3.0 指标准确度、精确度和召回率的值相同的主要内容,如果未能解决你的问题,请参考以下文章

精确率和召回率

有关平均精度AP 和精确度-召回率曲线PR AUC的疑惑

准确率、精确率、召回率

准确率,精确度(AP)与召回率(AR)

准确率、精确率、召回率

tflite 模型的准确度、精确度和召回率