A Quick and Simple Guide to TFRecord
By: Renu Khandelwal
Tags: Image Processing, Tfrecord, Tensorflow2, Protobuf, Deep Learning

A Quick and Simple Guide to TFRecord

In this post, you will learn the basics of TFRecord, benefits of using TFRecord. How to create a TFRecord file for an image dataset to train a deep learning model.

Photo by Anthony Martino on Unsplash

What is TFRecord?

TFRecord format stores structured data in a simple protocol buffer message format as a sequence of binary records for effiecient serialization

TFRecord uses tf.train.Example to create the protocol buffer(protobuf) message format that is represented by {“string”: value} where value is generated using tf.train.Feature.

Representation then is {“string”: tf.train.Feature}

tf.train.Feature accepts three different message type

tf.train.BytesList — used for images and strings tf.train.FloatList- used for float and double data tf.train.Int64List — used for interger values, booleans and enums

A simple example of the TFRecord using tf.train.Feature

feature

{

key: "label"

value

{

int64_list

{value: 1 }

}

}

What are the benefits of using TFRecord?

Reduced training time as the data is stored in the binary message format

as the data is stored in the binary message format Efficient memory usage as you need not load the entire dataset in the memory but only load a specified batch of records

as you need not load the entire dataset in the memory but only load a specified batch of records Allows easy experimentation as TFRecord files contain preprocessed data, so you can use them with different model architecture to figure the best model as part of the experimentation process

Create TFRecord file for an image dataset

To create a TFRecord file for an image dataset, follow the steps mentioned below

Convert Image data and target labels to bytes and int64 Transform the converted data to tf.train.feature message format Create a protobuf message using tf.train.Example Serialize protobuf message using serialize() function Use tf.io.TFRecordWriter to open the TFRecord file and start writing the serialized protobuf messages for the images and label after applying image preprocessing.

We will create TFRecord for a Dogs vs cats dataset

# Importing required libraries

import tensorflow as tf

config = tf.compat.v1.ConfigProto()

config.gpu_options.allow_growth = True

sess = tf.compat.v1.Session(config=config)

import numpy as np

import os

from PIL import Image

import random # Setup the train and test imgae directories

train_dir=r'\dogs-vs-cats\train_data'

test_dir=r'\dogs-vs-cats\validation_data' #Setting up Image dimension

IMG_HEIGHT=100

IMG_WIDTH=100 # setup train and test TFRecord file

train_tfrecord='train_data.tfrecords'

test_tfrecord = 'test_data.tfrecords' # Define the classes

classes=['cat', 'dog'] #List all train and test image path

train_image_path=[]

test_image_path=[]

for i in range(len(classes)):

for file in os.listdir(os.path.join(train_dir,classes[i])):

train_image_path.append(os.path.join(train_dir, classes[i],file)) for file in os.listdir(os.path.join(test_dir,classes[i])):



test_image_path.append( os.path.join(test_dir, classes[i],file) ) #Shuffle the image paths for better accuracy and precision

random.seed(0)

random.shuffle(train_image_path)

random.shuffle(test_image_path) # create train and test lables for shuffled image paths

test_labels=[]

train_labels=[]

for i in range(len(train_image_path)):



if os.path.basename(train_image_path[i])[:3]=='cat':

train_labels.append(0)

else:

train_labels.append(1)

for i in range(len(test_image_path)):



if os.path.basename(test_image_path[i])[:3]=='cat':

test_labels.append(0)

else:

test_labels.append(1)

Convert Image data and target labels to bytes and int64

Following function converts a data element value to a compatible type for tf.train.Example

def _bytes_feature(value):

"""Returns a bytes_list from a string / byte."""

if isinstance(value, type(tf.constant(0))):

value = value.numpy()

return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def _float_feature(value):

"""Returns a float_list from a float / double."""

return tf.train.Feature(float_list=tf.train.FloatList(value=[value])) def _int64_feature(value):

"""Returns an int64_list from a bool / enum / int / uint."""

return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

Store all features, images, and target labels in the tf.train.Example protobuf message, serialize the message and return it as a string

def serialize_example(image, label):

## Create a dictionary with features for images and their target labels

feature = {

'image': _bytes_feature(image),

'label': _int64_feature(label),



}

# Create a Features message using tf.train.Example.

example_proto = tf.train.Example(features=tf.train.Features(feature=feature))

#serializes the message and returns it as a string. Note that the bytes are binary

return example_proto.SerializeToString()

Apply the image preprocessing, write the serialized protobuf message to the TFRecord file

def write_TFRecord(image_path, label):

img=tf.keras.preprocessing.image.load_img(image_path, target_size=(IMG_HEIGHT, IMG_WIDTH))

img_array= tf.keras.preprocessing.image.img_to_array(img)

img_bytes= tf.io.serialize_tensor(img_array)

example= serialize_example(img_bytes, label)

return example #Write Train TFRecord file

with tf.io.TFRecordWriter(train_tfrecord) as writer:

for image_path, label in zip(train_image_path, train_labels):

writer.write(write_TFRecord(image_path, int(label))) #Write Test TFRecord file

with tf.io.TFRecordWriter(test_tfrecord) as writer:

for image_path, label in zip(test_image_path, test_labels):

writer.write(write_TFRecord(image_path, int(label)))

Train the deep learning model

Create the train and test dataset by iterating over all the records in the TFRecord files.

Initialize TFRecordDataset for the TFRecord file

#Initilizaing the TFRecordDataset for train and test TFRecord file

train_tfrecord_dataset=tf.data.TFRecordDataset(train_tfrecord)

test_tfrecord_dataset=tf.data.TFRecordDataset(test_tfrecord)

Create the feature dictionary describing the features. This should match with the feature names used while writing the data to the TFRecord file.

Extract the dictionary object using parse_single_example for each of the data records.

for each of the data records. Parse the image feature to a tensor and reshape based on the model input

def read_tfrecord(serialized_example):

feature_description={

'image': tf.io.FixedLenFeature((), tf.string),

'label':tf.io.FixedLenFeature((), tf.int64)

}

example= tf.io.parse_single_example(serialized_example, feature_description)

image=tf.io.parse_tensor(example['image'], out_type=float)

image = tf.reshape(image, [IMG_HEIGHT, IMG_WIDTH,3])



return image, example['label']

Extract the various features present in the TFRecord

train_dataset=train_tfrecord_dataset.map(read_tfrecord)

test_dataset=test_tfrecord_dataset.map(read_tfrecord)

Create the input pipeline

Prefetch, shuffle create a batch of records from the training dataset but skip shuffling for the test dataset.

train_dataset = train_dataset.prefetch(tf.data.experimental.AUTOTUNE)

train_dataset = train_dataset.shuffle(True)

train_dataset = train_dataset.batch(10) test_dataset = test_dataset.prefetch(tf.data.experimental.AUTOTUNE)test_dataset = test_dataset.batch(10)

Using a transfer learned deep learning model

def make_model():



base_model = tf.keras.applications.Xception(

input_shape=(IMG_WIDTH, IMG_HEIGHT, 3), include_top=False, weights=”imagenet”

) base_model.trainable = False inputs = tf.keras.layers.Input([IMG_WIDTH, IMG_HEIGHT, 3])

x = tf.keras.applications.xception.preprocess_input(inputs)

x = base_model(x)

x = tf.keras.layers.GlobalAveragePooling2D()(x)

x = tf.keras.layers.Dense(8, activation=”relu”)(x)

x = tf.keras.layers.Dropout(0.7)(x)

outputs = tf.keras.layers.Dense(1, activation=”sigmoid”)(x) model = tf.keras.Model(inputs=inputs, outputs=outputs) model.compile(

optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),

loss=”binary_crossentropy”,

metrics=tf.keras.metrics.AUC(name=”auc”),

) return model lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(

0.001, decay_steps=20, decay_rate=0.96, staircase=True

) checkpoint_cb = tf.keras.callbacks.ModelCheckpoint(

"model_cat_n_dog.h5", save_best_only=True

)

model=make_model() # Train the model on data extrcated from TFRecord file



history = model.fit(

train_dataset,

epochs=20,

validation_data=test_dataset,

callbacks=[checkpoint_cb]

)

with 20 epochs, we get a validation accuracy of 96.95%

Conclusion

TFRecord stores structured data in a simple protobuf file as a sequence of binary records for efficient serialization, which increases the performance while training a deep learning model. It also loads only the batched number of records in the memory and allows for quick experimentation to deliver a model with high accuracy and precision

References

https://www.tensorflow.org/tutorials/load_data/tfrecord#read_the_tfrecord_file