def main():
    mode = 'colour'

    if mode == 'gray':
        with open('./validation_ids_gray.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    elif mode == 'recoloured':
        with open('./validation_ids_recolour.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    elif mode == 'colour':
        with open('./validation_ids_tiny.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    dim_in = (64, 64, 3)
    shuffle = True
    batch_size = 32
    n_classes = 30
    dim_out = (n_classes)

    training_generator = data_utils.DataGenerator(validation_paths, batch_size,
                                                  dim_in, dim_out, shuffle,
                                                  mode, 'validation')

    model = keras.models.load_model(model_path)

    total = 0
    correct = 0
    for batch in training_generator:
        X, y = batch
        total += X.shape[0]

        y = np.argmax(y, axis=1)
        p = np.argmax(model.predict(X), axis=1)

        c = (y == p).sum()
        correct += c

    print("acc:", correct / total)

    pass
Пример #2
0
def _main():

    # Set testing mode (dropout/batchnormalization)
    K.set_learning_phase(TEST_PHASE)

    # Output dimension (empty place probability)
    output_dim = 1

    # Generate testing data
    test_datagen = data_utils.DataGenerator(rescale=1. / 255)

    # Iterator object containing testing data to be generated batch by batch
    test_generator = test_datagen.flow_from_directory(
        FLAGS.test_dir,
        output_dim,
        shuffle=False,
        img_mode=FLAGS.img_mode,
        target_size=(FLAGS.img_height, FLAGS.img_width),
        batch_size=FLAGS.batch_size)

    # Load json and create model
    json_model_path = os.path.join(FLAGS.experiment_rootdir,
                                   FLAGS.json_model_fname)
    model = utils.jsonToModel(json_model_path)

    # Load weights
    weights_load_path = os.path.join(FLAGS.experiment_rootdir,
                                     FLAGS.weights_fname)
    try:
        model.load_weights(weights_load_path)
        print("Loaded model from {}".format(weights_load_path))
    except:
        print("Impossible to find weight path. Returning untrained model")

    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam')

    # Get predictions and ground truth
    n_samples = test_generator.samples
    nb_batches = int(np.ceil(n_samples / FLAGS.batch_size))
    probs_per_class, ground_truth = utils.compute_predictions_and_gt(
        model, test_generator, nb_batches, verbose=1)

    # Predicted probabilities
    pred_probs = np.max(probs_per_class, axis=-1)
    # Prediced labels
    pred_labels = np.argmax(probs_per_class, axis=-1)
    # Real labels (ground truth)
    real_labels = np.argmax(ground_truth, axis=-1)

    # Evaluate predictions: Average accuracy and highest errors
    print("-----------------------------------------------")
    print("Evalutaion:")
    evaluation = evaluate_classification(pred_probs, pred_labels, real_labels)
    print("-----------------------------------------------")

    # Save evaluation
    utils.write_to_file(
        evaluation, os.path.join(FLAGS.experiment_rootdir,
                                 'test_results.json'))

    # Save predicted and real steerings as a dictionary
    labels_dict = {
        'pred_labels': pred_labels.tolist(),
        'real_labels': real_labels.tolist()
    }
    utils.write_to_file(
        labels_dict,
        os.path.join(FLAGS.experiment_rootdir,
                     'predicted_and_real_labels.json'))

    # Visualize confusion matrix
    utils.plot_confusion_matrix(FLAGS.experiment_rootdir,
                                real_labels,
                                pred_labels,
                                CLASSES,
                                normalize=True)
Пример #3
0
def _main():

    # Set training phase
    k.set_learning_phase(TRAIN_PHASE)

    # Create the experiment rootdir if not already there:
    if not os.path.exists(FLAGS.experiment_rootdir):
        os.makedirs(FLAGS.experiment_rootdir)

    # Split the data into training, validation and test sets
    if FLAGS.initial_epoch == 0:
        data_utils.cross_val_create(FLAGS.data_path)

    # Input image dimensions
    img_width, img_height = FLAGS.img_width, FLAGS.img_height
    print('Tamaño de los mel-espectrogramas: Alto: {}, Ancho: {}'.format(
        img_height, img_width))

    # Generate training data with real-time augmentation
    train_data_gen = data_utils.DataGenerator()

    # Iterator object containing training data to be generated batch by batch
    train_generator = train_data_gen.flow_from_directory(
        'train',
        shuffle=True,
        target_size=(img_height, img_width),
        classes=FLAGS.num_classes,
        batch_size=FLAGS.batch_size)

    # Generate validation data with real-time augmentation
    val_data_gen = data_utils.DataGenerator()

    # Iterator object containing validation data to be generated batch by batch
    val_generator = val_data_gen.flow_from_directory(
        'val',
        shuffle=False,
        target_size=(img_height, img_width),
        classes=FLAGS.num_classes,
        batch_size=FLAGS.batch_size)

    # Check if the number of classes in data corresponds to the one specified
    assert train_generator.num_classes == FLAGS.num_classes, \
        " Not matching output dimensions in training data."

    # Check if the number of classes in data corresponds to the one specified
    assert val_generator.num_classes == FLAGS.num_classes, \
        " Not matching output dimensions in validation data."

    # Weights to restore
    weights_path = FLAGS.initial_weights

    # Epoch from which training starts
    initial_epoch = FLAGS.initial_epoch

    if FLAGS.restore_model:
        # In this case weights are initialized as specified in pre-trained model
        # initial_epoch = FLAGS.initial_epoch
        try:
            # Carga estructura de la red
            json_model_path = os.path.join(FLAGS.experiment_rootdir,
                                           FLAGS.json_model_fname)
            model = json_to_model(json_model_path)

            # Carga los pesos
            model.load_weights(weights_path)
            print("Loaded model from {}".format(weights_path))
        except ImportError:
            print("Impossible to find weight path. Returning untrained model")
    else:
        # In this case weights are initialized randomly
        weights_path = None

        # Define model
        bot_model = InceptionV3(weights=None,
                                include_top=False,
                                input_shape=[img_height, img_width, 1],
                                classes=train_generator.num_classes)
        bot_model.summary()
        input = Input(shape=[img_height, img_width, 1])
        top = bot_model(input)

        # intermediate = Dropout()(top)
        # top = Flatten()(intermediate)
        top = Flatten()(top)
        top = Dense(FLAGS.num_classes,
                    activation='softmax',
                    name='predictions')(top)
        model = Model(inputs=input, outputs=top)

    model.summary()

    # Serialize model into json
    json_model_path = os.path.join(FLAGS.experiment_rootdir,
                                   FLAGS.json_model_fname)
    model_to_json(model, json_model_path)

    # Train model
    train_model(train_generator, val_generator, model, initial_epoch)

    # Plot training and validation losses
    utils.plot_loss(FLAGS.experiment_rootdir)
Пример #4
0
def main(dataset, batch_size, patch_size, epochs, label_smoothing,
         label_flipping):
    print(project_dir)

    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True  # dynamically grow the memory used on the GPU
    sess = tf.Session(config=config)
    K.tensorflow_backend.set_session(
        sess)  # set this TensorFlow session as the default session for Keras

    image_data_format = "channels_first"
    K.set_image_data_format(image_data_format)

    save_images_every_n_batches = 30
    save_model_every_n_epochs = 0

    # configuration parameters
    print("Config params:")
    print("  dataset = {}".format(dataset))
    print("  batch_size = {}".format(batch_size))
    print("  patch_size = {}".format(patch_size))
    print("  epochs = {}".format(epochs))
    print("  label_smoothing = {}".format(label_smoothing))
    print("  label_flipping = {}".format(label_flipping))
    print("  save_images_every_n_batches = {}".format(
        save_images_every_n_batches))
    print("  save_model_every_n_epochs = {}".format(save_model_every_n_epochs))

    model_name = datetime.strftime(datetime.now(), '%y%m%d-%H%M')
    model_dir = os.path.join(project_dir, "models", model_name)
    fig_dir = os.path.join(project_dir, "reports", "figures")
    logs_dir = os.path.join(project_dir, "reports", "logs", model_name)

    os.makedirs(model_dir)

    # Load and rescale data
    ds_train_gen = data_utils.DataGenerator(file_path=dataset,
                                            dataset_type="train",
                                            batch_size=batch_size)
    ds_train_disc = data_utils.DataGenerator(file_path=dataset,
                                             dataset_type="train",
                                             batch_size=batch_size)
    ds_val = data_utils.DataGenerator(file_path=dataset,
                                      dataset_type="val",
                                      batch_size=batch_size)
    enq_train_gen = OrderedEnqueuer(ds_train_gen,
                                    use_multiprocessing=True,
                                    shuffle=True)
    enq_train_disc = OrderedEnqueuer(ds_train_disc,
                                     use_multiprocessing=True,
                                     shuffle=True)
    enq_val = OrderedEnqueuer(ds_val, use_multiprocessing=True, shuffle=False)

    img_dim = ds_train_gen[0][0].shape[-3:]

    n_batch_per_epoch = len(ds_train_gen)
    epoch_size = n_batch_per_epoch * batch_size

    print("Derived params:")
    print("  n_batch_per_epoch = {}".format(n_batch_per_epoch))
    print("  epoch_size = {}".format(epoch_size))
    print("  n_batches_val = {}".format(len(ds_val)))

    # Get the number of non overlapping patch and the size of input image to the discriminator
    nb_patch, img_dim_disc = data_utils.get_nb_patch(img_dim, patch_size)

    tensorboard = TensorBoard(log_dir=logs_dir,
                              histogram_freq=0,
                              batch_size=batch_size,
                              write_graph=True,
                              write_grads=True,
                              update_freq='batch')

    try:
        # Create optimizers
        opt_dcgan = Adam(lr=1E-3, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
        # opt_discriminator = SGD(lr=1E-3, momentum=0.9, nesterov=True)
        opt_discriminator = Adam(lr=1E-3,
                                 beta_1=0.9,
                                 beta_2=0.999,
                                 epsilon=1e-08)

        # Load generator model
        generator_model = models.generator_unet_upsampling(img_dim)
        generator_model.summary()
        plot_model(generator_model,
                   to_file=os.path.join(fig_dir, "generator_model.png"),
                   show_shapes=True,
                   show_layer_names=True)

        # Load discriminator model
        # TODO: modify disc to accept real input as well
        discriminator_model = models.DCGAN_discriminator(
            img_dim_disc, nb_patch)
        discriminator_model.summary()
        plot_model(discriminator_model,
                   to_file=os.path.join(fig_dir, "discriminator_model.png"),
                   show_shapes=True,
                   show_layer_names=True)

        # TODO: pretty sure this is unnecessary
        generator_model.compile(loss='mae', optimizer=opt_discriminator)
        discriminator_model.trainable = False

        DCGAN_model = models.DCGAN(generator_model, discriminator_model,
                                   img_dim, patch_size, image_data_format)

        # L1 loss applies to generated image, cross entropy applies to predicted label
        loss = [models.l1_loss, 'binary_crossentropy']
        loss_weights = [1E1, 1]
        DCGAN_model.compile(loss=loss,
                            loss_weights=loss_weights,
                            optimizer=opt_dcgan)

        discriminator_model.trainable = True
        discriminator_model.compile(loss='binary_crossentropy',
                                    optimizer=opt_discriminator)

        tensorboard.set_model(DCGAN_model)

        # Start training
        enq_train_gen.start(workers=1, max_queue_size=20)
        enq_train_disc.start(workers=1, max_queue_size=20)
        enq_val.start(workers=1, max_queue_size=20)
        out_train_gen = enq_train_gen.get()
        out_train_disc = enq_train_disc.get()
        out_val = enq_val.get()

        print("Start training")
        for e in range(1, epochs + 1):
            # Initialize progbar and batch counter
            progbar = generic_utils.Progbar(epoch_size)
            start = time.time()

            for batch_counter in range(1, n_batch_per_epoch + 1):
                X_transformed_batch, X_orig_batch = next(out_train_disc)

                # Create a batch to feed the discriminator model
                X_disc, y_disc = data_utils.get_disc_batch(
                    X_transformed_batch,
                    X_orig_batch,
                    generator_model,
                    batch_counter,
                    patch_size,
                    label_smoothing=label_smoothing,
                    label_flipping=label_flipping)

                # Update the discriminator
                disc_loss = discriminator_model.train_on_batch(X_disc, y_disc)

                # Create a batch to feed the generator model
                X_gen_target, X_gen = next(out_train_gen)
                y_gen = np.zeros((X_gen.shape[0], 2), dtype=np.uint8)
                # Set labels to 1 (real) to maximize the discriminator loss
                y_gen[:, 1] = 1

                # Freeze the discriminator
                discriminator_model.trainable = False
                gen_loss = DCGAN_model.train_on_batch(X_gen,
                                                      [X_gen_target, y_gen])
                # Unfreeze the discriminator
                discriminator_model.trainable = True

                metrics = [("D logloss", disc_loss), ("G tot", gen_loss[0]),
                           ("G L1", gen_loss[1]), ("G logloss", gen_loss[2])]
                progbar.add(batch_size, values=metrics)

                logs = {k: v for (k, v) in metrics}
                logs["size"] = batch_size

                tensorboard.on_batch_end(batch_counter, logs=logs)

                # Save images for visualization
                if batch_counter % save_images_every_n_batches == 0:
                    # Get new images from validation
                    data_utils.plot_generated_batch(
                        X_transformed_batch, X_orig_batch, generator_model,
                        os.path.join(logs_dir, "current_batch_training.png"))
                    X_transformed_batch, X_orig_batch = next(out_val)
                    data_utils.plot_generated_batch(
                        X_transformed_batch, X_orig_batch, generator_model,
                        os.path.join(logs_dir, "current_batch_validation.png"))

            print("")
            print('Epoch %s/%s, Time: %s' % (e, epochs, time.time() - start))
            tensorboard.on_epoch_end(e, logs=logs)

            if (save_model_every_n_epochs >= 1 and e % save_model_every_n_epochs == 0) or \
                    (e == epochs):
                print("Saving model for epoch {}...".format(e), end="")
                sys.stdout.flush()
                gen_weights_path = os.path.join(
                    model_dir, 'gen_weights_epoch{:03d}.h5'.format(e))
                generator_model.save_weights(gen_weights_path, overwrite=True)

                disc_weights_path = os.path.join(
                    model_dir, 'disc_weights_epoch{:03d}.h5'.format(e))
                discriminator_model.save_weights(disc_weights_path,
                                                 overwrite=True)

                DCGAN_weights_path = os.path.join(
                    model_dir, 'DCGAN_weights_epoch{:03d}.h5'.format(e))
                DCGAN_model.save_weights(DCGAN_weights_path, overwrite=True)
                print("done")

    except KeyboardInterrupt:
        pass

    enq_train_gen.stop()
    enq_train_disc.stop()
    enq_val.stop()
Пример #5
0
def _main():
    
    # Set random seed
    if FLAGS.random_seed:
        seed = np.random.randint(0,2*31-1)
    else:
        seed = 5
    np.random.seed(seed)
    tf.set_random_seed(seed)

    # Set training phase
    K.set_learning_phase(TRAIN_PHASE)

    # Create the experiment rootdir if not already there
    if not os.path.exists(FLAGS.experiment_rootdir):
        os.makedirs(FLAGS.experiment_rootdir)

    # Input image dimensions
    img_width, img_height = FLAGS.img_width, FLAGS.img_height

    
    # Image mode (RGB or grayscale)
    if FLAGS.img_mode=='rgb':
        img_channels = 3
    elif FLAGS.img_mode == 'grayscale':
        img_channels = 1
    else:
        raise IOError("Unidentified image mode: use 'grayscale' or 'rgb'")

    # Output dimension (empty place probability)
    output_dim=1

    # Generate training data with real-time augmentation
    train_datagen = data_utils.DataGenerator(rescale = 1./255)
    
    # Iterator object containing training data to be generated batch by batch
    train_generator = train_datagen.flow_from_directory(FLAGS.train_dir,
                                                        output_dim,
                                                        shuffle = True,
                                                        img_mode = FLAGS.img_mode,
                                                        target_size=(img_height, img_width),
                                                        batch_size = FLAGS.batch_size)
    
    # Check if the number of classes in dataset corresponds to the one specified                                                    
#    assert train_generator.num_classes == num_classes, \
#                        " Not macthing output dimensions in training data."                                                    


    # Generate validation data with real-time augmentation
    val_datagen = data_utils.DataGenerator(rescale = 1./255)
    
    # Iterator object containing validation data to be generated batch by batch
    val_generator = val_datagen.flow_from_directory(FLAGS.val_dir,
                                                    output_dim,
                                                    shuffle = False,
                                                    img_mode = FLAGS.img_mode,
                                                    target_size=(img_height, img_width),
                                                    batch_size = FLAGS.batch_size)

    # Check if the number of classes in dataset corresponds to the one specified
#    assert val_generator.num_classes == num_classes, \
#                        " Not macthing output dimensions in validation data."
                        

    # Weights to restore
    weights_path = os.path.join(FLAGS.experiment_rootdir, FLAGS.weights_fname)
    
    # Epoch from which training starts
    initial_epoch = 0
    if not FLAGS.restore_model:
        # In this case weights are initialized randomly
        weights_path = None
    else:
        # In this case weigths are initialized as specified in pre-trained model
        initial_epoch = FLAGS.initial_epoch

    # Define model
    model = getModelResnet(FLAGS.n_layers, FLAGS.rn_version, img_width, img_height, img_channels,
                        output_dim, weights_path)  

    # Serialize model into json
    json_model_path = os.path.join(FLAGS.experiment_rootdir, FLAGS.json_model_fname)
    utils.modelToJson(model, json_model_path)

    # Train model
    trainModel(train_generator, val_generator, model, initial_epoch)
    
    # Plot training and validation losses
    utils.plot_loss(FLAGS.experiment_rootdir)
Пример #6
0
def main(model,
         input,
         truth,
         output,
         image_size,
         concat,
         batch_size,
         dataset):

    K.set_image_data_format("channels_first")

    # Load the model
    img_dim = (3,) + image_size
    generator_model = models.generator_unet_upsampling(img_dim)
    generator_model.load_weights(str(model))

    # Setup the data generator
    if h5py.is_hdf5(input):
        generator = data_utils.DataGenerator(file_path=input,
                                             dataset_type=dataset,
                                             batch_size=batch_size)
        batch_gen = get_batch_from_hdf5(generator)
        count = len(generator) * batch_size
    elif os.path.isdir(input):
        # Directory of images
        input_paths = [str(img) for img in sorted(Path(input).glob('**/*.jpg'))]
        if truth is not None:
            truth_paths = [str(img) for img in sorted(Path(truth).glob('**/*.jpg'))]
        else:
            truth_paths = []
        batch_gen = get_batch_from_images(input_paths, truth_paths, batch_size, image_size)
        count = len(input_paths)
    else:
        # Single image file
        input_paths = [input]
        if truth is not None:
            truth_paths = [truth]
        else:
            truth_paths = []
        batch_size = 1
        batch_gen = get_batch_from_images(input_paths, truth_paths, batch_size, image_size)
        count = 1

    # Setup the output
    if output is not None:
        # If input is multiple images, create directory for output images
        if count > 1:
            if os.path.exists(output):
                raise IOError('Output directory already exists')
            os.makedirs(output)

    # Inference
    with tqdm(None, total=count) as progress_bar:
        for batch_record in batch_gen:
            input_batch = batch_record.input
            truth_batch = batch_record.truth
            image_names = batch_record.image_names
            out_batch = generator_model.predict(input_batch)
            progress_bar.update(input_batch.shape[0])

            if output is not None:
                # Individually save each image in the batch
                for i in range(len(image_names)):
                    input_b = input_batch[i:i+1]
                    output_b = out_batch[i:i+1]
                    truth_b = truth_batch[i:i+1] if truth_batch is not None else None
                    image_name = image_names[i]
                    out_image = generate_output_image(input_b, output_b, truth_b, concat)
                    if count > 1:
                        out_path = os.path.join(str(output), image_name)
                    else:
                        out_path = output
                    plt.imsave(out_path, out_image)
            else:
                # Show the image
                out_image = generate_output_image(input_batch, out_batch, truth_batch, concat)
                plt.figure()
                plt.imshow(out_image)
                plt.show()
                plt.clf()
                plt.close()
def train(model: Sequential, mode):

    if mode == 'gray':
        with open('./train_ids_gray.pickle', 'rb') as fp:
            training_paths = pickle.load(fp)

        with open('./validation_ids_gray.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    elif mode == 'recoloured':
        with open('./train_ids_recolour.pickle', 'rb') as fp:
            training_paths = pickle.load(fp)

        with open('./validation_ids_recolour.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    elif mode == 'colour':
        with open('./train_ids_tiny.pickle', 'rb') as fp:
            training_paths = pickle.load(fp)
        with open('./validation_ids_tiny.pickle', 'rb') as fp:
            validation_paths = pickle.load(fp)

    # params
    dim_in = (64, 64, 3)
    shuffle = True
    batch_size = 64
    n_classes = 30
    dim_out = (n_classes)

    training_generator = data_utils.DataGenerator(training_paths, batch_size,
                                                  dim_in, dim_out, shuffle,
                                                  mode, 'training')
    validation_generator = data_utils.DataGenerator(validation_paths,
                                                    batch_size, dim_in,
                                                    dim_out, shuffle, mode,
                                                    'validation')

    callback_list = list()

    directory = create_result_dir('./vgg_classification')
    print('Directory:', directory)

    print("using tensorboard")
    tensor_directory = directory + '/' + 'tensorboard'
    tb_callback = callbacks.TensorBoard(log_dir=tensor_directory)
    callback_list.append(tb_callback)

    saving_period = 3
    print("saving model every {} epochs".format(saving_period))
    model_dir = os.path.join(directory, 'models',
                             'model.{epoch:02d}-loss_{val_loss:.2f}.hdf5')
    p_save_callback = callbacks.ModelCheckpoint(model_dir,
                                                period=saving_period)
    callback_list.append(p_save_callback)

    print("saving best model")
    bestmodels_dir = directory + '/' + 'bestmodels/best_model.hdf5'
    best_save_callback = callbacks.ModelCheckpoint(bestmodels_dir,
                                                   save_best_only=True,
                                                   mode='val_acc')
    callback_list.append(best_save_callback)

    lr_reduce = callbacks.ReduceLROnPlateau(monitor='val_acc',
                                            factor=0.2,
                                            patience=4)
    callback_list.append(lr_reduce)

    n_workers = 2
    n_epochs = 30

    model.fit_generator(generator=training_generator,
                        validation_data=validation_generator,
                        use_multiprocessing=True,
                        workers=n_workers,
                        verbose=1,
                        epochs=n_epochs,
                        callbacks=callback_list)
Пример #8
0
def _main():
    # Set testing mode (dropout/batch normalization)
    k.set_learning_phase(TEST_PHASE)

    # Split the data into training, validation and test sets
    if FLAGS.initial_epoch == 0:
        data_utils.cross_val_create(FLAGS.data_path)

    # Generate testing data
    test_data_gen = data_utils.DataGenerator()

    # Iterator object containing testing data to be generated batch by batch
    test_generator = test_data_gen.flow_from_directory(
        'test',
        shuffle=False,
        target_size=(FLAGS.img_height, FLAGS.img_width),
        batch_size=FLAGS.batch_size)

    # Load json and create model
    json_model_path = os.path.join(FLAGS.experiment_rootdir,
                                   FLAGS.json_model_fname)
    model = utils.json_to_model(json_model_path)

    # Load weights
    weights_load_path = os.path.abspath('./experiment_6/weights_039.h5')
    try:
        model.load_weights(weights_load_path)
        print("Loaded model from {}".format(weights_load_path))
    except ImportError:
        print("Impossible to find weight path. Returning untrained model")

    # Compile model
    model.compile(optimizer='adam', loss='mean_squared_error')

    # Get predictions and ground truth
    n_samples = test_generator.samples
    nb_batches = int(np.ceil(n_samples / FLAGS.batch_size))
    probs_per_class, ground_truth = utils.compute_predictions_and_gt(
        model, test_generator, nb_batches, verbose=FLAGS.verbose)

    # Predicted probabilities
    pred_probs = np.max(probs_per_class, axis=-1)
    # Predicted labels
    pred_labels = np.argmax(probs_per_class, axis=-1)
    # Real labels (ground truth)
    real_labels = np.argmax(ground_truth, axis=-1)

    # Evaluate predictions: Average accuracy and highest errors
    print("-----------------------------------------------")
    print("Evaluation:")
    evaluation = evaluate_classification(pred_probs, pred_labels, real_labels)
    print("-----------------------------------------------")

    # Save evaluation
    utils.write_to_file(
        evaluation, os.path.join(FLAGS.experiment_rootdir,
                                 'test_results.json'))

    # Save predicted and real steerings as a dictionary
    labels_dict = {
        'pred_labels': pred_labels.tolist(),
        'real_labels': real_labels.tolist()
    }
    utils.write_to_file(
        labels_dict,
        os.path.join(FLAGS.experiment_rootdir,
                     'predicted_and_real_labels.json'))

    # Visualize confusion matrix
    utils.plot_confusion_matrix('test',
                                FLAGS.experiment_rootdir,
                                real_labels,
                                pred_labels,
                                CLASSES,
                                normalize=True)

    print('Accuracy:', accuracy_score(real_labels, pred_labels))
    print('F1 score:', f1_score(real_labels, pred_labels, average='micro'))
    print('Recall:', recall_score(real_labels, pred_labels, average='micro'))
    print('Precision:',
          precision_score(real_labels, pred_labels, average='micro'))
    print('\n clasification report:\n',
          classification_report(real_labels, pred_labels))
    print('\n confussion matrix:\n', confusion_matrix(real_labels,
                                                      pred_labels))