Функция генератора в LSTM Keras для вывода мини-пакетов из одного файла

У меня есть функция генератора, которая работает нормально. У меня есть большой список файлов.txt, в котором каждый файл также довольно длинный. Теперь задача будет написать функцию генератора, которая принимает:

  1. пакет файлов
  2. а затем пакет размером 128 из одного файла

мой код сейчас:

data_files_generator <- function(train_set) {

  files <- train_set
  next_file <- 0

  function() {

    # move to the next file (note the <<- assignment operator)
    next_file <<- next_file + 1

    # if we've exhausted all of the files then start again at the
    # beginning of the list (keras generators need to yield
    # data infinitely -- termination is controlled by the epochs
    # and steps_per_epoch arguments to fit_generator())
    if (next_file > length(files))
    {next_file <<- 1}

    # determine the file name
    file <- files[[next_file]]

    text <- read_lines(paste(data_dir, file, sep = "" )) %>%
      str_to_lower() %>%
      str_c(collapse = "\n") %>%
      removeNumbers() %>%
      tokenize_characters(strip_non_alphanum = FALSE, simplify = TRUE)

    text <- text[text %in% chars]

    dataset <- map(
      seq(1, length(text) - maxlen - 1, by = 3), 
      ~list(sentece = text[.x:(.x + maxlen - 1)], next_char = text[.x + maxlen])
    )

    dataset <- transpose(dataset)

    # Vectorization
    x <- array(0, dim = c(length(dataset$sentece), maxlen, length(chars)))
    y <- array(0, dim = c(length(dataset$sentece), length(chars)))

    for(i in 1:length(dataset$sentece)){

      x[i,,] <- sapply(chars, function(x){
        as.integer(x == dataset$sentece[[i]])
      })

      y[i,] <- as.integer(chars == dataset$next_char[[i]])

    }
    rounded_dim <- floor(dim(x)[1]/mini_batch_size)
    match_size_to_batch <- 128 * rounded_dim

    x <- x[1:match_size_to_batch, 1:maxlen, 1:length(chars)]
    y <- y_val[1:match_size_to_batch, 1:length(chars)]

    return(list(x, y))

  }
}

Итак, что приходит, то идет, это текстовый файл, который преобразуется в меньшие куски текста (длиной maxlen), а затем кодируется в одну и ту же матрицу 0 и 1.

Проблема заключается в том, что из моего кода на выходе получается один куб данных размером maxlen x lenght(chars) x samples где количество выборок очень велико, и поэтому я хотел бы, чтобы моя функция генератора всегда выводила куб размера maxlen x lenght(chars) x samples(128) а затем вывести следующую партию размера maxlen x lenght(chars) x samples пока весь текстовый файл не будет прочитан, а затем перейдите к следующему текстовому файлу...

Вывод на данный момент является ошибкой:

 Error in py_call_impl(callable, dots$args, dots$keywords) : 
  ValueError: Cannot feed value of shape (112512, 40, 43) for Tensor 'lstm_layer_input_1:0', which has shape '(128, 40, 43)' 

надеюсь, я объяснил это достаточно хорошо, чтобы понять. Я думаю, что мне нужно ввести какой-то цикл for для итерации по длине выборки, но я понятия не имею, как включить это в ген. функция.

2 ответа

Решение

Я реализовал цикл for, который теперь возвращает партии размером 128:

Измененный код:

data_files_generator <- function(train_set) {

  files <- train_set
  next_file <- 0

  function() {

    # move to the next file (note the <<- assignment operator)
    next_file <<- next_file + 1

    # if we've exhausted all of the files then start again at the
    # beginning of the list (keras generators need to yield
    # data infinitely -- termination is controlled by the epochs
    # and steps_per_epoch arguments to fit_generator())
    if (next_file > length(files))
    {next_file <<- 1}

    # determine the file name
    file <- files[[next_file]]

    text <- read_lines(paste(data_dir, file, sep = "" )) %>%
      str_to_lower() %>%
      str_c(collapse = "\n") %>%
      removeNumbers() %>%
      tokenize_characters(strip_non_alphanum = FALSE, simplify = TRUE)

    text <- text[text %in% chars]

    dataset <- map(
      seq(1, length(text) - maxlen - 1, by = 3), 
      ~list(sentece = text[.x:(.x + maxlen - 1)], next_char = text[.x + maxlen])
    )

    dataset <- transpose(dataset)

    # Vectorization
    x <- array(0, dim = c(length(dataset$sentece), maxlen, length(chars)))
    y <- array(0, dim = c(length(dataset$sentece), length(chars)))

    for(i in 1:length(dataset$sentece)){

      x[i,,] <- sapply(chars, function(x){
        as.integer(x == dataset$sentece[[i]])
      })

      y[i,] <- as.integer(chars == dataset$next_char[[i]])

    }
    rounded_dim <- floor(dim(x)[1]/mini_batch_size)
    match_size_to_batch <- 128 * rounded_dim

    x <- x[1:match_size_to_batch, 1:maxlen, 1:length(chars)]
    y <- y_val[1:match_size_to_batch, 1:length(chars)]

    #Edit:
    span_start <-1
    for (iter in 1:rounded_dim){
     i <- iter * 128
     span_end <- iter * 128
     x <- x[span_start:span_end, 1:maxlen, 1:length(chars)]
     y <- y[span_start:span_end, 1:length(chars)]
     span_start <- i
     return(list(x, y))
    }
  }
}

В соответствии с ошибкой, вы пытаетесь подать объект формы (112512, 40, 43) но ваш слой LSTM ожидает объект формы (128, 40, 43), Кажется, что-то не хватает кода, но когда вы определяете входной слой, вы устанавливаете размер пакета? Мне повезло с определением моего входного слоя как:

l_input = Input(shape = (None, num_features), name = 'input_layer')

Я подозреваю, что ошибка происходит из-за этих строк кода:

rounded_dim <- floor(dim(x)[1]/mini_batch_size)
match_size_to_batch <- 128 * rounded_dim

Это дает размер пакета намного больше 128. Из документации Keras форма ввода должна быть (batch_size, timesteps, input_dim), Размеры партии не обязательно должны быть одинаковыми на протяжении всей эпопеи, но для партии все они должны иметь одинаковое количество timesteps (что, похоже, вы справляетесь с maxlen).

Другие вопросы по тегам