Keras模型训练准确率77%但预测仅输出单一类别问题排查
排查Keras自定义数据集单独预测仅输出单一类别的问题
我帮你梳理一下代码里的关键问题,主要集中在模型输入通道不匹配和预测结果的类别判断逻辑错误这两点:
1. 核心问题:预测时的类别判断逻辑错误
你的模型最后一层是Dense(1) + sigmoid激活,这是二分类的标准设置,输出的是一个0到1之间的概率值,对应flow_from_directory生成的类别映射(比如train_generator.class_indices会告诉你panca和canca分别对应0还是1)。
但你在predict.py里用了np.argmax(prediction),而prediction的形状是(1,1)——因为只有一个输出节点,argmax永远会返回索引0,所以你永远取到classes[0]也就是panca,这就是为什么单独预测时只输出单一类别!
2. 次要问题:灰度图像的通道数不匹配
你的数据集是灰度图,但训练代码里:
input_shape设置成了3通道(RGB),你自己也注释了应该改成1;flow_from_directory没有指定color_mode='grayscale',所以默认会把灰度图转换成3通道的RGB图像(三个通道值相同)来训练;- 预测时
image.load_img也没有指定color_mode='grayscale',同样会加载成3通道图像。
虽然这个问题暂时没导致训练崩溃,但会让模型学习冗余的通道信息,影响精度,也会和后续修正后的单通道模型输入不兼容。
修正后的代码
先修正train.py的通道问题
修改input_shape的判断,加上color_mode='grayscale':
# 修正灰度图的输入通道 if K.image_data_format() == 'channels_first': input_shape = (1, img_width, img_height) else: input_shape = (img_width, img_height, 1) # 生成器里加上color_mode='grayscale' train_generator = datagen.flow_from_directory( train_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary', color_mode='grayscale') validation_generator = datagen.flow_from_directory( val_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary', color_mode='grayscale') test_generator = datagen.flow_from_directory( test_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary', color_mode='grayscale')
修正predict.py的类别判断和通道问题
import numpy as np from keras.models import model_from_json from keras.preprocessing import image import os # 先确认训练时的类别映射,比如在train.py里打印train_generator.class_indices得到结果 classes = ['panca', 'canca'] directory = 'C:/tmp/anca_pc/test/' json_file = open("anca_pc.json", "r") loaded_model_json = json_file.read() json_file.close() loaded_model = model_from_json(loaded_model_json) loaded_model.load_weights("anca_pc.h5") print("Loaded model from disk") # 预测不需要重新编译,这行可以去掉 # loaded_model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy']) # 假设训练时的类别映射是{'panca': 0, 'canca': 1},可根据实际输出调整 class_indices = {'panca': 0, 'canca': 1} index_to_class = {v: k for k, v in class_indices.items()} for c in classes: aktdir=directory+c print(aktdir) for filename in os.listdir(aktdir): fn=os.path.join(aktdir, filename) # 加载灰度图,指定color_mode img = image.load_img(fn, target_size=(64, 64), color_mode='grayscale') x = image.img_to_array(img) x = x.astype('float32') x /= 255 x = np.expand_dims(x, axis=0) prediction = loaded_model.predict(x)[0][0] # 取出标量概率值 # 根据概率判断类别:sigmoid输出>0.5对应类别1,否则类别0 predicted_class_index = 1 if prediction > 0.5 else 0 predicted_class = index_to_class[predicted_class_index] print(f"真实类别: {c} | 预测类别: {predicted_class} | 概率值: {prediction:.4f}")
额外提示
- 训练时可以打印
train_generator.class_indices确认类别和索引的对应关系,避免判断逻辑搞反; - 你当前训练轮次只有5轮,可能模型还没充分收敛,可以尝试增加epochs到15-20轮,或者调整学习率、增加Dropout等提升精度;
- 测试时用
model.evaluate_generator得到的准确率是对的,因为生成器会正确传递标签和输入,而单独预测的错误完全是因为类别判断逻辑的问题。
内容的提问来源于stack exchange,提问作者Valentin H
相关产品推荐
相关产品推荐

