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

TensorFlow训练时如何在TensorBoard中显示各分类的F1分数

问题原因

TensorFlow 2.5的内置TensorBoard回调默认会将返回数组形式的指标(即你设置average=None得到的多类别F1数组)自动聚合为单个标量,因此训练过程中只会显示一条汇总曲线,不会拆分单类指标。你可以通过以下两种方案实现单类F1分数的TensorBoard可视化:


方案1:自定义回调(推荐,适配任意类别数量)

你可以自定义训练回调,在每个epoch结束时单独计算每个类别的F1值并写入TensorBoard日志,代码示例如下:

import tensorflow as tf
from tensorflow.keras.callbacks import Callback

class PerClassF1Callback(Callback):
    def __init__(self, eval_dataset, class_names=None, log_dir='./logs'):
        super().__init__()
        self.eval_data = eval_dataset # 可以传训练集或验证集
        # 未传入类别名时自动生成默认名称
        self.class_names = class_names if class_names else [f'class_{i}' for i in range(CLASSES)]
        self.writer = tf.summary.create_file_writer(log_dir + '/per_class_f1')
        # 初始化F1指标,和你编译模型时的参数保持一致
        self.f1_metric = tfa.metrics.F1Score(num_classes=CLASSES, average=None)
    
    def on_epoch_end(self, epoch, logs=None):
        # 重置指标状态避免历史数据干扰
        self.f1_metric.reset_states()
        # 遍历数据集计算当前epoch的F1分数
        for x, y_true in self.eval_data:
            y_pred = self.model.predict(x, verbose=0)
            self.f1_metric.update_state(y_true, y_pred)
        f1_scores = self.f1_metric.result().numpy()
        # 逐个类别写入TensorBoard日志
        with self.writer.as_default():
            for idx, score in enumerate(f1_scores):
                tf.summary.scalar(f'f1_score/{self.class_names[idx]}', score, step=epoch)
        self.writer.flush()
        # 可选:将单类F1加入日志,训练时终端也会打印
        for idx, score in enumerate(f1_scores):
            logs[f'f1_{self.class_names[idx]}'] = score

回调使用方式

在model.fit时将自定义回调传入回调列表即可:

# 初始化回调,这里以验证集为例,也可以传入训练集
f1_callback = PerClassF1Callback(eval_dataset=val_dataset, log_dir='./logs')
# 保留原有的TensorBoard回调
tb_callback = tf.keras.callbacks.TensorBoard(log_dir='./logs')

model.fit(
    train_dataset,
    validation_data=val_dataset,
    epochs=你的训练轮数,
    callbacks=[tb_callback, f1_callback]
)

方案2:拆分单类指标(适合类别数量少的场景)

你可以在编译模型时,为每个类别单独定义一个F1指标,内置的TensorBoard回调会自动识别为独立标量生成单独曲线:

metrics = [
    # 保留原有的整体多类F1指标
    tfa.metrics.F1Score(num_classes=CLASSES, average=None, name='overall_f1'),
    # 为每个类别单独定义F1指标,指定对应的class_id
    tfa.metrics.F1Score(num_classes=CLASSES, average='macro', class_id=0, name='f1_class_0'),
    tfa.metrics.F1Score(num_classes=CLASSES, average='macro', class_id=1, name='f1_class_1'),
    # 有多少个类就加多少个,依次类推
    # tfa.metrics.F1Score(num_classes=CLASSES, average='macro', class_id=N, name='f1_class_N')
]
model.compile(
    optimizer='adam',
    loss=tf.keras.losses.CategoricalCrossentropy(),
    metrics=metrics
)

该方案无需额外自定义逻辑,缺点是类别数量较多时配置重复度较高。

内容的提问来源于stack exchange,提问作者Konqi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:54:08