使用 xgboost 和 caret 进行并行处理
Parallel processing with xgboost and caret
我想在使用插入符号时并行化 xgboost 的模型拟合过程。根据我在 xgboost 的 documentation 中看到的内容,nthread
参数控制在以并行方式构建树的意义上拟合模型时使用的线程数。 Caret 的 train
函数将执行并行化,例如,运行 k 重 CV 中每次迭代的过程。这种理解是否正确,如果是,是否更好:
- 注册核心数(例如,使用
doMC
包和registerDoMC
函数),通过caret的train函数设置nthread=1
,以便将该参数传递给xgboost,在 trainControl
中设置 allowParallel=TRUE
,并让 caret
处理交叉验证的并行化;或
- 禁用插入符号并行化(
allowParallel=FALSE
并且没有并行后端注册)并将 nthread
设置为物理内核的数量,因此并行化只包含在 xgboost 中。
或者没有"better"执行并行化的方法?
编辑: I 运行 @topepo 建议的代码,tuneLength = 10
和 search="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
我想在使用插入符号时并行化 xgboost 的模型拟合过程。根据我在 xgboost 的 documentation 中看到的内容,nthread
参数控制在以并行方式构建树的意义上拟合模型时使用的线程数。 Caret 的 train
函数将执行并行化,例如,运行 k 重 CV 中每次迭代的过程。这种理解是否正确,如果是,是否更好:
- 注册核心数(例如,使用
doMC
包和registerDoMC
函数),通过caret的train函数设置nthread=1
,以便将该参数传递给xgboost,在trainControl
中设置allowParallel=TRUE
,并让caret
处理交叉验证的并行化;或 - 禁用插入符号并行化(
allowParallel=FALSE
并且没有并行后端注册)并将nthread
设置为物理内核的数量,因此并行化只包含在 xgboost 中。
或者没有"better"执行并行化的方法?
编辑: I 运行 @topepo 建议的代码,tuneLength = 10
和 search="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