You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TensorFlow二分类任务添加F1Score宏平均指标返回None的问题

二分类任务中TensorFlow F1Score宏平均返回None的解决方法

问题原因

tf.keras.metrics.F1Score设置average="macro"时,默认要求模型输出为多分类格式(形状为(batch_size, num_classes),即每个样本对应所有类别的概率)。而二分类任务常用sigmoid激活输出单个概率值(形状为(batch_size, 1)),指标无法正确解析类别维度,导致计算结果为None。

解决方案

根据模型输出格式,选择以下两种方案之一:

方案1:适配多分类输出格式(使用softmax)

若选择调整模型为多分类输出结构:

  1. 模型最后一层改为2个神经元,搭配softmax激活:
model = tf.keras.Sequential([
    # 你的其他网络层
    tf.keras.layers.Dense(2, activation='softmax')
])
  1. 将标签转换为one-hot编码(原标签为0/1时):
y_train_onehot = tf.one_hot(y_train, depth=2)
y_val_onehot = tf.one_hot(y_val, depth=2)
  1. 编译模型时使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:53:20