在 R 中嵌套并行函数(

dyn*_*amo 5 parallel-processing foreach nested r glmnet

我熟悉foreach,%dopar%之类的。我也是熟悉parallel的选项cv.glmnet。但是你如何设置嵌套的并行性如下?

library(glmnet)
library(foreach)
library(parallel)
library(doSNOW)
Npar <- 1000
Nobs <- 200
Xdat <- matrix(rnorm(Nobs * Npar), ncol = Npar)
Xclass <- rep(1:2, each = Nobs/2)
Ydat <- rnorm(Nobs)
Run Code Online (Sandbox Code Playgroud)

并行交叉验证:

cl <- makeCluster(8, type = "SOCK")
registerDoSNOW(cl)
system.time(mods <- foreach(x = 1:2, .packages = "glmnet") %dopar% {
    idx <- Xclass == x
    cv.glmnet(Xdat[idx,], Ydat[idx], nfolds = 4, parallel = TRUE)
})
stopCluster(cl)
Run Code Online (Sandbox Code Playgroud)

非并行交叉验证:

cl <- makeCluster(8, type = "SOCK")
registerDoSNOW(cl)
system.time(mods <- foreach(x = 1:2, .packages = "glmnet") %dopar% {
    idx <- Xclass == x
    cv.glmnet(Xdat[idx,], Ydat[idx], nfolds = 4, parallel = FALSE)
})
stopCluster(cl)
Run Code Online (Sandbox Code Playgroud)

对于两个系统时间,我只得到了很小的差异。

是否采用并行化?还是我需要明确使用嵌套运算符?

附带问题:如果集群对象中有 8 个内核可用并且foreach循环包含两个任务,那么每个任务会被分配 1 个内核(而其他 6 个内核空闲)还是每个任务会被分配 4 个内核(用完所有 8 个内核)总共)?查询在给定时间使用了多少内核的方法是什么?

Ste*_*ton 3

在并行交叉验证示例中,cv.glmnet 本身不会并行运行,因为集群工作线程中没有注册 foreach 并行后端。外部 foreach 循环将并行运行,但 cv.glmnet 函数中的 foreach 循环不会并行运行。

要将 doSNOW 用于外部和内部 foreach 循环,您可以使用 clusterCall 初始化雪集群工作人员:

cl <- makeCluster(2, type = "SOCK")
clusterCall(cl, function() {
  library(doSNOW)
  registerDoSNOW(makeCluster(2, type = "SOCK"))
  NULL
})
registerDoSNOW(cl)
Run Code Online (Sandbox Code Playgroud)

这会为主节点和工作节点注册 doSNOW,以便在parallel=TRUE指定时对 cv.glmnet 的每次调用都将在双工作节点集群上执行。

嵌套并行的技巧是避免创建太多进程和过度订阅 CPU(或多个 CPU),因此在注册并行后端时需要小心。我的示例对于具有四个核心的 CPU 来说是有意义的,即使总共创建了 6 个工作线程,因为“外部”工作线程在执行内部 foreach 循环时不会执行太多操作。在集群上运行时,通常使用 doSNOW 为每个节点启动一个工作程序,然后使用 doMC 在每个节点上为每个核心启动一个工作程序。

请注意,您的示例不会使用太多计算时间,因此使用两个并行级别并不值得。我会使用一个更大的问题来确定不同方法的好处。