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

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.

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

model prediction using CNN

I am currently build an CNN model using Tensor flow -2.0 but not using transfer learning. My question is that how to predict with a new images? I want to load it from my directory and need predictions (classification problem).
My code is given below -
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Conv2D,MaxPool2D,Dropout,Flatten
from tensorflow.keras.callbacks import EarlyStopping
model = Sequential()
model.add(Conv2D(filters = 16,kernel_size = (3,3), input_shape = image_shape, activation = 'relu'))
model.add(MaxPool2D(pool_size = (2,2)))
model.add(Conv2D(filters = 32,kernel_size = (3,3), activation = 'relu'))
model.add(MaxPool2D(pool_size = (2,2)))
model.add(Conv2D(filters = 64,kernel_size = (3,3), activation = 'relu'))
model.add(MaxPool2D(pool_size = (2,2)))
model.add(Flatten())
model.add(Dense(128,activation = 'relu'))
#model.add(Dropout(0.5))
model.add(Dense(1,activation = 'sigmoid'))
model.compile(loss = 'binary_crossentropy',optimizer = 'adam',
metrics = ['accuracy'])
early_stop = EarlyStopping(monitor = 'val_loss',patience = 2)
batch_size = 16
train_image_gen = image_gen.flow_from_directory(train_path,
target_size = image_shape[:2],
color_mode = 'rgb',
batch_size = batch_size,
class_mode = 'binary')
test_image_gen = image_gen.flow_from_directory(test_path,
target_size = image_shape[:2],
color_mode = 'rgb',
batch_size = batch_size,
class_mode = 'binary',
shuffle = False)
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
if(logs.get('accuracy')>0.97):
print("\nReached 97% accuracy so cancelling training!")
self.model.stop_training = True
callbacks = myCallback()
results = model.fit_generator(train_image_gen,epochs = 85,
validation_data = test_image_gen,
callbacks = [callbacks])
# Let's now save our model to a file
model.save('cell_image_classifier.h5')
# Load the model
model = tf.keras.models.load_model('cell_image_classifier.h5')
model.evaluate_generator(test_image_gen)
#Prediction on image
pred = model.predict_generator(test_image_gen)
predictions = pred > .5
print(classification_report(test_image_gen.classes,predictions))
confusion_matrix(test_image_gen.classes,predictions)
Now externally I want to load the image and need prediction.
This will do!
import numpy as np
from keras.preprocessing import image
# predicting images
fn = 'cat-2083492_640.jpg' # name of the image
path='/content/' + fn # path to the image
img=image.load_img(path, target_size=(150, 150)) # edit the target_size
x=image.img_to_array(img)
x=np.expand_dims(x, axis=0)
images = np.vstack([x])
classes = model.predict(images, batch_size=16) # edit the batch_size
print(classes)

Tensorflow2.0 reuse layers

def head(self, input, num_anchors, name, flatten=False):
out_channels = (self.num_classes + 4) * num_anchors
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv1')(input)
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv2')(conv)
conv = layers.Conv2D(256, 3, 1, 'same', activation='relu', name=name+'_conv3')(conv)
out = layers.Conv2D(out_channels, 3, 1, 'same', name=name+'output')(conv)
if flatten is True:
batch_size = tf.shape(out)[0]
out = tf.reshape(out, [batch_size, -1, num_anchors, self.num_classes+4])
out = tf.reshape(out, [batch_size, -1, self.num_classes+4])
return out
I want to know how to reuse these layers as tf.variable_scope(scope resue=tf.AUTO_REUSE) in tensorflow1
In tensorflow1
with tf.variable_scope('', resue=tf.AUTO_REUSE) as scope:
all layers here could be auto reuse
You can reuse the layers by just having a common reference. I have attached a sample code below. I am making use of a variable named as common_layer which will be used in three separate models (sequential and functional). The first model is trained and after that we subtract the weights from common_layer of all the three models. It proves that what changes happen in first model's layer gets reflected in other model's common layer.
import tensorflow as tf
import numpy as np
common_layer = tf.keras.layers.Dense(100, name='common_layer')
model1 = tf.keras.models.Sequential([
tf.keras.layers.Input((100)),
common_layer,
tf.keras.layers.Dense(1)
])
model2 = tf.keras.models.Sequential([
tf.keras.layers.Input((100)),
common_layer,
tf.keras.layers.Dense(10)
])
input_layer = tf.keras.layers.Input((100))
output_layer = common_layer(input_layer)
output_layer = tf.keras.layers.Dense(20)(output_layer)
model3 = tf.keras.Model(inputs=[input_layer], outputs=[output_layer])
model1.compile('adam', loss='mse')
model1.fit(np.random.rand(128, 100), np.random.rand(128, 1))
weights1 = model1.get_weights()[0]
weights2 = model2.get_weights()[0]
weights3 = model3.get_weights()[0]
print(np.sum(weights1 - weights2)) # 0.0
print(np.sum(weights1 - weights3)) # 0.0

Issue with running CNN in Tensorflow 0.12.0 version in macOS el capitan

I am trying to run this CNN classification for distinguishing cats and dogs. While I try to run this on a tensorflow 0.12.0 platform, I am repeatedly getting a Type error problem. I tried to sort this out with loss function to sparse_categorical_crossentropy but still I can't process the CNN properly. What could be the issue here?
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
# Initialising the CNN
classifier = Sequential()
# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))
# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
# Step 3 - Flattening
classifier.add(Flatten())
# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
# Part 2 - Fitting the CNN to the images
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,shear_range = 0.2,zoom_range = 0.2,horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('/Users/andrewsilvanus/Desktop/Classifier/training_set',target_size = (64, 64),batch_size = 32,class_mode = 'binary')
test_set=test_datagen.flow_from_directory('/Users/andrewsilvanus/Desktop/Classifier/test_set',target_size = (64, 64),batch_size = 32,class_mode = 'binary')
classifier.fit_generator(training_set,steps_per_epoch = 8000,epochs=25,validation_data = test_set,validation_steps = 2000)
# Part 3 - Making new predictions
import numpy as np
from keras.preprocessing import image
test_image = image.load_img('dataset/single_prediction/cat_or_dog_1.jpg',target_size = (64,64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
training_set.class_indices
if result[0][0] == 1:
prediction = 'dog'
else:
prediction = 'cat'
TypeError: sigmoid_cross_entropy_with_logits() got an unexpected keyword argument 'labels'
InvalidArgumentError (see above for traceback): Received a label value of 1 which is outside the valid range of [0, 1). Label values: 1 0 1 1 1 0 0 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1
[[Node:loss_5/dense_14_loss/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits = SparseSoftmaxCrossEntropyWithLogits[T=DT_FLOAT, Tlabels=DT_INT64, _device="/job:localhost/replica:0/task:0/cpu:0"](loss_5/dense_14_loss/Reshape_1, loss_5/dense_14_loss/Cast)]]

ValueError: in case of LSTM with `stateful=True`

I tried to use LSTM network with stateful=True as follows:
import numpy as np, pandas as pd, matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras.callbacks import LambdaCallback
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
raw = np.sin(2*np.pi*np.arange(1024)/float(1024/2))
data = pd.DataFrame(raw)
window_size = 3
data_s = data.copy()
for i in range(window_size):
data = pd.concat([data, data_s.shift(-(i+1))], axis = 1)
data.dropna(axis=0, inplace=True)
print (data)
ds = data.values
n_rows = ds.shape[0]
ts = int(n_rows * 0.8)
train_data = ds[:ts,:]
test_data = ds[ts:,:]
train_X = train_data[:,:-1]
train_y = train_data[:,-1]
test_X = test_data[:,:-1]
test_y = test_data[:,-1]
print (train_X.shape)
print (train_y.shape)
print (test_X.shape)
print (test_y.shape)
(816, 3)
(816,)
(205, 3)
(205,)
batch_size = 3
n_feats = 1
train_X = train_X.reshape(train_X.shape[0], batch_size, n_feats)
test_X = test_X.reshape(test_X.shape[0], batch_size, n_feats)
print(train_X.shape, train_y.shape)
regressor = Sequential()
regressor.add(LSTM(units = 64, batch_input_shape=(train_X.shape[0], batch_size, n_feats),
activation = 'sigmoid',
stateful=True, return_sequences=True))
regressor.add(Dense(units = 1))
regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')
resetCallback = LambdaCallback(on_epoch_begin=lambda epoch,logs: regressor.reset_states())
regressor.fit(train_X, train_y, batch_size=7, epochs = 1, callbacks=[resetCallback])
previous_inputs = test_X
regressor.reset_states()
previous_predictions = regressor.predict(previous_inputs).reshape(-1)
test_y = test_y.reshape(-1)
plt.plot(test_y, color = 'blue')
plt.plot(previous_predictions, color = 'red')
plt.show()
However, I got:
ValueError: Error when checking target: expected dense_1 to have 3 dimensions, but got array with shape (816, 1)
PS this code has been adapted from https://github.com/danmoller/TestRepo/blob/master/testing%20the%20blog%20code%20-%20train%20and%20pred.ipynb
Two minor bugs:
Here you have
regressor.add(LSTM(units = 64, batch_input_shape=(train_X.shape[0], batch_size, n_feats),
activation = 'sigmoid',
stateful=True, return_sequences=True))
This LSTM will return a 3D vector, but your y is 2D which throws a valuerror. You can fix this with return_sequences=False. I'm not sure why you initially had train_X.shape[0] inside of your batch_input, the number of samples in your entire set shouldn't affect the size of each batch.
regressor.add(LSTM(units = 64, batch_input_shape=(1, batch_size, n_feats),
activation = 'sigmoid',
stateful=True, return_sequences=False))
After this you have
regressor.fit(train_X, train_y, batch_size=7, epochs = 1, callbacks=[resetCallback])
In a stateful network you can only put in a number of inputs that divides the batch size. Since 7 doesn't divide 816 we change this to 1:
regressor.fit(train_X, train_y, batch_size=1, epochs = 1, callbacks=[resetCallback])
The same goes in your predict. You must specify batch_size=1:
previous_predictions = regressor.predict(previous_inputs, batch_size=1).reshape(-1)

Can KerasClassifier wtih TF model works with sklearn.cross_val_score when setting n_job=-1 and TF runs on a single GPU?

I have this sample code and it can only runs with n_jobs=1.
Tensorflow backend is running on a GPU.
When I run with n_jobs=-1 on method cross_val_score, the program jams/stops working or give any output, after output 4 lines Epoch 1/100 (as I have a 4 core CPU I assume it will use all 4 cores to do CV and each trys to start a tf session on GPU)
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
def build_classifier():
classifier = Sequential()
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dropout(0.3))
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
# classifier.add(Dropout(0.3))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
return classifier
classifier = KerasClassifier(build_fn = build_classifier, batch_size = 100, epochs = 100, verbose=0)
accuracies = cross_val_score(estimator = classifier, X = X_train, y = y_train, cv = 10, n_jobs = 1)
I have also tried to limit the TF GPU usage in this way but n_job=-1 still won't work.
np.random.seed(123)
tf.set_random_seed(123)
config = tf.ConfigProto(inter_op_parallelism_threads=1)
config.gpu_options.per_process_gpu_memory_fraction = 0.1 # in my case this setting will use around 1G memory on GPU
set_session(tf.Session(config=config))
I have the same issue, I use the below lines of code
Configure GPU to use all the memory
config = tf.ConfigProto(allow_soft_placement=True)
config.gpu_options.per_process_gpu_memory_fraction = 1.0
set_session(tf.Session(config=config))
def build_classifier():
classifier = Sequential()
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
return classifier
classifier = KerasClassifier(build_fn = build_classifier, batch_size = 10, epochs = 100)
accuracies = cross_val_score(estimator = classifier, X = X_train, y = y_train, cv = 10)
mean = accuracies.mean()
variance = accuracies.std()
then I removed the n_jobs = -1 then I tried to run it again and check the GPU utilization using GPU-Z below is a photo from the run.
Maybe your question is you don't feel the performance enhancement using GPU. To answer this question I run the same code with CPU and GPU.
GPU at least in my average experiment 3:1 CPU. I believe it should take less than the time but this is the max performance achieved.
You can also found some good discussions Run Keras with GPU