How to write a generator for keras fit_generator?
Ill supply two tutorials I used when I first started using fit_generator. That being said the first thing to remember is that a generator is essentially like any other function your write that returns something with the exception is that the function runs a continuous loop that is designed not to exit. For example, in a normal function, you would use return to return some chunk of data every time that function is called. In a generator, the function returns data in chunks continuously until there is no data to return. This is what the yield statement does. On my project, I have a couple of terabytes of signal data. Even on a powerful server that is a little bit too much data for hardware I use. So the generator function serves up chunks of data in batches, it can be run in parallel as well to increase speed. This approach also greatly reduces your memory usage and usually, your system's memory will hit some point and not really change until all data has been fed to the DNN. I apologize for the poor explanation but I am pretty new to this as well :-) I am sure someone else will provide a better answer but this should get you started.     

Here is one good tutorial https://www.pyimagesearch.com/2018/12/24/how-to-use-keras-fit-and-fit_generator-a-hands-on-tutorial/

and a very short one https://medium.com/@fromtheast/implement-fit-generator-in-keras-61aa2786ce98

also, look at the docs
https://keras.io/models/sequential/

and finally here is one I use on a current project. It is not very pretty but it works well

def batch_generator(X_train, Y_train):  

    while True:
         # samples_counter = 0
        for fl, lb in zip(X_train, Y_train):
            sam, lam = get_IQsamples(fl, lb)
            max_iter = sam.shape[0]
            sample = []  # store all the generated data batches
            label = [] # store all the generated label batches
            i = 0
            for d, l in zip(sam, lam):
                sample.append(d)
                label.append(l)
                i += 1
                if i == max_iter:
                    break
            sample = np.asarray(sample)        
            label = np.asarray(label)
            yield sample, label