这篇文章的另一个潜在标题可能是R中的并行处理,核心数、循环块大小和对象大小之间的比率重要吗?";
我有一个语料库,我正在使用tm包运行一些转换。由于语料库很大,我使用的是多并行程序包的并行处理。
![python中map函数的使用](https://p.xsw88.cn/allimgs/daicuo/20230903/4255.png)
有时转换会执行任务,但有时不会。例如,tm::removeNumbers()
。语料库中的第一个文档的内容值为&n417";。因此,如果预处理成功,则此文档将转换为仅&q;n&q;。
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个文档的足够大的样本来重新创建,这不能让我粘贴那么多,所以请参阅链接的文档以获取数据。
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"
但是,如果我将区块大小(&n&q;变量的值)更改为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之间迭代函数后,它有时会起作用,但随后不适用于相同的区块大小。我认为这个问题可能与以下三个变量有关:语料库的大小、块大小和registerdoparallel()
中的核心数量。我只是不知道这是什么。
解决方案是什么?这个问题能否在链接的样本语料库中重现?我很担心,因为我有时可以重现错误,但有时我不能。更改区块大小提供了一种查看删除编号错误的能力,但并非总是如此。
更新
今天我恢复了会话,无法复制该错误。我创建了一个Google Docs document,并使用不同的语料库大小、核心数和块大小进行了实验。在每一个案例中,一切都是成功的。所以,我试着用完整的数据运行,一切都正常。然而,为了保持理智,我再次尝试使用完整的数据运行,但失败了。现在,我又回到了昨天的状态。 在较大的数据集上运行该函数似乎改变了一些东西...我不知道是什么!也许是某种会话变量?因此,新的信息是,此错误仅在对非常大的数据集运行该函数后发生。重新启动会话没有解决问题,但在离开几个小时后恢复会话解决了问题。
新信息:
在更大的语料库上重现问题可能更容易,因为这似乎是触发问题的原因corpus <- do.call(c, replicate(250, corpus, simplify = F))
将基于我提供的示例创建一个500K的文档语料库。该函数可能在您第一次调用它时起作用,但对我来说,它第二次似乎失败了。
此问题很难解决,因为如果我可以重现该问题,我很可能能够识别并修复它。
新信息:
由于此函数发生了几件事,因此很难知道应该将重点放在调试工作上。我既考虑了使用多个临时RDS文件来节省内存的事实,也考虑了我正在进行并行处理的事实。我编写了该脚本的两个替代版本,一个仍然使用rds文件并拆分语料库,但不执行并行处理(仅用%do%替换了%DOPA%,还删除了RegisterDoParparal行);另一个使用并行处理,但不使用RDS临时文件来拆分小的样本语料库。
我无法使用脚本的单核版本生成错误,只有使用%DOPA%的版本才能重新创建该问题(虽然该问题是间歇性的,但使用DOPAR并不总是失败)。
因此,此问题仅在使用%dopar%
时出现。我使用的临时RDS文件似乎不是问题的一部分。
推荐答案
如果尝试使用使用并行处理的程序覆盖内存,应首先验证是否值得。
例如,检查您的磁盘是否处于80%-100%的写入速度;如果是这样,则您的程序也可能只使用单个内核,因为它无论如何都会被磁盘写入速度阻止。
如果不是这样,我建议您使用调试器或ad控制台/图形用户界面输出到您的程序,以验证一切都以正确的顺序执行。
如果这不起作用,我建议您验证您没有搞砸程序(例如,一个箭头指向错误的方向)。
相关推荐
最新文章