Comportamento inconsistente com funções de transformação tm_map ao usar vários núcleos

Outro título em potencial para este post pode ser "Quando o processamento paralelo em r, a relação entre o número de núcleos, o tamanho do pedaço de loop e o tamanho do objeto é importante?"

Eu tenho um corpus, estou executando algumas transformações no uso do pacote tm. Como o corpus é grande, estou usando processamento paralelo com pacote doparalelo.

Às vezes, as transformações fazem a tarefa, mas às vezes não. Por exemplo,tm::removeNumbers(). O primeiro documento do corpus tem um valor de conteúdo "n417". Portanto, se o pré-processamento for bem-sucedido, este documento será transformado em apenas "n".

O corpus da amostra está abaixo para reprodução. Aqui está o bloco 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)

Eaqui é um link para dados de amostra. Preciso colar uma amostra suficientemente grande de 2k documentos para recriar e, portanto, não me permitirá colar tanto, então consulte o documento vinculado para obter dados.

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

Se eu executar o meu bloco de código como acima com n = a 200, observe os resultados e vejo que os números permanecem onde deveriam ter sido removidos portm::removeNumbers()

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

No entanto, se eu alterar o tamanho do pedaço (o valor da variável "n") para 100:

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

Os números foram removidos.

Mas, isso é inconsistente. Tentei reduzi-lo testando 150, depois 125 ... e descobri que não funcionaria entre 120 e 125 tamanhos de bloco. Depois de iterar a função entre 120: 125, às vezes funcionava e não para o mesmo tamanho de bloco.

Eu acho que talvez exista uma relação com esse problema entre três variáveis: o tamanho do corpus, o tamanho do pedaço e o número de núcleos noregisterdoparallel(). Eu simplesmente não sei o que é isso.

Alguém pode ajudar ou mesmo se reproduzir com o corpus de amostra vinculado? Estou preocupado, pois posso reproduzir o erro algumas vezes, outras vezes não. Alterar o tamanho do pedaço fornece um tipo de capacidade de ver o erro com números removidos, mas nem sempre.

Atualizar Hoje retomei minha sessão e não consegui replicar o erro. Eu criei umDocumento do Google e experimentou valores diferentes para o tamanho do corpus, número de núcleos e tamanhos de bloco. Em cada caso, tudo foi um sucesso. Então, tentei rodar com dados completos e tudo funcionou. No entanto, para minha sanidade, tentei executar novamente com dados completos e falhou. Agora, voltei para onde estava ontem. Parece que a função em um conjunto de dados maior mudou alguma coisa ... Não sei o quê. Talvez uma variável de sessão de algum tipo? Portanto, a nova informação é que esse bug só ocorre após a execução da função em um conjunto de dados muito grande. Reiniciar minha sessão não resolveu o problema, mas reiniciar as sessões depois de ficar fora por várias horas.

Nova informação. Pode ser mais fácil reproduzir o problema em um corpus maior, pois é isso que parece desencadear o problemacorpus <- do.call(c, replicate(250, corpus, simplify = F)) criará um corpus de 500 mil documentos com base na amostra que forneci. A função pode funcionar na primeira vez em que você a chama, mas para mim parece falhar na segunda vez.

Esse problema é difícil porque, se eu pudesse reproduzir o problema, provavelmente seria capaz de identificá-lo e corrigi-lo.

Nova informação. Como há várias coisas acontecendo com essa função, era difícil saber onde concentrar os esforços de depuração. Eu estava olhando para o fato de estar usando vários arquivos RDS temporários para economizar memória e também para o processamento paralelo. Escrevi duas versões alternativas do script, uma que ainda usa os arquivos rds e divide o corpus, mas não realiza processamento paralelo (substituiu% dopar% por apenas% do% e também removeu a linha registerDoParallel) e uma que usa processamento paralelo, mas não usa arquivos temporários do RDS para dividir o pequeno corpus de amostra. Não foi possível produzir o erro com a versão de núcleo único do script, apenas a versão que usa% dopar% foi capaz de recriar o problema (embora o problema seja intermitente, nem sempre falha com o dopar). Portanto, esse problema aparece apenas ao usar%dopar%. O fato de eu estar usando arquivos temporários RDS não parece fazer parte do problema.

questionAnswers(0)

yourAnswerToTheQuestion