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 个内核)总共)?查询在给定时间使用了多少内核的方法是什么?
在并行交叉验证示例中,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 在每个节点上为每个核心启动一个工作程序。
请注意,您的示例不会使用太多计算时间,因此使用两个并行级别并不值得。我会使用一个更大的问题来确定不同方法的好处。