Is this a case of overfitting? CNN Image classifier - python

Pardon me if this question is considered off-topic or just generally a bad question, I am new to Computer Vision and CNNs in general.
I have 3440 images in total, for a total of 10 classes.
85 images per column of each row:
Because there are only 3440 images in my dataset, I used data augmentation to increase my dataset to 34400 images. (augment 10 times per image)
aug = ImageDataGenerator(
rescale = 1./255,
rotation_range = 20,
width_shift_range = 0.10,
height_shift_range = 0.10,
zoom_range= 0.05
)
This is the model that I used for both instances. (once with augmentation, once without)
model = Sequential()
model.add(Conv2D(32, (3,3), input_shape = (50, 50, 3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
# 2 hidden layers
model.add(Flatten())
model.add(Dense(128))
model.add(Activation("relu"))
model.add(Dense(128))
model.add(Activation("relu"))
# The output layer with 10 neurons, for 10 classes
model.add(Dense(10))
model.add(Activation("softmax"))
# Compiling the model using some basic parameters
model.compile(loss="sparse_categorical_crossentropy"
,optimizer="adam"
,metrics=["accuracy"])
I was able to increase my accuracy from ~90%(no augmentation) to ~97%(with augmentation), however the difference between training accuracy and validation accuracy remains similar.
Graph with data augmentation:
I have read that non converging training and validation accuracies/loss with a big difference is a sign of overfitting.
Is this the case for my CNN model? What else can I do to improve my model?
The full codes can be found on my github
https://github.com/jwngo/SimpleImageClassifier
Thank you everyone, I appreciate your time.
EDIT:
For the augmentated dataset, Training set is 29355 images, Validation set is 7331 images. The difference between accuracy is 0.9972(training) vs 0.9750(validation), difference in loss is 0.0102(training) vs 0.1245(validation)
The validation images have also been augmented, which I will change to only use non-augmented images.

You can use some regularizations (https://www.analyticsvidhya.com/blog/2018/04/fundamentals-deep-learning-regularization-techniques/) e.g. dropout. What is the difference between training and validation accuracy? How large is the validation set?

Related

CNN is not getting good accuracy using unseen data

My cnn model is not performing well on my test set. I have trained the images on dark and white background, the image is cropped to eliminate other objects in the picture. My goal is to determine the position a person is facing on the bed.
ImageDataGenerator was used for splitting and augmenting the data.The dataset for training contains 4800 images while the validation has 1500 images.
I have 3 classes:
Facing upward
Facing left
Facing Right
The testing results gives me an accuracy of below 50% while the loss is 1.0 and above. This was evaluated using the model.evaluate
INPUT_SHAPE = (250,150,1)
traindata = ImageDataGenerator(rescale=1./255, shear_range=0.2,width_shift_range=0.1, height_shift_range=0.1, zoom_range=0.2,rotation_range=45, horizontal_flip=False, vertical_flip=False, brightness_range=[0.3,2.0])
valdata = ImageDataGenerator(rescale=1./255)
training_set = traindata.flow_from_directory(TRAIN_DIR, target_size=INPUT_SHAPE[:-1],
shuffle=True,batch_size=BATCH_SIZE, color_mode='grayscale',
class_mode='categorical')
validation_set = valdata.flow_from_directory(VAL_DIR, target_size=INPUT_SHAPE[:-1],
shuffle=False,batch_size=BATCH_SIZE, color_mode='grayscale',
class_mode='categorical')
This is the code for the model:
model = Sequential()
model.add(Conv2D(64, (3,3), activation='relu', padding='same', input_shape=INPUT_SHAPE))
model.add(Conv2D(64, (3,3), activation='relu', padding='same'))
model.add(MaxPooling2D((2,2),strides=1))
model.add(Dropout(0.5))
model.add(Conv2D(32, (3,3), activation='relu', padding='same'))
model.add(Conv2D(32, (3,3), activation='relu', padding='same'))
model.add(MaxPooling2D((2,2),strides=1))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation="relu"))
# model.add(Dense(512, activation="relu"))
# model.add(Dropout(0.5))
model.add(Dense(units=3, activation="softmax"))
model.compile(optimizer=Adam(lr=0.001),loss='categorical_crossentropy',metrics=['accuracy'])
history = model.fit(training_set,
epochs = 100,
validation_data = validation_set,
callbacks=[tensorboard, earlyStop]
)
P.S. I have tried most of the solutions that I searched online. Posting here was my last resort since I really can't fix this problem. I am not allowed to use pretrained models.
different combination of neural network
adding batchnormalization and regularization
changing image size
increasing the data count
different optimizers with different learning rate
You have overfitting problem, try to balance the images between the test and train data and have more layers in the model because it's and reduce dropout value.
one more thing is you could try pretrained model on the same split you have now to check out the data integrity.

What is the best algorithm to differentiate these kidney pictures?

I work on medical images of kidneys scans.
My goal would be to differentiate normal ones from pathologic ones (binary problem).
Normal images have regular bilateral kidney contours, whereas abnormal cases can be patchy with foci of decreased intensity or defects.
Here are examples :
Normal kidney scan, with regular bilateral kidney contours
Pathologic right kidney, with irregular contours
I tried to train a convolutional neural network to differentiate normal and pathologic scans.
I have 824 images for my training set (552 normal, 272 pathologic).
The best results I get is by pre-treating images like this :
Cropping to have, from 1 picture, 2 pictures of unique kidney
Flipping right kidneys to only have "left" kidneys
Gaussian filter to limit noise and smooth the contours
Otsu threshold to binarise my pictures.
This is the kind of pictures I get after this :
Example of normal kidney (treated)
Example of pathological kidney (treated)
Unfortunately, the best results I get in validation is like ~ 85 % of accuracy.
I'd like to reach at least 90-95 %.
Here is my code, with tensorflow :
model = Sequential()
model.add(Conv2D(filters=16, kernel_size=(3, 3), padding='same', activation='relu', input_shape = [x_train.shape[1], x_train.shape[2], x_train.shape[3]]))
model.add(MaxPool2D(pool_size=(2,2), strides=2, padding='valid'))
model.add(Conv2D(filters=16, kernel_size=(3, 3), padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=(2,2), strides=2, padding='valid'))
model.add(Conv2D(filters=16, kernel_size=(3, 3), padding='same', activation='relu'))
model.add(MaxPool2D(pool_size=(2,2), strides=2, padding='valid'))
model.add(Flatten())
model.add(Dense(units = 16, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units = 1, activation='sigmoid'))
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
es = EarlyStopping(monitor = 'val_accuracy', mode = 'max', verbose = 1, patience = 6)
mc = ModelCheckpoint('best_model.h5', monitor='val_accuracy', mode='max', verbose=1, save_best_only=True)
history = model.fit(x_train, y_train, epochs=50, batch_size=128, verbose=1, validation_split=0.3, callbacks = [es, mc])
I get more or less the same results when I change number layers, of neurons by layer (from 16 to 128), dropout between each layer, batch size etc...
So I'm wondering if I am using the good method.
I also tried anomaly detection algorithm with autoencoders but the pictures seemed to close to get appropriate detection...
So my question is :
Do you see something I could do to improve my CNN algorithm ?
Do you know another algorithm I should try ? Like a one that would be good on detection of irregular contours ?
Thank you very much for your help !

Any suggestions to improve my CNN model (always the same low test accuracy)?

I am working on a project to detect the presence of a person in a painting. I have 4000 training images and 1000 test images resized to (256,256,3)
I tried a CNN model with 3 (Conv layers, MaxPool, BatchNormalization) and 2 fully connected layers.
model = Sequential()
model.add(Conv2D(32, kernel_size = (7, 7), activation='relu', input_shape=shape))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Conv2D(64, kernel_size=(7,7), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Conv2D(96, kernel_size=(5,5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(1, activation = 'sigmoid'))
The train accuracy always converges to 1 (with just 20-50 epochs) and the test accuracy always remains constant around 0.67.
I tried the following:
I tried changing the size of the layers and adding more layers.
I tried data augmentation
I tried smaller images 128x128x3.
But I always have the same results.
I don't know if this is due to the few images I have, or if the architecture isn't big enough to learn from complex paintings.
I thought of trying Transfer Learning (But I don't know if this will help because it is my first time trying it). Also, do you have any idea where can I find trained models?
So, I am asking from some suggestions to improve my model.
It might be that you are overfitting on your training data, in that case you can use dropout.
The other thing is If you have not already normalized your data, you can do that. I am not sure whether that would be much help but give it a try with sth like:
X_training = X_training / X_training.max()
I tried using VGG16 (frozen) with 4 fully connected layers and the validation accuracy went up to 0.83. Also, I am using ImageDataGenerator.

My CNN image recognition model produces fluctuating validation loss

My model is experiencing wild and big fluctuations in the validation loss and does not converge.
I am doing an image recognition project with my three dogs i.e. classifying the dog in the image. Two dogs are very similar and the 3rd is very different. I took 10 minute videos of each dog, separately. Frames were extracted as images at each second. My dataset consists of about 1800 photos, 600 of each dog.
This block of code is responsible for augmenting and creating the data to feed the model.
randomize = np.arange(len(imArr)) # imArr is the numpy array of all the images
np.random.shuffle(randomize) # Shuffle the images and labels
imArr = imArr[randomize]
imLab= imLab[randomize] # imLab is the array of labels of the images
lab = to_categorical(imLab, 3)
gen = ImageDataGenerator(zoom_range = 0.2,horizontal_flip = True , vertical_flip = True,validation_split = 0.25)
train_gen = gen.flow(imArr,lab,batch_size = 64, subset = 'training')
test_gen = gen.flow(imArr,lab,batch_size =64,subset = 'validation')
This picture is the result of the model below.
model = Sequential()
model.add(Conv2D(16, (11, 11),strides = 1, input_shape=(imgSize,imgSize,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(3,3),strides = 2))
model.add(BatchNormalization(axis=-1))
model.add(Conv2D(32, (5, 5),strides = 1))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(3,3),strides = 2))
model.add(BatchNormalization(axis=-1))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(3,3),strides = 2))
model.add(BatchNormalization(axis=-1))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(BatchNormalization(axis=-1))
model.add(Dropout(0.3))
#Fully connected layer
model.add(Dense(256))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Dropout(0.3))
model.add(Dense(3))
model.add(Activation('softmax'))
sgd = SGD(lr=0.004)
model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy'])
batch_size = 64
epochs = 100
model.fit_generator(train_gen, steps_per_epoch=(len(train_gen)), epochs=epochs, validation_data=test_gen, validation_steps=len(test_gen),shuffle = True)
Things I have tried.
High/low Learning rate ( 0.01 -> 0.0001)
Increase Dropout to 0.5 in both Dense layers
Increase/Decrease size of both Dense Layers ( 128 min -> 4048 max)
Increased number of CNN layers
Introduced Momentum
Increased/Decreased Batch Size
Things I have not tried
I have not used any other loss or metric
I have not used any other optimiser.
Have not adjusted any parameters of the CNN layers
It seems that there is some form of randomness or too many parameters in my model. I am aware that it is currently overfitting, but that should not be the cause of the volatility(?).
I am not too worried about the performance of the model. I would like to achieve about a 70% accuracy. All I want to do now is to stabilise the validation accuracy and to converge.
Note:
At some epochs, the training loss is very low ( <0.1 ) but validation
loss is very high ( > 3 ).
The videos are taken on different backgrounds, but +- the same amount on each background for each dog.
Some images are a bit blurry.
Change the optimizer to Adam, definitely better. In your code you are using it but with default parameters, you are creating an SGD optimizer but in the compile line you introduce an Adam with no parameters. Play with the actual parameters of your optimizer.
I encourage you to take out the dropout first, see what is happening and the if you manage to overfit, start with low dropout and go up.
Also it might be due to some of your test samples are very hard to detect and thus increase the loss, maybe take out the shuffle in the validation set and watch for any peridiocities to try to find out if there are validation samples hard to detect.
Hope it helps!
I see you have tried a lot of different things. Few suggestions:
I see you use large filters in your Conv2D eg. 11x11 and 5x5. If your image dimensions are not very big, you should definitely go for lower filter dimensions like 3x3.
Try different optimizers, try Adam with varying lr if you haven't.
Otherwise, I don't see much problems. Maybe you need more data for the network to learn better.

Building Convolutional Neural Network for Bull's eye rash recognition

I need to build a Bull's eye rash recognition system.
I chose to work with Tensorflow+Keras for this. I've batch downloaded about 300 images of bull's eye rash, and same amount of other skin diseases&clean skin images. Here is my model:
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
In the process (30 epochs) it does give 90%+ accuracy, however, the system shows only about 65% accuracy on the test set.
Then I tried to crop all the rash images so that they fill the entire image. The result was disappointing, again, I don't know why, but it showed about 55% accuracy on the test set.
Can you give me some suggestions on what to do? Is the model wrong or inefficient? Do I have to use some other ML techniques for this?
Examples of images from my dataset: here, here and here
Examples of cropped pictures I used for the second attempt: here, here and here
Well, hard to start with this information.
1) have you tried pre-processing your images?
2) have you tried to load in a pre trained VGG16 network (looks close to yours), then you only need to train the dense layers.
base_model = VGG16(weights='imagenet', include_top=False, input_shape=target_shape)
model_top = Sequential()
model_top.add(Flatten(name='flatten', input_shape=base_model.output_shape[1:]))
model_top.add(Dense(4096, activation='relu', name='fc1'))
model_top.add(Dense(4096, activation='relu', name='fc2'))
model_top.add(Dropout(0.5))
model_top.add(Dense(nr_classes, activation='softmax', name='predictions'))
model_full = Model(inputs=base_model.input, outputs=model_top(base_model.output))
# set the first 25 layers (up to the last convolution block)
# to non-trainable (weights will not be updated)
for layer in model_full.layers[:-5]:
layer.trainable = False
model_full.compile(loss='categorical_crossentropy',
optimizer=optimizers.Adam(lr=1e-7))
model_full.summary()
3) Create a validation set to see if you overfit the network (validation accuracy decreases, but training accuracy increases).

Categories