TensorFlow Addons的F1 Score为何对正确预测输出0值?
TensorFlow Addons F1Score 计算异常问题分析
问题场景
训练CNN模型使用F1 Score时出现计算结果不符合预期的情况,以下是测试代码:
import tensorflow_addons as tfa import numpy as np metric = tfa.metrics.F1Score( num_classes=4, threshold=0.5) y_true = np.array([ [0, 1, 0, 0], # [0, 1, 0, 0], # [1, 0, 0, 0] ], np.int32) y_pred = np.array([ [0, 1, 0, 0], # [0.2, 0.6, 0.2, 0.2], # [0.6, 0.2, 0.2, 0.2] ], np.float32) metric.update_state(y_true, y_pred) result = metric.result() result.numpy()
预期输出:
[1, 1, 1, 1]
按此计算宏平均F1 Score应为1,但实际得到:
[0, 1, 0, 0]
设置average=macro时,结果为0.25。
补充测试情况
给y_true添加一行数据后,结果恢复符合预期(原本以为会报错),测试代码如下:
import tensorflow_addons as tfa import numpy as np metric = tfa.metrics.F1Score( num_classes=4, threshold=0.5) y_true = np.array([ [0, 1, 0, 0], [1, 0, 0, 0] # [0, 1, 0, 0], # [1, 0, 0, 0] ], np.int32) y_pred = np.array([ [0, 1, 0, 0], # [0.2, 0.6, 0.2, 0.2], # [0.6, 0.2, 0.2, 0.2] ], np.float32) metric.update_state(y_true, y_pred) result = metric.result() result.numpy()
问题原因
这不是TensorFlow Addons的bug,是F1Score的计算逻辑导致的:
- F1 Score由精确率和召回率推导而来,而召回率的计算依赖真实标签中存在该类别的正样本(即该类别在
y_true中至少有一个1)。 - 第一个测试用例里,只有索引为1的类别有正样本,其余3个类别在
y_true中全为0。对于这类没有正样本的类别,tfa.metrics.F1Score会默认返回0——因为没有正样本时,召回率的分母为0,为避免除以0错误,指标直接置0。 - 宏平均会对所有类别的F1值取平均,所以(0+1+0+0)/4=0.25,和实际结果一致。
- 补充测试中添加了索引为0的类别正样本,该类别有了有效计算依据,若预测正确则F1为1,符合预期。
解决办法
如果需要对没有正样本的类别返回1(即认为无样本时预测正确),可以通过两种方式处理:
- 手动修正结果:
result = metric.result().numpy() # 标记每个类别是否有正样本 has_positive_samples = np.any(y_true == 1, axis=0) # 对无正样本的类别,将F1设为1 result[~has_positive_samples] = 1
- 设置
zero_division参数(需确认TensorFlow Addons版本支持):
初始化F1Score时指定zero_division=1,控制分母为0时返回1:
metric = tfa.metrics.F1Score( num_classes=4, threshold=0.5, zero_division=1)
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

