I want to build a CNN model to classify down syndrome faces from normal, then classify gender by another model. I've tried to change the number of layers, nodes, epochs, optimizers. Also, I tried with colored images and grayscale. The data set is 799 images including normal and down syndrome. This is my code
model.add(Conv2D(filters=16, kernel_size=(5,5), activation="relu",
input_shape=X_train[0].shape))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.2))
model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.3))
model.add(Conv2D(filters=64, kernel_size=(5,5), activation="relu"))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.3))
model.add(Conv2D(filters=64, kernel_size=(5,5), activation="relu"))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
#Two dense layers and then output layer
model.add(Dense(256, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5)) #Using dropouts to make sure that
#the model isn't overfitting
model.add(Dense(128, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))
I've tried to change the last activation layer from softmax to sigmoid and vise versa with no success. The size of the input images is 200x200
Model: "sequential_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_16 (Conv2D) (None, 196, 196, 16) 416
batch_normalization_24 (Bat (None, 196, 196, 16) 64
chNormalization)
max_pooling2d_16 (MaxPoolin (None, 98, 98, 16) 0
g2D)
dropout_24 (Dropout) (None, 98, 98, 16) 0
conv2d_17 (Conv2D) (None, 94, 94, 32) 12832
batch_normalization_25 (Bat (None, 94, 94, 32) 128
chNormalization)
max_pooling2d_17 (MaxPoolin (None, 47, 47, 32) 0
g2D)
dropout_25 (Dropout) (None, 47, 47, 32) 0
conv2d_18 (Conv2D) (None, 43, 43, 64) 51264
batch_normalization_26 (Bat (None, 43, 43, 64) 256
chNormalization)
max_pooling2d_18 (MaxPoolin (None, 21, 21, 64) 0
g2D)
dropout_26 (Dropout) (None, 21, 21, 64) 0
conv2d_19 (Conv2D) (None, 17, 17, 64) 102464
batch_normalization_27 (Bat (None, 17, 17, 64) 256
chNormalization)
max_pooling2d_19 (MaxPoolin (None, 8, 8, 64) 0
g2D)
dropout_27 (Dropout) (None, 8, 8, 64) 0
flatten_4 (Flatten) (None, 4096) 0
dense_12 (Dense) (None, 256) 1048832
batch_normalization_28 (Bat (None, 256) 1024
chNormalization)
dropout_28 (Dropout) (None, 256) 0
dense_13 (Dense) (None, 128) 32896
batch_normalization_29 (Bat (None, 128) 512
chNormalization)
dropout_29 (Dropout) (None, 128) 0
dense_14 (Dense) (None, 2) 258
=================================================================
Total params: 1,251,202
Trainable params: 1,250,082
Non-trainable params: 1,120
_________________________________________________________________
model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])
# split train and VALID data
X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=0.15)
I want to increase the accuracy at least to 70 but the highest score I reach is 47%
history = model.fit(X_train, y_train, epochs=50, validation_data=(X_valid, y_valid), batch_size=64)
Epoch 1/50
5/5 [==============================] - 23s 4s/step - loss: 0.9838 - accuracy: 0.5390 - val_loss: 0.6931 - val_accuracy: 0.4800
Epoch 2/50
5/5 [==============================] - 21s 4s/step - loss: 0.8043 - accuracy: 0.6348 - val_loss: 0.7109 - val_accuracy: 0.4800
Epoch 3/50
5/5 [==============================] - 21s 4s/step - loss: 0.6745 - accuracy: 0.6915 - val_loss: 0.7554 - val_accuracy: 0.4800
Epoch 4/50
5/5 [==============================] - 21s 4s/step - loss: 0.6429 - accuracy: 0.7589 - val_loss: 0.8261 - val_accuracy: 0.4800
Epoch 5/50
5/5 [==============================] - 21s 4s/step - loss: 0.5571 - accuracy: 0.8014 - val_loss: 0.9878 - val_accuracy: 0.4800
Is there any way to increase it more? and how do I combine two models? Any help will be appreciated. Thank you very much.
CodePudding user response:
Try Image Augmentation. I mean; it's pretty clear the model is overfitting the data
Maybe even change the train_test_split
ratio(Increase It.)
CodePudding user response:
I think one of 2 things is going on. The training data would point to over fitting but given the amount of dropout you have in the model I would not suspect that is the case. I think it may be that the probability distribution of the training data is significantly different from that of the validation data. That can happen if you have to few training samples. So how many training samples do you have in each of your 2 classes? If less than say 120 samples per class use image augmentation to create more training samples. How did you generate the validation images? If you have seperate validation images it is best to combine the train set with the validatioon set then use sklearn train_test_split to randomly split the combined data into train and validation sets. Note: only use augmentation for the training set not the validation set. I also recommend you use the Keras callback Reduce learning rate on plateau to implement an adjustable learning rate. Documentation is here. Code below shows the settings I use for that
rlronp=tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.5,
patience=1, verbose=1)
Also recommend using Keras callback Early Stopping, documentation is here. Code below shows my implementation for that
estop=tf.keras.callbacks.EarlyStopping( monitor="val_loss", patience=3,
verbose=1,
restore_best_weights=True)
In model.fit include the code
history=model.fit(..... callbacks[estop, rlronp])
Set the number of epoch to run to a fairly large value .