Dou*_*Fir 24 parallel-processing r text-mining tm doparallel
这篇文章的另一个潜在标题可能是"当r中的并行处理时,核心数量,循环块大小和对象大小之间的比例是否重要?"
我有一个语料库我正在运行一些使用tm包的转换.由于语料库很大,我使用多路并行包进行并行处理.
有时转换完成任务,但有时它们不会.例如,tm::removeNumbers().语料库中的第一个文档的内容值为"n417".因此,如果预处理成功,那么此doc将转换为"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)
Run Code Online (Sandbox Code Playgroud)
而这里是样本数据的链接.我需要粘贴一个足够大的2k文档样本来重新创建,因此不会让我粘贴那么多,所以请查看链接的doc数据.
corpus <- VCorpus(VectorSource([paste the chr vector from link above]))
Run Code Online (Sandbox Code Playgroud)
如果我运行我的代码块,如上所述,n = 200,那么看看结果,我可以看到数字仍然保留在应该被删除的位置 tm::removeNumbers()
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n417"
[1] "disturbance"
[1] "grand theft auto"
Run Code Online (Sandbox Code Playgroud)
但是,如果我将块大小("n"变量的值)更改为100:
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n"
[1] "disturbance"
[1] "grand theft auto"
Run Code Online (Sandbox Code Playgroud)
这些数字已被删除.
但是,这是不一致的.我试图通过测试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文件的事实似乎不是问题的一部分.
小智 1
如果您尝试使用使用并行处理的程序覆盖您的内存,您应该首先验证它是否值得。
例如,检查您的磁盘是否处于80%-100%的写入速度;如果是这种情况,那么您的程序也可以只使用单个核心,因为无论如何它都会受到磁盘写入速度的阻碍。
如果情况并非如此,我建议您使用调试器或广告控制台/GUI 输出到您的程序来验证所有内容是否按正确的顺序执行。
如果这没有帮助,那么我建议您验证是否没有搞乱程序(例如一个箭头指向错误的方向)。
| 归档时间: |
|
| 查看次数: |
607 次 |
| 最近记录: |