Question: I am working on Image Binarization using UNet and have a dataset of 150 images and their binarized versions too. My idea is to augment the images randomly to make them look like they are differentso I have made a function which inserts any of the 4-5 types of Noises, skewness, shearing and so on to an image. I could have easily used ImageDataGenerator(preprocess_function=my_aug_function) to augment the images but the problem is that my y target is also an image. Also, I could have used something like: train_dataset = ( train_dataset.map( encode_single_sample, num_parallel_calls=tf.data.experimental.AUTOTUNE ) .batch(batch_size) .prefetch(buffer_size=tf.data.experimental.AUTOTUNE) )  But it has 2 problems:  With larger dataset, it'll blow up the memory as data needs to be already in the memory This is the crucial part that I need to augment the images on the go to make it look like I have a huge dataset.  Another Solution could be saving augmented images to a directory and making them 30-40K and then loading them. It would be silly thing to do. Now the idea part is that I can use Sequence as the parent class but How can I keep on augmenting and generating new images on the fly with respective Y binarized images? I have an idea as the below code. Can somebody help me with the augmentation and generation of y images. I have my X_DIR, Y_DIR where image names for binarised and original are same but stored in different directories. class DataGenerator(tensorflow.keras.utils.Sequence): def __init__(self, files_path, labels_path, batch_size=32, shuffle=True, random_state=42): 'Initialization' self.files = files_path self.labels = labels_path self.batch_size = batch_size self.shuffle = shuffle self.random_state = random_state self.on_epoch_end() def on_epoch_end(self): 'Updates indexes after each epoch' # Shuffle the data here def __len__(self): return int(np.floor(len(self.files) / self.batch_size)) def __getitem__(self, index): # What do I do here? def __data_generation(self, files): # I think this is responsible for Augmentation but no idea how should I implement it and how does it works. 

Answer: Custom Image Data Generator load Directory data into dataframe for CustomDataGenerator def data_to_df(data_dir, subset=None, validation_split=None): df = pd.DataFrame() filenames = [] labels = [] for dataset in os.listdir(data_dir): img_list = os.listdir(os.path.join(data_dir, dataset)) label = name_to_idx[dataset] for image in img_list: filenames.append(os.path.join(data_dir, dataset, image)) labels.append(label) df["filenames"] = filenames df["labels"] = labels if subset == "train": split_indexes = int(len(df) * validation_split) train_df = df[split_indexes:] val_df = df[:split_indexes] return train_df, val_df return df train_df, val_df = data_to_df(train_dir, subset="train", validation_split=0.2)  Custom Data Generator  import tensorflow as tf from PIL import Image import numpy as np class CustomDataGenerator(tf.keras.utils.Sequence): ''' Custom DataGenerator to load img Arguments: data_frame = pandas data frame in filenames and labels format batch_size = divide data in batches shuffle = shuffle data before loading img_shape = image shape in (h, w, d) format augmentation = data augmentation to make model rebust to overfitting Output: Img: numpy array of image label : output label for image ''' def __init__(self, data_frame, batch_size=10, img_shape=None, augmentation=True, num_classes=None): self.data_frame = data_frame self.train_len = len(data_frame) self.batch_size = batch_size self.img_shape = img_shape self.num_classes = num_classes print(f"Found {self.data_frame.shape[0]} images belonging to {self.num_classes} classes") def __len__(self): ''' return total number of batches ''' self.data_frame = shuffle(self.data_frame) return math.ceil(self.train_len/self.batch_size) def on_epoch_end(self): ''' shuffle data after every epoch ''' # fix on epoch end it's not working, adding shuffle in len for alternative pass def __data_augmentation(self, img): ''' function for apply some data augmentation ''' img = tf.keras.preprocessing.image.random_shift(img, 0.2, 0.3) img = tf.image.random_flip_left_right(img) img = tf.image.random_flip_up_down(img) return img def __get_image(self, file_id): """ open image with file_id path and apply data augmentation """ img = np.asarray(Image.open(file_id)) img = np.resize(img, self.img_shape) img = self.__data_augmentation(img) img = preprocess_input(img) return img def __get_label(self, label_id): """ uncomment the below line to convert label into categorical format """ #label_id = tf.keras.utils.to_categorical(label_id, num_classes) return label_id def __getitem__(self, idx): batch_x = self.data_frame["filenames"][idx * self.batch_size:(idx + 1) * self.batch_size] batch_y = self.data_frame["labels"][idx * self.batch_size:(idx + 1) * self.batch_size] # read your data here using the batch lists, batch_x and batch_y x = [self.__get_image(file_id) for file_id in batch_x] y = [self.__get_label(label_id) for label_id in batch_y] return tf.convert_to_tensor(x), tf.convert_to_tensor(y)