Is there a simple way to subset 10 percent of train and test data using ImageDataGenerator? - tensorflow

I have a structure of directories like this:
-root_dir----------------------------
--train
---dog (contains 750 images of dogs)
---cat (contains 750 images of cats)
---mouse (contains 750 images of mice)
--test
---dog (contains 250 images of dogs)
---cat (contains 250 images of cats)
---mouse (contains 250 images of mice)
That is how I load the data:
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_data_gen = ImageDataGenerator(rescale=1./255)
train_data = train_data_gen.flow_from_directory(directory='/root_dir/train/',
target_size=(224, 224),
class_mode='categorical',
batch_size=32,
seed=42)
test_data_gen = ImageDataGenerator(rescale=1./255)
test_data = test_data_gen.flow_from_directory(directory='/root_dir/test/',
target_size=(224, 224),
class_mode='categorical',
batch_size=32,
seed=42)
It works fine.
train_data contains 750 images of each class.
However, I need to run fast experiments only on 10 percent of the data.
I need train_data_10_percent_subset that contains 75 randomly chosen images of each class.
Is there a simple way with ImageDataGenerator to randomly choose 10 percent of the images in the train directory in each sub-folder?
I need a generator that contains 75 images of each class from train subfolders

you can do this
train_data_gen = ImageDataGenerator(rescale=1./255, validation_split=.1)
train_data = train_data_gen.flow_from_directory(directory='/root_dir/train/',
target_size=(224, 224),
class_mode='categorical',
batch_size=32,
seed=42, subset='validation')
setting validation_split to .1 reserves 10 % of the data for validation. Setting subset='validation' will make the train_data have 10% of the training data

Related

How to view the image from test generator to see if the prediction is correct or not

I am training a fruit classification model. As of right now my classes are:
['Fresh Apples', 'Fresh Bananas', 'Fresh Oranges']
I am using train, validation, and test generators using ImageDataGenerator and flow_from_directory. I have trained the model and am now wanting to feed the test generator into the model to see the performance of the model. Right now I only have 2 images in the test generator. I have the following code to make predictions:
predictions = tuned_model.predict(test_generator)
score = tf.nn.softmax(predictions[0])
print(
'This image most likely belongs to {} with a {:.2f} percent
confidence.'.format(
class_names[np.argmax(score)], 100 * np.max(score)
)
)
And am getting the following as a result:
This image most likely belongs to Fresh Apples with a 46.19 percent confidence.
Yes it is low accuracy, I have only trained for 10 epochs lol. BUT, is there a way I can see which image is being tested? Or a way to know if this prediction is the correct prediction?
EDIT:
Including code of generators...
generator = ImageDataGenerator(
rotation_range=45,
rescale=1./255,
horizontal_flip=True,
vertical_flip=True,
validation_split=.2
)
train_generator = generator.flow_from_directory(
train_path,
target_size=(im_height, im_width),
batch_size = batch_size,
subset='training'
)
validation_generator = generator.flow_from_directory(
train_path,
target_size=(im_height, im_width),
batch_size=batch_size,
subset='validation'
)
test_generator = generator.flow_from_directory(
test_path,
target_size= (im_height, im_width),
batch_size= batch_size,
)
In terms of my class labels, as of right now I simply hard coded them
class_names = ['Fresh Apples', 'Fresh Bananas', 'Fresh Bananas']
I know I should probably import os and create labels based on file structure, but I will do this later unless I absolutely need to.
I assume when you created the test generator you set shuffle=False in flow_from_directory. Then use
files=test_generator.filenames
class_dict=test_generator.class_indices # a dictionary of the form class name: class index
rev_dict={}
for key, value in class_dict.items()
rev_dict[value]=key # dictionary of the form class index: class name
files is a list of filename in the order the files were presented for prediction.
Then do
predictions = tuned_model.predict(test_generator)
Then iterate through the predictions
for i, p in enumerate(predictions)
index=np.argmax(p)
klass=rev_dict[index]
prob=p[index]
print('for file ', files[i], ' predicted class is ', klass,' with probability ',prob)
Of course you could also display the image as well

transfer learning of Inception v3 returns the same predictions

I have tried to customize inception to classify. I used the cat, dog, human and other to classify cat, dog, human ( collection of family photos) and other (mostly natural scenes) I have about 2000 dog, 1000 cat, 7000 human and 3000 images split 80:20 among the train and validate. The essence of model is as below. When I train the training accuracy is close to 97% and validation accuracy is ~90%.
import os
from tensorflow.keras import layers
from tensorflow.keras import Model
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.applications.inception_v3 import InceptionV3
local_weights_file = 'C:/users/sethr/education/Healthcare/imagedetect/modelimageadvance /inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5'
pre_trained_model = InceptionV3(input_shape = (150, 150,3), include_top = False, weights = `enter code here`local_weights_file)
for layer in pre_trained_model.layers:
layer.trainable = False
# pre_trained_model.summary()
last_layer = pre_trained_model.get_layer('mixed7')
#print('last layer output shape: ', last_layer.output_shape)
last_output = last_layer.output
# Flatten the output layer to 1 dimension
x = tf.keras.layers.Flatten()(last_output)
# Add a fully connected layer with 1,024 hidden units and ReLU activation
x = tf.keras.layers.Dense(512, activation='relu')(x)
x = tf.keras.layers.Dense(256, activation='relu')(x)
# Add a dropout rate of 0.2
x = tf.keras.layers.Dropout(0.2)(x)
# Add a final sigmoid layer for classification
x = tf.keras.layers.Dense(4, activation='softmax')(x)
model = Model(pre_trained_model.input, x)
model.compile(optimizer = RMSprop(lr=0.0001), loss = 'categorical_crossentropy', metrics = ['accuracy'])
history = model.fit(train_generator,validation_data = validation_generator,steps_per_epoch = 20,epochs = 20,validation_steps = 25,verbose = 2)
model.save("dcho.rp5")
___________________
import numpy as np
import cv2
import glob
from keras.preprocessing import image
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
labels= ["cat","dog","human","other"]
path='C:/Users/sethr/education/Healthcare/imagedetect/images/*.jpg'
for fim in glob.glob(path):
# predicting images
img=image.load_img(fim, target_size=(150, 150))
x=image.img_to_array(img)
x=np.expand_dims(x, axis=0)
images = np.vstack([x])
plt.figure()
plt.imshow(img)
plt.show()
classes = model.predict(images,batch_size=10)
________________________________________________________
_______________________________________________________
# All images will be rescaled by 1./255.
train_datagen = ImageDataGenerator( rescale = 1.0/255. )
test_datagen = ImageDataGenerator( rescale = 1.0/255. )
# --------------------
# Flow training images in batches of 20 using train_datagen generator
# --------------------
train_generator = train_datagen.flow_from_directory(train_dir,
batch_size=20,
shuffle='True',
class_mode='categorical',
target_size=(150, 150))
# --------------------
# Flow validation images in batches of 20 using test_datagen generator
# --------------------
validation_generator = test_datagen.flow_from_directory(validation_dir,
target_size = (150, 150),
batch_size=20,
class_mode='categorical',
shuffle='True',
)
_______________________________________________________________
The problem is it is returning always human as prediction.. I played around with Adam, Adjusted learning rate but still the prediction remains the same. Any insight.
The issue is you have not done the rescaling part when you predicting images.
You are doing rescaling only for training and validation
train_datagen = ImageDataGenerator( rescale = 1.0/255. )
test_datagen = ImageDataGenerator( rescale = 1.0/255. )
# Note - this test_datagen used for validation
In order to get correct predictions, we should do the same preprocessing steps as we did for training and validation. So you need to rescale the image.
You can rescale the image by using this code
x = x* 1.0/255.0
So the correct predicting image part is shown below.
for fim in glob.glob(path):
# predicting images
img=image.load_img(fim, target_size=(150, 150))
x=image.img_to_array(img)
x=np.expand_dims(x, axis=0)
# Add this line
x = x* 1.0/255.0
images = np.vstack([x])
plt.figure()
plt.imshow(img)
plt.show()
classes = model.predict(images,batch_size=10)

Tensorflow: train multiple models in parallel with the same ImageDataGenerator

I'm doing HPO on a small custom CNN. During training the GPU is under-utilised and I'm finding a bottleneck in the CPU: the data augmentation process is too slow. Looking online, I found that I could use multiple CPU cores for the generator and speedup the process. I set up workers=n_cores and this did improve things, but not as much as I'd like.
So I though that I could train multiple models simultaneously on the GPU, and feed the same augmented data to the models. However, I can't come up with some idea on how to do this and I couldn't find any similar question.
Here's a minimal example (I'm leaving out imports for brevity):
# load model and set only last layer as trainable
def create_model(learning_rate, alpha, dropout):
model_path = '/content/drive/My Drive/Progetto Advanced Machine Learning/Model Checkpoints/Custom Model 1 2020-06-01 10:56:21.010759.hdf5'
model = tf.keras.models.load_model(model_path)
x = model.layers[-2].output
x = Dropout(dropout)(x)
predictions = Dense(120, activation='softmax', name='prediction', kernel_regularizer=tf.keras.regularizers.l2(alpha))(x)
model = Model(inputs=model.inputs, outputs=predictions)
for layer in model.layers[:-2]:
layer.trainable = False
model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate), metrics=['accuracy'])
return model
#declare the search space
SEARCH_SPACE = [skopt.space.Real(0.0001, 0.1, name='learning_rate', prior='log-uniform'),
skopt.space.Real(1e-9, 1, name='alpha', prior='log-uniform'),
skopt.space.Real(0.0001, 0.95, name='dropout', prior='log-uniform')]
# declare generator
train_datagenerator = ImageDataGenerator(rescale=1. / 255, rotation_range=30, zoom_range=0.2, horizontal_flip=True, validation_split=0.2, data_format='channels_last')
# training function to be called by the optimiser
#use_named_args(SEARCH_SPACE)
def fitness(learning_rate, alpha, dropout):
model = create_model(learning_rate, alpha, dropout)
#compile generators
train_batches = train_datagenerator.flow_from_directory(train_out_path, target_size=image_size, color_mode="rgb", class_mode="categorical" , batch_size=32, subset='training', seed = 20052020)
val_batches = train_datagenerator.flow_from_directory(directory=train_out_path, target_size=image_size, color_mode="rgb", class_mode="categorical" , batch_size=32, subset='validation', shuffle=False, seed = 20052020)
#train
early_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
training_results = model.fit(train_batches, epochs=5, verbose=1, shuffle=True, validation_data=val_batches, workers=2)
history[hyperpars] = training_results.history
with open(dict_save_path, 'wb') as f:
pickle.dump(history, f)
return training_results.history['val_accuracy'][-1]
# HPO
result = skopt.forest_minimize(fitness, SEARCH_SPACE, n_calls=10, callback=checkpoint_saver)

Are these images too 'noisy' to be correctly classified by a CNN?

I'm attempting to build an image classifier to identify between 2 types of images on property sites. I've split my dataset into 2 categories: [Property, Room]. I'm hoping to be able to differentiate between whether the image is of the outside of some property or a room inside the property.
Below are 2 examples of the types of image I am using. My dataset consists of 800 images for each category, and then a training set of an additional 160 images for each category (not present in the training set).
I always seem to be get reasonable results in training, but then when I test against some real samples it usually ends up classifying all of the images into a single category.
Below you can see the model I am using:
train_datagen = ImageDataGenerator(
rescale=1./255,
width_shift_range=0.1,
height_shift_range=0.1,
rotation_range=10,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
) # set validation split
validate_datagen = ImageDataGenerator(rescale=1./255)
IMG_HEIGHT = IMG_WIDTH = 128
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (11,11), activation='relu', input_shape=(IMG_HEIGHT, IMG_WIDTH, 3), padding='same'),
tf.keras.layers.MaxPooling2D(11, 11),
# tf.keras.layers.Dropout(0.5),
# Second convolutional layer
tf.keras.layers.Conv2D(64, (11, 11), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(11, 11),
# tf.keras.layers.Dropout(0.5),
# Flattening
tf.keras.layers.Flatten(),
# Full connection
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(1, activation='sigmoid')
])
from tensorflow.keras.optimizers import RMSprop
model.compile(
optimizer=RMSprop(lr=0.001),
loss='binary_crossentropy',
metrics=['accuracy']
)
# now train the model
history = model.fit_generator(
train_generator,
validation_data=validation_generator,
steps_per_epoch=75, #100
epochs=5, # 15, or 20, and 100 steps per epoch
validation_steps=50,
verbose=1
)
# Predict image
def load_image(img_path, show=False):
test_image = image.load_img(img_path, target_size=(IMG_HEIGHT, IMG_WIDTH))
test_image = image.img_to_array(test_image)
test_image /= 255.
test_image = np.expand_dims(test_image, axis = 0)
return test_image
def predict_image(img_path, show=False):
loaded_img = load_image(img_path, show)
pred = model.predict(loaded_img)
return 'property' if pred[0][0] == 0.0 else 'room'
print('Prediction is...')
print(predict_image('path/to/my/img')
Can anyone suggest the possible reasons for this? I've tried using different epochs and batch sizes, augmenting the images further, changing the Conv2D and Pooling layer size but nothing seems to help.
Do I perhaps not have enough data, or are they bad images to begin with? This is my first foray into ML so apologies if any of questions seem obvious.
You are not post-processing the output of the classifier correctly, it outputs a probability in [0, 1], with values < 0.5 corresponding to the first class, and values >= 0.5 for the second class. You should change the code accordingly.
Try Data Augmentation: it augments the image to some random transformations like Random Rotation, Random Zoom, Random Horizontal Flip, width shift and height shift. And also try to implement Batch Normalisation.

Why is my confusion matrix "shifted" to the right?

I built a classifier of 4 flower types based on ResNet 50. The accuracy is really high during training, and everything seems good. However, once I plot my confusion matrix, I see that the values are "shifted" to the right instead of in the main diagonal.
What does this mean? Is it a problem with my dataset, or my code?
Here's what I did to use ResNet 50:
def create_model(input_shape, top='flatten'):
if top not in ('flatten', 'avg', 'max'):
raise ValueError('unexpected top layer type: %s' % top)
# connects base model with new "head"
BottleneckLayer = {
'flatten': Flatten(),
'avg': GlobalAvgPooling2D(),
'max': GlobalMaxPooling2D()
}[top]
base = InceptionResNetV2(input_shape=input_shape,
include_top=False,
weights='imagenet')
x = BottleneckLayer(base.output)
x = Dense(NUM_OF_FLOWERS, activation='linear')(x)
model = Model(inputs=base.inputs, outputs=x)
return model
base = ResNet50(input_shape=input_shape, include_top=False)
x = Flatten()(base.output)
x = Dense(NUM_OF_FLOWERS, activation='softmax')(x)
model = Model(inputs=base.inputs, outputs=x)
Confusion Matrix Generation:
# Predict the values from the validation dataset
Y_pred = model.predict_generator(validation_generator, nb_validation_samples // batch_size+1)
# Convert predictions classes to one hot vectors
Y_pred_classes = numpy.argmax(Y_pred, axis = 1)
# Convert validation observations to one hot vectors
Y_true = validation_generator.classes
# compute the confusion matrix
confusion_mtx = confusion_matrix(Y_true, Y_pred_classes)
# plot the confusion matrix
plot_confusion_matrix(confusion_mtx, classes = range(4))
As requested, this is how I created the generators:
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
color_mode='rgb',
class_mode='categorical',
shuffle=True)
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
color_mode='rgb',
class_mode='categorical',
shuffle=False)
Here is an image album of my confusion matrix. Every time I execute model.predict(), the predictions change, always shifting one cell to the right.
Confusion Matrix Album
Yes I imagine it is the code, check your indexing where you create your confusion matrix, it will be off by one
look the validation_generator class. when you use data_generator.flow_from_directory you need see if param shuffle is equal to False like the example above:
val_generator = val_data_generator.flow_from_directory(
test_data_dir,
target_size=(IMAGE_WIDTH, IMAGE_HEIGHT),
batch_size=100,
class_mode="binary",
classes=['dog','cat'],
shuffle=False)
because the default param is True and the only shuffle the images and not labels.
This is an interesting problem. It can be fixed by reloading the imagedatagenerator right before you do a model.predict.
So:
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
color_mode='rgb',
class_mode='categorical',
shuffle=False)
Y_pred = model.predict_generator(validation_generator, nb_validation_samples // batch_size+1)
# Convert predictions classes to one hot vectors
Y_pred_classes = numpy.argmax(Y_pred, axis = 1)
# Convert validation observations to one hot vectors
Y_true = validation_generator.classes
# compute the confusion matrix
confusion_mtx = confusion_matrix(Y_true, Y_pred_classes)
# plot the confusion matrix
plot_confusion_matrix(confusion_mtx, classes = range(4))