Model.Predict is returning same values when using TF Keras ImageDataGenerator

Viewed 535

I am using Cat and Dog Dataset for Training a Model using Tensorflow Keras and the Files are Read using ImageDataGenerator.flow_from_directory.

Training and Validation Accuracy is Decent but when tried Predicting on Test Data, Model is predicting the Same Class for all the Images.

Code for Training is shown below:

import os, shutil
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dropout, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.losses import binary_crossentropy
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np
import matplotlib.pyplot as plt

# Path to Training Directory
train_dir = 'Dogs_Vs_Cats_Small/train'

# Path to Validation Directory
validation_dir = 'Dogs_Vs_Cats_Small/validation'

#### Create the Convolutional Base

Max_Pool_Size = (2,2)
model = Sequential([
    Conv2D(input_shape = (150, 150, 3), filters = 32, kernel_size = (3,3), activation = 'relu', 
           padding = 'valid', data_format = 'channels_last'),
    MaxPooling2D(pool_size = Max_Pool_Size),
    Conv2D(filters = 64, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
    MaxPooling2D(pool_size = Max_Pool_Size),
    Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
    MaxPooling2D(pool_size = Max_Pool_Size),
    Conv2D(filters = 128, kernel_size = (3,3), activation = 'relu', padding = 'valid'),
    MaxPooling2D(pool_size = Max_Pool_Size)
])


#### Define the Dense Layers on Top of Convolutional Base

model.add(Flatten())
model.add(Dense(units = 512, activation = 'relu'))
model.add(Dense(units = 1, activation = 'sigmoid'))
model.summary()

model.compile(optimizer = RMSprop(learning_rate = 0.001), loss = 'binary_crossentropy', metrics = 'acc')

Train_Gen = ImageDataGenerator(1./255)
Val_Gen = ImageDataGenerator(1./255)

Train_Generator = Train_Gen.flow_from_directory(train_dir, target_size = (150,150), batch_size = 20,
                                               class_mode = 'binary')

Val_Generator = Val_Gen.flow_from_directory(validation_dir, target_size = (150, 150), class_mode = 'binary',
                                           batch_size = 20)

batch_size = 20
target_size = (150,150)
No_Of_Training_Images = Train_Generator.classes.shape[0]
No_Of_Val_Images = Val_Generator.classes.shape[0]
steps_per_epoch = No_Of_Training_Images/batch_size
validation_steps = No_Of_Val_Images/batch_size

history = model.fit(x = Train_Generator, shuffle=True, epochs = 20, 
          steps_per_epoch = steps_per_epoch,
          validation_data = Val_Generator
          , validation_steps = validation_steps
         )

Now, I Predict on the Test Data as shown below:

Test_Dir = 'Dogs_Vs_Cats_Very_Small/test'

Test_Generator = ImageDataGenerator(1./255).flow_from_directory(Test_Dir, 
           target_size = (150,150), batch_size = 1, 
           shuffle = False, class_mode = 'binary') # This outputs Found 17 images belonging to 2 classes.

No_Of_Samples = len(Test_Generator.filenames)

testPredictions = model.predict(Test_Generator, steps = No_Of_Samples)


predictedClassIndices=np.argmax(testPredictions,axis=1)
print(predictedClassIndices)

filenames = Test_Generator.filenames
for f in range(len(filenames)):
    print(filenames[f],":",predictedClassIndices[f])

Output of the above Print Statement, i.e., Predicted Classes are shown below:

array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])


cats/cat.1546.jpg : 0
cats/cat.1547.jpg : 0
cats/cat.1548.jpg : 0
cats/cat.1549.jpg : 0
cats/cat.1550.jpg : 0
cats/cat.1566.jpg : 0
cats/cat.1593.jpg : 0
cats/cat.1594.jpg : 0
dogs/dog.1514.jpg : 0
dogs/dog.1520.jpg : 0
dogs/dog.1525.jpg : 0
dogs/dog.1551.jpg : 0
dogs/dog.1555.jpg : 0
dogs/dog.1574.jpg : 0
dogs/dog.1594.jpg : 0
dogs/dog.1597.jpg : 0
dogs/dog.1599.jpg : 0

As seen above, all the Images are Predicted as Class = 0 i.e., Cats.

I've already look into this Stack Overflow Question and my Data is Balanced (1000 Cat Images and 1000 Dog Images) so, as per my understanding, Rebalancing my dataset or Adjusting class weights doesn't apply. I've tried "Increasing the time of training" as well.

EDIT: Content of testPredictions is shown below:

[[1.0473319e-05]
 [9.8473930e-01]
 [2.9069009e-01]
 [5.0639841e-07]
 [1.8511847e-01]
 [6.0166395e-01]
 [4.2568660e-01]
 [4.6028453e-01]
 [7.8800195e-01]
 [8.5675471e-02]
 [8.2654454e-02]
 [7.2898394e-01]
 [1.5504999e-01]
 [8.2106847e-01]
 [8.7003058e-01]
 [9.9999285e-01]
 [5.1210046e-01]]

Can someone help me to correct it.

Thank you all in advance.

1 Answers

The problem here is in the final step when you are assigning class to the testPredictions outcome. The argmax method "returns the indices of the maximum values along an axis". In your case it's always 0 because along axis=1 you have only one element (with index 0).

Since you're doing binary classification and the classes are balanced, it makes most sense to apply 0.5 probability threshold to assign classes:

predictedClassIndices = testPredictions > 0.5

for idx, filename in enumerate(filenames):
    print(filename,":",predictedClassIndices[idx])
Related