history_callback = keras.callbacks.LambdaCallback(
    on_epoch_end=lambda epoch, logs: write_row(history_path, epoch, logs))

callbacks = [checkpoint, history_callback]

if lr_annealing:
    reduce_lr = keras.callbacks.ReduceLROnPlateau()
    callbacks.append(reduce_lr)

print("Loading validation data.")
# Load validation data once to save on IO costs
validation_data = localmodule.get_validation_data(valid_hdf5_dir,
                                                  n_input_hops,
                                                  valid_batch_size,
                                                  validation_steps,
                                                  tfr_str=tfr_str,
                                                  structured=False,
                                                  label_inputs=False,
                                                  single_output="coarse")

print("Performing rejection sampling for initialization.")
# Rejection sampling for best initialization.
n_inits = 10
for init_id in range(n_inits):
    model = keras.models.Model(inputs=inputs, outputs=outputs)
    model.compile(loss='binary_crossentropy',
                  optimizer=Adam(lr),
                  metrics=["accuracy"])

    training_streamer = localmodule.multiplex_tfr(
        train_data_dir,
    "y_medium": [categorical_accuracy],
    "y_fine": [categorical_accuracy]
}

loss_weights = {
    "y_coarse": loss_weight_coarse,
    "y_medium": loss_weight_medium,
    "y_fine": 1.0
}

print("Loading validation data.")
# Load validation data once to save on IO costs
validation_data = localmodule.get_validation_data(valid_hdf5_dir,
                                                  n_input_hops,
                                                  valid_batch_size,
                                                  validation_steps,
                                                  tfr_str=tfr_str,
                                                  structured=True,
                                                  label_inputs=False)

print("Performing rejection sampling for initialization.")
# Rejection sampling for best initialization.
n_inits = 10
for init_id in range(n_inits):
    model = keras.models.Model(inputs=inputs, outputs=outputs)
    model.compile(loss=losses,
                  loss_weights=loss_weights,
                  optimizer=Adam(lr),
                  metrics=metrics)

    training_streamer = localmodule.multiplex_tfr(