Keras 中具有自定义加权 F1 分数的 NaN
NaNs with customised weighted F1-Score in Keras
我需要以这种方式计算加权 F1 分数,以惩罚我最不受欢迎的标签(具有不平衡数据集的典型二元分类问题)上的更多错误。
不幸的是,我没有得到有效的 F1 分数。
以下是我的指标函数:
def sensitivity(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)))
return true_positives / (possible_positives + K.epsilon())
def specificity(y_true, y_pred):
true_negatives = K.sum(K.round(K.clip((1-y_true) * (1-y_pred), 0, 1)))
possible_negatives = K.sum(K.round(K.clip(1-y_true, 0, 1)))
return true_negatives / (possible_negatives + K.epsilon())
def f1(y_true, y_pred):
def recall(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
def precision(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
precision = precision(y_true, y_pred)
recall = recall(y_true, y_pred)
return 2*((precision*recall)/(precision+recall))
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(0.001),
metrics=[sensitivity, specificity, 'accuracy', f1])
我在这里训练模型并进行评估:
model.fit(x_train, y_train, epochs=12, batch_size=32, verbose=1, class_weight=class_weights_dict, validation_split=0.3)
classes = model.predict(x_test)
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=128, verbose=1)
我总是得到 nan 作为 f1score - 概念上或程序上有问题吗?因为数据是相同的,所以我使用了 scikit-learn 库 (SVM) 的另一个分类器并且它成功了。
这些是结果:
Epoch 1/12
5133/5133 [==============================] - 5s 976us/step - loss: 0.6955 - sensitivity: 0.0561 - specificity: 0.9377 - acc: 0.8712 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.8836 - val_specificity: 0.0000e+00 - val_acc: 0.0723 - val_f1: nan
Epoch 2/12
5133/5133 [==============================] - 5s 894us/step - loss: 0.6954 - sensitivity: 0.3865 - specificity: 0.5548 - acc: 0.5398 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
Epoch 3/12
5133/5133 [==============================] - 5s 925us/step - loss: 0.6953 - sensitivity: 0.3928 - specificity: 0.5823 - acc: 0.5696 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
Epoch 4/12
5133/5133 [==============================] - 5s 935us/step - loss: 0.6954 - sensitivity: 0.1309 - specificity: 0.8504 - acc: 0.7976 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
etc.
最终结果:
[0.6859536773606656, 0.0, 1.0, 0.9321705426356589, nan]
关于您的 f1 指标中的 nan:
如果您查看日志,您的验证灵敏度为 0。这意味着您的准确率和召回率也均为零。所以在 f1 计算中你除以零并得到一个 nan。
添加 K.epsilon(),就像您在其他函数中所做的那样。
旁注,根据你的损失判断,它对训练集的改进微乎其微,你的网络没有学到任何东西。我建议您从增加纪元数开始,使网络更深并且不要将任何内容传递给 class_weight 参数(您提到尚未使用加权计算,但您的代码确实设置了一些 class重量)。
还要检查其中一批 f1_score 是否等于 nan
。
我需要以这种方式计算加权 F1 分数,以惩罚我最不受欢迎的标签(具有不平衡数据集的典型二元分类问题)上的更多错误。 不幸的是,我没有得到有效的 F1 分数。 以下是我的指标函数:
def sensitivity(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)))
return true_positives / (possible_positives + K.epsilon())
def specificity(y_true, y_pred):
true_negatives = K.sum(K.round(K.clip((1-y_true) * (1-y_pred), 0, 1)))
possible_negatives = K.sum(K.round(K.clip(1-y_true, 0, 1)))
return true_negatives / (possible_negatives + K.epsilon())
def f1(y_true, y_pred):
def recall(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
def precision(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
precision = precision(y_true, y_pred)
recall = recall(y_true, y_pred)
return 2*((precision*recall)/(precision+recall))
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(0.001),
metrics=[sensitivity, specificity, 'accuracy', f1])
我在这里训练模型并进行评估:
model.fit(x_train, y_train, epochs=12, batch_size=32, verbose=1, class_weight=class_weights_dict, validation_split=0.3)
classes = model.predict(x_test)
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=128, verbose=1)
我总是得到 nan 作为 f1score - 概念上或程序上有问题吗?因为数据是相同的,所以我使用了 scikit-learn 库 (SVM) 的另一个分类器并且它成功了。
这些是结果:
Epoch 1/12
5133/5133 [==============================] - 5s 976us/step - loss: 0.6955 - sensitivity: 0.0561 - specificity: 0.9377 - acc: 0.8712 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.8836 - val_specificity: 0.0000e+00 - val_acc: 0.0723 - val_f1: nan
Epoch 2/12
5133/5133 [==============================] - 5s 894us/step - loss: 0.6954 - sensitivity: 0.3865 - specificity: 0.5548 - acc: 0.5398 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
Epoch 3/12
5133/5133 [==============================] - 5s 925us/step - loss: 0.6953 - sensitivity: 0.3928 - specificity: 0.5823 - acc: 0.5696 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
Epoch 4/12
5133/5133 [==============================] - 5s 935us/step - loss: 0.6954 - sensitivity: 0.1309 - specificity: 0.8504 - acc: 0.7976 - f1: nan - val_loss: 0.6884 - val_sensitivity: 0.0000e+00 - val_specificity: 1.0000 - val_acc: 0.9277 - val_f1: nan
etc.
最终结果:
[0.6859536773606656, 0.0, 1.0, 0.9321705426356589, nan]
关于您的 f1 指标中的 nan:
如果您查看日志,您的验证灵敏度为 0。这意味着您的准确率和召回率也均为零。所以在 f1 计算中你除以零并得到一个 nan。
添加 K.epsilon(),就像您在其他函数中所做的那样。
旁注,根据你的损失判断,它对训练集的改进微乎其微,你的网络没有学到任何东西。我建议您从增加纪元数开始,使网络更深并且不要将任何内容传递给 class_weight 参数(您提到尚未使用加权计算,但您的代码确实设置了一些 class重量)。
还要检查其中一批 f1_score 是否等于 nan
。