使用多核时tm_map变换函数的行为不一致多核、函数、行为、tm_map

由网友(浮若年华)分享简介:这篇文章的另一个潜在标题可能是R中的并行处理,核心数、循环块大小和对象大小之间的比率重要吗?";我有一个语料库,我正在使用tm包运行一些转换。由于语料库很大,我使用的是多并行程序包的并行处理。有时转换会执行任务,但有时不会。例如,tm::removeNumbers()。语料库中的第一个文档的内容值为&n41...

这篇文章的另一个潜在标题可能是R中的并行处理,核心数、循环块大小和对象大小之间的比率重要吗?";

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

python中map函数的使用

有时转换会执行任务,但有时不会。例如,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控制台/图形用户界面输出到您的程序,以验证一切都以正确的顺序执行。

如果这不起作用,我建议您验证您没有搞砸程序(例如,一个箭头指向错误的方向)。

阅读全文

相关推荐

最新文章