使用多个核心时,使用tm_map转换函数的行为不一致

时间:2017-08-25 06:21:13

标签: r parallel-processing text-mining tm doparallel

这篇文章的另一个潜在标题可能是"当在r中进行并行处理时,核心数,循环块大小和对象大小之间的比例是否重要?"

我有一个语料库我正在使用tm包运行一些转换。由于语料库很大,我使用并行处理多波并行包。

有时转换可以完成任务,但有时它们不会。例如,tm::removeNumbers()。语料库中的第一个文档的内容值为" n417"。因此,如果预处理成功,那么此文档将转换为" n"。

下面的样本语料库用于复制。这是代码块:

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)

here是示例数据的链接。我需要粘贴一个足够大的2k文档样本来重新创建,所以我不会粘贴那么多,所以请查看链接的doc数据。

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

如果我运行上面的代码块,n = 200,那么看一下结果 我可以看到数字仍然应该被tm::removeNumbers()

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

但是,如果我将块大小(&#34; n&#34;变量的值)更改为100:

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

这些数字已被移除。

但是,这是不一致的。我试图通过测试150,然后125 ...来缩小它,并发现它将在120和125块大小之间/不会工作。然后在120:125之间迭代函数之后,它有时会工作,然后不是相同的块大小。

我想也许在3个变量之间存在这个问题的关系:语料库的大小,块大小和registerdoparallel()中的核心数量。我只是不知道它是什么。

任何人都可以伸出援助之手,甚至可以使用链接的样本语料库进行复制吗?我担心,因为我有时可以重现错误,有时我不能。更改块大小可以通过删除数字来查看错误,但并非总是如此。

更新 今天我恢复了我的会话,无法复制错误。我创建了一个Google Doc并尝试了不同的语料库大小,核心数量和块大小的值。在每种情况下,一切都是成功的。所以,我尝试运行完整数据,一切正常。但是,为了我的理智,我尝试在完整数据上再次运行,但它失败了。现在,我回到了昨天的位置。 似乎已经在更大的数据集上运行功能已经改变了一些东西......我不知道是什么。也许某种会话变量? 因此,新信息是只有在非常大的数据集上运行函数后才会出现此错误。重新启动我的会话并没有解决问题,但是在离开几个小时之后恢复会话。

新信息。在较大的语料库上重现问题可能更容易,因为这似乎触发了问题corpus <- do.call(c, replicate(250, corpus, simplify = F))将根据我提供的示例创建500k文档语料库。该功能可能在您第一次调用它时起作用,但对我来说,它似乎第二次失败。

这个问题很难,因为如果我可以重现这个问题,我很可能会识别并修复它。

新信息。因为这个函数发生了很多事情,所以很难知道在哪里集中调试工作。我正在研究我使用多个临时RDS文件来节省内存的事实,以及我正在进行并行处理的事实。我写了两个替代版本的脚本,一个仍然使用rds文件并打破语料库但没有进行并行处理(用%do%替换%dopar%并且还删除了registerDoParallel行)和一个使用并行处理但是不使用RDS临时文件来分割小样本语料库。我无法使用单核心版本的脚本生成错误,只有使用%dopar%的版本才能重新创建问题(虽然问题是间歇性的,但并不总是会失败,因为多巴)。 因此,只有在使用%dopar%时才会出现此问题。我使用临时RDS文件的事实似乎不是问题的一部分。

0 个答案:

没有答案