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 指标准确度、精确度和召回率的值相同的主要内容,如果未能解决你的问题,请参考以下文章