Comportamiento inconsistente con las funciones de transformación tm_map cuando se usan múltiples núcleos

Otro título potencial para esta publicación podría ser "Cuando se procesa en paralelo en r, ¿importa la relación entre el número de núcleos, el tamaño del fragmento de bucle y el tamaño del objeto?"

Tengo un corpus en el que estoy ejecutando algunas transformaciones al usar el paquete tm. Como el corpus es grande, estoy usando el procesamiento paralelo con el paquete doparallel.

Algunas veces las transformaciones hacen la tarea, pero otras no. Por ejemplo,tm::removeNumbers(). El primer documento en el corpus tiene un valor de contenido de "n417". Entonces, si el preprocesamiento es exitoso, este documento se transformará en "n".

El corpus de muestra está debajo para reproducción. Aquí está el bloque de código:

library(tidyverse)
library(qdap)
library(stringr)
library(tm)
library(textstem)
library(stringi)
library(foreach)
library(doParallel)
library(SnowballC)

  corpus <- (see below)
  n <- 100 # this is the size of each chunk in the loop

  # split the corpus into pieces for looping to get around memory issues with transformation
  nr <- length(corpus)
  pieces <- split(corpus, rep(1:ceiling(nr/n), each=n, length.out=nr))
  lenp <- length(pieces)

  rm(corpus) # save memory

  # save pieces to rds files since not enough RAM
  tmpfile <- tempfile() 
  for (i in seq_len(lenp)) {
    saveRDS(pieces[[i]],
            paste0(tmpfile, i, ".rds"))
  }

  rm(pieces) # save memory

  # doparallel
  registerDoParallel(cores = 12)
  pieces <- foreach(i = seq_len(lenp)) %dopar% {
    piece <- readRDS(paste0(tmpfile, i, ".rds"))
    # regular transformations        
    piece <- tm_map(piece, content_transformer(removePunctuation), preserve_intra_word_dashes = T)
    piece <- tm_map(piece, content_transformer(function(x, ...) 
      qdap::rm_stopwords(x, stopwords = tm::stopwords("english"), separate = F)))
    piece <- tm_map(piece, removeNumbers)
    saveRDS(piece, paste0(tmpfile, i, ".rds"))
    return(1) # hack to get dopar to forget the piece to save memory since now saved to rds
  } 

  stopImplicitCluster()

  # combine the pieces back into one corpus
  corpus <- list()
  corpus <- foreach(i = seq_len(lenp)) %do% {
    corpus[[i]] <- readRDS(paste0(tmpfile, i, ".rds"))
  }
  corpus_done <- do.call(function(...) c(..., recursive = TRUE), corpus)

Yaquí es un enlace a datos de muestra. Necesito pegar una muestra suficientemente grande de 2k documentos para recrear y SO no me deja pegar tanto, así que por favor vea el documento vinculado para obtener datos.

corpus <- VCorpus(VectorSource([paste the chr vector from link above]))

Si ejecuto mi bloque de código como arriba con n = a 200, mire los resultados y puedo ver que los números permanecen donde deberían haber sido eliminados portm::removeNumbers()

> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n417"
[1] "disturbance"
[1] "grand theft auto"

Sin embargo, si cambio el tamaño del fragmento (el valor de la variable "n") a 100:

> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n"
[1] "disturbance"
[1] "grand theft auto"

Los números han sido eliminados.

Pero, esto es inconsistente. Traté de reducirlo probando 150, luego 125 ... y descubrí que no funcionaría / no funcionaría entre 120 y 125 trozos. Luego, después de iterar la función entre 120: 125, a veces funcionaría y luego no para el mismo tamaño de fragmento.

Creo que tal vez hay una relación con este problema entre 3 variables: el tamaño del corpus, el tamaño del fragmento y el número de núcleos enregisterdoparallel(). Simplemente no sé lo que es.

¿Alguien puede echar una mano o incluso reproducirse con el corpus de muestra vinculado? Me preocupa, ya que a veces puedo reproducir el error, otras veces no puedo. Cambiar el tamaño del fragmento proporciona una especie de capacidad para ver el error al eliminar números, pero no siempre.

Actualizar hoy Reanudé mi sesión y no pude replicar el error. Creé unGoogle Doc y experimentó con diferentes valores para el tamaño del cuerpo, número de núcleos y tamaños de trozos. En cada caso todo fue un éxito. Entonces, intenté ejecutar con datos completos y todo funcionó. Sin embargo, para mi cordura intenté ejecutar nuevamente con datos completos y falló. Ahora, estoy de vuelta a donde estaba ayer. Parece que haber ejecutado la función en un conjunto de datos más grande ha cambiado algo ... No sé qué. ¿Quizás una variable de sesión de algún tipo? Entonces, la nueva información es que este error solo ocurre después de ejecutar la función en un conjunto de datos muy grande. Reiniciar mi sesión no resolvió el problema, pero reanudar las sesiones después de estar fuera durante varias horas sí.

Nueva información. Puede ser más fácil reproducir el problema en un corpus más grande ya que esto es lo que parece desencadenar el problemacorpus <- do.call(c, replicate(250, corpus, simplify = F)) creará un corpus de 500k docs basado en la muestra que proporcioné. La función puede funcionar la primera vez que la llame, pero para mí parece fallar la segunda vez.

Este problema es difícil porque si pudiera reproducir el problema, probablemente podría identificarlo y solucionarlo.

Nueva información. Debido a que suceden varias cosas con esta función, fue difícil saber dónde enfocar los esfuerzos de depuración. Estaba mirando el hecho de que estoy usando múltiples archivos RDS temporales para ahorrar memoria y también el hecho de que estoy haciendo un procesamiento paralelo. Escribí dos versiones alternativas del script, una que todavía usa los archivos rds y divide el corpus pero no realiza el procesamiento paralelo (reemplazó% dopar% con solo% do% y también eliminó la línea registerDoParallel) y otra que usa el procesamiento paralelo pero no utiliza archivos temporales RDS para dividir el pequeño corpus de muestra. No pude producir el error con la versión de un solo núcleo del script, solo con la versión que usa% dopar% pude recrear el problema (aunque el problema es intermitente, no siempre falla con dopar). Entonces, este problema solo aparece cuando se usa%dopar%. El hecho de que estoy usando archivos temporales RDS no parece ser parte del problema.

Respuestas a la pregunta(0)

Su respuesta a la pregunta