CNN performance worse when loading data with tf.Data - python

I have a trained EfficientNetB2 neural network that I'm using for image classification. When I'm loading the images with PIL like this:
image = Image.open(item)
image = image.convert('RGB').resize((120, 120))
image = np.array(image)
if image.ndim == 3:
image = np.expand_dims(image, axis = 0)
predictions.append(model.predict(image))
I get accuracy at around 90%. This is, however, extremely slow so I tried using tf.data to load my dataset. This looks something like this:
ds = tf.data.Dataset.list_files(str(test_dir / '*' / '*'))
ds = (ds
.map(load_data, num_parallel_calls=tf.data.experimental.AUTOTUNE)
.cache()
.batch(32)
.prefetch(tf.data.experimental.AUTOTUNE)
)
And this is the load_data function:
def load_image_and_label(file_path):
label = tf.strings.split(file_path, os.sep)[-2]
image = tf.io.read_file(file_path)
image = tf.io.decode_jpeg(image, channels=3, dct_method='INTEGER_ACCURATE')
image = tf.image.resize(image, target_size)
return image, label
This is, as expected, much much faster but the accuracy drops to around ~70%. I've tried moving stuff around but I just can't figure out why this happens. If anyone has any suggestions it would be much appreciated.
P.S.
I'm aware that there is an almost identical question already asked on stack overflow but the answer to that question doesn't change anything for my situation, this is why I'm posting this as a separate question. Thank you.
Edit: I tried not using tf.Dataset but still using my load_image_and_label function, the results were again ~90% accuracy, meaning that there is a problem somewhere with tf.Dataset pipeline, anyone got any experience with this kind of a problem?

Related

TFLite - Post Training (full integer) Quantization - problems with using a representative dataset

I have a hard time to get good results for a full integer quantized TFLite Model using Post-training quantization. The model does not recognize anything corectly. I used the given notebook tutorial from google and changed it. Here is my version where I try to perform full integer quantization by using images from the coco validation dataset. It should run completely on its own.
Probably something is wrong with _representative_dataset_gen() which looks like this:
def _representative_dataset_gen():
print("200 rep dataset function called!")
root = 'val2017/'
pattern = "*.jpg"
imagePaths = []
for path, subdirs, files in os.walk(root):
for name in files:
if fnmatch(name, pattern):
imagePaths.append(root + name)
for index,p in enumerate(imagePaths[:200]):
if index % 10 == 0:
print(index)
image = cv2.imread(p)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (640, 640))
image = image.astype("float")
image = np.expand_dims(image, axis=1)
image = image.reshape(1, 640, 640, 3)
yield [image.astype("float32")]
#yield image
I also compared it to a full integer version which only gets one single image as a repr. dataset. Interestingly it performs really similar, therefore I am quite confident that my attempt is wrong.
Don't hesitate to ask questions. I would appreciate any help.

Tensorflow dataset generator error in channel dimension

I am trying to train my model for image segmentation task and for that i am using a generator to yield the dataset. i have trained it multiple times before but recently I am facing this error.
ValueError:'generator' yielded an element of shape (128,192,3) where an element of shape (128,192,1) was expected.
when i printed out the shapes of my image and mask that comes out of generator it shows.
image:(128,192,1)
mask:(128,192,3)
The generator element gets both the image and mask data loaded from the tensorflow dataset. The question is how does the shape of the mask of an grayscale image changes to 3 when even the input image is grayscale of 1?
How to possibly convert the mask back to channel of 1?
Unfortunately I cannot post the complete code to reproduce as its under privacy
Without knowing more of the library you're using for reading the image it's hard to know. I am assuming you're using PIL and I'll do
from PIL import Image
img = Image.open('im1.jpg','r')
img = img.convert('L')
'L' is for the grayscale, you can check more mode -> https://pillow.readthedocs.io/en/stable/handbook/concepts.html
While you're updating your code, you should check the preprocessing module of keras, then the code will be
# Returns a PIL image
image = tf.keras.preprocessing.image.load_img(image_path, color_mode="grayscale")
input_arr = keras.preprocessing.image.img_to_array(image)
input_arr = np.array([input_arr]) # Convert single image to a batch.
predictions = model.predict(input_arr)
More information -> https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/load_img

Extract image dataset from tensorflow record dataset in batches

I recently started studying CNNs with tensorflow and found tfrecords very helpful in speeding up the training, however I'm struggling with data API.
After parsing, my dataset is composed of (image, label) tuples, this is fine for training, however I'm trying to extract the image in another dataset to call keras.predict() on.
I've tried this solution:
test_set = get_set_tfrecord(test_path, _parse_function, num_parallel_calls = 4)
lab = []
f = True
for image, label in test_set.take(600):
if f:
img = tf.data.Dataset.from_tensors(image)
f = False
else:
img = img.concatenate(tf.data.Dataset.from_tensors(image))
lab.append(label.numpy())
naive, not great code, but it works EXCEPT in order to perform concatenation (i.e. stacking) it loads every image into RAM.
What's the proper way of doing this?
You can use the map API from tf.data.Dataset. You can write the following code.
result = test_set.map(lambda image, label: image)
# You can iterate and check what you have received at the end.
# I expect only the images.
for image in result.take(1):
print(image)
I hope that using the above code you resolve your issue and that this answer serves you well.

Handling larger tensorflow dataset

I am relatively new to Tensorflow and have been putting together some model training based on the tutorial I found on the ts website. I have been able to put together something functional that satisfies my preliminary requirements.
I am reading locally a csv files that provides some links towards images associated with labels written on the same csv row. My code roughly look like that:
def map_func(*row):
img = process_img(img_filename)
output = read(row)
return img, output
dataset = tf.data.experimental.CsvDataset(CSV_FILE, default_format, header=True)
dataset = dataset.map(map_func)
dataset = dataset.shuffle(buffer_size=shuffle_buffer_size)
dataset = dataset.batch(NB_IMG)
dataset = dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
X, y = next(iter(dataset))
X_train, X_test = tf.split(X, split, axis=0)
y_train, y_test = tf.split(y, split, axis=0)
model = create_model()
model.compile(optimizer=OPTIMIZER, loss='mse')
model.fit(x=X_train, y=y_train, epochs=EPOCHS, validation_data=(X_test, y_test))
NB_IMG is the total number of images I have. EPOCHS is here arbitrary fixed to a given value (in general 20 or 40) and the split is a ratio applied on NB_IMG.
All my images are locally on my computer and with that code my GPU currently can manage up to 50000 images roughly. The training is failing with more images (GPU exhausted). I can understand that is due to the fact that I am reading the data all at once, but I am bit blocked to take the next step here to be able to manage a bigger dataset.
This part below is the one that need improvement I guess:
X, y = next(iter(dataset))
Could someone here help me to move forward and guide me towards some examples or snippets where I can train the model on a bigger dataset? I am a bit lost here for the next move and not sure where to focus in the ts documentation. I did not really find a clear example online that would suit my needs. How should I loop on different batches? How is coded the iterator?
Thanks!
Well, can you give more details about the two functions process_img and read?
During my experiments, I have noticed that the shuffle function can be slow when you have a lot of data and the buffer size is big. Try to comment that line and check if it runs faster. If so, you can use pandas to load your CSV file and then shuffle it and use tf.data.Dataset.from_tensor_slices
Tensorflow has a great tool now to profile models and the dataset pipeline (https://www.tensorflow.org/tensorboard/tensorboard_profiling_keras).
process_img and read are very simple functions:
def process_img(filename):
img = tf.io.read_file(filename)
return tf.image.decode_jpeg(img, channels=3)
def read(row):
return row[1]
The shuffle part of my code is slow but does not seem to be the cause of failure, I can remove it and shuffle the data directly from the csv. It seems to fail at the X, y = next(iter(dataset)) line if the dataset is too big
Thanks for your suggestions to profile the code, I will give it a go. Is there any other possible approach to split and iterate among the dataset?

Convolutional neural network Newbie

I am new to CNN so I am trying to learn to code it with python by following tutorials online, and I came up to this tutorial: https://medium.com/nybles/create-your-first-image-recognition-classifier-using-cnn-keras-and-tensorflow-backend-6eaab98d14dd
I followed the code and all but I get this small error that I can't seem to know the solution:
FileNotFoundError: [Errno 2] No such file or directory: 'random.jpg'
This is the code where the error points out to:
import numpy as np
from keras.preprocessing import image
test_image = image.load_img('random.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] >= 0.5:
prediction = 'dog'
else:
prediction = 'cat'
print(prediction)
I'm going to include the whole code just in case people want to see: https://drive.google.com/open?id=1ew22sJOvl5Ea9VTM_PXqVKNZJm1OuXTG
Any help is appreciated. :)
You need to give full path to the image or put code file and the image to the same file.
Based on what I read on the blog post, he used just a random dog image (downloaded from any web), name it as "random.jpg", and use it as a test image. You can just seek for any dog/cat image around the web, download and rename it as "random.jpg".
The point is, you know the image is a dog or cat, then test your model to predict what image it is.
You need to put 'random.jpg' into your working directory. That is put any file( a dog, cat, or any) with that name inside your folder :)

Categories

Resources