def load_and_evaluate(
        filepath="model_simple_finetuning/cnn_model.ft.final.hdf5"):
    """
    Load and evaluate a model at the given file path.

    Args:
      filepath: The model filepath. (Default value = "model_simple_finetuning/cnn_model.ft.final.hdf5")

    Returns:
        None

    """
    model = models.load_model(filepath)
    concat_machine, concat_hand, concat_out, real_training, real_validation = load_datasets(
        TRANSFORMED_DATASET_NAMES)

    test_generator = SimpleDataGenerator(real_validation.test,
                                         batch_size=64,
                                         shuffle=False,
                                         to_simple_digit=True)

    evaluate(model, test_generator)
Example #2
0
def train_binary_model(path,
                       epochs=100,
                       ft_epochs=100,
                       learning_rate=0.01,
                       classes_to_match: Union[int, List[int]] = 0,
                       classes_to_drop: Union[int, List[int]] = None):
    """
    Train a smaller binary model for empty/not empty classification and save it under the given path. The method first
    loads the models using :py:doc:`generate_datasets.py <training.generate_datasets.py>` methods. Then the model is
    trained, saved and finally evaluated.

    Training is run in two steps: It is first trained with synthetic data and then finetuned with real data. Early
    stopping is used to prevent overfitting.

    Args:
        path(str): The directory to save the trained model to.
        epochs(int): The number of epochs. (Default value = 100)
        ft_epochs: The number of finetuning epochs. (Default value = 100)
        learning_rate: The learning rate for the Adadelta optimizer. (Default value = 0.01)
        classes_to_match(Union[int, list[int]]): The classes to match as class 1. (Default value = 0)
        classes_to_drop(Union[int, list[int]]): The classes to drop from the dataset. (Default value = None)

    Returns:
        None

    """
    os.makedirs(path, exist_ok=True)
    concat_machine, concat_hand, concat_out, real_training, real_validation = load_datasets(
        TRANSFORMED_DATASET_NAMES)

    batch_size = 192
    train_generator = ToBinaryGenerator(concat_machine.train,
                                        concat_hand.train,
                                        concat_out.train,
                                        classes_to_match=classes_to_match,
                                        classes_to_drop=classes_to_drop,
                                        batch_size=batch_size,
                                        shuffle=True,
                                        truncate=True)

    dev_generator = ToBinaryGenerator(concat_machine.test,
                                      concat_hand.test,
                                      concat_out.test,
                                      classes_to_match=classes_to_match,
                                      classes_to_drop=classes_to_drop,
                                      batch_size=batch_size,
                                      shuffle=True,
                                      truncate=True)

    ft_train_generator = ToBinaryGenerator(real_training.train,
                                           classes_to_match=classes_to_match,
                                           classes_to_drop=classes_to_drop,
                                           batch_size=batch_size,
                                           shuffle=True,
                                           truncate=True)

    ft_dev_generator = ToBinaryGenerator(real_training.test,
                                         classes_to_match=classes_to_match,
                                         classes_to_drop=classes_to_drop,
                                         batch_size=batch_size,
                                         shuffle=True,
                                         truncate=True)

    test_generator = ToBinaryGenerator(real_validation.test,
                                       classes_to_match=classes_to_match,
                                       classes_to_drop=classes_to_drop,
                                       batch_size=batch_size,
                                       shuffle=False)

    # Run training on the GPU
    with tf.device('/GPU:0'):
        # Keras Model
        print("Creating model..")
        model = Sequential()
        model.add(Conv2D(16, (5, 5), strides=2, input_shape=(28, 28, 1)))
        model.add(BatchNormalization())
        model.add(Activation('relu'))
        model.add(MaxPooling2D(pool_size=(4, 4)))
        model.add(Conv2D(32, (2, 2)))
        model.add(BatchNormalization())
        model.add(Activation('relu'))
        model.add(MaxPooling2D(pool_size=(2, 2)))
        model.add(Flatten())  # 32
        model.add(Dense(64, activation='relu'))
        model.add(Dropout(0.25))
        model.add(Dense(64, activation='relu'))
        model.add(Dense(1, activation='sigmoid'))

        # def mean_pred(_, y):
        #     return keras.backend.mean(y)

        print("Compiling model..")
        model.compile(
            loss=keras.losses.BinaryCrossentropy(from_logits=True),
            optimizer=keras.optimizers.Adadelta(learning_rate),
            metrics=[keras.metrics.binary_accuracy, 'mse'],
        )
        print(model.summary())

        print("Training model")
        model.fit_generator(train_generator,
                            validation_data=dev_generator,
                            epochs=epochs,
                            callbacks=[
                                EarlyStopping(monitor='val_accuracy',
                                              restore_best_weights=True,
                                              patience=3,
                                              min_delta=0.0001),
                            ])

        print("Finetuning model")
        model.fit_generator(ft_train_generator,
                            validation_data=ft_train_generator,
                            epochs=ft_epochs,
                            callbacks=[
                                EarlyStopping(monitor='val_accuracy',
                                              restore_best_weights=True,
                                              patience=3,
                                              min_delta=0.0001),
                            ])

        models.save_model(model, path + "model.h5", save_format='h5')

        print("Evaluating")
        print(
            "Training dev",
            list(
                zip(model.metrics_names,
                    model.evaluate_generator(dev_generator))))
        print(
            "Finetuning dev",
            list(
                zip(model.metrics_names,
                    model.evaluate_generator(ft_dev_generator))))
        print(
            "Test",
            list(
                zip(model.metrics_names,
                    model.evaluate_generator(test_generator))))
        evaluate(model, test_generator, binary=True)
Example #3
0
            "Test",
            list(
                zip(model.metrics_names,
                    model.evaluate_generator(test_generator))))
        evaluate(model, test_generator, binary=True)


if __name__ == '__main__':
    tf.get_logger().setLevel('ERROR')
    physical_devices = tf.config.list_physical_devices('GPU')
    tf.config.experimental.set_memory_growth(physical_devices[0], True)

    # Train empty vs. not-empty classifier
    train_binary_model("model_empty_finetuning/")

    validation = load_datasets([TRANSFORMED_DATASET_NAMES[-1]])[0]
    test_generator = ToBinaryGenerator(validation.test,
                                       classes_to_match=0,
                                       batch_size=64,
                                       shuffle=False)
    model = models.load_model("model_empty_finetuning/model.h5")
    # evaluate(model, test_generator)
    convert_to_tflite(model,
                      "model_empty_finetuning/",
                      test_generator,
                      binary=True)

    # Train handwritten vs. machine-written classifier
    classes_to_match = list(range(1, 10))
    train_binary_model("model_hand_finetuning/",
                       classes_to_match=classes_to_match)
def train_cnn(path="model/",
              to_simple_digit=False,
              epochs=100,
              ft_epochs=100,
              learning_rate=0.01):
    """
    Train the CNN model and save it under the given path. The method first loads the models using
    :py:doc:`generate_datasets.py <training.generate_datasets.py>` methods. Then the model is trained, saved and finally
    evaluated.

    Training is run in two steps: It is first trained with synthetic data and then finetuned with real data. Early
    stopping is used to prevent overfitting.

    Args:
        path(str): The directory to save the trained model to. (Default value = "model/")
        to_simple_digit(bool): If true, convert the datasets to simple 9 + 1 class digit recognition.
            (Default value = False)
        epochs(int): The number of epochs. (Default value = 100)
        ft_epochs: The number of finetuning epochs. (Default value = 100)
        learning_rate: The learning rate for the Adadelta optimizer. (Default value = 0.01)

    Returns:
        None

    """
    os.makedirs(path, exist_ok=True)

    print("Loading data..")
    concat_machine, concat_hand, concat_out, real_training, real_validation = load_datasets(
        TRANSFORMED_DATASET_NAMES)

    batch_size = 256
    train_generator = SimpleDataGenerator(concat_machine.train,
                                          concat_hand.train,
                                          concat_out.train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          to_simple_digit=to_simple_digit)

    dev_generator = SimpleDataGenerator(concat_machine.test,
                                        concat_hand.test,
                                        concat_out.test,
                                        batch_size=batch_size,
                                        shuffle=True,
                                        to_simple_digit=to_simple_digit)

    ft_train_generator = SimpleDataGenerator(real_training.train,
                                             batch_size=batch_size,
                                             shuffle=True,
                                             to_simple_digit=to_simple_digit)

    ft_dev_generator = SimpleDataGenerator(real_training.test,
                                           batch_size=batch_size,
                                           shuffle=True,
                                           to_simple_digit=to_simple_digit)

    test_generator = SimpleDataGenerator(real_validation.test,
                                         batch_size=batch_size,
                                         shuffle=False,
                                         to_simple_digit=to_simple_digit)

    # Run training on the GPU
    with tf.device('/GPU:0'):
        # Keras Model
        print("Creating model..")
        model = Sequential()
        model.add(layers.InputLayer(input_shape=(28, 28, 1)))
        model.add(layers.Conv2D(16, (3, 3), padding='same'))  # 28x28x16
        model.add(layers.BatchNormalization())
        model.add(layers.Activation('relu'))
        model.add(layers.MaxPooling2D(pool_size=(2, 2)))  # 14x14x16
        model.add(layers.Conv2D(32, (3, 3)))  # 12x12x32
        model.add(layers.BatchNormalization())
        model.add(layers.Activation('relu'))
        model.add(layers.MaxPooling2D(pool_size=(2, 2)))  # 6x6x32
        model.add(layers.Conv2D(64, (3, 3)))  # 4x4x64
        model.add(layers.BatchNormalization())
        model.add(layers.Activation('relu'))
        model.add(layers.MaxPooling2D(pool_size=(2, 2)))  # 2x2x64
        model.add(layers.Conv2D(128, (3, 3), padding='same'))  # 2x2x64
        model.add(layers.BatchNormalization())
        model.add(layers.Activation('relu'))
        model.add(layers.MaxPooling2D(pool_size=(2, 2)))  # 1x1x128
        model.add(layers.Flatten())  # 64
        model.add(layers.Dense(128, activation='relu'))
        model.add(layers.Dropout(0.25))
        model.add(layers.Dense(128, activation='relu'))
        model.add(layers.Dense(train_generator.num_classes))

        # Hyperparameters

        print("Compiling model..")
        model.compile(
            loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
            optimizer=keras.optimizers.Adadelta(learning_rate),
            metrics=['accuracy'])
        print(model.summary())

        print("Training model on")
        model.fit(train_generator,
                  validation_data=dev_generator,
                  epochs=epochs,
                  callbacks=[
                      EarlyStopping(monitor='val_accuracy',
                                    restore_best_weights=True,
                                    patience=3,
                                    min_delta=0.0001),
                  ])

        print("Finetuning model")
        model.fit(ft_train_generator,
                  validation_data=ft_dev_generator,
                  epochs=ft_epochs,
                  callbacks=[
                      EarlyStopping(monitor='val_accuracy',
                                    restore_best_weights=True,
                                    patience=3,
                                    min_delta=0.0001),
                  ])

        print("Saving keras model")
        models.save_model(model, path + "model.h5")

        print("Evaluating keras model")
        print("Training dev",
              dict(zip(model.metrics_names, model.evaluate(dev_generator))))
        print("Finetuning dev",
              dict(zip(model.metrics_names, model.evaluate(ft_dev_generator))))
        print("Test",
              dict(zip(model.metrics_names, model.evaluate(test_generator))))
        evaluate(model, test_generator)