There are several methods of reading image data in TensorFlow as mentioned in its documentation:

From disk: Using the typical feed_dict argument when running a session for the train_op. However, this is not always possible if your dataset is too large to be held in your GPU memory for it to be trained.

From CSV Files: Not as relevant for dealing with images.

From TFRecord files: This is done by first converting images that are already properly arranged in sub-directories according to their classes into a readable format for TensorFlow, so that you don’t have to read in raw images in real-time as you train. This is much faster than reading images from disk.

While the creation of TFRecord files may not be intuitive, and indeed, less straightforward than simply reading data in HDF5 format (as used in Keras), using this supported native format for TensorFlow gives you greater access to the data pipeline tools you can use to train your images in batches - think of queue runners, coordinators and supervisors that can help you manage your data flow. In this guide, I will focus on a less painful way of writing and reading TFRecord files using TensorFlow-slim instead of pure TensorFlow. To put the guide into concrete practice, we will use the standard Flowers dataset from TensorFlow.

Note: A side benefit of using TensorFlow-slim is that is you could use the official pre-trained models - including the inception-resnet-v2 model - from Google for performing transfer learning. I find this as the main advantage TF-slim has over Keras.

Downloading the Dataset

Arranging your data according to classes

Write a simple script that arranges your examples into subdirectories, where each subdirectory represents the class of the examples. For the Flowers dataset, this has already been done for you. you should be able to see that your data is arranged into the following structure:

Note: Your dataset directory will be path/to/flowers and not path/to/flowers/flower_photos. Make sure you do not have any other folders beyond flower_photos in the flowers root directory!

Writing a TFRecord File

Due to the low-level nature of TensorFlow, it is hard to write all the code from scratch in order to just prepare a dataset. In fact, we do not have to reinvent the wheel as TF-Slim has already most of the code available for writing TFRecord files. I have compiled all the necessary functions into a dataset_utils.py file that we will import our dataset functions from to create the TFRecord file. The functions in dataset_utils.py are quite general and could be used for other datasets with JPEG images.

Note: If your images are in PNG format, then you would have to go to dataset_utils.py to change all the JPEG decoding to PNG decoding. The change is as straightforward as changing the ‘jpeg’ and ‘jpg’ characters to ‘png’.

flags = tf.app.flags
#State your dataset directory
flags.DEFINE_string('dataset_dir', None, 'String: Your dataset directory')
# Proportion of dataset to be used for evaluation
flags.DEFINE_float('validation_size', 0.3, 'Float: The proportion of examples in the dataset to be used for validation')
# The number of shards to split the dataset into.
flags.DEFINE_integer('num_shards', 2, 'Int: Number of shards to split the TFRecord files into')
# Seed for repeatability.
flags.DEFINE_integer('random_seed', 0, 'Int: Random seed to use for repeatability.')
#Output filename for the naming the TFRecord file
flags.DEFINE_string('tfrecord_filename', None, 'String: The output filename to name your TFRecord file')
FLAGS = flags.FLAGS

Now we can proceed with writing the TFRecord file. We will need to use _get_filename_and_classes to return us a list of photo_filenames that contains strings of individual filenames and a list of sorted class_names that contains actual class names like ‘daisy’ and ‘roses’. But we can’t actually use strings as the class labels, so we proceed to create a dictionary to refers each class name to a label in class_names_to_ids. Here, we will realize how important it is to actually have your class_names sorted, otherwise you will always end up with different labels for each class.

In essence, what happens in the function _convert_dataset is that it searches the images one by one in the training_filenames or validation_filenames, read the image in byte form, find the height, width and class label of this image, before converting all the image data and its information (height, width, label) into a TFexample that could be encoded into the TFRecord file. This TFexample is then written down officially into a TFRecord. Most of the magic happens in the following code of _convert_dataset:

Note: To quickly verify whether your dataset is prepared correctly, you should see that the total size of your TFRecord files should have a similar (or slightly larger) size than the size of your entire dataset.

Conclusion

To sum it up, we’ve packaged all the required (and ugly) functions that we need to create TFRecord files into dataset_utils.py before actually starting to write one through a main script. This two files are what I usually use to prepare TFRecord files in a faster way, since I would only have to change certain arguments to prepare a dataset quickly. Certainly, for greater customization, you should look into the source code I provided in GitHub (see below). Unfortunately, I have not seen a fast way to create TFRecord files in a few lines or so, hence for now I’ll just stick to using these two files!

I hope this guide has been useful to you!

Source Code

Download the zip file from the official GitHub repository or by cloning:

$ git clone https://github.com/kwotsin/create_tfrecords.git

Credits

Credits to authors of TF-slim who have contributed this wonderful library for use by many people! A large part of this post was inspired by their source code, and I highly recommend you to carefully study related material offered by them - after all, they are few of the best engineers in the world!