0
$\begingroup$

I've been training an Xception model to recognize the disease of a plant from its leafs. So far i reached a training accuracy of 91% but the test accuracy is around 73%. So obviously my model is overfitting the data though i've already added dropout layers after the fully connected layers. I'm thinking that myabe because i've been updating 2 convolutional layers as well (fine tuning) or maybe the model is not adequate. I also should probably mention that I've chosen the Xception model because its light and according to the keras documentation it has a great accuracy compared to the other models. I'm also using a sklearn model to balance the weights of the neural net since my data is not balanced. Could that be the problem I need your advice on this matter, what do you think i should do ? Try another model ?

Here you are the code of my model:

model=Xception(include_top=True, weights='imagenet',input_shape=(299,299,3))


#function used by Xception model for preprocessing the data
preprocess = preprocess_input

#transfer learning for Xception
transfer_layer=model.get_layer('avg_pool')

inter_model=Model(inputs=model.input,outputs=transfer_layer.output)

final_model=Sequential()
final_model.add(inter_model)
final_model.add(Flatten())
final_model.add(Dense(1056))


act1 = ELU(1.0)
act1.__name__ = 'elu1'
final_model.add(act1)
final_model.add(Dropout(0.5,name="dropout1"))

final_model.add(Dense(512))
act2=ELU(1.0)
act2.__name__ = 'elu2'
final_model.add(act2)
final_model.add(Dropout(0.5,name="dropout2"))

#Defining the input shape
input_shape=model.layers[0].output_shape[1:3]

#data preparation
data_generator=ImageDataGenerator(
      rescale=1./255,
      rotation_range=180,
      width_shift_range=0.3, #try different values (or 0) 
      height_shift_range=0.3, #try different values (or 0)
      shear_range=0.2,
      zoom_range=[0.6, 1.5],
      horizontal_flip=True,
      vertical_flip=True,
      brightness_range=[0.4,2],
      validation_split=0.15,
      preprocessing_function=preprocess,
      fill_mode='nearest')

train_generator=data_generator.flow_from_directory(
        directory="D:/PlantVillage_extracted/PlantVillage-Dataset-master/raw/color",
        target_size=input_shape,
        batch_size=64,
        #save_to_dir="D:/PlantVillage_train_set",
        class_mode='categorical',
        shuffle=True,
        subset='training')

test_generator=data_generator.flow_from_directory(
        directory="D:/PlantVillage_extracted/PlantVillage-Dataset-master/raw/color",
        target_size=input_shape,
        batch_size=64,
        class_mode='categorical',
        #save_to_dir="D:/PlantVillage_test_set",
        subset='validation')

steps_test=test_generator.n /64 

image_paths_train=path_join("D:/PlantVillage_extracted/PlantVillage-Dataset-master/raw/color",train_generator.filenames)
image_paths_test=path_join("D:/PlantVillage_extracted/PlantVillage-Dataset-master/raw/color",test_generator.filenames)
image_paths_train=[i.replace('\\','/') for i in image_paths_train ]

#balancing neural net weights
class_weight=compute_class_weight(class_weight='balanced',classes=np.unique(train_generator.classes),y=train_generator.classes)

#defining the output shape
output_shape=len(np.unique(train_generator.classes))

#adding the prediction layer to the model
final_model.add(Dense(output_shape,activation='softmax'))

#defining an optimizer
optimizer=Adam(lr= 0.0001) #0.00001 with batch size=16
loss = 'categorical_crossentropy'
metrics = ['categorical_accuracy']

#function that displays the trainable layers and their names

def trainable_layer(model):
    for layer in model.layers:
        print("{0}:\t{1}".format(layer.trainable,layer.name))

#disabling the learning for the intermediate model layers
for layer in inter_model.layers:
    layer.trainable=False

inter_model.get_layer("block14_sepconv2").trainable=True
inter_model.get_layer("block14_sepconv2_bn").trainable=True

#compiling the model
final_model.compile(optimizer=optimizer,loss=loss,metrics=metrics)

#defining number of epochs and iterations per epoch

epochs=50
steps_per_epoch= (int)((len(train_generator.classes))/64)

#Creating ModelCheckpoint object to save the model every N epochs

checkpoints=ModelCheckpoint(filepath="D:/PlantVillage_models/"+ "weights.{epoch:02d}-.hdf5", monitor='val_acc', verbose=1, save_best_only=False, save_weights_only=False, mode='auto', period=1)

#creating a custumized callback to save the histories of the saved models

class ModelHistory(Callback):
    epoch_number=1
    def on_epoch_end(self, batch, logs={}):
        #if (ModelHistory.epoch_number%5==0):
            #val_acc=(logs.get('val_categorical_accuracy'))
        train_acc=(logs.get('categorical_accuracy'))
            #val_loss=(logs.get('val_loss'))
        train_loss=(logs.get('loss'))
        epoch_history=[train_acc,train_loss]
        f = open('D:/PlantVillage_models/Histories/train_acc_train_loss_epoch_'+(str)(ModelHistory.epoch_number)+'.pckl', 'wb')
        pickle.dump(epoch_history, f)
        f.close()
        ModelHistory.epoch_number+=1

#instanciating the ModelHistory callback

history_per_epoch = ModelHistory()

#Function used to copy the weights from one model to another
def weightsModel2Model(model_source,model_target):
    for layer_target,layer_source in zip(model_target.layers,model_source.layers):
            weights=layer_source.get_weights()
            layer_target.set_weights(weights)

#loading a saved model to continue training
model_source=load_model("D:/PlantVillage_models/weights.01-.hdf5")   
#copying weights
weightsModel2Model(model_source,final_model) 

#training
history=final_model.fit_generator(generator=train_generator,epochs=epochs,steps_per_epoch=steps_per_epoch,class_weight=class_weight,callbacks=[checkpoints,history_per_epoch])
$\endgroup$
  • 1
    $\begingroup$ Try batch-normalisation. $\endgroup$ – emudria Jul 3 at 1:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.