CNN with keras, accuracy not improving - python

I have started with Machine Learning recently, I am learning CNN, I planned to write an application for Car Damage severity detection, with the help of this Keras blog and this github repo.
This is how car data-set looks like:
F:\WORKSPACE\ML\CAR_DAMAGE_DETECTOR\DATASET\DATA3A
├───training (979 Images for all 3 categories of training set)
│ ├───01-minor
│ ├───02-moderate
│ └───03-severe
└───validation (171 Images for all 3 categories of validation set)
├───01-minor
├───02-moderate
└───03-severe
Following code gives me only 32% of accuracy.
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = 'dataset/data3a/training'
validation_data_dir = 'dataset/data3a/validation'
nb_train_samples = 979
nb_validation_samples = 171
epochs = 10
batch_size = 16
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
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'))
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=nb_validation_samples // batch_size)
model.save_weights('first_try.h5')
I tried:
By increasing the epochs to 10, 20,50.
By increasing images in the dataset (all validation images added to training set).
By updating the filter size in the Conv2D layer
Tried to add couple of Conv2D layer, MaxPooling layers
Also tried with different optimizers such as adam, Sgd, etc
Also Tried by updating the filter strides to (1,1) and (5,5) instead of (3,3)
Also tried by updating the changing image dimensions to (256, 256), (64, 64) from (150, 150)
But no luck, every-time I'm getting accuracy up to 32% or less than that but not more.
Any idea what I'm missing.
As in the github repo we can see, it gives 72% accuracy for the same dataset (Training -979, Validation -171). Why its not working for me.
I tried his code from the github link on my machine but it hanged up while training the dataset(I waited for more than 8 hours), so changed the approach, but still no luck so far.
Here's the Pastebin containing output of my training epochs.

The issue is caused by a mis-match between the number of output classes (three) and your choice of final layer activation (sigmoid) and loss-function (binary cross entropy).
The sigmoid function 'squashes' real values into a value between [0, 1] but it is designed for binary (two class) problems only. For multiple classes you need to use something like the softmax function. Softmax is a generalised version of sigmoid (the two should be equivalent when you have two classes).
The loss value also needs to be updated to one that can handle multiple classes - categorical cross entropy will work in this case.
In terms of code, if you modify the model definition and compilation code to the version below it should work.
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(3))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
Finally you need to specify class_mode='categorical' in your data generators. That will ensure that the output targets are formatted as a categorical 3-column matrix that has a one in the column corresponding to the correct value and zeroes elsewhere. This response format is needed by the categorical_cross_entropy loss function.

Minor correction:
model.add(Dense(1))
Should be:
model.add(Dense(3))
It has to comply with number of classes in the output.

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.

Getting Terrible Accuracy on CNN Model that I am Basing on a Research Paper: ~ 5%

I am following a research paper, trying to implement their proposed model using Tensorflow and Keras.
Here is the overview of the dataset:
92,000 total images of the Devanagari alphabet and numerals
78,200 total training images
13,800 total testing images
Number of classes: 46
Here is the proposed model in the research paper: model
And here is my keras implementation of the model:
INPUT_SHAPE = (32, 32, 1)
activation = 'relu'
model = Sequential()
model.add(Conv2D(filters=4, kernel_size=(5, 5), activation=activation, padding='valid', input_shape=INPUT_SHAPE))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='valid'))
model.add(Conv2D(filters=12, kernel_size=(5, 5), activation=activation, padding='valid'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), padding='valid'))
model.add(Flatten())
model.add(Dense(256, activation=activation))
model.add(Dropout(0.5))
model.add(Dense(46, activation=activation))
opt = SGD(learning_rate=0.005, momentum=0.9)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
print(model.summary())
my model output
And as the paper suggested, I have implemented data augmentation using keras to create my training and validation generators:
from keras.preprocessing.image import ImageDataGenerator
batch_size = 200
train_datagen = ImageDataGenerator(rescale=1./255, # normalization
rotation_range=50, # rotation
width_shift_range=0.2, # random crop
height_shift_range=0.2, # random crop
shear_range=0.8, # random manipulation
zoom_range=0.2, # zooming in
fill_mode='constant', # to fill with constant padding
horizontal_flip=True) # mirroring
train_generator = train_datagen.flow_from_directory(
'/content/Dataset/DevanagariHandwrittenCharacterDataset/Train',
target_size=(32, 32),
batch_size=batch_size,
class_mode='categorical',
color_mode='grayscale')
test_datagen = ImageDataGenerator(rescale=1./255)
validation_generator = test_datagen.flow_from_directory(
'/content/Dataset/DevanagariHandwrittenCharacterDataset/Test',
target_size=(32, 32),
batch_size=batch_size,
class_mode='categorical',
color_mode='grayscale')
Most of the hyperparameters (such as mini-batch size, kernel sizes, filters, optimizer choice, number of epochs, Dropout rate, and strides) were borrowed from the provided paper.
Finally, here is my model fitting code:
history = model.fit(
x=train_generator,
validation_data=validation_generator,
steps_per_epoch=78200 // batch_size,
validation_steps=13800 // batch_size,
epochs=50)
How come my training and validation accuracy metrics be stalled at around 0.05? I suspect that there is/are fundamental mistakes with my implementation or some part that I have overlooked. Can somebody guide me in the right direction with this?
Please check the activation fn in final layer. Use Softmax

How to create a Keras face classifier between myself and others with a restrictive data set?

For the past 2 months I've been trying to create a classification model that can distinguish between myself and other people with Keras. I started from the dogs vs cats classifier and substituted the data set. Since then I have tweaked the network and the data set with some success. Also I have tried to augment my data set in many different combinations(flip, rotate, grayscale, lighten & darken the gamma; my augmentation turns 1 picture into 9).
For training I use my laptop's webcam to capture my face in different orientations and angles and I then split it in 3 (1/3 for validation and 2/3 for training). For the negative examples I have another data set of random people divided in the same way.
validation:
person: 300
other: 300
train:
person: 600
other: 600
To check my model I use some family photos on which I achieved around 80% accuracy but for this I only use 60 pictures, 36 of which are of myself.
img_width, img_height = 150, 150
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
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'))
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
train_datagen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
print(train_generator.class_indices)
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
print(validation_generator.class_indices)
model.fit_generator(
train_generator,
steps_per_epoch=train_samples // batch_size,
epochs=epochs,
callbacks=[tensorboard],
validation_data=validation_generator,
validation_steps=validation_samples // batch_size)
model.save('model.h5')
All of my training attempts go pretty much the same way. First 1-2 epochs have close acc and loss values while the following ones jump to acc: 0.9 with loss: 0.1.
My assumption is that the problem is in the data set. What should I do in order to achieve a reasonable degree or accuracy by only using webcam taken photos?
Given the amount of data you have, a better approach would be to use transfer learning instead of training from scratch. You can start with one of the pre-trained models for ImageNet like Resnet or Inception. But I suspect models trained on large face dataset may perform better. You can check the facenet implementation from here. You can train only the last fully connected layer weights and 'freeze' the earlier layers. How to classify using Facenet can be found here.

Keras model overfiting

im working on a multi class image classification problem in keras. Using the dog-breeds dataset on kaggle. My accuracy for 12 breeds is 95% yet, my validation accuracy is only 50%. It looks like the model is overfitting, but im not sure what i would need to do to prevent overfitting
Here's my basic training setup
from keras.utils.np_utils import to_categorical
from keras.layers import Conv2D, Activation, MaxPooling2D
from keras import optimizers
from keras.layers.normalization import BatchNormalization
img_width, img_height = 224, 224
datagen_top = ImageDataGenerator(
rotation_range=180,
width_shift_range=0.2,
height_shift_range=0.2,
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
generator_top = datagen_top.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
nb_train_samples = len(generator_top.filenames)
num_classes = len(generator_top.class_indices)
train_data = bottleneck_features_train
# get the class lebels for the training data, in the original order
train_labels = generator_top.classes
# https://github.com/fchollet/keras/issues/3467
# convert the training labels to categorical vectors
train_labels = to_categorical(train_labels, num_classes=num_classes)
generator_top = datagen_top.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
nb_validation_samples = len(generator_top.filenames)
validation_data = bottleneck_features_validation
validation_labels = generator_top.classes
validation_labels = to_categorical(
validation_labels, num_classes=num_classes)
input_shape = train_data.shape[1:]
model = Sequential()
model.add(Flatten(input_shape=input_shape))
model.add(Dense(num_classes, activation='softmax'))
model.compile(optimizer=optimizers.RMSprop(lr=2e-4),
loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size,
callbacks=[],
validation_data=(validation_data, validation_labels))
model.save_weights(top_model_weights_path)
(eval_loss, eval_accuracy) = model.evaluate(
validation_data, validation_labels, batch_size=batch_size, verbose=1)
notebook is on colab.
https://colab.research.google.com/drive/13RzXpxE-yMEuMFPHnmBpzD1gFXWxVyXK
A single layer network isn't gonna fly with an image classification problem. The network will never be able to generalize because there is no opportunity to. Try expanding the network with a few more layers and maybe try a CNN.
Example:
model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same',
activation='relu',
input_shape=input_shape))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.RMSprop(),
metrics=['accuracy'])
This usually happens when you have too many layers and the resulting dimensionality (after striding and pooling) is lower than the minimum input size (convolutional kernel) of a subsequent layer.
Which is the image size of the dog-breeds data?
Have you made sure that the reshaping works correctly?

Add InputLayer to Existing Keras model to use with Android Tensor Flow Library

I'm very new on keras and TensorFlow,
when tring to convert a Keras Model (compiling and working correctly on the new iOS IA framework) to a tensorflow Model to be used in Android, I'm missing the input node.
I'm hence tring to add an InputLayer to my model without success.
The error I get is the following (at each run the Placeholder number is different...):
InvalidArgumentError: You must feed a value for placeholder tensor 'Placeholder_159' with dtype float
[[Node: Placeholder_159 = Placeholder[dtype=DT_FLOAT, shape=[], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
This is my code the modified parts compared to the working KERAS model are the few lines in between this tag #######################################
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = '/train'
validation_data_dir = '/validation'
nb_train_samples = 120 #target 2700
nb_validation_samples = 24 #target 600
epochs = 20 #target 50
batch_size = 15 #target 30
if K.image_data_format() == 'channels_first':
input_shape = (None, 3, img_width, img_height)
else:
input_shape = (None, img_width, img_height, 3)
##########################
#
# THIS IS THE CODE FOR INTRODUCING THE INPUT LAYER
# To create the input layer Instanciate an input placeholder
inputp = tensorflow.placeholder(tensorflow.float32, shape=input_shape)
model = Sequential()
# ADD the input layer as the first layer of the model
model.add(InputLayer(input_tensor=inputp, input_shape=input_shape))
#the working code without the input layer was (input_shape without the None dimension):
# model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Conv2D(32, (3, 3)))
#
# THE REST OF THE CODE IS IDENTICAL TO THE WORKING KERAS MODEL
##########################
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(3))
model.add(Activation('softmax')) #use sigmoid when binary and softmax when categorical
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=nb_validation_samples // batch_size)
model.save('androidtest_model.h5')
model.save_weights('androidtest_weights.h5')
With Keras API you don't have to use Tensor to input data.
First set the flattened input shape:
# Start construction of the Keras Sequential model.
model = Sequential()
# Add an input layer which is similar to a feed_dict in TensorFlow.
# Note that the input-shape must be a tuple containing the image-size.
model.add(InputLayer(input_shape=(3*img_width*img_height)))
# Add the real shape that conv layer spect
model.add(Reshape((img_width,img_height , 3)))
Then to train the network pass the images as numpy array, it's similar as scikitlearn
# Note that train_datagen and train_labels must be numpy array object
model.fit(x=train_datagen,
y=train_labels,
epochs=1, batch_size=128)

Categories