简体   繁体   中英

How to use .predict_generator() on new Images - Keras

I've used ImageDataGenerator and flow_from_directory for training and validation.

These are my directories:

train_dir = Path('D:/Datasets/Trell/images/new_images/training')
test_dir = Path('D:/Datasets/Trell/images/new_images/validation')
pred_dir = Path('D:/Datasets/Trell/images/new_images/testing')

ImageGenerator Code:

img_width, img_height = 28, 28
batch_size=32
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_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
    test_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='categorical')

Found 1852 images belonging to 4 classes

Found 115 images belonging to 4 classes

This is my model training code:

history = cnn.fit_generator(
        train_generator,
        steps_per_epoch=1852 // batch_size,
        epochs=20,
        validation_data=validation_generator,
        validation_steps=115 // batch_size)

Now I have some new images in a test folder (all images are inside the same folder only), on which I want to predict. But when I use .predict_generator I get:

Found 0 images belonging to 0 class

So I tried these solutions:

1) Keras: How to use predict_generator with ImageDataGenerator? This didn't work out, because its trying on validation set only.

2) How to predict the new image by using model.predict? module image not found

3) How to get predictions with predict_generator on streaming test data in Keras? This also didn't work out.

My train data is basically stored in 4 separate folders, ie 4 specific classes, validation also stored in same way and works out pretty well.

So in my test folder I have around 300 images, on which I want to predict and make a dataframe, like this:

image_name    class
gghh.jpg       1
rrtq.png       2
1113.jpg       1
44rf.jpg       4
tyug.png       1
ssgh.jpg       3

I have also used this following code:

img = image.load_img(pred_dir, target_size=(28, 28))
img_tensor = image.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, axis=0)
img_tensor /= 255.

cnn.predict(img_tensor)

But I get this error: [Errno 13] Permission denied: 'D:\\\\Datasets\\\\Trell\\\\images\\\\new_images\\\\testing'

But I haven't been able to predict_generator on my test images. So how can I predict on my new images using Keras. I have googled a lot, searched on Kaggle Kernels also but haven't been able to get a solution.

So first of all the test images should be placed inside a separate folder inside the test folder. So in my case I made another folder inside test folder and named it all_classes . Then ran the following code:

test_generator = test_datagen.flow_from_directory(
    directory=pred_dir,
    target_size=(28, 28),
    color_mode="rgb",
    batch_size=32,
    class_mode=None,
    shuffle=False
)

The above code gives me an output:

Found 306 images belonging to 1 class

And most importantly you've to write the following code:

test_generator.reset()

else weird outputs will come. Then using the .predict_generator() function:

pred=cnn.predict_generator(test_generator,verbose=1,steps=306/batch_size)

Running the above code will give output in probabilities so at first I need to convert them to class number. In my case it was 4 classes, so class numbers were 0,1,2 and 3.

Code written:

predicted_class_indices=np.argmax(pred,axis=1)

Next step is I want the name of the classes:

labels = (train_generator.class_indices)
labels = dict((v,k) for k,v in labels.items())
predictions = [labels[k] for k in predicted_class_indices]

Where by class numbers will be replaced by the class names. One final step if you want to save it to a csv file, arrange it in a dataframe with the image names appended with the class predicted.

filenames=test_generator.filenames
results=pd.DataFrame({"Filename":filenames,
                      "Predictions":predictions})

Display your dataframe. Everything is done now. You get all the predicted class for your images.

I had some trouble with predict_generator() . Some posts here helped a lot. I post my solution here as well and hope it will help others. What I do:

  • Make predictions on new images using predict_generator()
  • Get filename for each prediction
  • Store results in a data frame

I make binary predictions à la "cats and dogs" as documented here . However, the logic can be generalised to multiclass cases. In this case the outcome of the prediction has one column per class.

First, I load my stored model and set up the data generator:

import numpy as np
import pandas as pd
from keras.preprocessing.image import ImageDataGenerator
from keras.models import load_model

# Load model
model = load_model('my_model_01.hdf5')

test_datagen = ImageDataGenerator(rescale=1./255)
test_generator = test_datagen.flow_from_directory(
        "C:/kerasimages/pred/",
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary',
        shuffle=False)

Note: it is important to specify shuffle=False in order to preserve the order of filenames and predictions.

Images are stored in C:/kerasimages/pred/images/ . The data generator will only look for images in subfolders of C:/kerasimages/pred/ (as specified in test_generator ). It is important to respect the logic of the data generator, so the subfolder /images/ is required. Each subfolder in C:/kerasimages/pred/ is interpreted as one class by the generator. Here, the generator will report Found x images belonging to 1 classes (since there is only one subfolder). If we make predictions, classes (as detected by the generator) are not relevant.

Now, I can make predictions using the generator:

# Predict from generator (returns probabilities)
pred=model.predict_generator(test_generator, steps=len(test_generator), verbose=1)

Resetting the generator is not required in this case, but if a generator has been set up before, it may be necessary to rest it using test_generator.reset() .

Next I round probabilities to get classes and I retrieve filenames:

# Get classes by np.round
cl = np.round(pred)
# Get filenames (set shuffle=false in generator is important)
filenames=test_generator.filenames

Finally, results can be stored in a data frame:

# Data frame
results=pd.DataFrame({"file":filenames,"pr":pred[:,0], "class":cl[:,0]})

The most probably you are making a mistake using flow_from_directory . Reading the docs:

flow_from_directory(directory, ...)

Where:

directory: Path to the target directory. It should contain one subdirectory per class. Any PNG, JPG, BMP, PPM or TIF images inside each of the subdirectories directory tree will be included in the generator.

That means that inside the directory that you are passing to this function, you have to create subdirectories and place your images inside this subdirectories. Otherwise, when the images are in the directory that you are passing (not subdirectories), indeed there are 0 images and 0 classes.

EDIT

Okay so in case of the prediction you want to perform I believe that you want to use the predict function as follows: (note that you have to provide data to the network just in the same format as you did during learning process)

image = img_to_array(load_img(f"{directory}/{foldername}/{filename}"))
# here you prepare the input data, for example here we take the gray image
# gray scale is the 1st channel in the Lab color space
color_me = rgb2lab((1.0 / 255) * color_me)[:, :, 0]
color_me = color_me.reshape(color_me.shape + (1,))
# here data is in the format which is accepted by, in this case, my model
# for your model you have to do the preparation just the same as in the case of learning process
output = model.predict(np.array([color_me]))
# and here you have your predicted output

I strongly recommend you to make a parent folder in the test folder. Then move the test folder to the parent folder.

means if you have test folder in this manner:

/root/test/img1.png
/root/test/img2.png
/root/test/img3.png
/root/test/img4.png

this wrong way to use predict_generator. Update your test folder like this:

/root/test_parent/test/img1.png
/root/test_parent/test/img2.png
/root/test_parent/test/img3.png
/root/test_parent/test/img4.png

Use this command to update:

mv /root/test/ ./root/test_parent/test 

And, also don't forget to give a path to the model like this

"/root/test_parent/"

This method is work for me.

As per Keras documenation cited below, predict_generator is deprecated. Model.predict now supports generators, so there is no longer any need to use the predict_generator endpoint.

Keras documentation, Refernce: https://www.tensorflow.org/api_docs/python/tf/keras/Model#predict_generator

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM