def train(self):
        if self.find_lr == True:
            # Navigate to output folder in parent directory
            go_up_three_dirs()        

            # Plot learning rate finder plot
            self.lr_finder.plot_loss(
                "output/lr_finder_plot_A1.png")
                
        else:
            # Plot training loss accuracy and learning rate change
            # Navigate to output folder in parent directory
            go_up_three_dirs()

            plot_train_loss_acc_lr(
                self.history,
                int(self.epochs/2),
                self.schedule,
                self.schedule_type,
                "A1",
                "output/train_loss_acc_A1_xception.png",
                "output/lr_A1_xception.png")

            # Get the training accuracy
            training_accuracy = self.history.history['val_acc'][-1]
            return training_accuracy
    def train(self):
        if self.find_lr == True:
            # Navigate to output folder in parent directory
            go_up_three_dirs()        

            print("[INFO] Creating learning rate finder plot...")
            # Plot learning rate finder plot
            self.lr_finder.plot_loss(
                "output/lr_finder_plot_B2.png")
        else:
            # Plot training loss accuracy and learning rate change
            # Navigate to output folder in parent directory
            go_up_three_dirs()

            plot_train_loss_acc_lr(
                self.history,
                self.epochs,
                self.schedule,
                self.schedule_type,
                "B2",
                "output/train_loss_acc_B2_cnn.png",
                "output/lr_B2_cnn.png")

            # Get the training accuracy
            training_accuracy = self.history.history['val_acc'][-1]
            return training_accuracy
def train_frozen_xception(height, width, num_classes, batch_size, epochs,
                          learning_rate, schedule_type, train_gen, val_gen,
                          frozen_model_path, frozen_training_plot_path,
                          frozen_training_plot_name):

    # Store the number of epochs to train for in a convenience variable,
    # then initialize the list of callbacks and learning rate scheduler
    # to be used
    callbacks = []
    schedule = None

    # check to see if step-based learning rate decay should be used
    if schedule_type == "step":
        print("[INFO] using 'step-based' learning rate decay...")
        schedule = StepDecay(initAlpha=1e-1,
                             factor=0.25,
                             dropEvery=int(epochs / 5))

    # check to see if linear learning rate decay should should be used
    elif schedule_type == "linear":
        print("[INFO] using 'linear' learning rate decay...")
        schedule = PolynomialDecay(maxEpochs=epochs, initAlpha=1e-1, power=1)

    # check to see if a polynomial learning rate decay should be used
    elif schedule_type == "poly":
        print("[INFO] using 'polynomial' learning rate decay...")
        schedule = PolynomialDecay(maxEpochs=epochs, initAlpha=1e-1, power=5)

    elif schedule_type == "one_cycle":
        print("[INFO] using 'one cycle' learning...")
        schedule = OneCycleScheduler(learning_rate)
        callbacks = [schedule]

    # if the learning rate schedule is not empty, add it to the list of
    # callbacks
    if schedule_type != "none" and schedule_type != "one_cycle":
        callbacks = [LearningRateScheduler(schedule)]

    # initialize the decay for the optimizer
    decay = 0.0

    # if we are using Keras' "standard" decay, then we need to set the
    # decay parameter
    if schedule_type == "standard":
        print("[INFO] using 'keras standard' learning rate decay...")
        decay = 1e-1 / epochs

    # otherwise, no learning rate schedule is being used
    elif schedule_type == "none":
        print("[INFO] no learning rate schedule being used")

    # Xception is used as the base architecture for the model.
    # The top layers are not included in order to perform transfer learning.
    # Modified to allow for a custom input size
    base_model = Xception(weights="imagenet",
                          include_top=False,
                          input_shape=(height, width, 3))

    # Implement own pooling layer
    avg = GlobalAveragePooling2D()(base_model.output)

    # Output layer
    output = Dense(num_classes, activation="softmax")(avg)

    # Build model
    frozen_model = Model(inputs=base_model.input, outputs=output)

    # First, we freeze the layers for the first part of the training
    for layer in base_model.layers:
        layer.trainable = False

    if schedule_type != "one_cycle":
        # initialize optimizer and model, then compile it
        opt = SGD(lr=learning_rate, momentum=0.9, decay=decay)
    else:
        opt = SGD()

    # We now compile the Xception model for the first stage
    frozen_model.compile(loss="sparse_categorical_crossentropy",
                         optimizer=opt,
                         metrics=["accuracy"])

    # Training and evaluating the Xception model for the first stage
    history = frozen_model.fit(train_gen,
                               steps_per_epoch=train_gen.samples // batch_size,
                               validation_data=val_gen,
                               validation_steps=val_gen.samples // batch_size,
                               callbacks=callbacks,
                               epochs=int(epochs / 2))

    # Plot training plot for the frozen model
    plot_train_loss_acc_lr(history, int(epochs / 2), schedule, "none",
                           frozen_training_plot_name,
                           frozen_training_plot_path, None)

    # Save model
    frozen_model.save(frozen_model_path)