面部表情识别程序逻辑错误求助:模型准确率95%但预测异常
面部表情识别模型预测异常问题
模型训练准确率达95%,但对任意输入图像进行情绪预测时,总是输出同一种情绪。代码无语法错误,已尝试增加数据集、调整网络层等方法,问题仍未解决。
核心代码(省略数据预处理与导入部分)
classes = ['angry','disgust', 'fear', 'happy', 'neutral','sad', 'surprise'] training_data = [] x = [] y = [] for feature, label in training_data: x.append(feature) y.append(label) X = np.array(x).reshape(-1,224,224,3) Y = np.array(y) model = tf.keras.applications.MobileNetV2() base_input = model.layers[0].input base_output = model.layers[-2].output final_output = layers.Dense(128)(base_output) final_output = layers.Activation("relu")(final_output) final_output = layers.Dense(64)(final_output) final_output = layers.Activation("relu")(final_output) final_output = layers.Dense(7,activation="softmax")(final_output) new_model = keras.Model(inputs = base_input, outputs = final_output) new_model.summary() new_model.compile(loss = 'sparse_categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy']) new_model.save("emotion_detection") test_image = cv2.imread("/content/Happy image to test.jpg") img_bcp = test_image.copy() face_classifier = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') gray_img = cv2.cvtColor(test_image, cv2.COLOR_BGR2GRAY) faces_coordinates = face_classifier.detectMultiScale(gray_img) for (x, y, w, h) in faces_coordinates: # 绘制人脸框 cv2.rectangle(test_image, (x, y), (x + w, y + h), (0, 255, 0), 2) # 裁剪人脸区域 cropped_face = img_bcp[y:y+h, x:x+w] plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(test_image, cv2.COLOR_BGR2RGB)) plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(cropped_face, cv2.COLOR_BGR2RGB)) class_dictionary = {0: 'angry', 1: 'fear', 2: 'happy', 3: 'neutral', 4: 'sad', 5: 'surprise'} final_image = cv2.resize(cropped_face, (224,224)) final_image = np.expand_dims(final_image, axis=0) # 增加维度适配模型输入 final_image = final_image/255.0 # 归一化 new_model = tf.keras.models.load_model('emotion_detection') prediction = new_model.predict(final_image) class_dictionary[np.argmax(prediction)]
相关截图说明
- 训练准确率截图:训练集准确率达到95%
- 错误输出截图:所有测试图像的预测结果均为同一种情绪
问题排查与解决方案
1. 类别映射完全错误
原代码中classes定义了7类情绪,但class_dictionary只包含6类,且索引对应错误(跳过了disgust类别),这会导致预测结果的显示完全混乱,甚至出现“固定输出同一种情绪”的假象。
修正方案:
直接基于classes生成对应字典,保证索引与类别完全匹配:
class_dictionary = {i: cls for i, cls in enumerate(classes)} # 对应关系:0:angry,1:disgust,2:fear,3:happy,4:neutral,5:sad,6:surprise
2. 输入预处理不符合预训练模型要求
MobileNetV2预训练模型的输入预处理要求将像素值缩放到[-1, 1]区间,而非代码中的[0, 1]。错误的归一化方式会导致输入特征分布与训练时完全偏离,模型无法正确提取特征,最终输出异常。
修正方案:
替换归一化代码为官方标准预处理:
final_image = cv2.resize(cropped_face, (224,224)) final_image = np.expand_dims(final_image, axis=0) # 使用MobileNetV2专用预处理 final_image = tf.keras.applications.mobilenet_v2.preprocess_input(final_image)
3. 训练过程存在潜在问题
- 类别不平衡: 若训练集中某类情绪样本占比极高,模型会倾向于预测该类,导致所有输入输出同一种情绪。可通过
np.bincount(Y)查看标签分布,采用过采样、欠采样或训练时添加class_weight参数解决。 - 预训练模型未冻结: 直接训练整个MobileNetV2会破坏预训练权重,导致模型泛化能力极差。建议先冻结base层训练头部,再解冻部分层微调:
# 构建base模型时冻结所有层 model = tf.keras.applications.MobileNetV2(weights='imagenet', include_top=False) for layer in model.layers: layer.trainable = False # 之后构建头部并训练,训练完成后可解冻部分顶层微调 - 过拟合: 训练集95%准确率但测试异常,可能是训练集过拟合。需添加验证集监控,增加数据增强、Dropout层等抑制过拟合。
4. 人脸检测后的图像验证
检查裁剪后的人脸图像是否有效:打印cropped_face.shape确认是否成功裁剪到人脸,若人脸检测失败(返回空坐标),会导致输入无效图像,模型输出固定结果。
内容的提问来源于stack exchange,提问作者Veg Roast
相关产品推荐
相关产品推荐

