为何训练与测试时同一图像的神经网络表现差异巨大?
新冠快检图像分类模型训练与推理准确率不一致问题排查
我用TensorFlow搭建了一个神经网络,将新冠病毒快速检测图像分为三类:阴性、阳性、空白。训练过程中TensorBoard显示验证准确率约90%,但训练完成后用同一训练图像测试时,分类准确率却仅约60%;更换不同图像训练后,该问题依然存在。
训练相关细节
图像预处理流程
训练时图像先转为灰度图再调整尺寸,批量大小设为16:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = cv2.resize(image, (height, width))
数据增强设置
因数据集仅约450张图像,使用keras.preprocessing.image.ImageDataGenerator做数据增强,参数如下:width_shift_range=0.1、brightness_range=[0.9, 1.1]、height_shift_range=0.1、zoom_range=0.2、horizontal_flip=True、rotation_range=10、shear_range=0.2、fill_mode="nearest"、samplewise_center=True、samplewise_std_normalization=True
TFLite模型转换代码
为适配移动平台,将训练好的模型转为TFLite格式:
model = tf.keras.models.load_model(model_path) converter = tf.lite.TFLiteConverter.from_keras_model(model) # converter.optimizations = [tf.lite.Optimize.DEFAULT] # 未启用优化 tflite_model = converter.convert() # 保存模型 with open('rapid_test_strip_cleaned_model.tflite', 'wb') as f: f.write(tflite_model)
已尝试的解决方法
- 将图像裁剪至检测盒的试纸条区域,重新训练并测试
- 检查测试脚本中的标签映射是否正确
- 验证测试时图像是否正确转为灰度图并调整尺寸
- 在转换TFLite前,直接用
tensorflow.keras.models测试原模型
模型结构
img_width, img_height = (256, 256) model = Sequential() inputShape = (img_width, img_height, 1) model.add(Conv2D(32, (3, 3), activation="relu", input_shape=inputShape)) # 抑制过拟合 model.add(Dropout(0.25)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Conv2D(64, (3, 3), activation="relu")) # 抑制过拟合 model.add(Dropout(0.25)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Conv2D(128, (3, 3), activation="relu")) # 抑制过拟合 model.add(Dropout(0.25)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Flatten()) model.add(Dense(512, activation="relu")) # 抑制过拟合 model.add(Dropout(0.5)) model.add(Dense(3, activation="softmax")) opt = Adam(learning_rate=INIT_LR, decay=INIT_LR / EPOCHS) model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
训练的TensorBoard图表显示验证准确率约90%,其中直线来自另一次训练运行。
测试/推理脚本
interpreter = tf.lite.Interpreter(model_path=model_path) # 加载TFLite模型并分配张量 interpreter.allocate_tensors() # 获取输入输出张量信息 input_details = interpreter.get_input_details() output_details = interpreter.get_output_details() height = input_details[0]['shape'][1] width = input_details[0]['shape'][2] labels = ["positive", "negative", "initial"] # 加载图像并预处理 image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = cv2.resize(image, (height, width)) input_arr = img_to_array(image) input_arr = np.array([input_arr]) # 归一化 input_arr = input_arr / 255.0 interpreter.set_tensor(input_details[0]['index'], input_arr) interpreter.invoke() # 获取输出结果 output_data = interpreter.get_tensor(output_details[0]['index']) results = np.squeeze(output_data) top_k = results.argsort()[-5:][::-1] print(labels[top_k[0]])
问题可能的根源
- 预处理流程不一致:训练时用了
samplewise_center=True和samplewise_std_normalization=True,即对每张图像单独做均值中心化、标准差归一化,但推理脚本仅做了input_arr / 255.0,未同步这两步操作,导致输入数据分布与训练时偏差极大,模型输出错误。 - 标签映射不匹配:训练时的标签顺序与推理脚本中
labels列表的顺序可能不一致,比如训练时标签顺序是[阴性,阳性,空白],但推理时顺序颠倒,导致分类结果对应错误。 - 数据集划分偏差:验证集可能与训练集存在数据重叠,或验证集图像分布过于简单,导致验证准确率虚高,实际模型泛化能力不足。
- Dropout层状态异常:虽然Keras模型在推理时会自动关闭Dropout,但转换TFLite时若未正确处理,可能导致推理时仍启用Dropout,影响输出稳定性(不过你已测试原Keras模型,此可能性较低)。
内容的提问来源于stack exchange,提问作者Sohrab
相关产品推荐
相关产品推荐

