0

I am trying transfer learning via tensorflow.keras but someting is not working out. The training is showing a nice curves (Training Loss and Validation loss nicely droping ,validation_accuracy increases to 90%). So far all good. My issue is that testing a single image results in a totally different class being selected. What am I doing wrong? My guess it is in the preprocessing of the single image. But perhaps that is a wrong assumption, and is my trained VGG16 totally bad...

Thanks Michiel. Code below

import tensorflow as tf    
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.layers import Dense, Conv2D, MaxPool2D , Flatten
from tensorflow.keras.applications.vgg16 import preprocess_input
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Model
from tensorflow.keras import optimizers

tsdata = ImageDataGenerator(preprocessing_function=preprocess_input)
testdata = tsdata.flow_from_directory(directory=test_dir, target_size=(224,224),batch_size=64,shuffle=True)


trdata = ImageDataGenerator(horizontal_flip=True,vertical_flip=True,zoom_range=0.2,rotation_range=30,preprocessing_function=preprocess_input)
traindata = trdata.flow_from_directory(directory=train_dir,target_size=(224,224),batch_size=64,shuffle=True)

from tensorflow.keras.applications.vgg16 import VGG16
vggmodel = VGG16(weights='imagenet', include_top=True)

for layers in (vggmodel.layers)[:19]:
    print(layers)
    layers.trainable = False
    Dropout=0.2
X= vggmodel.layers[-2].output
predictions = Dense(102, activation="softmax")(X)
model_final = Model(vggmodel.input, predictions)


model_final.compile(loss = "categorical_crossentropy", optimizer = optimizers.SGD(learning_rate=0.001, momentum=0.9), metrics=["accuracy"])


checkpoint = ModelCheckpoint(vgg16_1.h5", monitor='val_accuracy', verbose=1, save_best_only=True,save_weights_only=False, mode='auto', save_freq="epoch")

early = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=40, verbose=1, mode='auto')
history=model_final.fit(traindata, steps_per_epoch= 2, epochs= 100, validation_data= testdata, validation_steps=1, callbacks=[checkpoint,early])
model_final.save("vgg16_1.h5")



import matplotlib.pyplot as plt
plt.plot(history.history["accuracy"])
plt.plot(history.history['val_accuracy'])
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title("model accuracy")
plt.ylabel("Accuracy")
plt.xlabel("Epoch")
plt.legend(["Accuracy","Validation Accuracy","loss","Validation Loss"])
plt.show()

image_path= path_to_image\image_06734.jpg"
image = tf.keras.preprocessing.image.load_img(image_path,target_size=(224,224))
input_arr = tf.keras.preprocessing.image.img_to_array(image)
input_arr = np.array([input_arr])  # Convert single image to a batch.
predictions = model_reload.predict(input_arr)
print(predictions)
print(np.argmax((predictions), axis=1))

'''

1 Answers1

0

Yes. The fundamental idea to predict an image is that you must process the image in the exact manner in which you processed the training image. For example if you pre processed your training images you must also preprocess the image to predict. The image must be of the same size and have the same number of color channel in the same order (Example RGB or BGR). model.predict expects a 4 dinnemsional input of the form (batch_size, image_shape) so for a single image you have to expand the dimensions using np.expand_dims. The code below will predict the image or images that reside in a directory sdir.

import numpy as np
import os
import cv2
import tensorflow as tf
from tensorflow.keras.models import Model, load_model
from tensorflow.keras.applications.vgg16 import preprocess_input

def predictions (sdir, model_path, img_shape, class_list): 
    model=load_model(model_path)
    print ('Model is loaded')
    img_list=[]
    flist=sorted(os.listdir(sdir)) # get list of files in sdir
    length=len(flist)    
    for i, f in enumerate(flist):  #iterate through the list of files
        fpath=os.path.join(sdir,f) # path to the image file
        img=cv2.imread(fpath) # read in the image - remember cv2 reads images as BGR
        img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # convert image to RGB  
        img=cv2.resize(img, (img_shape[0], img_shape[1])) # resize the image 
        img_list.append(img)
        img=preprocess_input(img) # preprocess the image        
    img_array=np.array(img_list)# create the img_array
    preds=model.predict (img_array, verbose=1) 
    print('{0:^30s}{1:^30s}{2:^10s}'.format('FILE NAME', 'PREDICTED CLASS', 'Probability'))
    for i,p in enumerate (preds):
        class_index=np.argmax(p)
        pred_class=class_list[class_index]
        prob= p[class_index] * 100
        print (f'{flist[i]:^30s}{pred_class:^30s}{prob:^10.2f}')


# example of use        
sdir=r'C:\Temp\people\special test' # directory holding images to predict
model_path=r'C:\Temp\people\character-97.00.h5' # path to saved mdel
img_shape=(150,150,3) # image shape the model was trained on
class_list = ['savory', 'unsavory'] # ordered list of classes get from classes = train_ds.class_names 
predictions (sdir, model_path, img_shape, class_list)

Gerry P
  • 7,662
  • 3
  • 10
  • 20
  • regarding -1 +1: I do not know since preprocessing gives between -123 and +150. (mean=+12) x = np.random.randint(0,255, (10,224,224,3)) datagen = ImageDataGenerator(preprocessing_function=preprocess_input) for x_i in datagen.flow(x, batch_size = 5): print(np.min(x_i)) print(np.mean(x_i)) print(np.max(x_i)) break – Michiel2019 Aug 22 '22 at 06:59
  • I stand corrected the new VGG16 does this Note: each Keras Application expects a specific kind of input preprocessing. For VGG16, call tf.keras.applications.vgg16.preprocess_input on your inputs before passing them to the model. vgg16.preprocess_input will convert the input images from RGB to BGR, then will zero-center each color channel with respect to the ImageNet dataset, without scaling. The old VGG used to scale the images between -1 to +1 – Gerry P Aug 22 '22 at 08:06
  • gerry: Do you know how i can prepare the input for my predictor so starting from a single jpg/png and put it into my trained vgg16. I am really stuck here – Michiel2019 Aug 22 '22 at 10:41