# My model is overfitting though i'v been using regularization techniques

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()

act1 = ELU(1.0)
act1.__name__ = 'elu1'

act2=ELU(1.0)
act2.__name__ = 'elu2'

#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

#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)