使用 xgboost 和 caret 进行并行处理

Parallel processing with xgboost and caret

我想在使用插入符号时并行化 xgboost 的模型拟合过程。根据我在 xgboost 的 documentation 中看到的内容,nthread 参数控制在以并行方式构建树的意义上拟合模型时使用的线程数。 Caret 的 train 函数将执行并行化,例如,运行 k 重 CV 中每次迭代的过程。这种理解是否正确,如果是,是否更好:

  1. 注册核心数(例如,使用doMC包和registerDoMC函数),通过caret的train函数设置nthread=1,以便将该参数传递给xgboost,在 trainControl 中设置 allowParallel=TRUE,并让 caret 处理交叉验证的并行化;或
  2. 禁用插入符号并行化(allowParallel=FALSE 并且没有并行后端注册)并将 nthread 设置为物理内核的数量,因此并行化只包含在 xgboost 中。

或者没有"better"执行并行化的方法?

编辑: I 运行 @topepo 建议的代码,tuneLength = 10search="random",并指定 nthread=1在最后一行(否则我知道 xgboost 将使用多线程)。有我得到的结果:

xgb_par[3]
elapsed  
283.691 
just_seq[3]
elapsed 
276.704 
mc_par[3]
elapsed 
89.074 
just_seq[3]/mc_par[3]
elapsed 
3.106451 
just_seq[3]/xgb_par[3]
elapsed 
0.9753711 
xgb_par[3]/mc_par[3]
elapsed 
3.184891

最后,事实证明,对于我的数据和这个测试用例,让 caret 处理并行化在运行时方面是更好的选择。

预测最佳策略并不简单。我的(有偏见的)想法是你应该并行化花费时间最长的过程。在这里,这将是重采样循环,因为打开 thread/worker 会多次调用模型。并行化模型拟合的相反方法将反复启动和停止工作人员,理论上会减慢速度。你的旅费可能会改变。

我没有安装 OpenMP,但下面有代码可以测试(如果您可以报告您的结果,那将会很有帮助)。

library(caret)
library(plyr)
library(xgboost)
library(doMC)

foo <- function(...) {
  set.seed(2)
  mod <- train(Class ~ ., data = dat, 
               method = "xgbTree", tuneLength = 50,
               ..., trControl = trainControl(search = "random"))
  invisible(mod)
}

set.seed(1)
dat <- twoClassSim(1000)

just_seq <- system.time(foo())


## I don't have OpenMP installed
xgb_par <- system.time(foo(nthread = 5))

registerDoMC(cores=5)
mc_par <- system.time(foo())

我的结果(没有 OpenMP)

> just_seq[3]
elapsed 
326.422 
> xgb_par[3]
elapsed 
319.862 
> mc_par[3]
elapsed 
102.329 
> 
> ## Speedups
> xgb_par[3]/mc_par[3]
elapsed 
3.12582 
> just_seq[3]/mc_par[3]
 elapsed 
3.189927 
> just_seq[3]/xgb_par[3]
 elapsed 
1.020509