我正在尝试对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, # 训练图像的源目录 target_size=(image_size, image_size), batch_size=batch_size) validation_generator = validation_datagen.flow_from_directory( validation_dir, # 验证图像的源目录 target_size=(image_size, image_size), batch_size=batch_size)
我还使用了提前停止(在100个周期后停止):
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=100) mc = ModelCheckpoint('best_model_%s_%s.h5' % (dataset_name, model_name), monitor='val_acc', mode='max', verbose=1, save_best_only=True) callbacks = [es, mc]
首先,我训练了最后一个层:
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教程训练了前面的层:
# 在顶层分类器训练后,我们微调网络的层base_model.trainable = True# 让我们看看基础模型中有多少层print("基础模型中的层数: ", len(base_model.layers))# 从这一层开始微调fine_tune_at = 1# 冻结`fine_tune_at`层之前的所有层for layer in base_model.layers[:fine_tune_at]: layer.trainable = Falsemodel.compile(optimizer = tf.keras.optimizers.RMSprop(lr=2e-5), loss='categorical_crossentropy', metrics=['accuracy'])epochs = 10000history_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("标签列表:\n") for label in label_list: fid.write("%s," % label) fid.write("\n") fid.write("真实类别,预测类别\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)。我不明白这是为什么。请帮助我,非常感谢。
更新15/10/2019:我尝试仅在网络顶部训练一个线性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的最后一个全连接层,并在每个全连接层后添加dropout层,dropout率(设置为0的比率)为60%,提前停止的耐心设置为10:
base_model = tf.keras.applications.VGG16(input_shape=IMG_SHAPE, \ include_top=True, \ weights='imagenet')base_model.layers[-3].Trainable = Truebase_model.layers[-2].Trainable = Truefc1 = base_model.layers[-3]fc2 = base_model.layers[-2]predictions = keras.layers.Dense(num_classes, activation='softmax')dropout1 = Dropout(0.6)dropout2 = Dropout(0.6)x = dropout1(fc1.output)x = fc2(x)x = dropout2(x)predictors = predictions(x)model = Model(inputs=base_model.input, outputs=predictors)
我得到了最高的验证准确率0.93750,测试准确率:0.966216。图表:
回答: