Keras CNN二分类:训练val_acc超95%,同验证集预测准确率不足60%?
这种情况绝对可能!问题全出在你的预测流程和数据细节上
先直接给结论:训练时验证准确率很高,但预测时结果拉胯,这种情况非常常见,核心问题都藏在你的代码细节里,我们一个个捋:
1. 训练和预测的图像预处理完全不一致(头号元凶)
你训练的时候,不管是训练集还是验证集的生成器,都加了rescale=1. / 255——也就是把图像的像素值从0-255缩放到了0-1之间,模型完全是在这种归一化后的图像上学到的特征。但你预测用的validgen居然彻底漏掉了这个关键操作!
看看你的代码对比:
# 训练时的预处理(正确操作) train_datagen = ImageDataGenerator(rescale=1. / 255, ...) test_datagen = ImageDataGenerator(rescale=1. / 255, ...) # 预测时的预处理(致命遗漏!) validgen = ImageDataGenerator(horizontal_flip=False, data_format='channels_first')
模型从来没见过0-255的原始像素数据,喂进去自然会彻底懵圈,预测结果当然不准。
立刻修复方案:给预测生成器加上一模一样的归一化:
validgen = ImageDataGenerator(rescale=1. / 255, horizontal_flip=False, data_format='channels_first')
2. 预测用的数据集根本不对
你说“使用同一验证数据进行预测”,但看代码里的路径和生成器输出完全矛盾:
- 训练时的验证集是
data/Validation(200个样本) - 预测时却用了
data/test,生成器显示Found 10 images belonging to 1 classes,但你又说“对全部100张class 0的验证图片进行预测”
这里的问题要么是:
data/test里根本不是你说的验证集数据- 要么你的
data/test目录结构不符合flow_from_directory的要求(这个函数必须要求每个类别对应一个子文件夹,比如data/test/class0、data/test/class1)
检查&修复:
- 如果要直接用验证集做预测,把
test_data_dir改成validation_data_dir就行 - 确认你的测试目录结构和训练/验证集完全一致,不然生成器读不到正确的标签
3. 模型输入格式的硬编码隐患
你代码里先判断了K.image_data_format()来设置input_shape,但后面加卷积层的时候直接硬编码了data_format='channels_first'和input_shape=(1,230,170):
if K.image_data_format() == 'channels_first': input_shape = (1, img_width, img_height) else: input_shape = (img_width, img_height, 1) # 这里直接写死了,白做了上面的判断 model.add(Convolution2D(32, (3, 3),data_format='channels_first' , input_shape=(1,230,170)))
虽然训练时没报错(因为你生成器也用了channels_first),但这写法很不鲁棒,万一换后端就会出问题。建议改成用变量,保持一致性:
model.add(Convolution2D(32, (3, 3), data_format=K.image_data_format(), input_shape=input_shape))
4. 预测结果的后处理要跟上
你的模型输出是sigmoid的概率值,得用阈值(比如0.5)转成类别标签,然后和真实标签对比才能算出准确率:
# 把概率转成类别(0或1) pred_classes = (preds > 0.5).astype(int) # 因为shuffle=False,所以预测结果和生成器的classes顺序完全对应 print("真实标签:", test_gen.classes) print("预测标签:", pred_classes.flatten())
这样你就能清楚看到哪些样本预测错了,而不是只看零散的结果。
按照上面的步骤改完,你的预测准确率应该会和训练时的val_acc差不多了。
内容的提问来源于stack exchange,提问作者keshav
相关产品推荐
相关产品推荐

