You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于TensorFlow后端Keras的坑洼与垃圾检测模型异常排查

问题分析与解决方案

嘿,我来帮你排查这个问题!首先看你的代码和问题描述,有几个关键问题导致了非目标图像全被识别成垃圾的情况,咱们一步步拆解解决:

一、核心问题定位

1. 模型架构与训练类别不匹配

你的代码里,训练时用np_utils.to_categorical(y_train, 2)把标签转换成了2分类的独热编码,但模型最后一层却是Dense(3, activation='softmax')——这意味着模型会输出3个类别的概率,但你的训练数据里只有坑洼(1)和垃圾(0)两类,第三个类别从来没被训练过。这种不匹配会让模型对非目标图像的概率分配完全混乱,最终只会把它分到训练过的两类里概率相对较高的那类(也就是垃圾类)。

2. 训练数据缺乏负样本

你的模型从来没见过汽车、自行车这类非目标图像,它根本不知道“这些不是我要检测的对象”,自然只会从它学过的两类里选一个,而垃圾类可能刚好是模型更“熟悉”的默认选项。

二、最优输出是什么?

对于非目标图像,最优输出应该是明确的“非目标/未知类别”提示,而不是错误地归类到坑洼或垃圾里。这样用户能清楚知道输入的图像不在模型的检测范围内,而不是得到一个误导性的结果。

三、具体修复步骤

1. 先修正模型架构的基础错误

如果你暂时只想区分坑洼和垃圾,把最后一层的神经元数量改成2:

# 原代码错误写法
model.add(Dense(3, activation='softmax'))

# 修正后
model.add(Dense(2, activation='softmax'))

如果你想让模型能识别“非目标”,那需要重新整理数据集,加入汽车、猫等非目标图像并标注为第3类(比如标签2),然后把独热编码的类别数改成3:

Y_train = np_utils.to_categorical(y_train, 3)
Y_test = np_utils.to_categorical(y_test, 3)

# 模型最后一层对应改成3个神经元
model.add(Dense(3, activation='softmax'))

2. 加入负样本训练

收集足够多的非目标图像(汽车、自行车、猫、人类、建筑物等),给它们打上统一的标签(比如2),混入你的训练集和测试集。只有让模型见过“什么不是坑洼/垃圾”,它才能学会区分。

3. 优化推理逻辑,加入概率阈值判断

即使加入了第三类,有时候模型对某些边缘图像的概率会很低,这时候直接输出第三类也不够严谨。可以在推理时检查最高概率值,低于阈值就输出“未知”:

# 替换原有的推理代码部分
prediction_probs = loaded_model.predict(X_test)[0]
max_prob = np.max(prediction_probs)
predicted_class = np.argmax(prediction_probs)

# 设置一个概率阈值,比如0.7
if max_prob < 0.7:
    print("未知/非目标图像!")
elif predicted_class == 1:
    print("Pothole")
elif predicted_class == 0:
    print("Garbage")
elif predicted_class == 2:
    print("非目标图像")

4. 可选:提升模型泛化能力

  • 数据增强:在训练时加入图像翻转、缩放、旋转等操作,让模型学习到更多图像变体,减少过拟合:
    from keras.preprocessing.image import ImageDataGenerator
    
    datagen = ImageDataGenerator(
        rotation_range=15,
        width_shift_range=0.1,
        height_shift_range=0.1,
        horizontal_flip=True
    )
    datagen.fit(X_train)
    # 训练时用datagen.flow替代直接传入X_train
    model.fit(datagen.flow(X_train, Y_train, batch_size=32), nb_epoch=20, verbose=1)
    
  • 迁移学习:如果你的数据集不大,可以用预训练的CNN模型(比如VGG16、ResNet50)做迁移学习,它们的特征提取能力更强,泛化效果更好。

四、修正后的完整训练代码示例(以3分类为例)

import numpy as np
np.random.seed(123) # for reproducibility
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
from dataset_pothole import pothole # 假设你已经更新了数据集包含第三类
from keras.models import model_from_json
from keras.preprocessing.image import ImageDataGenerator

# 加载包含3类的数据集:坑洼(1)、垃圾(0)、非目标(2)
(X_train, y_train), (X_test, y_test) = pothole.load_data()

# 预处理输入数据
X_train = X_train.reshape(X_train.shape[0], 50, 50, 3)
X_test = X_test.reshape(X_test.shape[0], 50, 50, 3)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255

# 预处理标签为3分类独热编码
Y_train = np_utils.to_categorical(y_train, 3)
Y_test = np_utils.to_categorical(y_test, 3)

# 定义模型架构
model = Sequential()
model.add(Convolution2D(32, 3, 3, activation='relu', input_shape=(50, 50, 3)))
model.add(Convolution2D(32, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(3, activation='softmax')) # 对应3分类

# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 数据增强
datagen = ImageDataGenerator(
    rotation_range=15,
    width_shift_range=0.1,
    height_shift_range=0.1,
    horizontal_flip=True
)
datagen.fit(X_train)

# 训练模型
model.fit(datagen.flow(X_train, Y_train, batch_size=32), nb_epoch=20, verbose=1)

# 评估与保存模型
score = model.evaluate(X_test, Y_test, verbose=0)
model_json = model.to_json()
with open("model.json", "w") as json_file:
    json_file.write(model_json)
model.save_weights("model.h5")
print("Saved model to disk")
print('Test loss: ', score[0])
print('Test accuracy: ', score[1])

内容的提问来源于stack exchange,提问作者KETAK SINGH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:10:52