【问题标题】:Assignment inside parallelized foreach loop并行化 foreach 循环内的赋值
【发布时间】:2016-02-24 02:20:09
【问题描述】:

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

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

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

有没有办法让子分配工作或解决这个问题?

在我的真实案例中,p[i] &lt;- 1 实际上是向量中随机(但在循环之前预先确定)位置的多个元素的子赋值,因此可悲的是,利用 .combine = c 之类的东西是不可能的问题。

到目前为止我尝试过的:

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

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

虽然这适用于我的小型测试用例,但当我将它应用到我的全尺寸用例时,我收到了一个错误(在运行大约 6 小时后,请注意)R 无法分配大小为 6.1 的向量国标。请注意,这比每个循环要生成的数百 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 循环的输出。

【问题讨论】:

  • 我不明白你的问题,但我通常使用的语法是:p_list &lt;- foreach(i=1:3) %dopar% 1; unlist(p_list) #returns c(1,1,1)。每个线程都有自己的小环境(这就是您必须加载 .packages= 的原因)所以我不确定您为什么希望在一个环境中进行的分配在另一个环境中持续存在。
  • 你试过p &lt;- foreach(i=1:3, .combine='c') %dopar% 1吗?不要尝试在循环之外使用对变量的赋值,就好像这是一个 for 循环:使用由 combine 函数处理的返回值。你希望最终的返回值是多少?
  • @SteveWeston 我想做这个作业的最初原因是,以正确的顺序返回结果很重要,而正确的顺序有点复杂。我将在问题中添加更多相关信息。

标签: r parallel-processing


【解决方案1】:

当许多人第一次注意到您不能使用 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 向量的初始值。每次调用 combine 函数时,预测都会在该向量中累积。

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

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

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

【讨论】:

    猜你喜欢
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 2016-09-26
    • 2012-07-19
    • 1970-01-01
    相关资源
    最近更新 更多