How to improve my CNN ? high and constant validation error - python

I am working on a problem for predicting a score of how fat cows are, based on images of cows.
I applied a CNN to estimate the value which is between 0-5 ( the dataset i have, contains only values between 2.25 and 4 )
I am using 4 CNN layers and 3 Hidden layers.
I actualy have 2 problems :
1/ I got 0.05 training error, but after 3-5 epochs the validation error remains at about 0.33.
2/ The value predicted by my NN are between 2.9 and 3.3 which is too narrow compared with the dataset range. Is it normal ?
How can i improve my model ?
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(512, 424,1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(input_shape=(512, 424)),
tf.keras.layers.Dense(256, activation=tf.nn.relu),
tf.keras.layers.Dense(128, activation=tf.nn.relu),
tf.keras.layers.Dense(64, activation=tf.nn.relu),
tf.keras.layers.Dense(1, activation='linear')
])
Learning Curve:
Prediction:

This seems to be the case of Overfitting. You can
Shuffle the Data, by using shuffle=True in cnn_model.fit. Code is shown below:
history = cnn_model.fit(x = X_train_reshaped,
y = y_train,
batch_size = 512,
epochs = epochs, callbacks=[callback],
verbose = 1, validation_data = (X_test_reshaped, y_test),
validation_steps = 10, steps_per_epoch=steps_per_epoch, shuffle = True)
Use Early Stopping. Code is shown below
callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=15)
Use Regularization. Code for Regularization is shown below (You can try l1 Regularization or l1_l2 Regularization as well):
from tensorflow.keras.regularizers import l2
Regularizer = l2(0.001)
cnn_model.add(Conv2D(64,3, 3, input_shape = (28,28,1), activation='relu', data_format='channels_last',
activity_regularizer=Regularizer, kernel_regularizer=Regularizer))
cnn_model.add(Dense(units = 10, activation = 'sigmoid',
activity_regularizer=Regularizer, kernel_regularizer=Regularizer))
You can try using BatchNormalization.
Perform Image Data Augmentation using ImageDataGenerator. Refer this link for more info about that.
If the Pixels are not Normalized, Dividing the Pixel Values with 255 also helps.
Finally, if there still no change, you can try using Pre-Trained Models like ResNet or VGG Net, etc..

Related

cnn model for binary classification always returning 1

I created a CNN model for binary classification. I used a balanced database of 300 images. I know it's a small database but I used data augmentation. After fitting the model I got 86% val_accuracy on the validation set, but when I wanted to print the probability for each picture, I got probability 1 for most pictures from the first class and even all probabilities are >0.5, and probability 1 for all images from the second class.
This is my model:
model = keras.Sequential([
layers.InputLayer(input_shape=[128, 128, 3]),
preprocessing.Rescaling(scale=1/255),
preprocessing.RandomContrast(factor=0.10),
preprocessing.RandomFlip(mode='horizontal'),
preprocessing.RandomRotation(factor=0.10),
layers.BatchNormalization(renorm=True),
layers.Conv2D(filters=64, kernel_size=3, activation='relu', padding='same'),
layers.MaxPool2D(),
layers.BatchNormalization(renorm=True),
layers.Conv2D(filters=128, kernel_size=3, activation='relu', padding='same'),
layers.MaxPool2D(),
layers.BatchNormalization(renorm=True),
layers.Conv2D(filters=256, kernel_size=3, activation='relu', padding='same'),
layers.Conv2D(filters=256, kernel_size=3, activation='relu', padding='same'),
layers.MaxPool2D(),
layers.BatchNormalization(renorm=True),
layers.Flatten(),
layers.Dense(8, activation='relu'),
layers.Dense(1, activation='sigmoid'),])
Edit:
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss='binary_crossentropy',
metrics=['binary_accuracy'],
)
history = model.fit(
ds_train,
validation_data=ds_valid,
epochs=50,
)
Thank you.
A pre-trained model like vgg16 does all the work pretty much well, there is no need to complicate very much the model. So try the following code:
base_model = keras.applications.VGG16(
weights='imagenet',
input_shape=(128, 128, 3),
include_top=False)
base_model.trainable = True
inputs = keras.Input(shape=(128, 128, 3))
x = base_model(inputs, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs, outputs)
Set base_model.trainable to False if you want the model to train fast and True for
more accurate results.
Notice that I used the GlobalAveragePooling2D layer, instead of Flatten, to reduce the number of parameters and to unstack the features.

Getting very poor accuracy on stanford_dogs dataset

I'm trying to train a model on the stanford_dogs dataset to classify 120 dog breeds but my code is acting strange.
I downloaded the image data from http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar
Then ran the following code to split each folder of the breeds into training and testing folders:
dataset_dict = {}
source_path = 'C:/Users/visha/Downloads/stanford_dogs/dataset'
dir_root = os.getcwd()
dataset_folders = [x for x in os.listdir(os.path.join(dir_root, source_path)) if os.path.isdir(os.path.join(dir_root, source_path, x))]
for category in dataset_folders:
dataset_dict[category] = {'source_path': os.path.join(dir_root, source_path, category),
'train_path': create_folder(new_path='C:/Users/visha/Downloads/stanford_dogs/train',
folder_type='train',
data_class=category),
'validation_path': create_folder(new_path='C:/Users/visha/Downloads/stanford_dogs/validation',
folder_type='validation',
data_class=category)}
dataset_folders = [x for x in os.listdir(os.path.join(dir_root, source_path)) if os.path.isdir(os.path.join(dir_root, source_path, x))]
for key in dataset_dict:
print("Splitting Category {} ...".format(key))
split_data(source_path=dataset_dict[key]['source_path'],
train_path=dataset_dict[key]['train_path'],
validation_path=dataset_dict[key]['validation_path'],
split_size=0.7)
I fed the images through the network after some image augmentation and used sigmoid activation in the final layer and categorical_crossentropy loss.
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import RMSprop
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(120, activation='softmax')
])
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
TRAINING_DIR = 'C:/Users/visha/Downloads/stanford_dogs/train'
train_datagen = ImageDataGenerator(rescale=1./255,rotation_range=40,width_shift_range=0.2,height_shift_range=0.2,
shear_range=0.2,zoom_range=0.2,horizontal_flip=True,fill_mode='nearest')
train_generator = train_datagen.flow_from_directory(TRAINING_DIR,
batch_size=10,
class_mode='categorical',
target_size=(150, 150))
VALIDATION_DIR = 'C:/Users/visha/Downloads/stanford_dogs/validation'
validation_datagen = ImageDataGenerator(rescale=1./255, rotation_range=40,width_shift_range=0.2, height_shift_range=0.2,
shear_range=0.2,zoom_range=0.2,horizontal_flip=True,fill_mode='nearest')
validation_generator = validation_datagen.flow_from_directory(VALIDATION_DIR,
batch_size=10,
class_mode='categorical',
target_size=(150, 150))
history = model.fit(train_generator,
epochs=10,
verbose=1,
validation_data=validation_generator)
But the code is not working as intended. The val_accuracy after 10 epochs is something like 4.756.
For validation data you should not do any image augmentation, just do rescale. In validation flow_from_directory set shuffle=False. Be advised that the Stanford Dog Data set is very difficult. To achieve a reasonable degree of accuracy you will need a much more complex model. I recommend you consider transfer learning using the Mobilenet model. The code below shows how to do that.
base_model=tf.keras.applications.mobilenet.MobileNet( include_top=False,
input_shape=(150,150,3) pooling='max', weights='imagenet',dropout=.4)
x=base_model.output
x=keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001 )(x)
x = Dense(1024, activation='relu')(x)
x=Dropout(rate=.3, seed=123)(x)
output=Dense(120, activation='softmax')(x)
model=Model(inputs=base_model.input, outputs=output)
model.compile(Adamax(lr=.001),loss='categorical_crossentropy',metrics=
['accuracy'] )
I forgot to mention that Mobilenet was trained on Images with pixel values in the range -1 to +1. So in ImageDataGenerator include the code
preprocessing_function=tf.keras.applications.mobilenet.preprocess_input
this scales the pixels so you do not need the code
rescale=1./255
or alternatively set
rescale=1/157.5-1
which will rescale the values between -1 and +1

Keras CNN accuracy is either static or way too high for image classification

I'm trying to implement a Convolutional Neural Network that can detect whether a person is wearing glasses or not. Unfortunately, I keep getting very strange results no matter which exact settings I use for learning rate, the specific optimizer, etc. With most settings, I notice that the accuracy of my model doesn't change after the second epoch and gets stuck at around 0.56 (which is close to the ratio of one label, 2700 images, compared to the other label, 2200 images). In other runs, with slightly different settings, the accuracy suddenly rockets to about 0.9 and keeps increasing. In both cases, however, the model predicts the exact same classification ('with glasses') each time (even on images that were in the training/validation set), always with a confidence level of 100% (the label is exactly 1 each time).
I'm not all that experienced with Neural Networks for image classification so I wasn't quite sure how to figure out the issue. I tried printing some values from my dataset and their respective labels, and the labels do contain both labels (0s and 1s). Therefore, I assume it's probably an issue with my model but I can't really figure out much myself. I've tried different optimizers (Adam, SGD mostly), smaller and bigger learning rates, different momentum values, less/more convolutional layers and different parameters for the padding and kernel_initializer, different batch sizes... It's still stuck with either the very quickly improving accuracy or the static one.
My code looks as follows:
#parameters
batch_size = 16
img_height = 180
img_width = 180
num_classes = 2
epochs = 10
#training data
train_db = tf.keras.preprocessing.image_dataset_from_directory(
`D:\archive\faces\`,
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width), color_mode = "grayscale",
batch_size=batch_size)
#validation data
val_db = tf.keras.preprocessing.image_dataset_from_directory(
`D:\archive\faces\`,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width), color_mode = "grayscale",
batch_size=batch_size)
#speeds up the model training
AUTOTUNE = tf.data.experimental.AUTOTUNE
train_db = train_db.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_db = val_db.cache().prefetch(buffer_size=AUTOTUNE)
#establishing the model
model = Sequential([
layers.experimental.preprocessing.Rescaling(1./255),
layers.Conv2D(16, (3,3), activation='relu', input_shape=(img_width, img_height, 1), kernel_initializer='he_uniform', padding='same'),
layers.MaxPooling2D(2, 2),
layers.Conv2D(32, (3,3), activation='relu', kernel_initializer='he_uniform', padding='same'),
layers.MaxPooling2D(2,2),
layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_uniform', padding='same'),
layers.MaxPooling2D(2,2),
layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_uniform', padding='same'),
layers.MaxPooling2D(2,2),
layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_uniform', padding='same'),
layers.MaxPooling2D(2,2),
layers.Flatten(),
layers.Dense(512, activation='relu', kernel_initializer='he_uniform'),
layers.Dense(1, activation='sigmoid')
])
#different optimizer options
opt = tf.keras.optimizers.SGD(learning_rate=0.001, momentum=0.9)
opt2 = tf.keras.optimizers.Adam(learning_rate=0.001)
#compiling the model
model.compile(
optimizer=opt,
loss=tf.losses.BinaryCrossentropy(),
metrics='accuracy')
#training the model
model.fit(train_db,validation_data=val_db,epochs=epochs)
since you are using loss=tf.losses.BinaryCrossentropy() then in image_dataset_from_directory you need to add label_mode='binary' for both the train_db and val_db. For val_db add shuffle=False

Training neural network gives multiple accuracies and then the number starts decreasing and accuracy is stagnant

I was trying to train my model and while the model is training, multiple accuracies are printed which then get deleted as the training in the same epoch progresses.
I see 3 ETAs in the new epoch while it should only be 1.
Also the training accuracy is not increasing.I have tried 15 epochs and even the training accuracy remains exactly the same.
model = tf.keras.models.Sequential([tf.keras.layers.Conv2D(64,kernel_size = (3,3), input_shape=(X_train.shape[1:]),activation = 'relu'),
tf.keras.layers.Conv2D(64,kernel_size = (3,3),activation = 'relu'),
tf.keras.layers.MaxPooling2D(pool_size = (2,2), strides = (2,2)),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Conv2D(64,kernel_size = (3,3),activation = 'relu'),
tf.keras.layers.Conv2D(64,kernel_size = (3,3),activation = 'relu'),
tf.keras.layers.MaxPooling2D(pool_size = (2,2), strides = (2,2)),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Conv2D(128,kernel_size = (3,3),activation = 'relu'),
tf.keras.layers.Conv2D(128,kernel_size = (3,3),activation = 'relu'),
tf.keras.layers.MaxPooling2D(pool_size = (2,2), strides = (2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(8*128, activation = 'relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(8*128, activation = 'relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(7, activation = 'softmax')])
model.compile( optimizer = 'SGD', loss = tf.keras.losses.categorical_crossentropy, metrics = ['accuracy'])
model.fit(X_train, y_train, epochs = 2, verbose = 1, shuffle = True, batch_size = 64, validation_split=0.05)
i. You're seeing multiple accuracy because multiple batches are being processed. All of them gets merged later. Don't worry about that. It's a normal process. But if you still want to know about it more, take a look into tensorflow multi processing and back propagation.
ii. It depends on your data. To increase accuracy you can try following:
Pre-process your data.
Try to use augmentation
Maybe your data needs more complex architecture. Try adding few more layers. I would have tried removing dropout layer first.
Please also try to train the same architecture with higher learning rate for 15-20 epochs. If you still see no difference, try the methods mentioned above.

Tensorflow image classification binary crossentropy loss is negative

I'm new to Tensorflow. I followed some tutorials with a provided dataset and wanted to try something on my own. I decided I'd try to classify Magic the Gathering sets. Each card has a symbol in different colors on it: Black, Gold and so on.
The colors don't matter, just the different symbols. So I created a dataset of 3 different sets (so 3 different symbols) and got around 15'000 images like this. Some are a little bit rotated, some have an X and Y offset, just to get some different images.
Then I adapted the tutorial on the tensorflow website for image classification. Instead of two classes I wanted to try three:
batch_size = 250
epochs = 3
IMG_HEIGHT = 55
IMG_WIDTH = 55
train_image_generator = ImageDataGenerator(rescale=1./255)
validation_image_generator = ImageDataGenerator(rescale=1./255)
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(IMG_HEIGHT, IMG_WIDTH),
class_mode='binary')
val_data_gen = validation_image_generator.flow_from_directory(batch_size=batch_size,
directory=validation_dir,
target_size=(IMG_HEIGHT, IMG_WIDTH),
class_mode='binary')
model = Sequential([
Conv2D(16, 3, padding='same', activation='relu', input_shape=(IMG_HEIGHT, IMG_WIDTH ,3)),
MaxPooling2D(),
Conv2D(32, 3, padding='same', activation='relu'),
MaxPooling2D(),
Conv2D(64, 3, padding='same', activation='relu'),
MaxPooling2D(),
Flatten(),
Dense(512, activation='relu'),
Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
history = model.fit_generator(
train_data_gen,
steps_per_epoch=total_train // batch_size,
epochs=epochs,
validation_data=val_data_gen,
validation_steps=total_val // batch_size,
callbacks=[cp_callback]
)
But my loss is negative and I don't get a good accuracy after training. What did I mess up? Is the model used in the tutorial not good for my usecase? Or is there an error in the code because I used three instead of two classes?
The model from the tutorial was used for binary classification (only two classes, cat or dog). You on the other hand want to classify 3 classes not 2. Therefore you have to adapt the architecture a little bit. Your last layer should be:
Dense(3, activation='softmax')
Three neurons because you have three classes and softmax activation because you want your outputs to be valid probabilities. To compile the model, use categorical_crossentropy instead of binary_crossentropy and make sure your labels are one-hot-encoded. Also for your ImageDataGenerator you should pass class_mode=categorical to the .flow_from_directory() function.

Categories

Resources