图像分类模型预测始终约50%,求助排查问题原因
我使用某文献中的50×50 PNG图像做bagger/nobagger二分类,预期bagger预测值接近0,nobagger接近1,但所有预测结果始终在0.5左右,调整训练参数也没用。相关代码和数据集结构如下:
预测代码
import numpy as np from tensorflow import keras from tensorflow.keras.preprocessing import image print ("1") model = keras.models.load_model('bagger_nobagger_png.h5') img_path = "Bagger_Patch_094745_1_19492575.png" # 替换为你的PNG路径 img = image.load_img(img_path,target_size=(50, 50), color_mode='grayscale') x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = x / 65535.0 # PNG像素归一化到[0,1] classes = model.predict(x) print(classes) # 接近0是bagger,接近1是nobagger img_path = "C:/Users/hdorn/Desktop/Extra/noBagger/noBagger_Patch_Wind_1_200_2851.png" # 替换为你的PNG路径 img = image.load_img(img_path,target_size=(50, 50), color_mode='grayscale') x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = x / 65535.0 # PNG像素归一化到[0,1] classes = model.predict(x) print(classes) # 接近0是bagger,接近1是nobagger
模型训练代码
import os from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout from keras.optimizers import RMSprop train_dir = "/Downloads/sensors-21-07527-s001 (1)/Data_and_Code_sensors-1424304/DL/DL_Data/Train" validation_dir = "/Downloads/sensors-21-07527-s001 (1)/Data_and_Code_sensors-1424304/DL/DL_Data/validate" # 训练数据增强 train_datagen = ImageDataGenerator(rescale=1./255, rotation_range=40, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) validation_datagen = ImageDataGenerator(rescale=1./255) # 训练数据生成器 train_generator = train_datagen.flow_from_directory(train_dir, target_size=(50, 50), color_mode='grayscale', batch_size=20, class_mode='binary') # 验证数据生成器 validation_generator = validation_datagen.flow_from_directory(validation_dir, target_size=(50, 50), color_mode='grayscale', batch_size=20, class_mode='binary') # 模型结构 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(50, 50, 1))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(128, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(optimizer=RMSprop(lr=0.0001), loss='binary_crossentropy', metrics=['acc']) # 训练模型 history = model.fit_generator(train_generator, steps_per_epoch=100, epochs=3, validation_data=validation_generator, validation_steps=50) model.save('bagger_nobagger_png.h5')
数据集结构
--DL_Data --Train --bagger --bagger1.png --xxxxxxxx.png --nobagger --nobagger1.png --zzzzzzzzzzzz.png --validate --bagger --bagger9000.png --nnnnnnnnnn.png --nobagger --nobagger9000.png --yyyyyyyyyyyyyy.png
预测结果始终在0.5左右,说明模型完全没学到有效特征,处于随机猜测状态,核心问题集中在以下几点:
1. 训练轮次严重不足
仅训练3个epochs,对于CNN模型来说远远不够——模型权重还停留在初始化的随机状态,根本没机会学习到数据中的特征模式,自然输出接近0.5的随机结果。
- 解决方案:将epochs调整为30-50,同时添加
EarlyStopping回调(监测验证准确率),当验证准确率连续多轮不再提升时自动停止训练,避免过拟合。
2. 训练与预测的归一化不统一
训练时用rescale=1./255将像素缩至[0,1],但预测时用x / 65535.0。如果你的PNG是8位灰度图(像素范围0-255),预测时的归一化会把输入值压到接近0,模型接收到的输入分布和训练时完全不一致,无法正确预测。
- 解决方案:统一归一化标准——要么预测时改用
x / 255.0,要么训练时把rescale改成1./65535(针对16位PNG)。
3. 训练参数与实际数据量不匹配
steps_per_epoch=100意味着每轮要跑100个batch(共2000张图),如果你的训练集实际数量远小于这个数,生成器会重复采样数据,但数据量本身不足的话,模型还是学不到有效特征。同理validation_steps=50也要对应验证集的实际规模。
- 解决方案:先统计训练集和验证集的图片总数,将
steps_per_epoch设为训练集总数//batch_size,validation_steps设为验证集总数//batch_size,保证每轮能遍历完所有真实数据。
4. 类别映射需确认
flow_from_directory会按文件夹名称的字母顺序分配类别ID,比如"bagger"会被设为0,"nobagger"设为1,这和你的预期一致,但建议训练时打印train_generator.class_indices确认映射关系,避免因类别搞反而误解结果。
5. 数据增强可能过度(可选排查)
同时使用旋转、平移、剪切、缩放、翻转等多种增强,如果数据集本身不大,过度增强会让模型难以学到稳定特征。可以先关掉所有增强,只保留rescale,训练几轮看准确率是否提升,再逐步添加增强操作。
内容的提问来源于stack exchange,提问作者hdorn

