tf.keras.metrics.Accuracy训练时为0,因其默认逐元素比较logits与label且不自动argmax;应改用SparseCategoricalAccuracy(int标签)或CategoricalAccuracy(one-hot标签)。

tf.keras.metrics.Accuracy 为什么在训练时显示为 0?
常见现象是:模型编译时用了 tf.keras.metrics.Accuracy(),但训练中 accuracy 始终为 0,而 loss 正常下降。这是因为 Accuracy 默认对 logits 和 label 做逐元素比较,没经过 argmax —— 它期望输入已经是整数类别(如 [1, 0, 2]),但大多数分类模型输出的是 logits 或概率分布(如 [[2.1, -1.3, 0.8], ...])。
- 解决方法:改用
tf.keras.metrics.SparseCategoricalAccuracy()(label 是 int 类型,logits 直接输入)或tf.keras.metrics.CategoricalAccuracy()(label 是 one-hot,需先对 logitstf.nn.softmax) - 验证方式:打印
y_pred.shape和y_true.shape—— 若y_true是 shape=(N,) 的整数,就用SparseCategoricalAccuracy;若是 shape=(N, C) 的 one-hot,就用CategoricalAccuracy - 注意:
Accuracy类本身不自动做 argmax,它只做y_pred == y_true,所以传 logits 过去几乎必然全错
如何写一个带阈值的二分类准确率 metric?
标准 BinaryAccuracy 允许设 threshold 参数,但有时你需要更细粒度控制,比如“预测概率 > 0.7 才算正类”,或想同时统计 TP/TN/FP/FN。这时自定义 metric 更灵活。
- 继承
tf.keras.metrics.Metric,重写__init__、update_state、result -
update_state中用tf.cast(tf.greater(y_pred, 0.7), tf.int32)得预测标签,再用tf.equal对比y_true,最后用self.total和self.count累加(推荐用tf.Variable+assign_add) - 别忘了在
reset_state里重置变量,否则多轮 eval 会累积 - 示例关键片段:
class ThresholdedBinaryAccuracy(tf.keras.metrics.Metric): def __init__(self, threshold=0.7, name='thresholded_acc', **kwargs): super().__init__(name=name, **kwargs) self.threshold = threshold self.total = self.add_weight(name='total', initializer='zeros') self.count = self.add_weight(name='count', initializer='zeros') def update_state(self, y_true, y_pred, sample_weight=None): y_pred = tf.cast(tf.greater(y_pred, self.threshold), tf.int32) y_true = tf.cast(y_true, tf.int32) values = tf.cast(tf.equal(y_pred, y_true), self.dtype) self.total.assign_add(tf.reduce_sum(values)) self.count.assign_add(tf.cast(tf.size(values), self.dtype)) def result(self): return self.total / self.count
自定义 metric 在 model.fit() 里不更新?检查这几个点
写完自定义 metric,加到 model.compile(metrics=[...]) 后发现训练日志里压根不显示,或者值恒为 0/NaN,大概率是这几处出问题:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
update_state没正确处理 batch 维度:确保y_true和y_pred的 batch 维一致,避免因 broadcasting 导致 shape 错误(例如y_true是 (32,),y_pred是 (32, 1) —— 要先tf.squeeze) - 忘记调用
super().__init__()或漏掉add_weight,导致内部状态变量未注册 - metric 返回值类型不匹配:
result()必须返回标量tf.Tensor,且 dtype 通常为tf.float32;若返回 Python float 或 numpy array,Keras 会静默失败 - 使用了不可微或非图模式操作(如
print、np.array),尤其在 TF 2.x eager 关闭时会报错,建议全程用tf.*操作
多输出模型怎么给每个 head 配独立准确率?
当模型有多个输出(如主任务 + 辅助任务),直接传 list 给 metrics 会报错或错配。Keras 要求 metrics 的结构与 model 输出严格对齐。
立即学习“Python免费学习笔记(深入)”;
- 如果 model 输出是 dict(如
{'main': ..., 'aux': ...}),metrics 也必须是 dict:metrics={'main': tf.keras.metrics.SparseCategoricalAccuracy(), 'aux': tf.keras.metrics.SparseCategoricalAccuracy()} - 如果 model 输出是 list(如
[main_out, aux_out]),metrics 就得是 list,且长度一致:metrics=[tf.keras.metrics.SparseCategoricalAccuracy(), tf.keras.metrics.SparseCategoricalAccuracy()] - label 数据也要对应:list 输出时,
y_train必须是[y_main, y_aux];dict 输出时,y_train是{'main': ..., 'aux': ...} - 注意:自定义 metric 若用于某一个 head,它的
update_state只会收到对应位置的y_true和y_pred,无需额外切片
update_state + result 测一遍,比等整个 fit() 跑完再调试快得多。

















