I have a directory of 8-bit rgb (3 channel) images of different sizes. I'm trying to use them to train an autoencoder in R 3.6.3, using keras 2.2.5.0 with tensorflow 2.0.0 on a linux mint 19 machine. The dataset is here (zipped): https://github.com/hrj21/processing-imagestream-images/blob/master/ciliated_cells.zip
The images are split into two labelled classes, but I don't care about this class structure.
When I run the fit_generator()
function I get the error:
Error in py_call_impl(callable, dots$args, dots$keywords) :
IndexError: list index out of range
I'm sure it's something I'm doing wrong but I'm not experienced enough with keras to understand what that is. Any help you can give would be much appreciated. Here is the code:
# Load package ------------------------------------------------------------
library(keras)
# Defining the file paths -------------------------------------------------
base_dir <- "ciliated_cells"
train_dir <- file.path(base_dir, "train")
validation_dir <- file.path(base_dir, "validation")
test_dir <- file.path(base_dir, "test")
# Define data generators --------------------------------------------------
# To scale and resize images
datagen <- image_data_generator(rescale = 1/255)
train_generator <- flow_images_from_directory(
train_dir,
datagen,
target_size = c(150, 150),
batch_size = 88,
class_mode = NULL
)
validation_generator <- flow_images_from_directory(
validation_dir,
datagen,
target_size = c(150, 150),
batch_size = 36,
class_mode = NULL
)
test_generator = flow_images_from_directory(
test_dir,
datagen,
target_size = c(150, 150),
batch_size = 30,
class_mode = NULL,
shuffle = FALSE) # keep data in same order as labels
# Defining the model architecture from scratch ----------------------------
input <- layer_input(shape = c(150, 150, 3))
output <- input %>%
layer_flatten(input_shape = c(150, 150, 3)) %>%
layer_flatten() %>%
layer_dense(units = 32, activation = "relu") %>%
layer_dense(units = 16, name = "code") %>%
layer_dense(units = 32, activation = "relu") %>%
layer_dense(units = 150 * 150 * 3) %>%
layer_reshape(c(150, 150, 3))
model <- keras_model(input, output)
# Compiling and fitting the model -----------------------------------------
model %>% compile(
loss = "mse",
optimizer = optimizer_rmsprop(lr = 2e-5)
)
history <- model %>% fit_generator(
train_generator,
steps_per_epoch = 1,
epochs = 100,
validation_data = validation_generator,
validation_steps = 1
)
Here is the output of sessionInfo()
:
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Linux Mint 19
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
locale:
[1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C LC_TIME=en_GB.UTF-8
[4] LC_COLLATE=en_GB.UTF-8 LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8
[7] LC_PAPER=en_GB.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] forcats_0.5.0 stringr_1.4.0 dplyr_0.8.5 purrr_0.3.3 readr_1.3.1 tidyr_1.0.2
[7] tibble_3.0.0 ggplot2_3.3.0 tidyverse_1.3.0 keras_2.2.5.0
loaded via a namespace (and not attached):
[1] reticulate_1.15-9000 tidyselect_1.0.0 haven_2.2.0 lattice_0.20-41
[5] colorspace_1.4-1 vctrs_0.2.4 generics_0.0.2 base64enc_0.1-3
[9] rlang_0.4.5 pillar_1.4.3 withr_2.1.2 glue_1.4.0
[13] DBI_1.1.0 rappdirs_0.3.1 dbplyr_1.4.2 modelr_0.1.6
[17] readxl_1.3.1 lifecycle_0.2.0 tensorflow_2.0.0 munsell_0.5.0
[21] gtable_0.3.0 cellranger_1.1.0 rvest_0.3.5 tfruns_1.4
[25] fansi_0.4.1 broom_0.5.5 Rcpp_1.0.4.6 backports_1.1.6
[29] scales_1.1.0 jsonlite_1.6.1 fs_1.4.1 hms_0.5.3
[33] packrat_0.5.0 stringi_1.4.6 grid_3.6.3 cli_2.0.2
[37] tools_3.6.3 magrittr_1.5 crayon_1.3.4 whisker_0.4
[41] pkgconfig_2.0.3 zeallot_0.1.0 ellipsis_0.3.0 Matrix_1.2-18
[45] xml2_1.3.1 reprex_0.3.0 lubridate_1.7.4 assertthat_0.2.1
[49] httr_1.4.1 rstudioapi_0.11 R6_2.4.1 nlme_3.1-145
[53] compiler_3.6.3
So I realised my mistake. My data generators were generating the input images, but not the output images (which should be the same) for the autoencoder to learn from. So the solution was to change the class_mode
argument inside each flow_images_from_directory()
function to "input". The 'fit_generator()` function then runs without issue. Without this, the autoencoder doesn't "know" it's trying to reproduce the input image in the output layer.