Predictive model giving only one class on holdout set keras - python

Currently, using a CNN to predict a model for some black and white images. The model is working well for what I want it to do. This is the model:
lr = 0.2
Adam(lr=lr, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.001)
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
dropout = 0.3
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Dropout(rate=dropout))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'sigmoid'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Dropout(rate=dropout))
classifier.add(Conv2D(32, (3, 3), activation = 'sigmoid'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
epoch_number = 40
epochs = 25
steps_validation = 100
history = classifier.fit_generator(training_set,
steps_per_epoch = epoch_number,
epochs = epochs,
validation_data = test_set,
validation_steps = steps_validation)
classifier.save('epoch40epochs25softmax.h5')
Now, after I train this model I want to use it in the 'real world' so I have a holdout set that I use it on. The problem is it only predicts class 1 when I do a classifier.predict_classes(test_image) I figured I was doing something wrong so I tried doing a classifier.predict_classes(test_image) for all the elements in the testing set since I knew I was getting 75% accuracy on that set and still upon doing a:
for test_image in test_set_dir:
classifier.predict_classes(test_image)
I am still only getting numbers very close to [[1]]. My question is am I using keras correctly, or if not, what is going on? I should get some [[0]] classifications.
I am absolutely sure that the model is not predicting just class 1 since I have a 50% - 50% split on the two classes and I am getting 75% accuracy.
Edit:
I am normalizing the images thusly
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0,
zoom_range = 0,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('datasetI/training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('datasetI/test_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
If I want to get the class prediction on the test_set what should I do to get it?

Related

Validation accurary doesn't get better

I'm doing a project on Neural network and was trying a python code using keras and tensorflow package. Currently, I'm experiencing a problem of not getting the validation accurary to going up at all. I have a training set of 9815 images and 200 test set images. I'm really stuck here please help.
Right now, the validation result is at exactly 0.5000 for almost all 100 epoch and not going up at all.
#Image Processing Stage
train_data = ImageDataGenerator(rescale = 1./255, shear_range = 0.2, zoom_range = 0.2, horizontal_flip = True)
test_data = ImageDataGenerator(rescale = 1./255)
training_set = train_data.flow_from_directory('dataset/train_data', target_size = (128, 128), batch_size = 42, class_mode = 'binary')
test_set = test_data.flow_from_directory('dataset/test_data', target_size = (128, 128), batch_size = 42, class_mode = 'binary')
# Starting Convolutional Neural Network
start_cnn = load_model('CNN.h5')
start_cnn.get_weights()
start_cnn = Sequential()
start_cnn.add(Conv2D(32, (3, 3), input_shape = (128, 128, 3), activation = 'relu', padding='same')) #3*3*3*32+32
start_cnn.add(Conv2D(32, (3, 3), activation = 'relu'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
for i in range(0,2):
start_cnn.add(Conv2D(128, (3, 3), activation = 'relu', padding='same'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
for i in range(0,2):
start_cnn.add(Conv2D(128, (3, 3), activation = 'relu', padding='same'))
start_cnn.add(MaxPooling2D(pool_size = (2, 2)))
# Flattening
start_cnn.add(Flatten())
# Step 4 - Full connection
start_cnn.add(Dense(activation="relu", units=128))
start_cnn.add(Dense(activation="relu", units=64))
start_cnn.add(Dense(activation="relu", units=32))
start_cnn.add(Dense(activation="softmax", units=1))
start_cnn.summary()
# Compiling the CNN
start_cnn.compile(Adam(learning_rate=0.001), loss = 'binary_crossentropy', metrics = ['accuracy'])
start_cnn.fit(training_set, steps_per_epoch=234, epochs = 100, validation_data = test_set)
start_cnn.save('CNN.h5')
You cannot use the softmax activation with one neuron, like you are doing here:
start_cnn.add(Dense(activation="softmax", units=1))
To do binary classification with one neuron, you have to use the sigmoid activation:
start_cnn.add(Dense(activation="sigmoid", units=1))

Multi-class image classification using CNN - to find 3 to 5 class & to display their name

I have tried the below code, but its only working on cat and dog, not working for the 3rd, 4th,etc class. I have downloaded data-set and stored it in train & test folders according to their name.
Please let me know the approach & plz do modify my code.
# Initialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
from keras_preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('test_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 800,
epochs = 15,
validation_data = test_set,
validation_steps = 2000)
# Part 3 - Making new predictions
import numpy as np
from keras_preprocessing import image
test_image = image.load_img('cat1.jpg', target_size = (64, 64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
training_set.class_indices
if result[0][0] ==0:
prediction = 'dog'
#print ("Dog")
else:
prediction = 'cat'
#print ("Cat")
print (prediction)
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
According to this, your network is making one "binary" output, which definitely won't scale to N way classification.
Depending on the exclusiveness of your label, you can either:
# make N binary output, and change your input label to 1 hot label (eg. 0 0 1 0 0 ...)
classifier.add(Dense(units = N, activation = 'sigmoid'))
# make N probabilistic output which sum to 1, and change your input label to class_index (eg. 2)
classifier.add(Dense(units = N, activation = 'sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'crossentropy', metrics = ['accuracy'])
either way I assume you have to dig a little deeper into your training set loader (train_datagen.flow_from_director) to make it work.
If you have more then two classes you have to change your loss function like this,
classifier.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
binary_crossentropy will work if you have one or two classes i.e., cat or dog, is_mango or not mango like that
hope this will help you

Image classification using Keras for 3 classes return only one value instead of 1 X 3 array

I am training a Keras model for multi-label image classification, i.e. 3 classes namely flood, wildfire, storm.
But I am getting only [[1.]] instead of something like [0 0 1]. So if third bit is one, its a storm. But I don't know why it's returning just a single value [[1.]].
# # Importing the Keras libraries and packages
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
import numpy as np
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
def create_model() :
# Initialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
return classifier
def train_save_model():
classifier = create_model()
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('validation_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 1407,
epochs = 1,
validation_data = test_set,
validation_steps = 100)
classifier.save_weights("model.h5")
# Part 3 - Making new predictions
def test_model():
classifier = create_model()
classifier.load_weights("model.h5")
test_image = image.load_img('validation_set/tornado/110.jpg', target_size = (64, 64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
# print(test_image)
result = classifier.predict(test_image)
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True,
)
training_set = train_datagen.flow_from_directory('training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
training_set.class_indices
# print(training_set.class_indices)
print(result)
train_save_model()
test_model()
result = classifier.predict(test_image)
I tried printing this result variable and I get [[1.]]. I cannot understand at all how's that happening.
If you have N labels, then the last layer (i.e. the sigmoid classifier layer) must also have N neurons, one for each of the classes:
classifier.add(Dense(units=3, activation='sigmoid'))
Then the output of the model, for each input sample, would be 3 numbers corresponding to three labels.
Update: Remove the class_mode = 'binary' from all flow_from_directory calls. That's because you are doing classification among multiple classes and therefore the generated labels should be either categorical (default behavior) or sparse (i.e. class_mode='sparse'). Further, after reading the relevant parts of your code, it seems that you are doing multi-class classification, and not multi-label classification. Read this answer to make sure and also to find out which activation and loss function you should use.
As loss function use categorical_crossentropy instead of binary_crossentropy.

Keras returns binary results

I want to predict the kind of 2 diseases but I get results as binary (like 1.0 and 0.0). How can I get accuracy of these (like 0.7213)?
Training code:
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
# Intialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
import h5py
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('training_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('test_set',
target_size = (64, 64),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 100,
epochs = 1,
validation_data = test_set,
validation_steps = 100)
Single prediction code:
import numpy as np
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img,image
test_image = image.load_img('path_to_image', target_size = (64, 64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
print(result[0][0]) # Prints 1.0 or 0.0
# I want accuracy rate for this prediction like 0.7213
The file structures is like:
test_set
benigne
benigne_images
melignant
melignant_images
training set
Training set structure is also the same as test set.
Update: As you clarified in the comments, you are looking for the probabilities of each class given one single test sample. Therefore you can use predict method. However, note that you must first preprocess the image the same way you have done in the training phase:
test_image /= 255.0
result = classifier.predict(test_image)
The result would be the probability of the given image belonging to class one (i.e. positive class).
If you have a generator for test data, then you can use evaluate_generator() to get the loss as well as the accuracy (or any other metric you have set) of the model on the test data.
For example, right after fitting the model, i.e. using fit_generator, you can use evaluate_generator on your test data generator, i.e. test_set:
loss, acc = evaluate_generator(test_set)

Having trouble with CNN prediction

I am using Convolutional Neural Networking for vehicle identification, my first time. Currently, I am working with just 2 classes(bike and car). Training set: 420 car images and 825 bike images. Test set: 44 car images and 110 bike images Car and Bike images are in different format(bmp,jpg). In single prediction, I am always getting 'bike'. I have tried using the Sigmoid function in the output layer. Then I get only 'car'. My code is like following: ``
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense,Dropout
classifier = Sequential()
classifier.add(Conv2D(32, (3, 3), input_shape = (128, 128, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (3, 3)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (3, 3)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dropout(0.3))
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
rotation_range= 3,
fill_mode = 'nearest',
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
rotation_range= 3,
fill_mode = 'nearest',
horizontal_flip = True)
training_set = train_datagen.flow_from_directory('dataset/training_set',
target_size = (128, 128),
batch_size = 10,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory('dataset/test_set',
target_size = (128, 128),
batch_size = 10,
class_mode = 'binary')
classifier.fit_generator(training_set,
steps_per_epoch = 1092//10,
epochs = 3,
validation_data = test_set,
validation_steps = 20)
classifier.save("car_bike.h5")
And I wanted to test a single image like the following:
test_image = image.load_img('dataset/single_prediction/download (3).jpg', target_size = (128, 128))
test_image = image.img_to_array(test_image)
test_image *= (1/255.0)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
if result[0][0] == 1:
prediction = 'bike'
else:
prediction = 'car'
print(" {}".format(prediction))
If you print your result matrix you'll see that it doesn't have only 1s and 0s but floats between these numbers. You may pick a threshold and set values that exceed it to 1 and everything else to 0.

Categories