Why am I getting very small number as CNN prediction? - python

I created a CNN using Tensorflow to identify pneumonia and sometimes it returns a very small number as a prediction. why is this happening?
I have attached the link for the dataset
Here I how I process and load the data.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator( rescale = 1.0/255. )
val_datagen = ImageDataGenerator( rescale = 1.0/255. )
test_datagen = ImageDataGenerator( rescale = 1.0/255. )
train_generator = train_datagen.flow_from_directory('/kaggle/input/chest-xray-pneumonia/chest_xray/chest_xray/train/',
batch_size=20,
class_mode='binary',
target_size=(350, 350))
validation_generator = val_datagen.flow_from_directory('/kaggle/input/chest-xray-pneumonia/chest_xray/chest_xray/val/',
batch_size=20,
class_mode = 'binary',
target_size = (350, 350))
test_generator = test_datagen.flow_from_directory('/kaggle/input/chest-xray-pneumonia/chest_xray/chest_xray/test/',
batch_size=20,
class_mode = 'binary',
target_size = (350, 350
And here the Model, compile and fit functions
import tensorflow as tf
model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 150x150 with 3 bytes color
tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(350, 350, 3)),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(1024, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('cats') and 1 for the other ('dogs')
tf.keras.layers.Dense(1, activation='sigmoid')
])
compile the model
from tensorflow.keras.optimizers import RMSprop
model.compile(optimizer=RMSprop(learning_rate=0.001),
loss='binary_crossentropy',
metrics = ['accuracy'])
model fit
history = model.fit(train_generator,
validation_data=validation_generator,
steps_per_epoch=200,
epochs=2000,
validation_steps=200,
callbacks=[callbacks],
verbose=2)
The evaluation metrics as followings, loss: 0.2351 - accuracy: 0.9847
The prediction shows a very small number for the negative pneumonia, and for positive it shows more than .50.
I have two questions:
why I get a very small number as 2.xxxx * 10e-20?
why I can't get the following values as null?
val_acc = history.history[ 'val_accuracy' ]
val_loss = history.history['val_loss' ]

I see that there is no problem with your code, neither with the results you get.
This is a binary classification problem (2 classes: Positive or negative pneumonia), and the output of your model is one neurone giving values between 0 and 1.
So if the output is higher than 0.5, this means positive pneumonia. Otherwise, when you have a very small value like 2 * 10e-20 this means that it's negative pneumonia.
For your second question, you are not supposed to have accuracy and loss values to be null simply because the model is well trained and has 98% accuracy on training data.

Related

Optimising Keras CNN

I am having trouble increasing accuracy and reducing loss in my CNN.
Here are some initial parameters:
batch_size = 32
image_shape = 150 # Sizes input to 150x150
EPOCHS = 250
STEPS_PER_EPOCH = 7
IMAGES_IN_CLASS_FOLDERS > 100
I have the training and validation set as the same images but I pre process the training images so that the validation images are not the same thus:
# Image formatting - Preprocessing images into floating point tensors before being fed into the network
# Generator for our training data - Rescales the image, Flips Images Horizontally, Rotates it
train_image_generator = ImageDataGenerator(rescale=1./255, horizontal_flip=True, rotation_range=45)
# Generator for our validation data - Rescales the image
validation_image_generator = ImageDataGenerator(rescale=1./255)
# Applies scaling and resizing
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
directory=training_Images,
shuffle=True,
target_size=(image_shape,image_shape), #(100,100)
class_mode='categorical')
val_data_gen = validation_image_generator.flow_from_directory(batch_size=batch_size,
directory=validate_Images,
shuffle=True ,
target_size=(image_shape, image_shape),
class_mode='categorical')
Further I have a Sequential model, which I have tried various parameters such as an input CONV2D(32) -> CONV2D(64) -> CONV2D(128) but I am currently testing this model with no success:
# Defining our model
model = tf.keras.models.Sequential([
# Old Method #
tf.keras.layers.Conv2D(8 , (2,2) , activation='LeakyReLU', input_shape=(image_shape, image_shape, 3)),
tf.keras.layers.Conv2D(16, (2,2) , activation='LeakyReLU'),
tf.keras.layers.Conv2D(32, (2,2) , activation='LeakyReLU'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(40, (2,2) , activation='LeakyReLU'),
tf.keras.layers.Conv2D(56, (2,2) , activation='LeakyReLU'),
tf.keras.layers.Conv2D(64, (2,2) , activation='LeakyReLU'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(96, (2,2) , activation='LeakyReLU'),
tf.keras.layers.Conv2D(128, (2,2), activation='LeakyReLU'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(16, activation='softmax'),
#tf.keras.layers.Dense(128, activation='relu'),
#tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(120)
# End Old Method #
])
I have tried various CONV2D layers, various activation methods. Here is the model.compile:
model.compile(optimizer=SGD(lr=0.01),
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=['accuracy'])
I am using an SGD Optimizer, I have tried ADAM but with similar results. Loss is reduced overtime but it seems to reach a certain value range and stagnate with no increase in Accuracy.
model.fit:
history = model.fit(
train_data_gen,
steps_per_epoch= stepForEpoch,
epochs=EPOCHS,
validation_data=val_data_gen,
validation_steps=stepForEpoch
)
Can anyone offer some tips or point me in the right direction on how to increase the accuracy and reduce loss even further? Thank you!
Image of Results
Final Update
As of 06/23/2021 my model is improving significantly, not only with more EPOCHS but with more STEPS_PER_EPOCH:
Dividing the number of images like thus (IMAGES_IN_DATASET(20700) / BATCH_SIZE(32) = 677 STEPS_PER_EPOCH) and choosing 100 EPOCHS to test I am getting an increasing value for accuracy + 10% and an ever decreasing loss with an improvement in MSE.
ACCURACY_INCREASE = %10
MSE_IMPROVEMENT = -0.0004
ACCURACY_LOSS_IMPROVEMENT = -1.1
Thank you to users
#Reda El Hail
#Dr. Snoopy
To sum up the discussion in comments, the error comes from the last layer where an activation function is not set tf.keras.layers.Dense(120).
For a classification task, it should be tf.keras.layers.Dense(120, activation = 'softmax').
As #Snoopy announced: there is no sense to use softmax in hidden layers. It should be only used in the output layer.

How to deal with np.array as training set in Image Generator

I'm doing a ML model that takes pixel values from a numpy array as training and testing data. I defined a function that divides the dataset into images and labels. My task is to use Image Generator for data augmentation and then train the model. Everything goes smoothly until I am to train the model. It keeps giving me errors about the loss function used. When I use categorical_crossentropy it says I can either use 'sparse_categorical_crossentropy' or use function to_categorical. Well I tried both and there were still errors so I decided to try and use tf.convert_to_tensor() on my labels but now I get a shape error:
ValueError: A target array with shape (126, 25, 2) was passed for an output of shape (None, 3) while using as loss `categorical_crossentropy`. This loss expects targets to have the same shape as the output.
This is my code:
training_labels = tf.convert_to_tensor(training_labels)
testing_labels = tf.convert_to_tensor(testing_labels)
# Create an ImageDataGenerator and do Image Augmentation
train_datagen = ImageDataGenerator(
rescale = 1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
validation_datagen = ImageDataGenerator(rescale = 1./255)
train_generator = train_datagen.flow(training_images,
training_labels,
batch_size=126
)
validation_generator = validation_datagen.flow(
testing_images,
testing_labels,
batch_size=126
)
# Keep These
print(training_images.shape)
print(testing_images.shape)
# Their output should be:
# (27455, 28, 28, 1)
# (7172, 28, 28, 1)
And here goes the model:
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax')
])
# Compile Model.
model.compile(loss = 'categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
# Train the Model
history = model.fit_generator(train_generator, validation_data=validation_generator, epochs=2)
model.evaluate(testing_images, testing_labels, verbose=0)
I got stuck with it, I googled for solution but with no success. Can you please help me somehow make a move?
Thanks a lot!
When using categorical cross entropy as the loss function, the labels should be one hot encoded and hence the number of neurons present in the final layer should be equal to the number of classes present in the dataset and that's the error you are getting. Since the number of output neurons is 3, I'm guessing you have 3 classes and hence the shape of training_labels/testing_labels should be (num of images in train/test, 3).
Below is a small snippet for cifar dataset.
from tf.keras.utils import to_categorical
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
num_classes = 10
# convert to one hot encoding
# shape will be (60000, 10) since there are 60000 images and 10 classes in cifar
y_train = to_categorical(y_train, num_classes)
# shape will be (10000, 10) since there are 10000 images and 10 classes in cifar
y_test = to_categorical(y_test, num_classes)
datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(x_train)
history = model.fit_generator(datagen.flow(x_train, y_train, batch_size=32), epochs=2)

How can I solve Value error in resnet 50 implementation?

I am implementing resnet-50 on Kaggle and I am getting a value error. Kindly help me out
train_dir='../input/project/data/train'
test_dir='../input/project/data/test'
train_datagen=ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
test_datagen = ImageDataGenerator(rescale = 1./255)
train_generator = train_datagen.flow_from_directory(
train_dir,
color_mode='grayscale',
target_size=(28,28),
class_mode='binary',
batch_size=32,
)
test_generator = test_datagen.flow_from_directory(
test_dir,
color_mode='grayscale',
target_size=(28,28),
class_mode='binary',
batch_size=32,
shuffle='False',
)
model = Sequential()
model.add(ResNet50(include_top=False, pooling='avg', weights=resnet_weights_path,input_tensor=Input(shape=(224,224,3))))
model.add(Flatten())
model.add(BatchNormalization())
model.add(Dense(2048, activation='relu'))
model.add(BatchNormalization())
model.add(Dense(1024, activation='relu'))
model.add(BatchNormalization())
model.add(Dense(2, activation='sigmoid'))
model.layers[0].trainable = False
I am training a binary classifier and I am getting the error below
ValueError: Cannot assign to variable conv3_block1_0_conv/kernel:0 due to variable shape (1, 1, 256, 512) and value shape (512, 128, 1, 1) are incompatible
You have given input_tensor=Input(shape=(224,224,3)) while defining the ResNet50 base model. But you are giving target_size=(28,28) in your train_generator and test_generator. The training image shape which ResNet50 receiving i.e. target_size is different from what it expects i.e. input_tensor. Change your target_size to match with the shape mentioned in the input_tensor. Also, ResNet50 expects color_mode to be rgb rather grayscale.
This is because of weights which you are using(weights=resnet_weights_path). You've to use latest trained model. Input Image size can be any as per pre-trained model guidelines
Below worked for me
n_h, n_w, n_c =(256, 256, 3)
weights_path = '../input/d/aeryss/keras-pretrained- models/ResNet50_NoTop_ImageNet.h5'
ResNet50 = keras.applications.ResNet50(weights=weights_path ,include_top=False, input_shape=(n_h, n_w, n_c))
It looks like you are using pre-trained weights on your model. You should set the skip_mismatch=True keyword on the model.load_weights function. After returning the model variable, please set the following code:
model.load_weights(weights, by_name=True, skip_mismatch=True)
Where weight is your pre-trained model weight. It should ignore any mismatch of your model and the pre-trained weights.

How to check "test data" accuracy and plot them

I want to test the accuracy of 11000+ images.
I split the data into two classes ,"Yes" and "No". Then ,split them into 80/20 in training set and test set respectively.
Then I split,the training data again into 80/20 for validation set.
I create "Yes" and "No" folder for each one,validation set, test set, training set.And keep the data in respective folders.
Now, I want to train the model in Google Colab.
After train the model, I want to test the "Accuracy" of the "Test Data Set" and plot them with, specificity, sensitivity, accuracy, loss_Function and recall.
Help need for this. Detailed help will be more appreciated.
Thanks in advance.
#Yefet
Code is here:
import tensorflow as tf
import matplotlib.pyplot as plt
import zipfile
import cv2
import os
import numpy as np
import matplotlib.image as mpimg
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing import image
from sklearn.model_selection import KFold, StratifiedKFold
img = image.load_img("drive/MyDrive/data03/train/no/1 no.jpeg" , target_size=(200, 200))
plt.imshow(img)
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self,epoch,logs={}):
if (logs.get('accuracy') > .98) & (logs.get('val_accuracy') > .9):
print("Reached 98% accuracy so cancelling training!")
self.model.stop_training = True
callbacks = myCallback()
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory(
'drive/MyDrive/data03/train', # This is the source directory for training images
target_size=(200, 200), # All images will be resized to 150x150
batch_size=128,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
validation_generator = train_datagen.flow_from_directory(
'drive/MyDrive/data03/validation', # This is the source directory for training images
target_size=(200, 200), # All images will be resized to 150x150
batch_size=128,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
from tensorflow.keras.optimizers import RMSprop
model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 150x150 with 3 bytes color
# This is the first convolution
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(200, 200, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
# The second convolution
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The third convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fourth convolution
#tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
#tf.keras.layers.MaxPooling2D(2,2),
# The fifth convolution
#tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
#tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=0.001),
metrics=['accuracy'])
history = model.fit(
train_generator,
steps_per_epoch=1,
epochs=29,
validation_data = validation_generator,callbacks=[callbacks])
dir_path = "drive/MyDrive/data03/test"
for i in os.listdir(dir_path):
img = image.load_img(dir_path+ '//' + i, target_size=(200, 200) )
plt.imshow(img)
plt.show()
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
images = np.vstack([x])
classes =model.predict(images)
if classes[0]==0:
print("NO TUMOR")
else:
print("YES ")

Tensorflow: loss and accuracy stay flat training CNN on image classification

I copied / pasted this Tensorflow tutorial into a Jupyter notebook. (As of this writting they changed the tutorial to the flower data set instead of the dog one, but the question still applies).
https://www.tensorflow.org/tutorials/images/classification
The first part (without augmentation) runs fine and I get similar results.
But with data augmentation, my Loss and Accuracy stay flat across all epoch. I've checked this posts already on SO :
Keras accuracy does not change
How to fix flatlined accuracy and NaN loss in tensorflow image classification
Tensorflow: loss decreasing, but accuracy stable
None of this applied, since the dataset is a standard one, I don't have the problem of corrupted data, plus I printed a couple of images augmented and it works fine (see below).
I've tried adding more fully connected layers to increase the model capacity, dropout to limit over fitting,... nothing change here are the curve :
Any ideas as to why? Have I missed something in the code?
I know training a DL model is a lot of trial and error, but I'm sure there must be some logic or intuition beyond randomly turning the knobs until something happens.
Thanks !
Source Data :
_URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=_URL, extract=True)
PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered')
Params :
batch_size = 128
epochs = 15
IMG_HEIGHT = 150
IMG_WIDTH = 150
Preprocessing stage :
image_gen = ImageDataGenerator(rescale=1./255,
rotation_range=20,
width_shift_range=0.15,
height_shift_range=0.15,
horizontal_flip=True,
zoom_range=0.2)
train_data_gen = image_gen.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(IMG_HEIGHT, IMG_WIDTH))
augmented_images = [train_data_gen[0][0][i] for i in range(5)]
plotImages(augmented_images)
image_gen_val = ImageDataGenerator(rescale=1./255)
val_data_gen = image_gen_val.flow_from_directory(batch_size=batch_size,
directory=validation_dir,
target_size=(IMG_HEIGHT, IMG_WIDTH),
class_mode='binary')
Model :
model_new = Sequential([
Conv2D(16, 2, padding='same', activation='relu',
input_shape=(IMG_HEIGHT, IMG_WIDTH ,3)),
MaxPooling2D(),
Conv2D(32, 2, padding='same', activation='relu'),
MaxPooling2D(),
Conv2D(64, 2, padding='same', activation='relu'),
MaxPooling2D(),
Dropout(0.2),
Flatten(),
Dense(512, activation='relu'),
Dense(1)
])
model_new.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
model_new.summary()
history = model_new.fit(
train_data_gen,
steps_per_epoch= total_train // batch_size,
epochs=epochs,
validation_data=val_data_gen,
validation_steps= total_val // batch_size
)
As suggested by #today, class_method= 'binary' was missing from the training data generator
Now the model is able to train properly.
train_data_gen = image_gen.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(IMG_HEIGHT, IMG_WIDTH),
class_method = 'binary')

Categories