使用mlrMBO做XGBoost超参数贝叶斯优化结果不可复现问题求解
问题根因及修复方案
以下是导致结果无法复现的核心原因及对应修改方案:
- XGBoost内部随机性未控制
仅设置R语言全局种子无法控制XGBoost本身的随机状态,同时nthreads = NULL会调用所有可用CPU核心,多线程并行本身会引入计算误差和随机性。
修复方式:在xgb.cv参数中添加seed = 1234,固定nthreads = 1(如需多线程可固定为明确数值,如nthreads = 4,不要留空)。 - rgenoud优化器种子未固定
克里金模型选用的优化方式optim.method = "gen"本质是调用rgenoud优化器,该优化器的随机过程不受R全局种子控制,需要显式传入种子参数。
修复方式:在makeLearner的control参数中添加seed = 1234,对应rgenoud的随机种子设置。 - 全局种子设置不一致
函数内部设置种子时指定了"L'Ecuyer-CMRG"类型,但最后两次调用bayes()函数前仅设置了数值种子,未指定类型,导致种子序列不匹配。
修复方式:所有set.seed调用统一使用set.seed(1234, kind = "L'Ecuyer-CMRG")。 - MBO内部采样随机性未控制
mlrMBO的infill优化过程自带随机采样步骤,需要在控制对象中显式设置种子。
修复方式:在创建control对象后添加control$seed = 1234。
修改后可复现的完整代码
db <- read.delim("https://drive.google.com/uc?export=download&id=1JXMUbwAWi8jjRPGQxzC15tUzSIWrPfNH") db <- as.data.frame(db) # 贝叶斯优化 library("xgboost") library("data.table") library("tidymodels") library("mlrMBO") library("skimr") library("DiceKriging") library("rgenoud") library("Matrix") sparse_matrix <- sparse.model.matrix(outcome ~ .-1, data = db) labels <- db$outcome db_xgb <- xgb.DMatrix(data = sparse_matrix, label = labels) obj.fun <- smoof::makeSingleObjectiveFunction( name = "xgbcv", fn = function(x) { set.seed(1234, kind = "L'Ecuyer-CMRG") xgbcv <- xgb.cv( params = list( nthreads = 1, max_depth = x["max_depth"], min_child_weight = x["min_child_weight"], eta = x["eta"], gamma = x["gamma"], max_delta_step = x["max_delta_step"], alpha = x["alpha"], lambda = x["lambda"], booster = "gbtree", objective = "binary:logistic", eval_metric = "logloss" ), tree_method = "hist", nround = 1000, nfold = 5, early_stopping_rounds = 50, verbose = 0, maximize = F, data = db_xgb, seed = 1234 ) min(xgbcv$evaluation_log$test_logloss_mean) }, par.set = makeParamSet( makeNumericParam("eta", lower = 0.0001, upper = 0.5), makeNumericParam("gamma", lower = 0, upper = 20), makeIntegerParam("max_depth", lower = 1, upper = 50), makeIntegerParam("min_child_weight", lower = 1, upper = 10), makeNumericParam("max_delta_step", lower = 0, upper = 10), makeNumericParam("alpha", lower = 0, upper = 10), makeNumericParam("lambda", lower = 0, upper = 10) ), minimize = T ) bayes <- function(n_design = (10*getNumberOfParameters(obj.fun)), opt_steps = 50) { set.seed(1234, kind = "L'Ecuyer-CMRG") des <- generateDesign(n = n_design, par.set = getParamSet(obj.fun), fun = lhs::optimumLHS) set.seed(1234, kind = "L'Ecuyer-CMRG") des$y <- apply(des, 1, obj.fun) control <- makeMBOControl() control <- setMBOControlTermination(control, iters = 50) control <- setMBOControlInfill(control, crit = makeMBOInfillCritEI()) control$seed <- 1234 set.seed(1234, kind = "L'Ecuyer-CMRG") run <- mbo( fun = obj.fun, design = des, learner = makeLearner( "regr.km", predict.type = "se", covtype = "matern3_2", optim.method = "gen", nugget.estim = F, jitter = F, nugget = 1e-22, control = list(trace = F, seed = 1234) ), control = control, show.info = T ) optimization_process <- as.data.frame( run$opt.path$env$path %>% dplyr::mutate(round = row_number()) %>% dplyr::mutate(type = case_when( round <= n_design ~ "design", TRUE ~ "bayesian optimization" )) ) return(list(optimization_process)) } set.seed(1234, kind = "L'Ecuyer-CMRG") runs <- bayes() bayes_1 <- as.data.frame(runs[[1]]) set.seed(1234, kind = "L'Ecuyer-CMRG") runs <- bayes() bayes_2 <- as.data.frame(runs[[1]]) # 验证一致性 all.equal(bayes_1, bayes_2)
内容的提问来源于stack exchange,提问作者dean
相关产品推荐
相关产品推荐

