TensorFlow训练Food-101分类CNN:混淆矩阵与评估结果不符
问题排查与解决思路
核心矛盾分析
你遇到的问题本质是整体测试准确率与局部类别混淆矩阵结果不匹配,同时训练集的混淆矩阵也不符合训练准确率,大概率是混淆矩阵计算逻辑、数据筛选或预处理环节出了问题,以下是具体排查方向:
1. 混淆矩阵计算逻辑错误
这是最常见的原因,需逐一验证:
- 标签与预测值格式不匹配:
模型predict输出的是每个类别的概率,必须用np.argmax(preds, axis=1)转换为类别索引;如果你的测试集标签是one-hot编码格式,也要用np.argmax(labels, axis=1)转成索引,否则两者无法对应。 - 参数顺序搞反:
使用sklearn.metrics.confusion_matrix时,必须是confusion_matrix(y_true, y_pred)(真实标签在前,预测标签在后),如果颠倒顺序,主对角线的数值会完全错误。 - 类别筛选逻辑错误:
如果你只关注3个类别,需要先从全量测试集中筛选出这3个类的样本和标签,再计算混淆矩阵。如果直接用全量预测结果计算局部类别的混淆矩阵,会混入其他类的预测值,导致主对角线数值被稀释。
正确计算局部类别混淆矩阵的代码示例:
import numpy as np from sklearn.metrics import confusion_matrix, accuracy_score # 获取测试集真实标签(假设已加载为numpy数组) y_true = np.argmax(test_labels, axis=1) if test_labels.ndim == 2 else test_labels # 获取模型预测的类别索引 y_pred = np.argmax(model.predict(test_data, verbose=0), axis=1) # 筛选目标3个类的样本(替换为你实际的类别索引) target_class_indices = [10, 20, 30] mask = np.isin(y_true, target_class_indices) y_true_filtered = y_true[mask] y_pred_filtered = y_pred[mask] # 计算混淆矩阵与局部准确率 cm = confusion_matrix(y_true_filtered, y_pred_filtered) local_acc = accuracy_score(y_true_filtered, y_pred_filtered) print(f"目标3类的准确率:{local_acc:.2f}") print("混淆矩阵:\n", cm)
2. 整体准确率与局部类别的关系误解
Food-101包含101个类别,整体测试准确率是所有类别的平均准确率加权值。如果你的3个目标类别恰好是模型表现最差的几类,而其他98类的准确率远高于80%(比如多数类达到90%+),整体平均后依然能达到80%。这种情况下,混淆矩阵的结果是合理的,只是你选的3个类属于模型的薄弱项。
验证方法:计算全量测试集的混淆矩阵,统计每个类别的准确率,就能看到多数类的表现是否达标。
3. 训练/测试集预处理不一致
如果训练时用了数据增强(比如旋转、翻转、缩放),但测试时的预处理逻辑和训练时不一致,会导致模型预测失真:
- 确保训练和测试时的图像resize尺寸完全相同(比如都是224×224)。
- 归一化逻辑一致:比如训练时用
image /= 255.0,测试时不能遗漏这一步;如果用了预训练模型的均值方差归一化,测试时也要用相同的均值和方差。 - 数据增强仅在训练时启用,测试时关闭(比如
ImageDataGenerator中仅训练集添加rotation_range等增强参数)。
4. 训练集混淆矩阵异常的排查
训练过程中准确率超90%但混淆矩阵异常,大概率是混淆矩阵计算用错了数据集:
- 你可能误将验证集当成训练集来计算混淆矩阵,验证集的准确率本来就低于训练集。
- 如果用
ImageDataGenerator加载训练集且开启了shuffle=True,直接从生成器中抽取batch计算混淆矩阵会导致样本与标签顺序不匹配,必须用model.predict在完整训练集上生成预测结果,再和原始训练标签对比。
5. 模型保存/加载问题
如果model.evaluate用的是训练完成的模型,但绘制混淆矩阵时用的是未训练或加载错误的模型,会导致结果矛盾。验证方法:在计算混淆矩阵前,重新运行model.evaluate确认准确率是否仍为80%,再执行预测。
内容的提问来源于stack exchange,提问作者Tommaso Fava
相关产品推荐
相关产品推荐

