Image Classification using keras predict same output for different classes - python

I have problem with my image classification model using keras.
This is the code which have binary class.
tried to set the number of images in datasets as equal.
this is a code for Keras model
train_data_dir = 'path'
validation_data_dir = 'path'
nb_train_samples = 2000
nb_validation_samples = 800
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'])
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')
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.load_weights('second_try.h5')
and the model saved well.
so I run the test code
from keras.models import load_model
from keras.preprocessing import image
import numpy as np
# dimensions of our images
img_width, img_height = 150, 150
# load the model we saved
model = load_model('modelpath')
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
#predicting multiple images at once
img = image.load_img('imgpath', target_size=(img_width, img_height))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
y = image.img_to_array(img)
y = np.expand_dims(y, axis=0)
images = np.vstack([x, y])
classes = model.predict_classes(images, batch_size=10)
print(classes)
and both images from different classes are printed as 1.
Why does this happening?

You should be saving the model or model weights after your training, rather than doing load_weights after fit(). So, 2 ways to do this
After model.fit(), do model.save_weights('second_try.hdf5') which only saves weights. To load the weights, you should first compile your model, and then call load_weights on the model as model.load_weights('second_try.hdf5')
After model.fit(), do model.save('model.hdf5') which saves the weights and the model structure to a single HDF5 file. Then you can use that HDF5 file with load() to reconstruct the whole model, including weights.
model = load_model('model.hdf5')
Also, do check if your test data is being prepared correctly. As your training loop uses a generator to prepare the data, you should use a similar generator for preparing the test data as well.

Related

image classifer with multiple categories

hiya i followed a guide on how to make an image classifier from here https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html and this categorizes it into only 2 categories these code gives me the F1 score and confusion matrix is there a way to make a multiple category image classifier using these codes my data sets right now are types of mushroom
import numpy
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
import matplotlib.pyplot as plt
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = r'C:\Users\Acer\imagerec\Mushrooms\TRAIN'
validation_data_dir = r'C:\Users\Acer\imagerec\Mushrooms\VAL'
nb_train_samples = 7025
nb_validation_samples = 6262
epochs = 50
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')
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
import seaborn as sns
test_steps_per_epoch = numpy.math.ceil(validation_generator.samples / validation_generator.batch_size)
predictions = model.predict_generator(validation_generator, steps=test_steps_per_epoch)
# Get most likely class
predicted_classes = numpy.argmax(predictions, axis=1)
true_classes = validation_generator.classes
class_labels = list(validation_generator.class_indices.keys())
report = classification_report(true_classes, predicted_classes, target_names=class_labels)
print(report)
cm=confusion_matrix(true_classes,predicted_classes)
sns.heatmap(cm, annot=True)
print(cm)
plt.show()
You clearly defined a binary classification in your code. To turn it to a multi-class task, let's say to N class, you need to change your last layer from 1 Dense to N Dense, and for the activation, you should change it from sigmoid to softmax.
Last but not least, you should change your loss function from binary_crossentropy to categorical_crossentropy if your classes are already hot-encoded. Otherwise, you might want to go with sparse_categorical_crossentropy
That part of your code should seems something like this after applying the changes:
model.add(Dense(N))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
Where N is the number of different classes you have.
Edit: you also need to go from "binary" to "categorical" for class_mode in your generators. You should also check how to generate the labels (one-hot-encoded)

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?

How to predict input probability of image using trained model in Keras?

I'm beginning ML and have come to a huge road bump, looked at this thing for hours. I want to get the predict() probability as output but the predictions are only outputting [[1.]] for every test image. Using larger numbers of training data and more epochs, the acc and validation acc are up to about 90% each. This is only binary classification but I don't want predict_classes. I have no idea why it's printing [[1.]]
Here is the code I'm using:
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
img_width, img_height = 150, 150
train_data_dir = 'D:\Machine_Learning\\train'
validation_data_dir = 'D:\Machine_Learning\\test'
nb_train_samples = 20000
nb_validation_samples = 7000
epochs = 50
batch_size = 40
if K.image_data_format() == 'channels_first':
input_shape = (3, img_width, img_height)
else:
input_shape = (img_width, img_height, 3)
# Build model structure
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='adam',
metrics=['accuracy'])
# Image augmentation
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')
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('first_try.h5')
model.save_weights('my_weights.model')
And for predictions:
from keras.models import load_model
from keras.preprocessing import image
model = load_model('first_try.h5')
def prepare(image):
imageSize = 150
#imageArray = cv2.imread(filePath)
newImageArray = cv2.resize(image, (imageSize, imageSize))
return newImageArray.reshape(-1, imageSize, imageSize, 3)
for i in range(len(test_images)):
print(test_images[i])
im = prepare(test_images[i])
prediction = model.predict([im])
print(prediction)

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)

Why my prediction result is very bad comparing with the accuracy

I write a code for image classification(2 categories, 'good'&'bad') in python using Keras, the accuracy on training data is about 99%, and on validation data is about 95%. (the image is 60 times 30 pixels grayscale png file)
img_width, img_height = 60, 30
nb_train_samples = 4000
nb_validation_samples = 600
epochs = 30
batch_size = 32
if K.image_data_format() == 'channels_first':
input_shape = (1, img_width, img_height)
else:
input_shape = (img_width, img_height, 1)
model = Sequential()
model.add(Conv2D(16, (3, 3), input_shape=input_shape,padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3),padding='same'))
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=['binary_accuracy'])
train_datagen = ImageDataGenerator(rescale= 1. /255)
validation_datagen = ImageDataGenerator(rescale= 1. /255)
train_generator = train_datagen.flow_from_directory(
'/home/admin/Desktop/dataset/train',
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary',
color_mode='grayscale')
validation_generator = validation_datagen.flow_from_directory(
'/home/admin/Desktop/dataset/validation',
target_size=(img_width, img_height),
batch_size= batch_size,
class_mode='binary',
color_mode='grayscale')
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('test_weights.h5')
now I want to make prediction for all the 600 images in validation directory, using this code.
path='/home/admin/Desktop/dataset/validation/good'
for file in os.listdir(path):
im=cv2.imread(os.path.join(path,file))
im=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
im=np.reshape(im,[1, img_width,img_height,1])*(1. /255)
result=model.predict_classes(im)
However, the result for 300 images in 'bad' directory is 9[1] with 291[0], and for 300 images in 'good' directory is 42[1] with 258[0], this is obviously wrong.
I think my way for data processing is different from ImageDataGenerator and flow_from_directory, which leads to the bug, but I'm not sure.
********update********
When I use the following code, the result is correct
predict_data=ImageDataGenerator(rescale=1. / 255).flow_from_directory(
'/home/admin/Desktop/dataset/validation/good',
target_size=(img_width, img_height),
batch_size= 300,
class_mode=None,
color_mode='grayscale')
result=model.predict_generator(
predict_data,
steps=1)
But I still don't know where the bug is.

Categories