混淆矩阵全零主因是label与prediction的dtype不一致,需同为int32或int64;须用tf.argmax取类别索引并显式tf.cast转整型,且二者必须为一维张量,num_classes应显式指定。

混淆矩阵输出结果全是0?检查label和prediction的dtype是否一致
直接用 tf.math.confusion_matrix 却得到全零矩阵,大概率是 labels 和 predictions 类型不匹配。该函数要求二者必须同为 int32 或 int64;如果其中一个是 float32(比如模型输出未取整的logits或prob),就会静默截断为0,导致整个矩阵归零。
实操建议:
- 用
tf.cast(labels, tf.int32)和tf.cast(tf.argmax(predictions, axis=-1), tf.int32)显式转换 - 别依赖
predictions原始输出——即使你做了softmax,也要用argmax得到类别索引,再转整型 - 加一句
assert labels.dtype == predictions.dtype == tf.int32在调用前快速捕获类型问题
维度不对报InvalidArgumentError?确认输入是一维张量
tf.math.confusion_matrix 只接受一维 labels 和一维 predictions。如果你传入的是 batch×classes 的 logits(如 shape=(32, 10))或带 batch 维度的标签(如 shape=(32, 1)),会直接报错:InvalidArgumentError: Labels must be 1-D。
实操建议:
- 预测侧:用
tf.argmax(y_pred, axis=1)→ 得到 shape=(batch_size,) 的 int32 向量 - 标签侧:如果是 one-hot,先
tf.argmax(y_true, axis=1);如果是 sparse 标签,确保它已经是 shape=(batch_size,) 且 dtype=int32 - 调试时打印
tf.shape(labels), tf.shape(predictions),确认两者都是 rank-1
类别数没对上?num_classes参数不能靠猜
默认 num_classes 是基于输入最大值自动推断的,但容易出错:比如测试集没覆盖全部类别,最大值偏小,矩阵列数就不够,导致类别错位甚至索引越界。
实操建议:
- 显式传入
num_classes=10(按你的任务真实类别数),不要省略 - 如果类别从1开始编号(比如 label=1~10),记得先
labels - 1再传入,否则第0行永远空着 - 若用
tf.keras.metrics.ConfusionMatrix(旧版TF),注意它已被弃用,坚持用tf.math.confusion_matrix+ 手动tf.print或tf.py_function转 numpy 更可控
想可视化或导出为numpy数组?绕过EagerTensor限制
在 tf.function 或 graph mode 下,tf.math.confusion_matrix 返回的是 EagerTensor 或符号张量,不能直接用 np.array() 转换,会报 OperatorNotAllowedInGraphError。
实操建议:
- 训练中调试:用
tf.print("cm:", cm)查看数值(支持 tensor 直接打印) - 评估阶段导出:在
@tf.function外、eager 模式下计算,或用tf.py_function(func=lambda x: x.numpy(), inp=[cm], Tout=tf.float32) - 更稳妥的做法:在
model.evaluate()后用原生 numpy 处理 —— 把y_true和y_pred转成 numpy,再调用sklearn.metrics.confusion_matrix,避免 TF 张量生命周期干扰
真正麻烦的不是调用函数本身,而是 label 编码方式、维度隐含假设、以及 eager/graph 模式切换时的 tensor 生命周期——这些地方不动手试一次,光看文档很难意识到哪步悄悄变了数据形态。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











