Output order in Keras predict_generator

Viewed 846

I have followed online tutorial about image recognition using Keras in R ending up with the following code:

library(keras)

view_list <- c("Inside", "Outside")
output_n <- length(view_list)

# image size to scale down to (original images are 100 x 100 px)
img_width <- 20
img_height <- 20
target_size <- c(img_width, img_height)

# RGB = 3 channels
channels <- 3

train_image_files_path <- "C:/Users/Tomek/Desktop/Photos"
valid_image_files_path <- "C:/Users/Tomek/Desktop/Photos valid"
test_image_files_path <- "C:/Users/Tomek/Desktop/Photos test"

# optional data augmentation
train_data_gen = image_data_generator(rescale = 1/255 )

# Validation data shouldn't be augmented! But it should also be scaled.
valid_data_gen <- image_data_generator(rescale = 1/255)  
test_data_gen <- image_data_generator(rescale = 1/255) 

# training images
train_image_array_gen <- flow_images_from_directory(train_image_files_path, 
                                                    train_data_gen,
                                                    target_size = target_size,
                                                    class_mode = "categorical",
                                                    classes = view_list,
                                                    seed = 42)


# validation images
valid_image_array_gen <- flow_images_from_directory(valid_image_files_path, 
                                                    valid_data_gen,
                                                    target_size = target_size,
                                                    class_mode = "categorical",
                                                    classes = view_list,
                                                    seed = 42)

# test images
test_image_array_gen <- flow_images_from_directory(test_image_files_path, 
                                                   test_data_gen,
                                                   target_size = target_size,
                                                   class_mode = "categorical",
                                                   classes = view_list,
                                                   seed = 42)

cat("Number of images per class:")
table(factor(train_image_array_gen$classes))
train_image_array_gen$class_indices

views_classes_indices <- train_image_array_gen$class_indices
save(views_classes_indices, file = "C:/Users/Tomek/Desktop/views_classes_indices.RData")

# number of training samples
train_samples <- train_image_array_gen$n
# number of validation samples
valid_samples <- valid_image_array_gen$n
# number of test samples
test_samples <- test_image_array_gen$n

# define batch size and number of epochs
batch_size <- 1
epochs <- 10

# initialise model
model <- keras_model_sequential()

# add layers
model %>%
  layer_conv_2d(filter = 32, kernel_size = c(3,3), padding = "same", input_shape = c(img_width, img_height, channels)) %>%
  layer_activation("relu") %>%

  # Second hidden layer
  layer_conv_2d(filter = 16, kernel_size = c(3,3), padding = "same") %>%
  layer_activation_leaky_relu(0.5) %>%
  layer_batch_normalization() %>%

  # Use max pooling
  layer_max_pooling_2d(pool_size = c(2,2)) %>%
  layer_dropout(0.25) %>%

  # Flatten max filtered output into feature vector 
  # and feed into dense layer
  layer_flatten() %>%
  layer_dense(100) %>%
  layer_activation("relu") %>%
  layer_dropout(0.5) %>%

  # Outputs from dense layer are projected onto output layer
  layer_dense(output_n) %>% 
  layer_activation("softmax")

# compile
model %>% compile(
  loss = "categorical_crossentropy",
  optimizer = optimizer_rmsprop(lr = 0.0001, decay = 1e-6),
  metrics = "accuracy"
)

summary(model)

# fit
hist <- model %>% fit_generator(
  # training data
  train_image_array_gen,

  # epochs
  steps_per_epoch = as.integer(train_samples / batch_size), 
  epochs = epochs, 

  # validation data
  validation_data = valid_image_array_gen,
  validation_steps = as.integer(valid_samples / batch_size),

  # print progress
  verbose = 2,
  callbacks = list(
    # save best model after every epoch
    callback_model_checkpoint("C:/Users/Tomek/Desktop/views_checkpoints.h5", save_best_only = TRUE),
    # only needed for visualising with TensorBoard
    callback_tensorboard(log_dir = "C:/Users/Tomek/Desktop/keras/logs")
  )
)
plot(hist)

#prediction
a <- model %>% predict_generator(test_image_array_gen, steps = 5, verbose = 1, workers = 1)
a <- round(a, digits = 4)

The classification model (with two output classes) seems to work quite nicely. The accuracy on the train and the validation sets is equal to ~99% and ~95% respectively. However, I am not sure about the results of predictions on the test set. It looks like the predictions for observations are shuffled and I am not able to find a way to check which prediction refers to which image(observation). I have seen some threads on that issue: github medium 1 medium 2.

Nevertheless, I am really new to Keras and Python and I have hard time applying the suggested solutions in R. What is the easiest way to track which prediction refers to which image from the test set in predict_generator output?

1 Answers

I figured it out and the answer is simple. The shuffling is caused by argument shuffle which by default is set to true. After changing it, predictions correspond to the order of test_image_array_gen$filenames However, bear in mind that the order of predictions (and filenames) is different than the one on Windows which may be a bit confusing.

Order in Windows: Photo 1 Photo 2 ... Photo 10 Photo 11

Order in R: Photo 1 Photo 10 Photo 11 ... Photo 2

# test images
test_image_array_gen <- flow_images_from_directory(test_image_files_path, 
                                                   test_data_gen,
                                                   target_size = target_size,
                                                   class_mode = "categorical",
                                                   classes = view_list,
                                                   seed = 42,
                                                   shuffle = FALSE)

#prediction 
a <- model %>% predict_generator(test_image_array_gen, steps = ceiling(test_samples/32), verbose = 1, workers = 1)

#bind predictions with photos names
b <- cbind.data.frame(a, test_image_array_gen$filenames)
Related