50

I'm only beginning with keras and machine learning in general.

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]]?

Thanks in advance.

Løiten
  • 2,907
  • 3
  • 17
  • 32
ritiek
  • 1,654
  • 2
  • 14
  • 21
  • 4
    Using `model.compile()` is not necessary if you used `model.save()`. https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model – Borealis Apr 22 '18 at 01:20

5 Answers5

35

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]
ritiek
  • 1,654
  • 2
  • 14
  • 21
  • 2
    I get a message: 'Model' object has no attribute 'predict_classes'. Use **predict** method instead. – Serġan Dec 19 '17 at 17:18
  • 1
    Thanks for this. This worked for me but I have a few questions. 1. What is the `y = np.expand_dims(y, axis=0)` line doing in this? And perhaps more in depth, I am able to classify towards a 0 or 1 in this binary approach...but i don't where/how binary classified result is set up (meaning I can tell that 1 is for dogs and 0 is for not dogs, but why is it that way and not 1 for cats and 0 for not cats?). Hopefully this makes some intuitive sense as a question. – Rivers31334 Feb 20 '18 at 01:18
  • 1
    hi,after using your code, it says , [[1]] [[1] [1]] [1] 1 how to convert it to result – James Aug 07 '18 at 12:20
  • Did you mean print(classes)? :) – hesam rajaei Feb 05 '20 at 13:12
  • How to predict for one class? – Chandni Soni Mar 12 '20 at 07:50
  • I think you are missing x /= 255. – Juan Zamora Apr 20 '20 at 06:01
  • why `batch_size=10` is required in the prediction – alex3465 Apr 23 '21 at 10:59
20

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).

auraham
  • 1,589
  • 2
  • 18
  • 27
19

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'

DNK
  • 1,248
  • 1
  • 13
  • 12
  • I tried running the model on images from both my classes but they all return `[[0]]`. Also how can I pass multiple images at once in `model.predict_classes()`? – ritiek Apr 18 '17 at 16:17
  • Nevermind. Reading some examples on the internet, now I am able to predict classes into `[[0]]` and `[[1]]` correctly but still trying to figure out a way to pass multiple images at once. – ritiek Apr 18 '17 at 18:35
  • 1
    in `img = np.reshape(img,[1,320,240,3])` you actually make var `img` into an array of 1 320x240 image. So to pass multiple images you will need array, something like this: `images = [] for image_name in image_list: img = cv2.imread(image_name) img = cv2.resize(img,(320,240)) images.append(img) images = np.asarray(images)` then pass images to `model.predict_classes` – DNK Apr 19 '17 at 02:14
  • to pass multiple images you will need *list, and then convert it into numpy array. sorry – DNK Apr 19 '17 at 02:25
  • I seem to get it now. Thanks! – ritiek Apr 20 '17 at 11:49
  • @Ritiek I am facing a similar issue, I consistently get [[1]] regardless of what test images I tried, what was your solution? – mkto May 04 '17 at 07:15
  • @mkto I am not entirely sure but I think I was loading the images incorrectly.. It worked when I used the in-built `load_img` and `img_to_array` functions in keras. I added my own solution. Check the other answer to this question by me. – ritiek May 04 '17 at 07:25
  • @ritiek I am having the same problem of classifying all the images to the same category. How did you fix it? – Preetom Saha Arko Dec 23 '17 at 03:47
  • @PreetomSahaArko Here is the full code https://github.com/ritiek/deep-learning-practise/blob/master/keras/image_prediction.ipynb but it might be out of date now. – ritiek Dec 24 '17 at 15:12
  • 1
    @DNK how would I convert my labels (cat, dog, not cat, not dog) into binary encoding? – Ryan Fasching Jul 18 '18 at 23:11
14

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'

Javapocalypse
  • 1,725
  • 14
  • 21
1

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
Vineeth Sai
  • 3,113
  • 7
  • 19
  • 28