Why You Should Be Using Pandas Dataframes for Keras Trainings on Image Classification Problems  | Towards Data Science

As seen in my previous article, research projects can be arduous with a lack of organization. So many resources around, that sometimes slow down the process of researching.
In this article, I am going to focused on datasets that are composed of images, especially those for Image Classification problems. We are going to see how launching Keras trainings on this kind of datasets has some advantages when using Pandas dataframes.
Keras provides a way to use large datasets when working with neural networks: either in the training or evaluation stage. This is the Keras preprocessing module, which has several methods to load data from disk and dynamically pre-process it. The most common method is flow_from_directory(), which is a very simple workflow since you just have to separate your image files into folders for each class. The generator will take each folder as the classes to be trained. This is pretty simple, yes, but it involves having to develop time-consuming scripts to copy or move images from one side to another for each training dataset version.
But, what if you decide to make some modifications for a specific experiment such as dividing one class into two? — Dataset versioning
What if you want to compose a dataset with images that come from two or more datasets? — Combination of multiple datasets
What if you want to train two labels at the same time because your network model has two outputs? — Multi-task problems
We will see how using Pandas library will help relieve these problems.
Keras has a generator function that is meant to use a Pandas dataframe to load data from disk: flow_from_dataframe(). This dataframe must have a column where you specify the image filename for each item. With this and the directory parameter, Keras will compose the path for each image file in the following way:os.path.join(directory, <filename_column>)At this point, you can forget the idea of having the files organized in folders of classes, and instead, you can just have them all in the same folder.
Each of the following sections attempts to answer one of the three previous questions by using thisflow_from_dataframe() method.
My workflow when working with datasets is that I manually create a versioning control system: each version is the result of any modification I make for a particular experiment: adding additional data, modifications to the labels, corrections, etc.
This results in having different dataset versions that are more clearly represented by dataframes, instead of having to create a separate folder where the images are copied to with a new class-structure. The most powerful thing about this is that the large-size files (the images) are still in the same directory. Therefore, you can have several dataset versions (csv files) composed of different combinations of the same images.
As I mentioned before, Keras composes the path of the images to be read by using the directory parameter and filename column. The latest must have the file name but it may contain sub-paths too. Keras will perform the join without asking if there is only a filename. This is very powerful for datasets that you download online and have a particular structure in which images are located in different subdirectories. Furthermore, with this, we can easily compose a dataset version where there are images that come from different sources, without having to move them to the same folder.
Let’s see an example:
Suppose you have dataset 1 and dataset 2 with the following image paths:
/media/datasets/dataset_1/train/image_1.png/media/datasets/dataset_1/train/image_2.png/media/datasets/dataset_2/train/0289323/image_1.png/media/datasets/dataset_2/train/3453453/image_1.png
Dataset 1 has a structure where all images are under the same directory: dataset_1/train/*. However, dataset 2 is different, it has subfolders and the image filename itself is repeated (“image_1.png”), so we need to add this subfolder to the filename column. These would be the two dataframes and their corresponding Keras method calls:
To create a merged version (dataset 3) we just need to add the path from where both paths become different: “dataset_1/” and “dataset_2/”.
For this example, we have to set the directory parameter in flow_from_dataframe() to the common path, in order for Keras to be able to compose paths that work for both datasets.
One thing I suggest here is to create a folder, for instance, dataset_3, with symlinks to both datasets:
~/datasets $ mkdir dataset_3~/datasets $ cd dataset_3~/datasets/dataset_3 $ ln -s ~/datasets/dataset_1/train dataset_1~/datasets/dataset_3 $ ln -s ~/datasets/dataset_2/train dataset_2~/datasets/dataset_3 $ ls -ldataset_1 -> /home/sruiz/datasets/dataset_1/traindataset_2 -> /home/sruiz/datasets/dataset_2/train
This is just for organization purposes since the base path where both datasets differ would be: /home/datasets/dataset_3 instead of the more general one: /home/datasets. But, it could also be very useful if datasets are located in different places and they don’t share any base path — and you don’t want to move them.
In one task using dataframes is unnegotiable is when training a multi-task problem. This refers to networks models that can predict multiple outputs for one input: for instance, if an image has a cat or a dog and the color of its skin.
For this kind of problems, we need two labels for each input in the training step. So the approach of separating the files into folders for each label, though it is possible, involves having one folder for each label combination. Something it could result in creating a great number of folders.
The good thing of a dataframe is that you can have a column for label cat/dog and another one for the skin color. When using the flow_from_dataframe() method with your two-output network, you just need to specify in the y_col parameter in which columns are the labels:
Thanks for reading.
Sergio Ruiz (@serchu)