How to predict input image using trained model in Keras? - python

I trained a model to classify images from 2 classes and saved it using model.save(). Here is the code I used:
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 = 320, 240
train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
nb_train_samples = 200 #total
nb_validation_samples = 10 # total
epochs = 6
batch_size = 10
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=5)
model.save('model.h5')
It successfully trained with 0.98 accuracy which is pretty good. To load and test this model on new images, I used the below code:
from keras.models import load_model
import cv2
import numpy as np
model = load_model('model.h5')
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
img = cv2.imread('test.jpg')
img = cv2.resize(img,(320,240))
img = np.reshape(img,[1,320,240,3])
classes = model.predict_classes(img)
print classes
It outputs:
[[0]]
Why wouldn't it give out the actual name of the class and why [[0]]?

If someone is still struggling to make predictions on images, here is the optimized code to load the saved model and make predictions:
# Modify 'test1.jpg' and 'test2.jpg' to the images you want to predict on
from keras.models import load_model
from keras.preprocessing import image
import numpy as np
# dimensions of our images
img_width, img_height = 320, 240
# load the model we saved
model = load_model('model.h5')
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# predicting images
img = image.load_img('test1.jpg', target_size=(img_width, img_height))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
images = np.vstack([x])
classes = model.predict_classes(images, batch_size=10)
print classes
# predicting multiple images at once
img = image.load_img('test2.jpg', target_size=(img_width, img_height))
y = image.img_to_array(img)
y = np.expand_dims(y, axis=0)
# pass the list of multiple images np.vstack()
images = np.vstack([x, y])
classes = model.predict_classes(images, batch_size=10)
# print the classes, the images belong to
print classes
print classes[0]
print classes[0][0]

You can use model.predict() to predict the class of a single image as follows [doc]:
# load_model_sample.py
from keras.models import load_model
from keras.preprocessing import image
import matplotlib.pyplot as plt
import numpy as np
import os
def load_image(img_path, show=False):
img = image.load_img(img_path, target_size=(150, 150))
img_tensor = image.img_to_array(img) # (height, width, channels)
img_tensor = np.expand_dims(img_tensor, axis=0) # (1, height, width, channels), add a dimension because the model expects this shape: (batch_size, height, width, channels)
img_tensor /= 255. # imshow expects values in the range [0, 1]
if show:
plt.imshow(img_tensor[0])
plt.axis('off')
plt.show()
return img_tensor
if __name__ == "__main__":
# load model
model = load_model("model_aug.h5")
# image path
img_path = '/media/data/dogscats/test1/3867.jpg' # dog
#img_path = '/media/data/dogscats/test1/19.jpg' # cat
# load a single image
new_image = load_image(img_path)
# check prediction
pred = model.predict(new_image)
In this example, a image is loaded as a numpy array with shape (1, height, width, channels). Then, we load it into the model and predict its class, returned as a real value in the range [0, 1] (binary classification in this example).

keras predict_classes (docs) outputs A numpy array of class predictions. Which in your model case, the index of neuron of highest activation from your last(softmax) layer. [[0]] means that your model predicted that your test data is class 0. (usually you will be passing multiple image, and the result will look like [[0], [1], [1], [0]] )
You must convert your actual label (e.g. 'cancer', 'not cancer') into binary encoding (0 for 'cancer', 1 for 'not cancer') for binary classification. Then you will interpret your sequence output of [[0]] as having class label 'cancer'

That's because you're getting the numeric value associated with the class. For example if you have two classes cats and dogs, Keras will associate them numeric values 0 and 1. To get the mapping between your classes and their associated numeric value, you can use
>>> classes = train_generator.class_indices
>>> print(classes)
{'cats': 0, 'dogs': 1}
Now you know the mapping between your classes and indices. So now what you can do is
if classes[0][0] == 1:
prediction = 'dog'
else:
prediction = 'cat'

Forwarding the example by #ritiek, I'm a beginner in ML too, maybe this kind of formatting will help see the name instead of just class number.
images = np.vstack([x, y])
prediction = model.predict(images)
print(prediction)
i = 1
for things in prediction:
if(things == 0):
print('%d.It is cancer'%(i))
else:
print('%d.Not cancer'%(i))
i = i + 1

Related

Matrix size incompatible: ln[0] : [1:43264], ln[16,512]

I want to build a model that classifies and predicts words from the users lips. With adverb a total of 142657 images that have been preproccessed using the dataset of videos of individual speakers but I get this error when running the model and doesnt even get past the first epoch
heres my code
import os
from silence_tensorflow import silence_tensorflow
silence_tensorflow()
import tensorflow as tf
from tensorflow.keras.layers import Dense, Activation, Dropout, Input, Conv2D, \
MaxPooling2D, Flatten, BatchNormalization
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.image import ImageDataGenerator
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
tf.autograph.set_verbosity(0)
tf.get_logger().setLevel('ERROR')
class AdverbNet(object):
def __init__(self):
self.Model = Sequential()
self.build()
def build(self):
self.Model.add(Input(name='the_input', shape=(224, 224, 1), batch_size=16, dtype='float32'))
self.Model.add(Conv2D(32, (3, 3), activation='sigmoid', name='convo2'))
self.Model.add(MaxPooling2D(pool_size=(2, 2)))
self.Model.add(Conv2D(32, (3, 3), activation='sigmoid', name='convo3'))
self.Model.add(MaxPooling2D(pool_size=(2, 2)))
self.Model.add(Conv2D(64, (3, 3), activation='relu', name='convo4'))
self.Model.add(MaxPooling2D(pool_size=(2, 2)))
self.Model.add(Flatten())
self.Model.add(Dense(512))
self.Model.add(Dropout(0.5))
self.Model.add(BatchNormalization(scale=False))
self.Model.add(Activation('relu'))
self.Model.add(Dropout(0.5))
self.Model.add(Dense(4, activation='softmax'))
def summary(self):
self.Model.summary()
if __name__ == "__main__":
common_path = 'C:/Users/Loide/Desktop/Liphy/'
C = AdverbNet()
C.Model.compile(optimizer="Adam", loss='categorical_crossentropy', metrics=['accuracy'])
C.Model.summary()
with tf.device('/device:GPU:0')
batch_size = 16
epochs = 32
train_dir = common_path + 'Images/Adverb/'
test_dir = common_path + 'Images/Adverb/'
checkpoint_path = common_path + 'SavedModels/Adverb/'
train_image_generator = ImageDataGenerator(rescale=1. / 255) # Generator for training data generate training anD test set
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(224, 224),
class_mode='categorical',
color_mode='grayscale')
test_image_generator = ImageDataGenerator(rescale=1. / 255) # Generator for test data
test_data_gen = test_image_generator.flow_from_directory(batch_size=batch_size,
directory=test_dir,
shuffle=False,
target_size=(224, 224),
class_mode='categorical',
color_mode='grayscale')
callback = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',
patience=10,
restore_best_weights=True,
baseline=0.45)
history = C.Model.fit(train_data_gen,
steps_per_epoch=8916, # Number of images // Batch size
epochs=epochs,
verbose=1,
validation_data=test_data_gen,
validation_steps=187,
callbacks=[callback])
C.Model.save(checkpoint_path, save_format='tf')
**and I get the following error **
[Matrix size-incompatible: In[0]: [1,43264], In[1]: [16,512]
[[{{node gradient_tape/sequential/dense/MatMul/MatMul_1}}]] [Op:__inference_train_function_1179]
Seems like you have two matrices (one 1x43265 and one 16x512). You try to multiply them but its product is mathematically not defined. You need one matrix to be a (a x b) matrix and the other to be a (b x c) matrix. Thats why your program can't run. If your images are a test dataset try to follow the instructions step by step. If not, your preprocessing is probably bad.

Keras image classification prediction error on image resize

I have a trained model, which has been trained to recognize different documents, I got the dataset from http://www.cs.cmu.edu/~aharley/rvl-cdip/.
Below is how I built my model
import numpy as np
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import pickle
from keras.optimizers import SGD
from keras.models import Sequential, save_model
from keras.layers import Dense, Dropout, Flatten, Activation
from keras.layers.convolutional import Conv2D, MaxPooling2D
# Set image information
channels = 1
height = 1000
width = 754
model = Sequential()
# Add a Conv2D layer with 32 nodes to the model
model.add(Conv2D(32, (3, 3), input_shape=(1000, 754, 3)))
# Add the reLU activation function to the 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(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten()) # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('relu'))
model.compile(loss='categorical_crossentropy', # sparse_categorical_crossentropy
# Adam(lr=.0001) SGD variation with learning rate
optimizer='adam',
metrics=['accuracy'])
# Image data generator to import iamges from data folder
datagen = ImageDataGenerator()
# Flowing images from folders sorting by labels, and generates batches of images
train_it = datagen.flow_from_directory(
"data/train/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
test_it = datagen.flow_from_directory(
"data/test/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
val_it = datagen.flow_from_directory(
"data/validate/", batch_size=16, target_size=(height, width), shuffle=True, class_mode='categorical')
history = model.fit(
train_it,
epochs=2,
batch_size=16,
validation_data=val_it,
shuffle=True,
steps_per_epoch=2000 // 16,
validation_steps=800 // 16)
save_model(model, "./ComplexDocumentModel")
model.save("my_model", save_format='h5')
As in the last line, I saved my model in an h5 format.
I am trying now to use that trained model to predict on a single image, to see on which category it belongs with the below script.
from keras.models import load_model
import cv2
import numpy as np
import keras
from keras.preprocessing import image
model = load_model('my_model')
# First try
def prepare(file):
img_array = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (1000, 754))
return new_array.reshape(3, 1000, 754, 1)
# Second try
img = image.load_img(
"/home/user1/Desktop/Office/image-process/test/0000113760.tif")
img = image.img_to_array(img)
img = np.expand_dims(img, axis=-1)
prediction = model.predict(
[prepare("/home/user1/Desktop/Office/image-process/test/0000113760.tif")])
print(prediction)
I tried predicting the image in two ways, but both give the error
ValueError: Input 0 of layer sequential is incompatible with the layer: expected axis -1 of input shape to have value 3 but received input with shape (None, 762, 3, 1)
I have also tried opening the image with PIL and converting it to NumPy array, an approach found on google. Unfortunately no other answer, blog, or video tutorial that I found, helped me.
You are trying to feed a grayscale image to a network that expects an image with 3 channels. You can stack the last channel 3 times to have a compatible shape, but it is possible that the prediction will be poor:
def prepare(file):
img_array = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (1000, 754)) # shape is (1000,754)
# converting to RGB
array_color = cv2.cvtColor(new_array, cv2.COLOR_GRAY2RGB) # shape is (1000,754,3)
array_with_batch_dim = np.expand_dims(array_color, axis=0) # shape is (1,1000,754,3)
return array_with_batch_dim
Another solution is to not convert your image to grayscale when you read it, by omitting the flag cv2.IMREAD_GRAYSCALE. The default behaviour of opencv is to load an image with 3 channels.
def prepare(file):
img_array = cv2.imread(file)
new_array = cv2.resize(img_array, (1000, 754)) # shape is (1000,754, 3)
# converting to RGB
array_with_batch_dim = np.expand_dims(new_array, axis=0) # shape is (1,1000,754,3)
return array_with_batch_dim
Note: Depending on your preprocessing, you might need to normalize your image between 0 and 1 by dividing it by 255 before feeding it to the network.

How to check "test data" accuracy and plot them

I want to test the accuracy of 11000+ images.
I split the data into two classes ,"Yes" and "No". Then ,split them into 80/20 in training set and test set respectively.
Then I split,the training data again into 80/20 for validation set.
I create "Yes" and "No" folder for each one,validation set, test set, training set.And keep the data in respective folders.
Now, I want to train the model in Google Colab.
After train the model, I want to test the "Accuracy" of the "Test Data Set" and plot them with, specificity, sensitivity, accuracy, loss_Function and recall.
Help need for this. Detailed help will be more appreciated.
Thanks in advance.
#Yefet
Code is here:
import tensorflow as tf
import matplotlib.pyplot as plt
import zipfile
import cv2
import os
import numpy as np
import matplotlib.image as mpimg
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
from sklearn.model_selection import KFold, StratifiedKFold
img = image.load_img("drive/MyDrive/data03/train/no/1 no.jpeg" , target_size=(200, 200))
plt.imshow(img)
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self,epoch,logs={}):
if (logs.get('accuracy') > .98) & (logs.get('val_accuracy') > .9):
print("Reached 98% accuracy so cancelling training!")
self.model.stop_training = True
callbacks = myCallback()
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory(
'drive/MyDrive/data03/train', # This is the source directory for training images
target_size=(200, 200), # All images will be resized to 150x150
batch_size=128,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
validation_generator = train_datagen.flow_from_directory(
'drive/MyDrive/data03/validation', # This is the source directory for training images
target_size=(200, 200), # All images will be resized to 150x150
batch_size=128,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
from tensorflow.keras.optimizers import RMSprop
model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 150x150 with 3 bytes color
# This is the first convolution
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(200, 200, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
# The second convolution
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The third convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fourth convolution
#tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
#tf.keras.layers.MaxPooling2D(2,2),
# The fifth convolution
#tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
#tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=0.001),
metrics=['accuracy'])
history = model.fit(
train_generator,
steps_per_epoch=1,
epochs=29,
validation_data = validation_generator,callbacks=[callbacks])
dir_path = "drive/MyDrive/data03/test"
for i in os.listdir(dir_path):
img = image.load_img(dir_path+ '//' + i, target_size=(200, 200) )
plt.imshow(img)
plt.show()
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
images = np.vstack([x])
classes =model.predict(images)
if classes[0]==0:
print("NO TUMOR")
else:
print("YES ")

Categorize a not trained object as unknown object in machine learning using python

I'm new in machine learning. Currently I'm working on a fruit/vegetable classification project using deep learning with keras. I was able to train the model. So far, it can detect already trained objects correctly but when I'm providing an other fruit/vegetable which was not trained, its predicts from the trained model whereas, It should recognize it as unknown fruit.
Suppose, I trained a model with Apple, Potato and Banana images. As long as I provide the images of Apple/Potato/Banana its predicts correctly. But the moment I provide a image of an Orange, it predicts as an Potato or lemon predicts as an Apple. Here is the code snippet that I'm using to train & predicts fruits:
import os.path
import numpy as np
np.random.seed(123)
from keras import applications
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras.utils.np_utils import to_categorical
from keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from keras.layers.normalization import BatchNormalization
import matplotlib.pyplot as plt
import math
import cv2
#dimensions of images
img_width, img_height = 224, 224
#file paths & directories
top_model_weights_path = 'bottleneck_fc_model.h5'
bottleneck_train_path = 'bottleneck_features_train.npy'
bottleneck_validation_path = 'bottleneck_features_validation.npy'
train_data_dir = 'data/train'
validation_data_dir = 'data/validation/'
#hyperparameters
epochs = 10
batch_size = 16
def save_bottleneck_features():
model = applications.VGG16(include_top=False, weights='imagenet')
datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
generator = datagen.flow_from_directory(train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
shuffle=False)
no_train_samples = len(generator.filenames)
predict_size_train = int(math.ceil(no_train_samples / batch_size))
bottleneck_features_train = model.predict_generator(generator, predict_size_train)
np.save(bottleneck_train_path, bottleneck_features_train)
datagen = ImageDataGenerator(rescale=1./255)
generator = datagen.flow_from_directory(validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
no_validation_samples = len(generator.filenames)
predict_size_validation = int(math.ceil(no_validation_samples / batch_size))
bottleneck_features_validation = model.predict_generator(generator, predict_size_validation)
np.save(bottleneck_validation_path, bottleneck_features_validation)
def train_top_model():
datagen_top = ImageDataGenerator(rescale=1./255)
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)
num_classes = len(generator_top.class_indices)
# save the class indices to use later in predictions
np.save('class_indices.npy', generator_top.class_indices)
# get the class labels for the training data, in the original order
train_labels = generator_top.classes
# 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)
validation_labels = generator_top.classes
validation_labels = to_categorical(validation_labels, num_classes=num_classes)
# load the bottleneck features saved earlier
train_data = np.load('bottleneck_features_train.npy')
validation_data = np.load('bottleneck_features_validation.npy')
# build the model
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(BatchNormalization())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_data, train_labels, epochs=epochs, batch_size=batch_size)
model.save_weights(top_model_weights_path)
def predict(image_path):
class_dictionary = np.load('class_indices.npy').item()
#print("Values: ",class_dictionary)
num_classes = len(class_dictionary)
orig = cv2.imread(image_path)
print('[INFO] loading and preprocessing image...')
image = load_img(image_path, target_size=(224, 224))
image = img_to_array(image)
image = image / 255
image = np.expand_dims(image, axis=0)
model = applications.VGG16(include_top=False, weights='imagenet')
bottleneck_prediction = model.predict(image)
# build top model
model = Sequential()
model.add(Flatten(input_shape=bottleneck_prediction.shape[1:]))
model.add(BatchNormalization())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='sigmoid'))
model.load_weights(top_model_weights_path)
# use the bottleneck prediction on the top model to get the final classification
class_predicted = model.predict_classes(bottleneck_prediction)
probabilities = model.predict_proba(bottleneck_prediction)
inID = class_predicted[0]
inv_map = {v: k for k, v in class_dictionary.items()}
label = inv_map[inID]
print("Image ID: {}, Label: {}".format(inID, label))
cv2.putText(orig, "Predicted: {}".format(label), (10, 30),
cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 0, 0), 2)
cv2.imshow('Classification', orig)
cv2.imwrite('predicted.jpg', orig)
cv2.waitKey(0)
if __name__ == '__main__':
if not os.path.exists(bottleneck_train_path):
save_bottleneck_features()
if not os.path.exists(top_model_weights_path):
train_top_model()
image_path = 'fruits/orange.jpg'
predict(image_path)
How to overcome this situation? Any help will be appreciated.
When training with loss='categorical_crossentropy' , and activation='softmax' at the last layer, each class is represented by 1 node in the graph at the last layer. softmax ensures the value of all the nodes is summed to 1, by normalizing all the values.
categorial crossentropy assumes the node with the highest value is the predicted class, and compares it with the labels.
For example, after predicting a sample you might can have the following values for nodes: 0.33 banana, 0.33 apple, 0.34 potato , thus potato will be the class selected for the prediction.
If you wish to have an 'unknown class' prediction, you should add it as another possible class, and have some samples labeled as unknown class during training.
Edit:
Note that while what i suggested above can work for you, training it can be very difficulty, as it might require a larger number of samples, both known and unkown, as the 'unkown' features are harder to generalize, and might damage the other classes generalization.
A more practical way would be to define a threshold, as i mentioned earlier, after predicting you recieve some value for each one of the possible labels. When picking the label, this value is the 'confidence' score of the label.
Examining the example above, we will pick potato with 0.34 confidence.
You could define some threshold, say 0.6, and when assuming the label for the image, check the different confidence score, if the highest (the 'chosen') label is lower then the threshold, you can mark it as 'unknown fruit'.
Another Edit
Several good works on the subject as come up since that question, for future reference, this:
https://github.com/hendrycks/outlier-exposure
would be a good place to start.

My CNN model predicts only the first class no matter what image I put

I am beginner in Machine Learning and followed a template in one of the ML courses to train images of Cats and Dogs to classify them.
If I load an image to be predicted in my model, no matter what, the prediction comes to be the first class I have defined in the list platetype at the end.
I am doing this to classify other type of images however I was getting the same error to that dataset so I thought of using the classic cats and dogs dataset.
I want to predict that if the image of text I give to the trained model has a fancy text or a standard text font.
Here is my code.
#create classifier
classifier = Sequential()
#adding convolution layer
classifier.add(Convolution2D(32, 3, 3, input_shape = (64, 64, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2,2), strides = (2,2)))
classifier.add(Convolution2D(32, 3, 3, activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2,2), strides = (2,2)))
classifier.add(Flatten())
classifier.add(Dense(output_dim = 128, activation = 'relu'))
classifier.add(Dense(output_dim = 1, activation = 'sigmoid'))
# In[54]:
#compiling
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# In[55]:
#making Image size same
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(
'D:/Third Year/kaggle/cats/New Data/Convolutional_Neural_Networks/dataset/training_set',
target_size=(64, 64),
batch_size=32,
class_mode='binary')
test_set = test_datagen.flow_from_directory(
'D:/Third Year/kaggle/cats/New Data/Convolutional_Neural_Networks/dataset/test_set',
target_size=(64, 64),
batch_size=32,
class_mode='binary')
print('TRAINING:',training_set)
print('TEST: ',test_set)
# In[56]:
#checking if already a weight file exists. if it does loads it into the model
if os.path.isfile("modelCNN_CD.h5") :
classifier.load_weights("modelCNN_CD.h5")
#checkpoint saves the model.
filepath="modelCNN_CD.h5"
checkpoint1 = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
classifier.summary()
classifier.fit_generator(
training_set,
steps_per_epoch=8000,
epochs=25,
validation_data=test_set,
validation_steps=2000,callbacks=[checkpoint1,])
# In[67]:
# load the model
#model = VGG16()
# load an image from file
image = load_img('D:/Third Year/kaggle/cats/New Data/Convolutional_Neural_Networks/dog.4029.jpg', target_size=(64, 64))
# convert the image pixels to a numpy array
image = img_to_array(image)
# reshape data for the model
image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
yhat = classifier.predict(image)
print(yhat)
import numpy as np
print(platetype[np.argmax(yhat)])
# In[57]:
platetype = ['Cat','Dog']
# In[9]:
from keras.models import load_model
classifier = load_model('modelCNN_LP.h5')
Is your predictor always returning 0 as the class?
The reason why I ask is that I was having the same problem and the issue is with "platetype[np.argmax(yhat)]" and the fact you are using binary class mode classification.
argmax would be returning the index position of the result but as you are using binary classes and in your final layer you have 1 dense. It will only return a single value so it will always return the first class (0 as the index position). As the network is only set, to return one class.
There are 2 solutions and it depends which you prefer:
Is to change the class_mode to 'categorical' for the train and test generators, change the final dense layer from 1 to 2 so this will return scores/probabilities for both classes. So when you use argmax, it will return the index position of the top score indicating which class it has predicted.
The other way would be to stick with what you have got but you would have to change how to determine the class. You would use the score so yhat will be a list. You would need to access the score and based on that determine which class the model has predicted. Maybe someone can clarify this as I have not use this method and I am not sure.
Hope this helps!. I had the same issue as you and this fixed it for me (I went with option 1).
Let me know if it worked for you.
It seems that the reason why your model is unable to make an accurate prediction of your new image is because you forgot to rescale it.
You used ImageDataGenerator() during training with a rescaling factor of 1./255.
Just add :
...
image = load_img('D:/Third Year/kaggle/cats/New Data/Convolutional_Neural_Networks/dog.4029.jpg', target_size=(64, 64))
image = img_to_array(image)
image = image/255.  # Add this line
image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
yhat = classifier.predict(image)
...
and it should work.

Categories