gpt4 book ai didi

r - 多集群并行方法中启动中的可变范围

转载 作者:行者123 更新时间:2023-12-02 01:59:43 25 4
gpt4 key购买 nike

我想弄清楚如何将函数和包传递给 boot()运行并行计算时的功能。在循环中加载包或定义函数似乎非常昂贵。 foreach()我经常用于其他并行任务的函数有一个 .packages 和 .export 参数,可以很好地处理这个问题(见 SO question ),但我不知道如何用引导包来做到这一点。

下面是一个无意义的例子,显示了切换到并行时会发生什么:

library(boot)
myMean <- function(x) mean(x)
meaninglessTest <- function(x, i){
return(myMean(x[i]))
}

x <- runif(1000)

bootTest <- function(){
out <- boot(data=x, statistic=meaninglessTest, R=10000, parallel="snow", ncpus=4)
return(boot.ci(out, type="perc"))
}

bootTest()

提示(如预期)找不到 myMean .

旁注:运行此示例时,它的运行速度比单核慢,这可能是因为将这个简单的任务拆分到多个核上比实际任务更耗时。为什么默认情况下不拆分为 R/ncpus 的偶数作业批次- 这不是默认行为有什么原因吗?

边注更新 :正如 Steve Weston 所指出的,boot() 使用的 parLapply 实际上将作业拆分为均匀的批次/块。该函数是 clusterApply 的简洁包装器:
docall(c, clusterApply(cl, splitList(x, length(cl)), lapply, 
fun, ...))

我有点惊讶的是,当我扩大重复次数时,这并没有更好的表现:
> library(boot)
> set.seed(10)
> x <- runif(1000)
>
> Reps <- 10^4
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="no")
> Sys.time()-start_time
Time difference of 0.52335 secs
>
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="snow", ncpus=4)
> Sys.time()-start_time
Time difference of 3.539357 secs
>
> Reps <- 10^5
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="no")
> Sys.time()-start_time
Time difference of 5.749831 secs
>
> start_time <- Sys.time()
> res <- boot(data=x, statistic=function(x, i) mean(x[i]),
+ R=Reps, parallel="snow", ncpus=4)
> Sys.time()-start_time
Time difference of 23.06837 secs

我希望这只是由于非常简单的均值函数,并且更复杂的情况表现得更好。我必须承认,我觉得这有点令人不安,因为集群初始化时间在 10.000 和 100.000 情况下应该相同,但绝对时间差增加了,4 核版本需要 5 倍的时间。我想这一定是列表合并的结果,因为我找不到任何其他解释。

最佳答案

如果要并行执行的函数(在本例中为 meaninglessTest)有额外的依赖项(例如 myMean),标准的解决方案是通过 clusterExport 将这些依赖项导出到集群中。功能。这需要创建一个集群对象并将其传递给 boot通过“cl”参数:

library(boot)
library(parallel)
myMean <- function(x) mean(x)
meaninglessTest <- function(x, i){
return(myMean(x[i]))
}
cl <- makePSOCKcluster(4)
clusterExport(cl, 'myMean')

x <- runif(1000)

bootTest <- function() {
out <- boot(data=x, statistic=meaninglessTest, R=10000,
parallel="snow", ncpus=4, cl=cl)
return(boot.ci(out, type="perc"))
}

bootTest()
stopCluster(cl)

请注意,一旦集群工作线程被初始化,它们就可以被 boot 使用。很多次并且不需要重新初始化,所以它不是那么昂贵。

要在集群工作器上加载包,您可以使用 clusterEvalQ :
clusterEvalQ(cl, library(randomForest))

这很好也很简单,但是对于更复杂的 worker 初始化,我通常会创建一个“worker init”函数并通过 clusterCall 执行它。这非常适合在每个工作人员上执行一次功能。

至于你的旁注,性能很差,因为统计函数做的工作很少,正如你所说,但我不确定为什么你认为工作没有在 worker 之间平均分配。 parLapply在这种情况下,函数用于并行执行工作,它确实均匀且高效地拆分工作,但这并不能保证比使用 lapply 顺序运行更好的性能。 .但也许我误解了你的问题。

关于r - 多集群并行方法中启动中的可变范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17879766/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com