I'm trying to build a CNN model in order to classify an image, but whenever the training is done and I try to feed it a single image (from the training dataset) it misclassifies this image always.
Please take a look at the code I wrote below.
Thank you in advance.
First, I declared an Image Data Generator for both my training and testing sets:
train_datagen = ImageDataGenerator(rescale = 1./255, rotation_range=20, horizontal_flip = True,
validation_split=0.3)
test_datagen = ImageDataGenerator(rescale = 1./255,validation_split=0.3)
Then, I used the flow_from_directory() function to load the images:
train_generator = train_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='training',
target_size = (224, 224),
class_mode = 'categorical'
)
test_generator = test_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='validation',
target_size = (224, 224),
class_mode = 'categorical'
)
I then loaded a pretrained model and added a few layers to build my model:
pretrained_model = VGG16(weights="imagenet", include_top=False,
input_tensor=input_shape)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
Flatten(name="flatten"),
Dense(3, activation="softmax")
])
I then trained the model :
INIT_LR = 3e-4
EPOCHS = 15
opt = Adam(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer='Adam', metrics=["accuracy"])
H = model.fit(
train_generator,
validation_data=test_generator,
epochs=EPOCHS,
verbose= 1)
Then came the part to predict a single image:
I chose an image that was part of the training set, I even overfitted the model to make sure the predictions should be correct, but it was giving me wrong results for every image I input to the model.
I tried the following ways:
image = image.load_img(url,target_size = (224, 224))
img = tf.keras.preprocessing.image.img_to_array(image)
img = np.array([img])
img = img.astype('float32') / 255.
img = tf.keras.applications.vgg16.preprocess_input(img)
This didn't work
image = cv2.imread(url)
image = cv2.normalize(image, None,beta=255, dtype=cv2.CV_32F)
image = cv2.resize(image, (224, 224))
image = np.expand_dims(image, axis=0)
This also didn't work, I also tried many other ways to predict a single image, but none worked.
Finally, the only way was that I had to create an Image Data Generator and Flow From Directory for this single image, and it worked, but I believe that's not how it should be done.
The code img = tf.keras.applications.vgg16.preprocess_input(img) scales the pixel
values in the image to values between -1 to +1 assuming the original pixel values are in the range 0 to 255. In the previous line of code
img = img.astype('float32') / 255.
You rescaled the pixels. So remove that line of code. Now to predict a single image you need to expand the dimensions with
img = np.expand_dims(img, axis=0)
In your second code effort be aware the CV2 reads in images as BGR. If your model was trained on RGB images then your predictions will be wrong. Use the code below to convert the image to RGB.
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
As a side note you can replace tf.keras.applications.vgg16.preprocess_input(img) with the function below which will scale the images between -1 to +1
def scalar(img):
return img/127.5 - 1
This answer could be one starting point:
Resnet50 produces different prediction when image loading and resizing is done with OpenCV
These are possible differences (short gist):
RGB vs BGR (OpenCV loads BGR)
The interpolation method used (INTER_LINEAR vs INTER_NEAREST).
img_to_array() transforms the data type into float32 rather than uint8 which is obtained by default when loading with OpenCV.
tf.keras.applications.vgg16.preprocess_input(img). This preprocessing function can actually differ from what you have written above as image preprocessing; it is also notable that, if you do not preprocess it while training in this particular way (preprocess_input()) then it also makes sense to have bad results on the test set, since the preprocessings are different.
Hope these observations shed some light.
Related
I'm a beginner programmer trying out image classification using CNN. I'm aiming to build a model which classifies if an image is an aluminum can or not, and I want to test it with my own image.
I've resized the images with the code below:
#Resizing to 128,128
files = os.listdir("../input/aluminum-can-image-data/Aluminum Cans")
for f in files:
img = Image.open("../input/aluminum-can-image-data/Aluminum Cans/" + f)
img = img.resize((128,128))
ds_train_ = image_dataset_from_directory(
'../input/aluminum-can-image-data',
labels='inferred',
image_size=[128, 128],
interpolation='nearest',
batch_size=64,
)
ds_valid_ = image_dataset_from_directory(
'../input/aluminum-can-image-data',
labels='inferred',
image_size=[128, 128],
interpolation='nearest',
batch_size=64,
)
ds_train, ds_valid = train_test_split(files, test_size=0.2, random_state=1)
I want to build a code which shows the percentage of how likely an image is an aluminum can when it has received a single image. Any help with the codes to build this function would be highly appreciated~!
let us suppose the model you use is named "model" and you have has 2 ouput labels -"Aluminium","Not Aluminium" .
As you only need the prediction of only a single image, you have to use np.expandims(image,axis=0) to increase the dimension for the input for the model to work.
Code:
class=["alum","not_alum"]
prediction=model.predict(np.expand_dims(image,axis=0))
confidence=round(100 * (np.max(prediction[0]),2)
argclass=np.argmax(prediction,axis=1)
print(class[argclass[0])
print(confidence) .
i want to build a covid-19 cnn detector from x-ray images with keras and my input shape is (224,244,3)
but i dont know how to change my dataset images to that size can't find specific resource for that
and also i watch many youtube videos all of them put 3 channels for x-ray photos (for the input shape) while it is black and white can any one explain
i am using google colab
Try this:
I assume your dataset images is inside folder images
import pandas as pd
import numpy as np
import os, cv2
for image in os.listdir(os.path.join("images")):
img = cv2.imread(os.path.join("images",image))
img = cv2.resize(img, (224,224,3))
cv2.imwrite(os.path.join("images", image), img)
Try this,
I assume you have the images with different shapes, now in order to achieve size of (224,224,3) you need to follow below steps.
Step-1
define shape size in variable
IMG_SHAPE = 224
Step-2
if you are using flow_from_directory method then pass target_size like below.
image_gen_train = 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')
train_data_gen = image_gen_train.flow_from_directory(batch_size = batch_size,
directory = train_dir,
shuffle= True,
target_size = (IMG_SHAPE,IMG_SHAPE),
class_mode = "categorical")
Step-3
Now in convolutional layer of model architecture pass input_shape as below.
classifier = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,(3,3),activation='relu',input_shape=(IMG_SHAPE, IMG_SHAPE, 3)),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(32,(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),
tf.keras.layers.Conv2D(128,(3,3),activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Dropout(0.32),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1024,activation= 'relu'),
tf.keras.layers.Dense(3, activation = "softmax")
])
I have trained an image similarity network. The network is designed to distinguish between similar/dissimilar pairs of images.
Whare a pair contains a camera image and its corresponding sketch image.
The test dataset contains 4 image directories (camera_positive, sketch_positive, camera_negative, sketch_negative).
I am facing problem while evaluating the performance of the network on the test dataset.
As the test dataset is huge to fit into the memory, I decided to use Keras ImageDataGenerator.
I implemented the following code. Each directory contains 20 images (for small demonstration).
Therefore, in total 80 images and 40 predictions.
As the ImageDataGenerator gives us the option to save the image I used "save_to_dir" parameter as can be seen in the following code to verify the correct working.
Each directory contains 20 images therefore, I am expecting after running the predictions it will save the same images to the specified directories.
After running the code, it generates 31 images in each folder instead of 20!
I played around the different step sizes but no one gives accurate results.
What is wrong with this code. Please suggest!
import os
import numpy as np
from keras.models import load_model
from keras.preprocessing.image import ImageDataGenerator
batch_size = 1
image_size = 224
class_mode = None
"""
c_pos/neg: camera positive/neg image
s_pos/neg: sketch positive/neg image
"""
c_pos = r"testing\c_pos"
c_neg = r"testing\c_neg"
s_pos = r"testing\s_pos"
s_neg = r"testing\s_neg"
datagen_constructor = ImageDataGenerator()
def initialize_generator(generator, c_pos, s_pos, c_neg, s_neg):
camera_pos=generator.flow_from_directory(
c_pos,
target_size=(image_size, image_size),
color_mode="rgb",
batch_size=batch_size,
class_mode=class_mode,
shuffle = False,
seed=7,
save_to_dir='results/c_pos',
save_format='jpeg',
save_prefix='CPOS'
)
sketch_pos=generator.flow_from_directory(
s_pos,
target_size=(image_size, image_size),
color_mode="rgb",
batch_size=batch_size,
class_mode=class_mode,
shuffle = False,
seed=7,
save_to_dir='results/s_pos',
save_format='jpeg',
save_prefix='SPOS'
)
camera_neg=generator.flow_from_directory(
c_neg,
target_size=(image_size, image_size),
color_mode="rgb",
batch_size=batch_size,
class_mode=class_mode,
shuffle = False,
seed=7,
save_to_dir='results/c_neg',
save_format='jpeg',
save_prefix='CNEG'
)
sketch_neg=generator.flow_from_directory(
s_neg,
target_size=(image_size, image_size),
color_mode="rgb",
batch_size=batch_size,
class_mode=class_mode,
shuffle = False,
seed=7,
save_to_dir='results/s_neg',
save_format='jpeg',
save_prefix='SNEG'
)
while True:
camerapos = np.expand_dims(camera_pos.next(), axis=0)
sketchpos = np.expand_dims(sketch_pos.next(), axis=0)
cameraneg = np.expand_dims(camera_neg.next(), axis=0)
sketchneg = np.expand_dims(sketch_neg.next(), axis=0)
camera = np.concatenate((camerapos[0], cameraneg[0]))
sketch = np.concatenate((sketchpos[0], sketchneg[0]))
camera = np.asarray(list(camera), dtype=np.float32)
sketch = np.asarray(list(sketch), dtype=np.float32)
yield [camera, sketch]
test_datagen = initialize_generator(datagen_constructor, c_pos, s_pos, c_neg, s_neg)
# Load pre-trained model
model = load_model("model.h")
# Evaluating network performance on test dataset
predict = model.predict_generator(test_datagen, steps = 20)
You could manually iterate through each folder and make a prediction like this:
model = load_model("model.h")
image_paths = [image.path for image in os.scandir(path_to_my_folder)]
for image_path in image_paths:
image = cv2.imread(image_path)
image_to_predict = np.expand_dims(image,axis=0) # this is important to add the batch index, keras only predicts on batches and here we have batch of size 1
prediction = model.predict(image_to_predict)
Then, you could compare each prediction with the ground truth label you know it belongs to.
I have trained a basic CNN model for image classification.
While training the model I have used ImageDataGenerator from keras api.
After the model is being trained i used testdatagenerator and flow_from_directory method for testing.
Everything Went well.
Then I saved the model for future use.
Now i am using the same model and used predict method from keras api with a single image, but the prediction is very different every time I test using different images.
Could you please let me know any solution.
training_augmentation = ImageDataGenerator(rescale=1 / 255.0)
validation_testing_augmentation = ImageDataGenerator(rescale=1 / 255.0)
# Initialize training generator
training_generator = training_augmentation.flow_from_directory(
JPG_TRAIN_IMAGE_DIR,
class_mode="categorical",
target_size=(32, 32),
color_mode="rgb",
shuffle=True,
batch_size=batch_size
)
# initialize the validation generator
validation_generator = validation_testing_augmentation.flow_from_directory(
JPG_VAL_IMAGE_DIR,
class_mode="categorical",
target_size=(32, 32),
color_mode="rgb",
shuffle=False,
batch_size=batch_size
)
# initialize the testing generator
testing_generator = validation_testing_augmentation.flow_from_directory(
JPG_TEST_IMAGE_DIR,
class_mode="categorical",
target_size=(32, 32),
color_mode="rgb",
shuffle=False,
batch_size=batch_size
)
history = model.fit_generator(
training_generator,
steps_per_epoch=total_img_count_dict['train'] // batch_size,
validation_data=validation_generator,
validation_steps=total_img_count_dict['val'] // batch_size,
epochs=epochs,
callbacks=callbacks)
testing_generator.reset()
prediction_stats = model.predict_generator(testing_generator, steps=(total_img_count_dict['test'] // batch_size) + 1)
### Trying to use predict method
img_file = '/content/drive/My Drive/Traffic_Sign_Recognition/to_display_output/Copy of 00003_00019.jpg'
img = cv2.imread(img_file)
img=cv2.resize(img, (32,32))
img = img/255.0
a=np.reshape(img, (1, 32, 32, 3))
model = load_model('/content/drive/My Drive/Traffic_Sign_Recognition/basic_cnn.h5')
prediction = model.predict(a)
When I am trying to use predict, every time wrong prediction is coming.
Any leads will be appreciated.
Keras generator uses PIL for image reading which read images from disk as RGB.
You are using opencv for reading which reads images as BGR. You have to convert your image from BGR to RGB.
img = cv2.imread(img_file)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
...
I'm trying to do an image segmentation problem where I want to segment 5 objects in an image. I'm using a U-net architecture. My final layer looks like this:
conv_final = Conv2D(OUTPUT_MASK_CHANNELS, (1, 1))(up_conv_224)
conv_final = Activation('sigmoid')(conv_final)
model = Model(inputs, conv_final, name="ZF_UNET_224")
However I get an error saying:
ValueError: Error when checking target: expected conv2d_24 to have shape (224, 224, 5) but got array with shape (224, 224, 3)
This is the generator that I'm using
image_generator = train_datagen.flow_from_directory(
'data/train', # this is the target directory
target_size=(224, 224),
color_mode = 'rgb',# all images will be resized to 150x150
batch_size=batch_size,
class_mode=None,
seed = 1) # since we use binary_crossentropy loss, we need binary labels
# this is a similar generator, for validation data
mask_generator = mask_datagen.flow_from_directory(
'data/train',
target_size=(224, 224),
color_mode = 'rgb',
batch_size=batch_size,
class_mode=None,
seed = 1)
train_generator = zip(image_generator, mask_generator)
What can I do to fix this? Any help appreciated!
You have to convert the data into one hot encoded format.
Use from keras.utils import to_categorical