How to use Keras ImageDataGenerator while reading ground truth from CSV file

Viewed 757

I'm trying to load ISIC 2019 dataset using Keras (version: 2.5.0) to later be fed to a CNN model. Basically, I would use keras.preprocessing.image.ImageDataGenerator() and flow_from_directory() to load and augment my image dataset. Here's an example:

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1./255)
train_set = train_datagen.flow_from_directory(path_to_training_subdir,
                                              target_size=(224, 224),
                                              batch_size=20,
                                              class_mode='categorical',
                                              subset='training')

Everything works fine as long as the directory of my dataset is structured like this:

main_directory/
...class_a/
......a_image_1.jpg
......a_image_2.jpg
...class_b/
......b_image_1.jpg
......b_image_2.jpg

However, some datasets (such as ISIC 2019) take another approach: putting all images in a single directory and attaching a CSV file which contains the title of each image and its corresponding label. In this case:

image,MEL,NV,BCC,AK,BKL,DF,VASC,SCC,UNK
ISIC_0000000,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
ISIC_0000001,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
...

Since I'm new to Keras, I have no idea how to use ImageDataGenerator() in such situation. The only way I can think of is writing some sort of script to distribute all samples among multiple subdirectories corresponding to class labels and actually building the desired directory structure before passing it to flow_from_directory(), but I know no efficient way to do that either.

I was wondering if Keras itself features a specific function for this matter, or if there's any library to help restructuring the dataset based on a CSV file to be compatible with Keras.

2 Answers

There is another function flow_from_dataframe() with the same functionality as flow_from_directory() which provides for you reading from CSV instead from a structured directory.

Here is an example:

from tensorflow.keras.preprocessing.image import ImageDataGenerator
import pandas as pd

df = pd.read_csv("ISIC.csv")
# merge all classes into one column 
df["labels"] = df[["MEL","NV","BCC","AK","BKL","DF","VASC","SCC","UNK"]].values.tolist()
# if your image names have no extension
df['image'] = df['image'].astype(str) + '.jpg' 

train_datagen = ImageDataGenerator(rescale=1./255)
train_set = train_datagen.flow_from_dataframe(df,
                                              directory="./isic_images",
                                              x_col="image",
                                              y_col="labels",
                                              target_size=(224, 224),
                                              batch_size=32,
                                              class_mode='categorical',
                                              )

I would suggest you should create a Data Generator. Refer to the example here

https://www.tensorflow.org/api_docs/python/tf/keras/utils/Sequence

What you need is a class that inherits tensorflow.keras.utils.Sequence. Then implement the len and getitem methods. You can then use this object of this class as generator in the model.fit and model.evaluate functions.

Related