I'm trying to do some image classification on the Caltech101 dataset. I used several pretrained models in Keras. I used some augmentation on the training set:
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)
I also used some early stopping (stop after 100 epochs):
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]
At first I train the last layer:
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)
Then I train the previous layers, following the Keras tutorial:
# 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
)
Finally, after the model has finished training, I test it manually on a separate test set
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)
I had to do this because the library does not output F1 score. However what I found out is that the val_acc goes up very high (about 0.8) but during the test phase after training the accuracy is very low (about 0.1 I think). I do not understand why this is so. Please help me, thank you very much.
UPDATE 15/10/2019: I tried to just train a linear svm on top of the network without finetuning anything and I got 70% accuracy on Caltech101 using VGG16 (with RMSProp optimizer). However I'm not sure if this is the best choice.
UPDATE 2: I used the preprocessing part suggested by Daniel Moller on my custom dataset (about 450 images, 283 class "open", 203 class "closed", and got this accuracy and loss when using early stopping with patience=100, just training the last layer with:
model = tf.keras.Sequential([
base_model,
keras.layers.GlobalAveragePooling2D(),
keras.layers.Dense(num_classes, activation='softmax')
])
UPDATE 3: I tried to use the last fully connected layers in VGG16 also, and added dropout layer after each of them, with the dropout rate (the rate that is set to 0) of 60%, and patience=10 (for early stopping):
base_model = tf.keras.applications.VGG16(input_shape=IMG_SHAPE, \
include_top=True, \
weights='imagenet')
base_model.layers[-3].Trainable = True
base_model.layers[-2].Trainable = True
fc1 = 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)
And I got the highest validation accuracy of 0.93750, test accuracy: 0.966216. Graphs:


