Python Keras图像分类:显示精度高,但测试图像精度低

Python Keras图像分类:显示精度高,但测试图像精度低,python,tensorflow,machine-learning,keras,Python,Tensorflow,Machine Learning,Keras,我正在尝试对Caltech101数据集进行一些图像分类。我在Keras中使用了几个经过预训练的模型。我在训练集中使用了一些增强功能: train_datagen = keras.preprocessing.image.ImageDataGenerator( rescale=1./255, rotation_range=15, width_shift_range=0.1,

我正在尝试对Caltech101数据集进行一些图像分类。我在Keras中使用了几个经过预训练的模型。我在训练集中使用了一些增强功能:

train_datagen = keras.preprocessing.image.ImageDataGenerator(
                    rescale=1./255, rotation_range=15,
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   shear_range=0.01,
                                   zoom_range=[0.9, 1.25],
                                   horizontal_flip=False,
                                   vertical_flip=False,
                                   fill_mode='reflect',
                                   data_format='channels_last',
                                   brightness_range=[0.5, 1.5])
    validation_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1./255)

    train_generator = train_datagen.flow_from_directory(
                    train1_dir,  # Source directory for the training images
                    target_size=(image_size, image_size),
                    batch_size=batch_size)

    validation_generator = validation_datagen.flow_from_directory(
                    validation_dir, # Source directory for the validation images
                    target_size=(image_size, image_size),
                    batch_size=batch_size)
我还使用了一些早期停止(100个纪元后停止):

首先,我训练最后一层:

base_model.trainable = False
    model = tf.keras.Sequential([
      base_model,
      keras.layers.GlobalAveragePooling2D(),
      keras.layers.Dense(num_classes, activation='softmax')
    ])
    model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=0.0001),
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    epochs = 10000
    steps_per_epoch = train_generator.n // batch_size
    validation_steps = validation_generator.n // batch_size
    history = model.fit_generator(train_generator,
                                  steps_per_epoch = steps_per_epoch,
                                  epochs=epochs,
                                  workers=4,
                                  validation_data=validation_generator,
                                  validation_steps=validation_steps, 
                                  callbacks=callbacks)
然后,我按照Keras教程训练前面的层:

# After top classifier is trained, we finetune the layers of the network
base_model.trainable = True
# Let's take a look to see how many layers are in the base model
print("Number of layers in the base model: ", len(base_model.layers))
# Fine tune from this layer onwards
fine_tune_at = 1
# Freeze all the layers before the `fine_tune_at` layer
for layer in base_model.layers[:fine_tune_at]:
    layer.trainable =  False

model.compile(optimizer = tf.keras.optimizers.RMSprop(lr=2e-5),
              loss='categorical_crossentropy',
              metrics=['accuracy'])
epochs = 10000
history_fine = model.fit_generator(train_generator,
                                   steps_per_epoch = steps_per_epoch,
                                   epochs=epochs,
                                   workers=4,
                                   validation_data=validation_generator,
                                   validation_steps=validation_steps, 
                                   callbacks=callbacks
                                   )
最后,在模型完成训练后,我在一个单独的测试集上手动测试它

label_list = train_generator.class_indices
    numeric_to_class = {}
    for key, val in label_list.items():
        numeric_to_class[val] = key
    total_num_images = 0
    acc_num_images = 0
    with open("%s_prediction_%s.txt" % (dataset_name, model_name), "wt") as fid:
        fid.write("Label list:\n")
        for label in label_list:
            fid.write("%s," % label)
        fid.write("\n")
        fid.write("true_class,predicted_class\n")
        fid.write("--------------------------\n")
        for label in label_list:
            testing_dir = os.path.join(test_dir, label)
            for img_file in os.listdir(testing_dir):
                img = cv2.imread(os.path.join(testing_dir, img_file))
                img_resized = cv2.resize(img, (image_size, image_size), interpolation = cv2.INTER_AREA)                
                img1 = np.reshape(img_resized, (1, img_resized.shape[0], img_resized.shape[1], img_resized.shape[2]))
                pred_class_num = model.predict_classes(img1)
                pred_class_num = pred_class_num[0]
                true_class_num = label_list[label]                
                predicted_label = numeric_to_class[pred_class_num]               
                fid.write("%s,%s\n" % (label, predicted_label))
                if predicted_label == label:
                    acc_num_images += 1
                total_num_images += 1

    acc = acc_num_images / (total_num_images * 1.0)
我必须这样做,因为库不输出F1分数。然而,我发现val_acc上升非常高(约0.8),但在训练后的测试阶段,精确度非常低(我认为约0.1)。我不明白为什么会这样。请帮帮我,非常感谢

2019年10月15日更新:我尝试在网络顶部只训练线性svm,而不进行任何微调,我使用VGG16(使用RMSProp优化器)在Caltech101上获得了70%的准确率。但是我不确定这是否是最好的选择

更新2:我在我的自定义数据集上使用了Daniel Moller建议的预处理部分(大约450张图像,283张“打开”,203张“关闭”),并且在使用“提前停止”和“耐心=100”时获得了这种精度和损失,只需使用以下方法训练最后一层:

model = tf.keras.Sequential([
  base_model,
  keras.layers.GlobalAveragePooling2D(),
  keras.layers.Dense(num_classes, activation='softmax')
])

更新3:我还尝试使用VGG16中最后一个完全连接的层,并在每个层之后添加了退出层,退出率(设置为0的比率) 60%,耐心=10(提前停止):

我得到了最高的验证精度0.93750,测试精度0.966216。图表:

主要问题似乎在这里: 在以下位置打开图像进行预测时,您忘记重新缩放
1/255。

。。。。。
img=cv2.imread(os.path.join(testing\u dir,img\u文件))
img_resized=cv2.resize(img,(图像大小,图像大小),插值=cv2.INTER_区域)
img1=np.重塑(img_调整大小,
(1,调整了img_大小的.shape[0],调整了img_大小的.shape[1],调整了img_大小的.shape[2]))
#您可能需要:
img1=img1/255。
pred_class_num=模型预测类(img1)
...........
另外,请注意,
cv2
将以
BGR
格式打开图像,而Keras可能会以
RGB
格式打开图像

  • 从Keras生成器获取图像
  • 获取由您打开的图像
  • 绘制这些图像以检查它们是否看起来正常(或者至少相同,如果一切都是BGR,这不是问题,尽管所有的绘制看起来都很有趣)
例如:

keras_train = train_generator[0][0] #first image from first batch
keras_val = validation_generator[0][0]

img = cv2.imread(os.path.join(testing_dir, img_file))
img_resized = cv2.resize(img, (image_size, image_size), interpolation = cv2.INTER_AREA) 
img1 = np.reshape(img_resized, 
                  (1, img_resized.shape[0], img_resized.shape[1], img_resized.shape[2]))    
your_image = img1[0]/255. #first image from your batch rescaled 
使用
matplotlib
打印这些图像
还要确保它们具有相同的范围:

plt.imshow(keras_train)
plt.plot()
plt.imshow(keras_val)
plt.plot()
plt.imshow(your_image)
plt.plot()
print(keras_train.max(), keras_val.max(), img1.max())
您可能需要使用
np.flip(图像,轴=-1)
将BGR转换为RGB

导入keras模型的提示 如果从keras导入基础模型,则应从同一模块导入预处理,并使用keras image opener。这将消除可能的不匹配:

from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image #use this instead of cv2   
from keras.applications.resnet50 import preprocess_input #use this in the generators    
在两个生成器中,使用预处理功能:

#no rescale, only preprocessing function
train_datagen = keras.preprocessing.image.ImageDataGenerator(
                               rotation_range=15,
                               width_shift_range=0.1,
                               height_shift_range=0.1,
                               shear_range=0.01,
                               zoom_range=[0.9, 1.25],
                               horizontal_flip=False,
                               vertical_flip=False,
                               fill_mode='reflect',
                               data_format='channels_last',
                               brightness_range=[0.5, 1.5],
                               preprocessing_function=preprocess_input)
validation_datagen = keras.preprocessing.image.ImageDataGenerator(
                               preprocessing_function=preprocess_input)
加载并预处理图像以进行预测:

img = image.load_img(img_path, target_size=(image_size,image_size))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
更多信息请访问:

其他可能性 但可能还有其他一些事情,比如:

  • 非常强烈的过度拟合,你对提前停止的耐心是100!通常这是一个非常高的数字。但唯一确认这一点的方法是检查val_acc是否比最好的一个上升太多。
    • 建议:在开始预测之前,重新加载由
      ModelCheckpoint
      保存的最佳模型
    • 建议:张贴acc历史记录,以便我们可以看到它是否糟糕
  • 基本模型是否有
    BatchNormalization
    层?-当您冻结一个批处理规范化层时,它将保持
    moving_mean
    moving_variance
    不变,但这些值是用不同的数据训练的。如果您的数据没有相同的均值和方差,您的模型将训练良好,但会验证这将是一场灾难
    • 建议:查看验证丢失/acc是否从一开始就严重错误
    • 建议:不要冻结基本模型中的
      BatchNormalization
      层(迭代层,仅冻结其他类型)
    • 建议:如果您碰巧知道基础模型所使用的数据库,请将您的数据平均值和变异值与该数据库的平均值和变异值进行比较(分别处理每个通道)

时代的数量不是太多了吗?为什么要使用averageglobalpooling而不是maxpooling?难道你的网络不太适合(因为时代太多了)?尝试使用正规化技术,如辍学和l2。@CeliusStingher Hi我使用提前停止来停止,如果在100个时代后没有改善,那么时代的数量只是最大数量。我根据Keras的初学者辅导使用平均全局工具。我认为如果训练和验证精度都很高,那么它就可以uld可以吗?是的,如果两者都很高,那么就可以了,但是你之间有很大的差异,这可能应该通过正则化技术来解决。@CeliusStingher但是如果两者都很高(>=90%),那么它们之间怎么会有很大的差异呢?:)如果你可以发布你的度量/损失的历史记录,这将是很有帮助的。虽然你这里有很多信息,但是没有任何迹象表明什么是错误的。我尝试过除以255,但是值会从0到1,所以它不再是整数,所以我得到了一个错误。好吧,你是为了训练而重新缩放,你肯定必须为了预测而重新缩放。好的,我会尝试这样做。理想情况下,如果基础模型是从keras导入的,您还应该从导入模型的同一模块加载
preprocess\u input
。不需要重新缩放,您将拥有该模型所需的精确预处理(您需要在生成器和您的图像中使用相同的预处理)@Dangmanchuong,我更新了显示如何使用Keras预处理的问题
#no rescale, only preprocessing function
train_datagen = keras.preprocessing.image.ImageDataGenerator(
                               rotation_range=15,
                               width_shift_range=0.1,
                               height_shift_range=0.1,
                               shear_range=0.01,
                               zoom_range=[0.9, 1.25],
                               horizontal_flip=False,
                               vertical_flip=False,
                               fill_mode='reflect',
                               data_format='channels_last',
                               brightness_range=[0.5, 1.5],
                               preprocessing_function=preprocess_input)
validation_datagen = keras.preprocessing.image.ImageDataGenerator(
                               preprocessing_function=preprocess_input)
img = image.load_img(img_path, target_size=(image_size,image_size))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)