分类报告表现良好但模型预测错误的原因及解决方法
问题
我运行MobileNetV2垃圾分类模型,在Colab用2100张6类图片训练后,分类报告表现良好,但添加预测上传图片的代码后,模型预测结果始终错误(比如常误判为trash类,重启后会切换类别但仍错误)。
预测代码如下:
from google.colab import files from PIL import Image def process_uploaded_image(image_path, target_size=(224, 224)): img = Image.open(image_path) img = img.resize(target_size) img_array = np.array(img) if img_array.shape[-1] == 4: img_array = img_array[..., :3] img_array = img_array / 255.0 img_array = np.expand_dims(img_array, axis=0) img_array = mobilenetv2.preprocess_input(img_array) return img_array uploaded = files.upload() for fn in uploaded.keys(): processed_image = process_uploaded_image(fn, target_size=IMAGE_SIZE) preds = model.predict(processed_image) pred_class = np.argmax(preds, axis=1) plt.imshow(Image.open(fn)) # Display the uploaded image plt.title(f'Predicted class: {categories[pred_class[0]]}') plt.axis('off') plt.show() print(f'File {fn} is predicted as: {categories[pred_class[0]]}')
添加概率输出代码后,得到如下结果:
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 24ms/step Prediction probabilities: [0.31027108 0.12315894 0.47848797 0.00863316 0.07789086 0.00155797] Predicted class: metal
请问问题原因是什么?如何让模型做出正确预测?
问题原因
- 预处理流程不一致:手动将像素值除以255后又调用
mobilenetv2.preprocess_input,但MobileNetV2的预处理函数本身会将0-255范围的像素值转换为[-1,1],重复处理会导致输入分布与训练时不符。 - 类别顺序不匹配:训练时
flow_from_directory生成的类别顺序(存在class_indices字典中),可能和预测时用的categories列表顺序不一致,导致索引对应错误的类别。 - 模型加载错误:如果预测时加载的是初始预训练的MobileNetV2模型,而非训练完成后的微调模型,自然无法得到正确结果。
- 图像插值方式差异:训练时的图像resize插值方式(如Keras默认插值)和PIL
resize的默认插值不同,会导致输入图像的特征分布偏移。 - 数据集分布差异:上传的测试图片在角度、光照、背景等方面和训练集差异过大,模型泛化能力不足。
解决方法
- 对齐预处理流程:删除
img_array = img_array / 255.0这一行,直接用原始像素值(0-255)调用mobilenetv2.preprocess_input,同时指定插值方式匹配训练设置:def process_uploaded_image(image_path, target_size=(224, 224)): img = Image.open(image_path) img = img.resize(target_size, resample=Image.BICUBIC) # 匹配训练时的插值方式 img_array = np.array(img) if img_array.shape[-1] == 4: img_array = img_array[..., :3] img_array = np.expand_dims(img_array, axis=0) img_array = mobilenetv2.preprocess_input(img_array) return img_array - 确认类别顺序一致:训练时打印
train_generator.class_indices,将categories列表设置为对应顺序,比如:# 假设train_generator.class_indices输出为{'glass':0, 'paper':1, 'metal':2, 'plastic':3, 'cardboard':4, 'trash':5} categories = ['glass', 'paper', 'metal', 'plastic', 'cardboard', 'trash'] - 验证模型加载正确性:训练完成后保存模型,预测时加载训练好的模型:
# 训练完成后保存 model.save('garbage_classifier.h5') # 预测时加载 from tensorflow.keras.models import load_model model = load_model('garbage_classifier.h5') - 提升模型泛化能力:训练时添加数据增强,丰富训练集多样性:
from tensorflow.keras.preprocessing.image import ImageDataGenerator train_datagen = ImageDataGenerator( preprocessing_function=mobilenetv2.preprocess_input, rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True, zoom_range=0.2 ) - 先验证测试集:用训练拆分出的测试集图片做预测,确认模型本身没问题后,再测试上传的外部图片。
内容的提问来源于stack exchange,提问作者Eff Zoee
相关产品推荐
相关产品推荐

