在并行化的foreach循环内分配

时间:2016-02-24 02:20:10

标签: r parallel-processing

我一直在尝试运行一个大型的并行操作,但我很懊恼地知道我无法在并行foreach循环中进行分配。也就是说,尝试运行以下代码不会导致p

更改
p <- numeric(3)
foreach(i=1:3) %dopar% {
  p[i] <- 1
}
p
# [1] 0 0 0

我认为这可能是一个环境问题(即p的作业是本地的),但将<-更改为<<-只会给我一个错误:Error in { : task 1 failed - "object 'p' not found"

是否有某种方法可以使子分配工作或解决此问题?

在我的实际案例中,p[i] <- 1实际上是一个子元素的子分配,它是随机的(但在循环之前预先确定)放置在向量中,所以利用像.combine = c这样的东西是遗憾的是,不可能。

到目前为止我已尝试过:

我尝试使用.combine = `+`解决此问题,如下所示:

s <- foreach(i=1:3, .combine = `+`) %dopar% {
  p <- numeric(3)
  p[i] <- 1
  p
}

虽然这适用于我的小型测试案例,但当我将其应用于我的全尺寸案例时,我得到一个错误(在它运行了大约6个小时后,请注意)R无法分配矢量尺寸6.1 GB。请注意,这比每个循环要生成的单个几百MB向量的大小要大得多,我想这意味着发生了一些隐藏的连接。

我案件的详情

我的问题涉及执行k折交叉验证,这意味着每行数据都会分配到1K,并且foreach循环遍历折叠k = 1:K ,使用folds != k拟合数据模型,然后使用该模型预测剩余数据(folds == k)。所以,暂时忽略这段代码不起作用,我想做一些像

这样的事情。
folds <- sample(1:K, nrow(mydata), replace = TRUE)
preds <- numeric(nrow(mydata))
foreach(k=1:K) %do% {
  m <- fit_model(...)                    # Pseudocode
  preds[folds == k] <- predict_on_model(...) # Pseudocode
}

因此,我的挑战是以正确的顺序获取foreach循环的输出。

1 个答案:

答案 0 :(得分:4)

许多人在第一次注意到你无法使用foreach修改并行循环之外的变量时会感到困惑。您可以使用执行相应分配的“组合”功能来解决您的问题。例如:

library(doSNOW)
cl <- makeSOCKcluster(4)
registerDoSNOW(cl)
K <- 10
N <- 100
set.seed(4325)
folds <- sample(1:K, N, replace=TRUE)

comb <- function(p, ...) {
  for (r in list(...)) {
    p[folds == r$k] <- r$p
  }
  p
}

preds <-
  foreach(k=1:K, .combine='comb', .init=numeric(N),
          .multicombine=TRUE) %dopar% {
    p <- 100 + k  # replace this
    list(k=k, p=p)  # include data needed by the combine function
  }

foreach循环执行并行计算,“combine”功能执行分配。请注意使用foreach .init参数来指定preds向量的初始值。每次调用组合函数时,预测都将在此向量中累积。

另一个解决方案是使用使用folds向量的“final”函数对结果重新排序:

reorder <- function(p) p[folds]
preds <-
  foreach(k=1:K, .combine='c', .final=reorder) %dopar% {
    100 + k  # replace this
  }

虽然这是一种不那么通用的技术,但我怀疑这会更有效率。