TensorFlow二分类任务添加F1Score宏平均指标返回None的问题
二分类任务中TensorFlow F1Score宏平均返回None的解决方法
问题原因
tf.keras.metrics.F1Score设置average="macro"时,默认要求模型输出为多分类格式(形状为(batch_size, num_classes),即每个样本对应所有类别的概率)。而二分类任务常用sigmoid激活输出单个概率值(形状为(batch_size, 1)),指标无法正确解析类别维度,导致计算结果为None。
解决方案
根据模型输出格式,选择以下两种方案之一:
方案1:适配多分类输出格式(使用softmax)
若选择调整模型为多分类输出结构:
- 模型最后一层改为2个神经元,搭配
softmax激活:
model = tf.keras.Sequential([ # 你的其他网络层 tf.keras.layers.Dense(2, activation='softmax') ])
- 将标签转换为one-hot编码(原标签为0/1时):
y_train_onehot = tf.one_hot(y_train, depth=2) y_val_onehot = tf.one_hot(y_val, depth=2)
- 编译模型时使用
categorical_crossentropy损失,原F1Score指标即可正常计算:
model.compile( optimizer='adam', loss="categorical_crossentropy", metrics=['accuracy', tf.keras.metrics.F1Score(threshold=0.5, average="macro")] )
方案2:自定义二分类宏平均F1指标(适配sigmoid输出)
若想保留sigmoid单输出的二分类结构,可自定义指标单独计算正负类F1后求平均:
import tensorflow as tf class BinaryMacroF1(tf.keras.metrics.Metric): def __init__(self, name='binary_macro_f1', threshold=0.5, **kwargs): super().__init__(name=name, **kwargs) self.threshold = threshold # 正类精确率、召回率 self.prec_pos = tf.keras.metrics.Precision(threshold=threshold) self.recall_pos = tf.keras.metrics.Recall(threshold=threshold) # 负类精确率、召回率 self.prec_neg = tf.keras.metrics.Precision(threshold=threshold) self.recall_neg = tf.keras.metrics.Recall(threshold=threshold) def update_state(self, y_true, y_pred, sample_weight=None): # 更新正类指标 self.prec_pos.update_state(y_true, y_pred, sample_weight) self.recall_pos.update_state(y_true, y_pred, sample_weight) # 反转标签和预测值,计算负类指标 y_true_neg = 1 - y_true y_pred_neg = 1 - y_pred self.prec_neg.update_state(y_true_neg, y_pred_neg, sample_weight) self.recall_neg.update_state(y_true_neg, y_pred_neg, sample_weight) def result(self): # 计算正负类F1并求平均 f1_pos = 2 * (self.prec_pos.result() * self.recall_pos.result()) / (self.prec_pos.result() + self.recall_pos.result() + tf.keras.backend.epsilon()) f1_neg = 2 * (self.prec_neg.result() * self.recall_neg.result()) / (self.prec_neg.result() + self.recall_neg.result() + tf.keras.backend.epsilon()) return (f1_pos + f1_neg) / 2 def reset_state(self): # 重置指标状态 self.prec_pos.reset_state() self.recall_pos.reset_state() self.prec_neg.reset_state() self.recall_neg.reset_state()
编译模型时使用该自定义指标:
model.compile( optimizer='adam', loss="binary_crossentropy", metrics=['accuracy', BinaryMacroF1(threshold=0.5)] )
内容的提问来源于stack exchange,提问作者amirhossien derakhshan
相关产品推荐
相关产品推荐

