Tensorflow 2 Image Batch Prediction Return Results

Viewed 569

I have an already trained model and I want to make binary classification predictions on images in a directory. I have over 100,000 images so for efficiency, I want to do batch predictions. How can I do batch predictions on my images, get the prediction results, and store the images in two separate folders after they have been predicted on based on the class?

This is what my code looks like so far...

model_filepath = r"C:\Users\model_200.h5"
model = tf.keras.models.load_model(model_filepath)

test_dir = r"C:\Users\image_testing_folder"

batch_size = 64
IMG_HEIGHT = 200
IMG_WIDTH = 200

test_image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
test_image_gen = test_image_generator.flow_from_directory(directory=str(test_dir),
                                                         batch_size=batch_size,
                                                         shuffle=False,
                                                         target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                         )

predictions = (model.predict(test_image_gen) > 0.5).astype("int32")
predictions

One solution would be to tie the prediction with an image filepath, then use shutil.move() to move original image to a destination folder. How would I do this? Is there a better way to do batch predictions than using an ImageDataGenerator and .flow_from_directory?

1 Answers

You can do a custom dataset so you can also easily retrieve the filename:

import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras import Sequential
from glob2 import glob
from shutil import copy
import numpy as np

files = glob('group1\\*\\*.jpg')

imsize = 64

def load(file_path):
    img = tf.io.read_file(file_path)
    img = tf.image.decode_png(img, channels=3)
    img = tf.image.convert_image_dtype(img, tf.float32)
    img = tf.image.resize(img, size=(imsize, imsize))
    return img, file_path

ds = tf.data.Dataset.from_tensor_slices(files).\
    take(100).\
    shuffle(100).\
    map(load).batch(4)

model = Sequential()
model.add(Conv2D(8, (3, 3), input_shape=(imsize, imsize, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(units=32, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=2, activation='sigmoid'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

model.build(input_shape=(imsize, imsize, 3))

categories = np.array(['cats', 'dogs'])

target_dir = 'newpics'

for cat in categories:
    os.makedirs(os.path.join(target_dir, cat), exist_ok=True)

for images, filenames in ds:
    preds = model(images)
    targets = categories[np.argmax(preds, axis=1)]
    for file, destination in zip(filenames, targets):
        copy(file.numpy().decode(), os.path.join(target_dir, destination,
                                os.path.basename(file.numpy().decode())
                                ))
        print(file.numpy().decode(), '-->', os.path.join(target_dir, destination,
                                os.path.basename(file.numpy().decode())
                                ))
group1\cats\cat.4051.jpg --> newpics\cats\cat.4051.jpg
group1\cats\cat.4091.jpg --> newpics\dogs\cat.4091.jpg
group1\cats\cat.4055.jpg --> newpics\cats\cat.4055.jpg
group1\cats\cat.4041.jpg --> newpics\cats\cat.4041.jpg
group1\cats\cat.4090.jpg --> newpics\cats\cat.4090.jpg
group1\cats\cat.4071.jpg --> newpics\dogs\cat.4071.jpg
group1\cats\cat.4082.jpg --> newpics\cats\cat.4082.jpg
group1\cats\cat.4037.jpg --> newpics\cats\cat.4037.jpg
group1\cats\cat.4005.jpg --> newpics\cats\cat.4005.jpg

All you have to change is the glob pattern and folders.

Related