From 06042020d2f6f6d4e3ab738e0670c75c554f19b0 Mon Sep 17 00:00:00 2001 From: be-marc Date: Thu, 8 Feb 2024 11:41:09 +0100 Subject: [PATCH 01/26] draft --- DESCRIPTION | 4 +- NAMESPACE | 2 + R/AcqFunction.R | 2 +- R/OptimizerADBO.R | 114 ++++++++++++++++++++++++++ R/Surrogate.R | 2 +- R/SurrogateLearner.R | 14 +++- R/TunerADBO.R | 20 +++++ R/helper.R | 6 +- R/mbo_defaults.R | 2 +- man/AcqFunction.Rd | 8 +- man/ResultAssigner.Rd | 4 +- man/loop_function.Rd | 4 +- man/mlr_acqfunctions.Rd | 4 +- man/mlr_acqfunctions_aei.Rd | 8 +- man/mlr_acqfunctions_cb.Rd | 8 +- man/mlr_acqfunctions_ehvi.Rd | 6 +- man/mlr_acqfunctions_ehvigh.Rd | 6 +- man/mlr_acqfunctions_ei.Rd | 6 +- man/mlr_acqfunctions_eips.Rd | 6 +- man/mlr_acqfunctions_mean.Rd | 8 +- man/mlr_acqfunctions_pi.Rd | 8 +- man/mlr_acqfunctions_sd.Rd | 8 +- man/mlr_acqfunctions_smsego.Rd | 8 +- man/mlr_loop_functions_ego.Rd | 4 +- man/mlr_loop_functions_emo.Rd | 4 +- man/mlr_loop_functions_mpcl.Rd | 4 +- man/mlr_loop_functions_parego.Rd | 4 +- man/mlr_loop_functions_smsego.Rd | 4 +- man/mlr_result_assigners_archive.Rd | 4 +- man/mlr_result_assigners_surrogate.Rd | 4 +- tests/testthat/helper.R | 12 +++ tests/testthat/test_OptimizerADBO.R | 113 +++++++++++++++++++++++++ 32 files changed, 341 insertions(+), 70 deletions(-) create mode 100644 R/OptimizerADBO.R create mode 100644 R/TunerADBO.R create mode 100644 tests/testthat/test_OptimizerADBO.R diff --git a/DESCRIPTION b/DESCRIPTION index 2f73386d..10a6743d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -72,7 +72,7 @@ Config/testthat/edition: 3 Config/testthat/parallel: false NeedsCompilation: yes Roxygen: list(markdown = TRUE, r6 = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Collate: 'mlr_acqfunctions.R' 'AcqFunction.R' @@ -88,6 +88,7 @@ Collate: 'AcqFunctionSmsEgo.R' 'AcqOptimizer.R' 'aaa.R' + 'OptimizerADBO.R' 'OptimizerMbo.R' 'mlr_result_assigners.R' 'ResultAssigner.R' @@ -96,6 +97,7 @@ Collate: 'Surrogate.R' 'SurrogateLearner.R' 'SurrogateLearnerCollection.R' + 'TunerADBO.R' 'TunerMbo.R' 'mlr_loop_functions.R' 'bayesopt_ego.R' diff --git a/NAMESPACE b/NAMESPACE index 1a02acdc..19a9927f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,6 +16,7 @@ export(AcqFunctionPI) export(AcqFunctionSD) export(AcqFunctionSmsEgo) export(AcqOptimizer) +export(OptimizerADBO) export(OptimizerMbo) export(ResultAssigner) export(ResultAssignerArchive) @@ -23,6 +24,7 @@ export(ResultAssignerSurrogate) export(Surrogate) export(SurrogateLearner) export(SurrogateLearnerCollection) +export(TunerADBO) export(TunerMbo) export(acqf) export(acqo) diff --git a/R/AcqFunction.R b/R/AcqFunction.R index d7045f91..6b21f46d 100644 --- a/R/AcqFunction.R +++ b/R/AcqFunction.R @@ -176,7 +176,7 @@ AcqFunction = R6Class("AcqFunction", stopf("Acquisition function '%s' requires the surrogate to have `\"se\"` as `$predict_type`.", format(self)) } private$.surrogate = rhs - private$.archive = assert_r6(rhs$archive, classes = "Archive") + private$.archive = assert_multi_class(rhs$archive, c("Archive", "ArchiveRush")) codomain = generate_acq_codomain(rhs, id = self$id, direction = self$direction) self$surrogate_max_to_min = surrogate_mult_max_to_min(rhs) domain = generate_acq_domain(rhs) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R new file mode 100644 index 00000000..24b6e0f0 --- /dev/null +++ b/R/OptimizerADBO.R @@ -0,0 +1,114 @@ +#' @export +OptimizerADBO = R6Class("OptimizerADBO", + inherit = bbotk::Optimizer, + + public = list( + + initialize = function() { + param_set = ps( + init_design_size = p_int(lower = 1L), + initial_design = p_uty() + ) + + super$initialize("adbo", + param_set = param_set, + param_classes = c("ParamLgl", "ParamInt", "ParamDbl", "ParamFct"), + properties = c("dependencies", "multi-crit", "single-crit"), + packages = "mlr3mbo", + label = "Asynchronous Decentralized Bayesian Optimization", + man = "mlr3mbo::OptimizerADBO") + }, + + optimize = function(inst) { + + if (rush_available()) { + + # generate initial design + pv = self$param_set$values + design = if (is.null(pv$initial_design)) { + generate_design_sobol(inst$search_space, n = pv$init_design_size)$data + } else { + pv$initial_design + } + + # send initial design to workers + inst$rush$push_tasks(transpose_list(design), extra = list(list(timestamp_xs = Sys.time()))) + + # start rush workers + inst$rush$start_workers( + worker_loop = bbotk_worker_loop_decentralized, + packages = c("bbotk", "mlr3mbo"), + optimizer = self, + instance = inst, + lgr_thresholds = c(rush = "debug", bbotk = "debug"), + wait_for_workers = TRUE) + } else { + stop("No rush plan available. See `?rush::rush_plan()`") + } + + lg$info("Starting to optimize %i parameter(s) with '%s' and '%s' on %i worker(s)", + inst$search_space$length, + self$format(), + inst$terminator$format(with_params = TRUE), + inst$rush$n_running_workers + ) + + # wait + while(!inst$is_terminated) { + Sys.sleep(1) + inst$rush$detect_lost_workers() + } + + # assign result + private$.assign_result(inst) + + # assign result + private$.assign_result(inst) + lg$info("Finished optimizing after %i evaluation(s)", inst$archive$n_evals) + lg$info("Result:") + lg$info(capture.output(print(inst$result, lass = FALSE, row.names = FALSE, print.keys = FALSE))) + return(inst$result) + + result + } + ), + + private = list( + + .optimize_remote = function(inst) { + search_space = inst$search_space + rush = inst$rush + + surrogate = default_surrogate(inst) + surrogate$param_set$set_values(impute_missings = TRUE) + acq_function = acqf("cb", lambda = runif(1, 1 , 3)) + acq_optimizer = acqo(opt("random_search", batch_size = 1000L), terminator = trm("evals", n_evals = 10000L)) + + surrogate$archive = inst$archive + acq_function$surrogate = surrogate + acq_optimizer$acq_function = acq_function + + # evaluate initial design + while (rush$n_queued_tasks > 0) { + task = rush$pop_task(fields = "xs") + xs_trafoed = trafo_xs(task$xs, inst$search_space) + ys = inst$objective$eval(xs_trafoed) + rush$push_results(task$key, yss = list(ys), extra = list(list(timestamp_ys = Sys.time(), stage = "initial_design"))) + } + + # actual loop + while (!inst$is_terminated) { + acq_function$surrogate$update() + acq_function$update() + xdt = acq_optimizer$optimize() + xss = transform_xdt_to_xss(xdt, search_space) + keys = rush$push_running_task(xss, extra = list(list(timestamp_xs = Sys.time()))) + ys = inst$objective$eval(xss[[1]]) + rush$push_results(keys, list(ys), extra = list(list(timestamp_ys = Sys.time(), stage = "mbo"))) + } + } + ) +) + +#' @include aaa.R +optimizers[["adbo"]] = OptimizerADBO diff --git a/R/Surrogate.R b/R/Surrogate.R index b1b15b28..506c5f42 100644 --- a/R/Surrogate.R +++ b/R/Surrogate.R @@ -99,7 +99,7 @@ Surrogate = R6Class("Surrogate", if (missing(rhs)) { private$.archive } else { - private$.archive = assert_r6(rhs, classes = "Archive") + private$.archive = assert_multi_class(rhs, c("Archive", "ArchiveRush")) invisible(private$.archive) } }, diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index c7ed9549..35730b01 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -87,9 +87,10 @@ SurrogateLearner = R6Class("SurrogateLearner", ParamLgl$new("assert_insample_perf"), ParamUty$new("perf_measure", custom_check = function(x) check_r6(x, classes = "MeasureRegr")), # FIXME: actually want check_measure ParamDbl$new("perf_threshold", lower = -Inf, upper = Inf), - ParamLgl$new("catch_errors")) + ParamLgl$new("catch_errors"), + ParamLgl$new("impute_missings")) ) - ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE) + ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE, impute_missings = FALSE) ps$add_dep("perf_measure", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) ps$add_dep("perf_threshold", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) @@ -214,7 +215,14 @@ SurrogateLearner = R6Class("SurrogateLearner", # Train learner with new data. # Also calculates the insample performance based on the `perf_measure` hyperparameter if `assert_insample_perf = TRUE`. .update = function() { - xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] + + if (self$param_set$values$impute_missings) { + xydt = self$archive$rush$fetch_tasks(fields = c("xs", "ys"))[, c(self$cols_x, self$cols_y), with = FALSE] + setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) + } else { + xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] + } + task = TaskRegr$new(id = "surrogate_task", backend = xydt, target = self$cols_y) assert_learnable(task, learner = self$learner) self$learner$train(task) diff --git a/R/TunerADBO.R b/R/TunerADBO.R new file mode 100644 index 00000000..e0fa1f04 --- /dev/null +++ b/R/TunerADBO.R @@ -0,0 +1,20 @@ +#' @export +TunerADBO = R6Class("TunerADBO", + inherit = mlr3tuning::TunerFromOptimizer, + public = list( + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + initialize = function() { + super$initialize( + optimizer = OptimizerADBO$new(), + man = "mlr3tuning::mlr_tuners_adbo" + ) + } + ) +) + +mlr_tuners$add("adbo", TunerADBO) + +#' @include aaa.R +tuners[["adbo"]] = TunerADBO diff --git a/R/helper.R b/R/helper.R index 1caf1ca1..cc19e336 100644 --- a/R/helper.R +++ b/R/helper.R @@ -1,5 +1,5 @@ generate_acq_codomain = function(surrogate, id, direction = "same") { - assert_r6(surrogate$archive, classes = "Archive") + assert_multi_class(surrogate$archive, c("Archive", "ArchiveRush")) assert_string(id) assert_choice(direction, choices = c("same", "minimize", "maximize")) if (direction == "same") { @@ -18,7 +18,7 @@ generate_acq_codomain = function(surrogate, id, direction = "same") { } generate_acq_domain = function(surrogate) { - assert_r6(surrogate$archive, classes = "Archive") + assert_multi_class(surrogate$archive, c("Archive", "ArchiveRush")) domain = surrogate$archive$search_space$clone(deep = TRUE)$subset(surrogate$cols_x) domain$trafo = NULL domain @@ -130,7 +130,7 @@ check_learner_surrogate = function(learner) { return(TRUE) } } - + "Must inherit from class 'Learner' or be a list of elements inheriting from class 'Learner'" } diff --git a/R/mbo_defaults.R b/R/mbo_defaults.R index a7d68d7e..9d54e411 100644 --- a/R/mbo_defaults.R +++ b/R/mbo_defaults.R @@ -147,7 +147,7 @@ default_rf = function(noisy = FALSE) { #' @family mbo_defaults #' @export default_surrogate = function(instance, learner = NULL, n_learner = NULL) { - assert_r6(instance, "OptimInstance") + assert_multi_class(instance, c("OptimInstance", "OptimInstanceRush")) assert_r6(learner, "Learner", null.ok = TRUE) assert_int(n_learner, lower = 1L, null.ok = TRUE) noisy = "noisy" %in% instance$objective$properties diff --git a/man/AcqFunction.Rd b/man/AcqFunction.Rd index 9d031bfa..ba807720 100644 --- a/man/AcqFunction.Rd +++ b/man/AcqFunction.Rd @@ -10,17 +10,17 @@ Based on the predictions of a \link{Surrogate}, the acquisition function encodes } \seealso{ Other Acquisition Function: +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super class}{ diff --git a/man/ResultAssigner.Rd b/man/ResultAssigner.Rd index aba61af4..28ea502a 100644 --- a/man/ResultAssigner.Rd +++ b/man/ResultAssigner.Rd @@ -11,9 +11,9 @@ Normally, it is only used within an \link{OptimizerMbo}. } \seealso{ Other Result Assigner: +\code{\link{mlr_result_assigners}}, \code{\link{mlr_result_assigners_archive}}, -\code{\link{mlr_result_assigners_surrogate}}, -\code{\link{mlr_result_assigners}} +\code{\link{mlr_result_assigners_surrogate}} } \concept{Result Assigner} \section{Active bindings}{ diff --git a/man/loop_function.Rd b/man/loop_function.Rd index 623d171a..063bb38c 100644 --- a/man/loop_function.Rd +++ b/man/loop_function.Rd @@ -15,11 +15,11 @@ As an example, see, e.g., \link{bayesopt_ego}. } \seealso{ Other Loop Function: +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_ego}}, \code{\link{mlr_loop_functions_emo}}, \code{\link{mlr_loop_functions_mpcl}}, \code{\link{mlr_loop_functions_parego}}, -\code{\link{mlr_loop_functions_smsego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_smsego}} } \concept{Loop Function} diff --git a/man/mlr_acqfunctions.Rd b/man/mlr_acqfunctions.Rd index 5172c72e..1cb921ac 100644 --- a/man/mlr_acqfunctions.Rd +++ b/man/mlr_acqfunctions.Rd @@ -34,10 +34,10 @@ Other Acquisition Function: \code{\link{AcqFunction}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, diff --git a/man/mlr_acqfunctions_aei.Rd b/man/mlr_acqfunctions_aei.Rd index 729a1bfa..56957d63 100644 --- a/man/mlr_acqfunctions_aei.Rd +++ b/man/mlr_acqfunctions_aei.Rd @@ -79,16 +79,16 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_cb.Rd b/man/mlr_acqfunctions_cb.Rd index 6d211a30..d94ae789 100644 --- a/man/mlr_acqfunctions_cb.Rd +++ b/man/mlr_acqfunctions_cb.Rd @@ -68,16 +68,16 @@ In Pereira F, Burges CJC, Bottou L, Weinberger KQ (eds.), \emph{Advances in Neur \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_ehvi.Rd b/man/mlr_acqfunctions_ehvi.Rd index fe06da33..160eb8fa 100644 --- a/man/mlr_acqfunctions_ehvi.Rd +++ b/man/mlr_acqfunctions_ehvi.Rd @@ -54,16 +54,16 @@ Springer International Publishing, Cham. \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, \code{\link{mlr_acqfunctions_ehvigh}}, -\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_ehvigh.Rd b/man/mlr_acqfunctions_ehvigh.Rd index bd331c8f..9d9a2c27 100644 --- a/man/mlr_acqfunctions_ehvigh.Rd +++ b/man/mlr_acqfunctions_ehvigh.Rd @@ -68,16 +68,16 @@ In Rudolph, Günter, Kononova, V. A, Aguirre, Hernán, Kerschke, Pascal, Ochoa, \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_ei.Rd b/man/mlr_acqfunctions_ei.Rd index ddb9d3a1..0fe783ea 100644 --- a/man/mlr_acqfunctions_ei.Rd +++ b/man/mlr_acqfunctions_ei.Rd @@ -60,16 +60,16 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_eips.Rd b/man/mlr_acqfunctions_eips.Rd index d67e3392..214f654b 100644 --- a/man/mlr_acqfunctions_eips.Rd +++ b/man/mlr_acqfunctions_eips.Rd @@ -68,16 +68,16 @@ In Pereira F, Burges CJC, Bottou L, Weinberger KQ (eds.), \emph{Advances in Neur \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_mean.Rd b/man/mlr_acqfunctions_mean.Rd index ced81a81..c9d602e2 100644 --- a/man/mlr_acqfunctions_mean.Rd +++ b/man/mlr_acqfunctions_mean.Rd @@ -53,16 +53,16 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_pi}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_pi.Rd b/man/mlr_acqfunctions_pi.Rd index bb7ac077..cc69d6e0 100644 --- a/man/mlr_acqfunctions_pi.Rd +++ b/man/mlr_acqfunctions_pi.Rd @@ -60,16 +60,16 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_sd.Rd b/man/mlr_acqfunctions_sd.Rd index f415bb47..ab434ac9 100644 --- a/man/mlr_acqfunctions_sd.Rd +++ b/man/mlr_acqfunctions_sd.Rd @@ -53,16 +53,16 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, -\code{\link{mlr_acqfunctions_smsego}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_smsego}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_acqfunctions_smsego.Rd b/man/mlr_acqfunctions_smsego.Rd index ad51095c..e5d6c865 100644 --- a/man/mlr_acqfunctions_smsego.Rd +++ b/man/mlr_acqfunctions_smsego.Rd @@ -70,16 +70,16 @@ In \emph{International Conference on Evolutionary Multi-Criterion Optimization}, \seealso{ Other Acquisition Function: \code{\link{AcqFunction}}, +\code{\link{mlr_acqfunctions}}, \code{\link{mlr_acqfunctions_aei}}, \code{\link{mlr_acqfunctions_cb}}, -\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ehvi}}, -\code{\link{mlr_acqfunctions_eips}}, +\code{\link{mlr_acqfunctions_ehvigh}}, \code{\link{mlr_acqfunctions_ei}}, +\code{\link{mlr_acqfunctions_eips}}, \code{\link{mlr_acqfunctions_mean}}, \code{\link{mlr_acqfunctions_pi}}, -\code{\link{mlr_acqfunctions_sd}}, -\code{\link{mlr_acqfunctions}} +\code{\link{mlr_acqfunctions_sd}} } \concept{Acquisition Function} \section{Super classes}{ diff --git a/man/mlr_loop_functions_ego.Rd b/man/mlr_loop_functions_ego.Rd index 02f95fbd..1420a86d 100644 --- a/man/mlr_loop_functions_ego.Rd +++ b/man/mlr_loop_functions_ego.Rd @@ -134,10 +134,10 @@ In Pereira F, Burges CJC, Bottou L, Weinberger KQ (eds.), \emph{Advances in Neur \seealso{ Other Loop Function: \code{\link{loop_function}}, +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_emo}}, \code{\link{mlr_loop_functions_mpcl}}, \code{\link{mlr_loop_functions_parego}}, -\code{\link{mlr_loop_functions_smsego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_smsego}} } \concept{Loop Function} diff --git a/man/mlr_loop_functions_emo.Rd b/man/mlr_loop_functions_emo.Rd index 1b765d17..bcb212bc 100644 --- a/man/mlr_loop_functions_emo.Rd +++ b/man/mlr_loop_functions_emo.Rd @@ -101,10 +101,10 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Loop Function: \code{\link{loop_function}}, +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_ego}}, \code{\link{mlr_loop_functions_mpcl}}, \code{\link{mlr_loop_functions_parego}}, -\code{\link{mlr_loop_functions_smsego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_smsego}} } \concept{Loop Function} diff --git a/man/mlr_loop_functions_mpcl.Rd b/man/mlr_loop_functions_mpcl.Rd index bd9ae1b8..7d56c763 100644 --- a/man/mlr_loop_functions_mpcl.Rd +++ b/man/mlr_loop_functions_mpcl.Rd @@ -125,10 +125,10 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Loop Function: \code{\link{loop_function}}, +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_ego}}, \code{\link{mlr_loop_functions_emo}}, \code{\link{mlr_loop_functions_parego}}, -\code{\link{mlr_loop_functions_smsego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_smsego}} } \concept{Loop Function} diff --git a/man/mlr_loop_functions_parego.Rd b/man/mlr_loop_functions_parego.Rd index 527e60c3..f87fa2a6 100644 --- a/man/mlr_loop_functions_parego.Rd +++ b/man/mlr_loop_functions_parego.Rd @@ -128,10 +128,10 @@ if (requireNamespace("mlr3learners") & \seealso{ Other Loop Function: \code{\link{loop_function}}, +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_ego}}, \code{\link{mlr_loop_functions_emo}}, \code{\link{mlr_loop_functions_mpcl}}, -\code{\link{mlr_loop_functions_smsego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_smsego}} } \concept{Loop Function} diff --git a/man/mlr_loop_functions_smsego.Rd b/man/mlr_loop_functions_smsego.Rd index 79a4fd13..82284754 100644 --- a/man/mlr_loop_functions_smsego.Rd +++ b/man/mlr_loop_functions_smsego.Rd @@ -112,10 +112,10 @@ In \emph{Proceedings of the 10th International Conference on Parallel Problem So \seealso{ Other Loop Function: \code{\link{loop_function}}, +\code{\link{mlr_loop_functions}}, \code{\link{mlr_loop_functions_ego}}, \code{\link{mlr_loop_functions_emo}}, \code{\link{mlr_loop_functions_mpcl}}, -\code{\link{mlr_loop_functions_parego}}, -\code{\link{mlr_loop_functions}} +\code{\link{mlr_loop_functions_parego}} } \concept{Loop Function} diff --git a/man/mlr_result_assigners_archive.Rd b/man/mlr_result_assigners_archive.Rd index 94f44c44..11e3c5a5 100644 --- a/man/mlr_result_assigners_archive.Rd +++ b/man/mlr_result_assigners_archive.Rd @@ -14,8 +14,8 @@ result_assigner = ras("archive") \seealso{ Other Result Assigner: \code{\link{ResultAssigner}}, -\code{\link{mlr_result_assigners_surrogate}}, -\code{\link{mlr_result_assigners}} +\code{\link{mlr_result_assigners}}, +\code{\link{mlr_result_assigners_surrogate}} } \concept{Result Assigner} \section{Super class}{ diff --git a/man/mlr_result_assigners_surrogate.Rd b/man/mlr_result_assigners_surrogate.Rd index c337fc61..1a0d3251 100644 --- a/man/mlr_result_assigners_surrogate.Rd +++ b/man/mlr_result_assigners_surrogate.Rd @@ -16,8 +16,8 @@ result_assigner = ras("surrogate") \seealso{ Other Result Assigner: \code{\link{ResultAssigner}}, -\code{\link{mlr_result_assigners_archive}}, -\code{\link{mlr_result_assigners}} +\code{\link{mlr_result_assigners}}, +\code{\link{mlr_result_assigners_archive}} } \concept{Result Assigner} \section{Super class}{ diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index ad1644de..e2b090b2 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -199,3 +199,15 @@ expect_acqfunction = function(acqf) { expect_man_exists(acqf$man) } +expect_rush_reset = function(rush, type = "kill") { + processes = rush$processes + rush$reset(type = type) + expect_list(rush$connector$command(c("KEYS", "*")), len = 0) + walk(processes, function(p) p$kill()) +} + +flush_redis = function() { + config = redux::redis_config() + r = redux::hiredis(config) + r$FLUSHDB() +} diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R new file mode 100644 index 00000000..11adc987 --- /dev/null +++ b/tests/testthat/test_OptimizerADBO.R @@ -0,0 +1,113 @@ +test_that("search works with decentralized network", { + flush_redis() + library(rush) + rush_plan(n_workers = 2) + + learner = lrn("classif.rpart", + minsplit = to_tune(2, 128), + cp = to_tune(1e-04, 1e-1)) + + instance = TuningInstanceRushSingleCrit$new( + task = tsk("pima"), + learner = learner, + resampling = rsmp("cv", folds = 3), + measure = msr("classif.ce"), + terminator = trm("evals", n_evals = 20), + store_benchmark_result = FALSE + ) + + optimizer = tnr("adbo", init_design_size = 4) + optimizer$optimize(instance) + + instance$archive$data[order(timestamp_ys)] + instance$rush$processes[[1]]$read_all_error_lines() + instance$rush$read_log() + + expect_data_table(instance$archive$data, min.rows = 3L) + + expect_rush_reset(instance$rush) +}) + +test_that("search works with transformation functions", { + flush_redis() + library(rush) + rush_plan(n_workers = 2) + + learner = lrn("classif.rpart", + minsplit = to_tune(2, 128, logscale = TRUE), + cp = to_tune(1e-04, 1e-1, logscale = TRUE)) + + instance = TuningInstanceRushSingleCrit$new( + task = tsk("pima"), + learner = learner, + resampling = rsmp("cv", folds = 3), + measure = msr("classif.ce"), + terminator = trm("evals", n_evals = 20), + store_benchmark_result = FALSE + ) + + optimizer = tnr("adbo", init_design_size = 4) + optimizer$optimize(instance) + + expect_data_table(instance$archive$data, min.rows = 20) + + expect_rush_reset(instance$rush) +}) + +test_that("search works with dependencies", { + flush_redis() + library(rush) + rush_plan(n_workers = 2) + + learner = lrn("classif.rpart", + minsplit = to_tune(p_int(2, 128, depends = keep_model == TRUE)), + cp = to_tune(1e-04, 1e-1), + keep_model = to_tune()) + + instance = TuningInstanceRushSingleCrit$new( + task = tsk("pima"), + learner = learner, + resampling = rsmp("cv", folds = 3), + measure = msr("classif.ce"), + terminator = trm("evals", n_evals = 20), + store_benchmark_result = FALSE + ) + + optimizer = tnr("adbo", init_design_size = 4) + optimizer$optimize(instance) + + expect_data_table(instance$archive$data, min.rows = 20) + + expect_rush_reset(instance$rush) +}) + +test_that("adbo works with branching", { + flush_redis() + library(rush) + library(mlr3pipelines) + rush_plan(n_workers = 2) + + graph_learner = as_learner(ppl("branch", graphs = list(rpart = lrn("classif.rpart", id = "rpart"),debug = lrn("classif.debug", id = "debug")))) + graph_learner$param_set$set_values( + "rpart.cp" = to_tune(p_dbl(1e-04, 1e-1, depends = branch.selection == "rpart")), + "rpart.minsplit" = to_tune(p_int(2, 128, depends = branch.selection == "rpart")), + "debug.x" = to_tune(p_dbl(0, 1, depends = branch.selection == "debug")), + "branch.selection" = to_tune(c("rpart", "debug")) + ) + + instance = TuningInstanceRushSingleCrit$new( + task = tsk("pima"), + learner = graph_learner, + resampling = rsmp("cv", folds = 3), + measure = msr("classif.ce"), + terminator = trm("evals", n_evals = 20), + store_benchmark_result = FALSE + ) + + optimizer = tnr("adbo", init_design_size = 4) + optimizer$optimize(instance) + + expect_data_table(instance$archive$data, min.rows = 20) + + expect_rush_reset(instance$rush) +}) From d4b56b96a9bd1303480373acd26775686051d776 Mon Sep 17 00:00:00 2001 From: be-marc Date: Thu, 8 Feb 2024 13:30:27 +0100 Subject: [PATCH 02/26] fix: add start time --- R/OptimizerADBO.R | 2 ++ tests/testthat/test_OptimizerADBO.R | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 24b6e0f0..040347e4 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -22,6 +22,7 @@ OptimizerADBO = R6Class("OptimizerADBO", optimize = function(inst) { if (rush_available()) { + inst$archive$start_time = Sys.time() # generate initial design pv = self$param_set$values @@ -56,6 +57,7 @@ OptimizerADBO = R6Class("OptimizerADBO", # wait while(!inst$is_terminated) { Sys.sleep(1) + inst$rush$print_log() inst$rush$detect_lost_workers() } diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 11adc987..5dbe0100 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -19,9 +19,9 @@ test_that("search works with decentralized network", { optimizer = tnr("adbo", init_design_size = 4) optimizer$optimize(instance) - instance$archive$data[order(timestamp_ys)] - instance$rush$processes[[1]]$read_all_error_lines() - instance$rush$read_log() + # instance$archive$data[order(timestamp_ys)] + # instance$rush$processes[[1]]$read_all_error_lines() + # instance$rush$read_log() expect_data_table(instance$archive$data, min.rows = 3L) From 71fdc661982496a1c205df0c701ee13ef95a793a Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 9 Feb 2024 11:36:29 +0100 Subject: [PATCH 03/26] refactor: remove rush debug --- R/OptimizerADBO.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 040347e4..1083f5f2 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -41,7 +41,7 @@ OptimizerADBO = R6Class("OptimizerADBO", packages = c("bbotk", "mlr3mbo"), optimizer = self, instance = inst, - lgr_thresholds = c(rush = "debug", bbotk = "debug"), + lgr_thresholds = c(bbotk = "debug"), wait_for_workers = TRUE) } else { stop("No rush plan available. See `?rush::rush_plan()`") From 762b136347a9a708a9a6f266269e62201c613005 Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 9 Feb 2024 17:14:44 +0100 Subject: [PATCH 04/26] fix: add callback --- R/OptimizerADBO.R | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 1083f5f2..5dd011c6 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -23,6 +23,8 @@ OptimizerADBO = R6Class("OptimizerADBO", if (rush_available()) { inst$archive$start_time = Sys.time() + inst$.__enclos_env__$private$.context = ContextOptimization$new(instance = inst, optimizer = self) + call_back("on_optimization_begin", inst$callbacks, get_private(inst)$.context) # generate initial design pv = self$param_set$values @@ -69,9 +71,8 @@ OptimizerADBO = R6Class("OptimizerADBO", lg$info("Finished optimizing after %i evaluation(s)", inst$archive$n_evals) lg$info("Result:") lg$info(capture.output(print(inst$result, lass = FALSE, row.names = FALSE, print.keys = FALSE))) + call_back("on_optimization_end", inst$callbacks, get_private(inst)$.context) return(inst$result) - - result } ), @@ -92,6 +93,7 @@ OptimizerADBO = R6Class("OptimizerADBO", # evaluate initial design while (rush$n_queued_tasks > 0) { + lg$debug("Evaluating initial design") task = rush$pop_task(fields = "xs") xs_trafoed = trafo_xs(task$xs, inst$search_space) ys = inst$objective$eval(xs_trafoed) @@ -100,6 +102,7 @@ OptimizerADBO = R6Class("OptimizerADBO", # actual loop while (!inst$is_terminated) { + lg$debug("Optimizing") acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() From 6a62d753a8a5dee2659023e693a9da31f68563bc Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 9 Feb 2024 22:30:13 +0100 Subject: [PATCH 05/26] fix: transformation --- R/OptimizerADBO.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 5dd011c6..a28780dd 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -97,7 +97,7 @@ OptimizerADBO = R6Class("OptimizerADBO", task = rush$pop_task(fields = "xs") xs_trafoed = trafo_xs(task$xs, inst$search_space) ys = inst$objective$eval(xs_trafoed) - rush$push_results(task$key, yss = list(ys), extra = list(list(timestamp_ys = Sys.time(), stage = "initial_design"))) + rush$push_results(task$key, yss = list(ys), extra = list(list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "initial_design"))) } # actual loop @@ -106,10 +106,11 @@ OptimizerADBO = R6Class("OptimizerADBO", acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() - xss = transform_xdt_to_xss(xdt, search_space) - keys = rush$push_running_task(xss, extra = list(list(timestamp_xs = Sys.time()))) - ys = inst$objective$eval(xss[[1]]) - rush$push_results(keys, list(ys), extra = list(list(timestamp_ys = Sys.time(), stage = "mbo"))) + xs = transpose_list(xdt) + xs_trafoed = transform_xdt_to_xss(xdt, search_space) + keys = rush$push_running_task(xs, extra = list(list(timestamp_xs = Sys.time()))) + ys = inst$objective$eval(xs_trafoed[[1]]) + rush$push_results(keys, list(ys), extra = list(list(x_domain = xs_trafoed, timestamp_ys = Sys.time(), stage = "mbo"))) } } ) From c62f7c8efa438eb54f5399f874b6944992ba444b Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 9 Feb 2024 23:46:33 +0100 Subject: [PATCH 06/26] fix: xdomain --- R/OptimizerADBO.R | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index a28780dd..67f66167 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -106,11 +106,14 @@ OptimizerADBO = R6Class("OptimizerADBO", acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() - xs = transpose_list(xdt) - xs_trafoed = transform_xdt_to_xss(xdt, search_space) - keys = rush$push_running_task(xs, extra = list(list(timestamp_xs = Sys.time()))) - ys = inst$objective$eval(xs_trafoed[[1]]) - rush$push_results(keys, list(ys), extra = list(list(x_domain = xs_trafoed, timestamp_ys = Sys.time(), stage = "mbo"))) + xss = transpose_list(xdt) + xs = xss[[1]][inst$archive$cols_x] + xs_trafoed = trafo_xs(xs, search_space) + extra = xss[[1]][c("acq_cb", ".already_evaluated")] + + keys = rush$push_running_task(list(xs), extra = list(list(timestamp_xs = Sys.time()))) + ys = inst$objective$eval(xs_trafoed) + rush$push_results(keys, yss = list(ys), extra = list(c(extra, list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "mbo")))) } } ) From d92dc556aafe896b29019dc3ba84194d3c9c9cbc Mon Sep 17 00:00:00 2001 From: be-marc Date: Sat, 10 Feb 2024 11:42:56 +0100 Subject: [PATCH 07/26] refactor: kill workers --- R/OptimizerADBO.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 67f66167..b62051ee 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -43,7 +43,7 @@ OptimizerADBO = R6Class("OptimizerADBO", packages = c("bbotk", "mlr3mbo"), optimizer = self, instance = inst, - lgr_thresholds = c(bbotk = "debug"), + lgr_thresholds = c(bbotk = "debug", rush = "debug"), wait_for_workers = TRUE) } else { stop("No rush plan available. See `?rush::rush_plan()`") @@ -63,6 +63,8 @@ OptimizerADBO = R6Class("OptimizerADBO", inst$rush$detect_lost_workers() } + inst$rush$stop_workers(type = "kill") + # assign result private$.assign_result(inst) From 2bb45a97583aa710bae6c12cf4e4db9430e0bcd5 Mon Sep 17 00:00:00 2001 From: be-marc Date: Sat, 10 Feb 2024 23:25:26 +0100 Subject: [PATCH 08/26] feat: cache archive --- R/SurrogateLearner.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index 35730b01..27e73cc6 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -217,7 +217,7 @@ SurrogateLearner = R6Class("SurrogateLearner", .update = function() { if (self$param_set$values$impute_missings) { - xydt = self$archive$rush$fetch_tasks(fields = c("xs", "ys"))[, c(self$cols_x, self$cols_y), with = FALSE] + xydt = self$archive$rush$fetch_active_tasks()[, c(self$cols_x, self$cols_y), with = FALSE] setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) } else { xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] From 2f0576448e2666fa9ee13dc6c2698ecc4640784a Mon Sep 17 00:00:00 2001 From: be-marc Date: Sat, 10 Feb 2024 23:29:19 +0100 Subject: [PATCH 09/26] chore: debug --- R/OptimizerADBO.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index b62051ee..e3f1a424 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -43,7 +43,7 @@ OptimizerADBO = R6Class("OptimizerADBO", packages = c("bbotk", "mlr3mbo"), optimizer = self, instance = inst, - lgr_thresholds = c(bbotk = "debug", rush = "debug"), + lgr_thresholds = c(bbotk = "debug", rush = "debug", mlr3automl = "debug"), wait_for_workers = TRUE) } else { stop("No rush plan available. See `?rush::rush_plan()`") From 0ed1969c648993557d53bc9db696696cceea787e Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 12 Feb 2024 11:29:52 +0100 Subject: [PATCH 10/26] chore: import rush --- DESCRIPTION | 3 ++- NAMESPACE | 1 + R/SurrogateLearner.R | 2 +- R/zzz.R | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 10a6743d..53a61a14 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -50,7 +50,8 @@ Imports: mlr3tuning (>= 0.14.0), paradox (>= 0.10.0), spacefillr, - R6 (>= 2.4.1) + R6 (>= 2.4.1), + rush Suggests: DiceKriging, emoa, diff --git a/NAMESPACE b/NAMESPACE index 19a9927f..4a32731a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -53,6 +53,7 @@ import(mlr3) import(mlr3misc) import(mlr3tuning) import(paradox) +import(rush) import(spacefillr) importFrom(R6,R6Class) importFrom(stats,dnorm) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index 27e73cc6..a9ca5897 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -217,7 +217,7 @@ SurrogateLearner = R6Class("SurrogateLearner", .update = function() { if (self$param_set$values$impute_missings) { - xydt = self$archive$rush$fetch_active_tasks()[, c(self$cols_x, self$cols_y), with = FALSE] + xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finsished"))[, c(self$cols_x, self$cols_y), with = FALSE] setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) } else { xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] diff --git a/R/zzz.R b/R/zzz.R index 74689172..c8d60cab 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -9,6 +9,7 @@ #' @import lgr #' @import mlr3 #' @import mlr3tuning +#' @import rush #' @importFrom stats setNames runif dnorm pnorm quantile #' @useDynLib mlr3mbo c_sms_indicator c_eps_indicator "_PACKAGE" From b7217e42a2f258ef31771e0c9ef9bed628a05e38 Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 12 Feb 2024 12:42:30 +0100 Subject: [PATCH 11/26] feat: add logging --- R/OptimizerADBO.R | 9 +++++---- R/SurrogateLearner.R | 3 +-- tests/testthat/test_OptimizerADBO.R | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index e3f1a424..5630aec7 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -43,7 +43,6 @@ OptimizerADBO = R6Class("OptimizerADBO", packages = c("bbotk", "mlr3mbo"), optimizer = self, instance = inst, - lgr_thresholds = c(bbotk = "debug", rush = "debug", mlr3automl = "debug"), wait_for_workers = TRUE) } else { stop("No rush plan available. See `?rush::rush_plan()`") @@ -93,26 +92,28 @@ OptimizerADBO = R6Class("OptimizerADBO", acq_function$surrogate = surrogate acq_optimizer$acq_function = acq_function + lg$debug("Optimizer '%s' evaluates the initial design", self$id) + # evaluate initial design while (rush$n_queued_tasks > 0) { - lg$debug("Evaluating initial design") task = rush$pop_task(fields = "xs") xs_trafoed = trafo_xs(task$xs, inst$search_space) ys = inst$objective$eval(xs_trafoed) rush$push_results(task$key, yss = list(ys), extra = list(list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "initial_design"))) } + lg$debug("Optimizer '%s' starts the tuning phase", self$id) + # actual loop while (!inst$is_terminated) { - lg$debug("Optimizing") acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() xss = transpose_list(xdt) xs = xss[[1]][inst$archive$cols_x] + lg$trace("Optimizer '%s' draws %s", self$id, as_short_string(xs)) xs_trafoed = trafo_xs(xs, search_space) extra = xss[[1]][c("acq_cb", ".already_evaluated")] - keys = rush$push_running_task(list(xs), extra = list(list(timestamp_xs = Sys.time()))) ys = inst$objective$eval(xs_trafoed) rush$push_results(keys, yss = list(ys), extra = list(c(extra, list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "mbo")))) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index a9ca5897..d1981362 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -215,9 +215,8 @@ SurrogateLearner = R6Class("SurrogateLearner", # Train learner with new data. # Also calculates the insample performance based on the `perf_measure` hyperparameter if `assert_insample_perf = TRUE`. .update = function() { - if (self$param_set$values$impute_missings) { - xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finsished"))[, c(self$cols_x, self$cols_y), with = FALSE] + xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finished"))[, c(self$cols_x, self$cols_y), with = FALSE] setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) } else { xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 5dbe0100..fb443459 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -19,6 +19,8 @@ test_that("search works with decentralized network", { optimizer = tnr("adbo", init_design_size = 4) optimizer$optimize(instance) + # instance$rush = RushWorker$new(instance$rush$network_id, host = "local") + # inst = instance # instance$archive$data[order(timestamp_ys)] # instance$rush$processes[[1]]$read_all_error_lines() # instance$rush$read_log() From 6982d12132e79bd1e4bd4cd88de9740375e0ab3a Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 12 Feb 2024 15:35:29 +0100 Subject: [PATCH 12/26] refactor: use optimize_decentralized() --- R/OptimizerADBO.R | 60 +++++++---------------------- tests/testthat/test_OptimizerADBO.R | 3 +- 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 5630aec7..90e9a14b 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -21,65 +21,31 @@ OptimizerADBO = R6Class("OptimizerADBO", optimize = function(inst) { - if (rush_available()) { - inst$archive$start_time = Sys.time() - inst$.__enclos_env__$private$.context = ContextOptimization$new(instance = inst, optimizer = self) - call_back("on_optimization_begin", inst$callbacks, get_private(inst)$.context) - - # generate initial design - pv = self$param_set$values - design = if (is.null(pv$initial_design)) { - generate_design_sobol(inst$search_space, n = pv$init_design_size)$data - } else { - pv$initial_design - } - - # send initial design to workers - inst$rush$push_tasks(transpose_list(design), extra = list(list(timestamp_xs = Sys.time()))) - - # start rush workers - inst$rush$start_workers( - worker_loop = bbotk_worker_loop_decentralized, - packages = c("bbotk", "mlr3mbo"), - optimizer = self, - instance = inst, - wait_for_workers = TRUE) + # generate initial design + pv = self$param_set$values + design = if (is.null(pv$initial_design)) { + generate_design_sobol(inst$search_space, n = pv$init_design_size)$data } else { - stop("No rush plan available. See `?rush::rush_plan()`") + pv$initial_design } - lg$info("Starting to optimize %i parameter(s) with '%s' and '%s' on %i worker(s)", - inst$search_space$length, - self$format(), - inst$terminator$format(with_params = TRUE), - inst$rush$n_running_workers - ) + # send initial design to workers + inst$rush$push_tasks(transpose_list(design), extra = list(list(timestamp_xs = Sys.time()))) - # wait - while(!inst$is_terminated) { - Sys.sleep(1) - inst$rush$print_log() - inst$rush$detect_lost_workers() - } + # optimize + inst$archive$start_time = Sys.time() + result = optimize_decentralized(inst, self, private) + # FIXME: kill workers to increase the chance of a fitting the final model inst$rush$stop_workers(type = "kill") - # assign result - private$.assign_result(inst) - - # assign result - private$.assign_result(inst) - lg$info("Finished optimizing after %i evaluation(s)", inst$archive$n_evals) - lg$info("Result:") - lg$info(capture.output(print(inst$result, lass = FALSE, row.names = FALSE, print.keys = FALSE))) - call_back("on_optimization_end", inst$callbacks, get_private(inst)$.context) - return(inst$result) + result } ), private = list( - .optimize_remote = function(inst) { + .optimize = function(inst) { search_space = inst$search_space rush = inst$rush diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index fb443459..3bdc9371 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -1,7 +1,6 @@ test_that("search works with decentralized network", { flush_redis() - library(rush) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) learner = lrn("classif.rpart", minsplit = to_tune(2, 128), From 0363e5d24d81416a9e939a53bfd46a3ee6bb7481 Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 19 Feb 2024 07:49:01 +0100 Subject: [PATCH 13/26] feat: add exponential decay --- R/OptimizerADBO.R | 71 +++++++++++++++++++-- R/TunerADBO.R | 28 +++++++++ man/mlr_optimizers_adbo.Rd | 98 +++++++++++++++++++++++++++++ man/mlr_tuners_adbo.Rd | 76 ++++++++++++++++++++++ tests/testthat/test_OptimizerADBO.R | 55 +++++++++++----- 5 files changed, 308 insertions(+), 20 deletions(-) create mode 100644 man/mlr_optimizers_adbo.Rd create mode 100644 man/mlr_tuners_adbo.Rd diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 90e9a14b..98ff90d5 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -1,30 +1,74 @@ +#' @title Asynchronous Decentralized Bayesian Optimization +#' @name mlr_optimizers_adbo +#' +#' @description +#' Asynchronous Decentralized Bayesian Optimization (ADBO). +#' +#' @notes +#' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. +#' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. +#' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. +#' +#' @section Parameters: +#' \describe{ +#' \item{`lambda`}{`numeric(1)`\cr +#' \eqn{\lambda} value used for the confidence bound. +#' Defaults to `1.96`.} +#' \item{`exponential_decay`}{`lgl(1)`\cr +#' Whether to use periodic exponential decay for \eqn{\lambda}.} +#' \item{`rate`}{`numeric(1)`\cr +#' Rate of the exponential decay.} +#' \item{`t`}{`integer(1)`\cr +#' Period of the exponential decay.} +#' \item{`initial_design_size`}{`integer(1)`\cr +#' Size of the initial design.} +#' \item{`initial_design`}{`data.table`\cr +#' Initial design.} +#' } +#' #' @export OptimizerADBO = R6Class("OptimizerADBO", inherit = bbotk::Optimizer, public = list( + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. initialize = function() { param_set = ps( - init_design_size = p_int(lower = 1L), + lambda = p_dbl(lower = 0, default = 1.96), + exponential_decay = p_lgl(default = TRUE), + rate = p_dbl(lower = 0, default = 0.1), + period = p_int(lower = 1L, default = 25L), + design_size = p_int(lower = 1L), initial_design = p_uty() ) + param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L) + super$initialize("adbo", param_set = param_set, param_classes = c("ParamLgl", "ParamInt", "ParamDbl", "ParamFct"), - properties = c("dependencies", "multi-crit", "single-crit"), + properties = c("dependencies", "single-crit"), packages = "mlr3mbo", label = "Asynchronous Decentralized Bayesian Optimization", man = "mlr3mbo::OptimizerADBO") }, + + #' @description + #' Performs the optimization and writes optimization result into + #' [OptimInstance]. The optimization result is returned but the complete + #' optimization path is stored in [Archive] of [OptimInstance]. + #' + #' @param inst ([OptimInstance]). + #' @return [data.table::data.table]. optimize = function(inst) { # generate initial design pv = self$param_set$values design = if (is.null(pv$initial_design)) { - generate_design_sobol(inst$search_space, n = pv$init_design_size)$data + generate_design_sobol(inst$search_space, n = pv$design_size)$data } else { pv$initial_design } @@ -46,9 +90,14 @@ OptimizerADBO = R6Class("OptimizerADBO", private = list( .optimize = function(inst) { + pv = self$param_set$values search_space = inst$search_space rush = inst$rush + # sample lambda from exponential distribution + lambda_0 = rexp(1, 1 / pv$lambda) + t = 0 + surrogate = default_surrogate(inst) surrogate$param_set$set_values(impute_missings = TRUE) acq_function = acqf("cb", lambda = runif(1, 1 , 3)) @@ -72,6 +121,15 @@ OptimizerADBO = R6Class("OptimizerADBO", # actual loop while (!inst$is_terminated) { + + if (pv$exponential_decay) { + lambda = lambda_0 * exp(-pv$rate * (t %% pv$period)) + t = t + 1 + } else { + lambda = pv$lambda + } + + acq_function$constants$set_values(lambda = lambda) acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() @@ -82,7 +140,12 @@ OptimizerADBO = R6Class("OptimizerADBO", extra = xss[[1]][c("acq_cb", ".already_evaluated")] keys = rush$push_running_task(list(xs), extra = list(list(timestamp_xs = Sys.time()))) ys = inst$objective$eval(xs_trafoed) - rush$push_results(keys, yss = list(ys), extra = list(c(extra, list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "mbo")))) + rush$push_results(keys, yss = list(ys), extra = list(c(extra, list( + x_domain = list(xs_trafoed), + timestamp_ys = Sys.time(), + stage = "mbo", + lambda_0 = lambda_0, + lambda = lambda)))) } } ) diff --git a/R/TunerADBO.R b/R/TunerADBO.R index e0fa1f04..fc51bbf9 100644 --- a/R/TunerADBO.R +++ b/R/TunerADBO.R @@ -1,3 +1,31 @@ +#' @title Asynchronous Decentralized Bayesian Optimization +#' @name mlr_tuners_adbo +#' +#' @description +#' Asynchronous Decentralized Bayesian Optimization (ADBO). +#' +#' @notes +#' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. +#' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. +#' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. +#' +#' @section Parameters: +#' \describe{ +#' \item{`lambda`}{`numeric(1)`\cr +#' \eqn{\lambda} value used for the confidence bound. +#' Defaults to `1.96`.} +#' \item{`exponential_decay`}{`lgl(1)`\cr +#' Whether to use periodic exponential decay for \eqn{\lambda}.} +#' \item{`rate`}{`numeric(1)`\cr +#' Rate of the exponential decay.} +#' \item{`t`}{`integer(1)`\cr +#' Period of the exponential decay.} +#' \item{`initial_design_size`}{`integer(1)`\cr +#' Size of the initial design.} +#' \item{`initial_design`}{`data.table`\cr +#' Initial design.} +#' } +#' #' @export TunerADBO = R6Class("TunerADBO", inherit = mlr3tuning::TunerFromOptimizer, diff --git a/man/mlr_optimizers_adbo.Rd b/man/mlr_optimizers_adbo.Rd new file mode 100644 index 00000000..9b91b3f9 --- /dev/null +++ b/man/mlr_optimizers_adbo.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/OptimizerADBO.R +\name{mlr_optimizers_adbo} +\alias{mlr_optimizers_adbo} +\alias{OptimizerADBO} +\title{Asynchronous Decentralized Bayesian Optimization} +\description{ +Asynchronous Decentralized Bayesian Optimization (ADBO). +} +\section{Parameters}{ + +\describe{ +\item{\code{lambda}}{\code{numeric(1)}\cr +\eqn{\lambda} value used for the confidence bound. +Defaults to \code{1.96}.} +\item{\code{exponential_decay}}{\code{lgl(1)}\cr +Whether to use periodic exponential decay for \eqn{\lambda}.} +\item{\code{rate}}{\code{numeric(1)}\cr +Rate of the exponential decay.} +\item{\code{t}}{\code{integer(1)}\cr +Period of the exponential decay.} +\item{\code{initial_design_size}}{\code{integer(1)}\cr +Size of the initial design.} +\item{\code{initial_design}}{\code{data.table}\cr +Initial design.} +} +} + +\section{Super class}{ +\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{OptimizerADBO} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-OptimizerADBO-new}{\code{OptimizerADBO$new()}} +\item \href{#method-OptimizerADBO-optimize}{\code{OptimizerADBO$optimize()}} +\item \href{#method-OptimizerADBO-clone}{\code{OptimizerADBO$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-OptimizerADBO-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this \link[R6:R6Class]{R6} class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{OptimizerADBO$new()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-OptimizerADBO-optimize}{}}} +\subsection{Method \code{optimize()}}{ +Performs the optimization and writes optimization result into +\link{OptimInstance}. The optimization result is returned but the complete +optimization path is stored in \link{Archive} of \link{OptimInstance}. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{OptimizerADBO$optimize(inst)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{inst}}{(\link{OptimInstance}).} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +\link[data.table:data.table]{data.table::data.table}. +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-OptimizerADBO-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{OptimizerADBO$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/mlr_tuners_adbo.Rd b/man/mlr_tuners_adbo.Rd new file mode 100644 index 00000000..adf79f94 --- /dev/null +++ b/man/mlr_tuners_adbo.Rd @@ -0,0 +1,76 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/TunerADBO.R +\name{mlr_tuners_adbo} +\alias{mlr_tuners_adbo} +\alias{TunerADBO} +\title{Asynchronous Decentralized Bayesian Optimization} +\description{ +Asynchronous Decentralized Bayesian Optimization (ADBO). +} +\section{Parameters}{ + +\describe{ +\item{\code{lambda}}{\code{numeric(1)}\cr +\eqn{\lambda} value used for the confidence bound. +Defaults to \code{1.96}.} +\item{\code{exponential_decay}}{\code{lgl(1)}\cr +Whether to use periodic exponential decay for \eqn{\lambda}.} +\item{\code{rate}}{\code{numeric(1)}\cr +Rate of the exponential decay.} +\item{\code{t}}{\code{integer(1)}\cr +Period of the exponential decay.} +\item{\code{initial_design_size}}{\code{integer(1)}\cr +Size of the initial design.} +\item{\code{initial_design}}{\code{data.table}\cr +Initial design.} +} +} + +\section{Super classes}{ +\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerFromOptimizer]{mlr3tuning::TunerFromOptimizer}} -> \code{TunerADBO} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-TunerADBO-new}{\code{TunerADBO$new()}} +\item \href{#method-TunerADBO-clone}{\code{TunerADBO$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TunerADBO-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this \link[R6:R6Class]{R6} class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TunerADBO$new()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-TunerADBO-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{TunerADBO$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 3bdc9371..c2e0bb3c 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -1,4 +1,37 @@ -test_that("search works with decentralized network", { +test_that("adbo optimizer works", { + #options("bbotk_local" = TRUE) + rush::rush_plan(n_workers = 5) + + search_space = domain = ps( + x1 = p_dbl(-5, 10), + x2 = p_dbl(0, 15) + ) + + codomain = ps(y = p_dbl(tags = "minimize")) + + fun = function(xs) { + list(y = branin(x1 = xs$x1, x2 = xs$x2)) + } + + objective = ObjectiveRFun$new( + fun = fun, + domain = domain, + codomain = codomain + ) + + instance = OptimInstanceRushSingleCrit$new( + objective = objective, + search_space = search_space, + terminator = trm("evals", n_evals = 100) + ) + + optimizer = opt("adbo", design_size = 4) + optimizer$optimize(instance) +}) + + +test_that("adbo tuner works", { + #options("bbotk_local" = TRUE) flush_redis() rush::rush_plan(n_workers = 2) @@ -18,21 +51,13 @@ test_that("search works with decentralized network", { optimizer = tnr("adbo", init_design_size = 4) optimizer$optimize(instance) - # instance$rush = RushWorker$new(instance$rush$network_id, host = "local") - # inst = instance - # instance$archive$data[order(timestamp_ys)] - # instance$rush$processes[[1]]$read_all_error_lines() - # instance$rush$read_log() - - expect_data_table(instance$archive$data, min.rows = 3L) - + expect_data_table(instance$archive$data, min.rows = 20L) expect_rush_reset(instance$rush) }) -test_that("search works with transformation functions", { +test_that("adbo works with transformation functions", { flush_redis() - library(rush) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) learner = lrn("classif.rpart", minsplit = to_tune(2, 128, logscale = TRUE), @@ -57,8 +82,7 @@ test_that("search works with transformation functions", { test_that("search works with dependencies", { flush_redis() - library(rush) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) learner = lrn("classif.rpart", minsplit = to_tune(p_int(2, 128, depends = keep_model == TRUE)), @@ -84,9 +108,8 @@ test_that("search works with dependencies", { test_that("adbo works with branching", { flush_redis() - library(rush) + rush::rush_plan(n_workers = 2) library(mlr3pipelines) - rush_plan(n_workers = 2) graph_learner = as_learner(ppl("branch", graphs = list(rpart = lrn("classif.rpart", id = "rpart"),debug = lrn("classif.debug", id = "debug")))) graph_learner$param_set$set_values( From c48a4848ced9eff919cd7203244eea23ae50c1f3 Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 19 Feb 2024 11:43:28 +0100 Subject: [PATCH 14/26] feat: add min-max imputation --- R/OptimizerADBO.R | 7 ++++--- R/SurrogateLearner.R | 14 +++++++++++--- tests/testthat/test_OptimizerADBO.R | 8 ++++---- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 98ff90d5..380cf1a4 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -41,10 +41,11 @@ OptimizerADBO = R6Class("OptimizerADBO", rate = p_dbl(lower = 0, default = 0.1), period = p_int(lower = 1L, default = 25L), design_size = p_int(lower = 1L), - initial_design = p_uty() + initial_design = p_uty(), + impute_method = p_fct(c("mean", "random"), default = "random") ) - param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L) + param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L, impute_method = "random") super$initialize("adbo", param_set = param_set, @@ -99,7 +100,7 @@ OptimizerADBO = R6Class("OptimizerADBO", t = 0 surrogate = default_surrogate(inst) - surrogate$param_set$set_values(impute_missings = TRUE) + surrogate$param_set$set_values(impute_missings = pv$impute_method) acq_function = acqf("cb", lambda = runif(1, 1 , 3)) acq_optimizer = acqo(opt("random_search", batch_size = 1000L), terminator = trm("evals", n_evals = 10000L)) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index d1981362..ac88c451 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -88,9 +88,9 @@ SurrogateLearner = R6Class("SurrogateLearner", ParamUty$new("perf_measure", custom_check = function(x) check_r6(x, classes = "MeasureRegr")), # FIXME: actually want check_measure ParamDbl$new("perf_threshold", lower = -Inf, upper = Inf), ParamLgl$new("catch_errors"), - ParamLgl$new("impute_missings")) + ParamFct$new("impute_missings", levels = c("none", "mean", "random"))) ) - ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE, impute_missings = FALSE) + ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE, impute_missings = "none") ps$add_dep("perf_measure", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) ps$add_dep("perf_threshold", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) @@ -215,9 +215,17 @@ SurrogateLearner = R6Class("SurrogateLearner", # Train learner with new data. # Also calculates the insample performance based on the `perf_measure` hyperparameter if `assert_insample_perf = TRUE`. .update = function() { - if (self$param_set$values$impute_missings) { + if (self$param_set$values$impute_missings == "mean") { xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finished"))[, c(self$cols_x, self$cols_y), with = FALSE] setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) + } else if (self$param_set$values$impute_missings == "random") { + xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finished"))[, c(self$cols_x, self$cols_y, "state"), with = FALSE] + walk(self$cols_y, function(col) { + min = min(xydt[[col]], na.rm = TRUE) + max = max(xydt[[col]], na.rm = TRUE) + xydt[state %in% c("queued", "running"), (col) := runif(.N, min, max)] + }) + set(xydt, j = "state", value = NULL) } else { xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] } diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index c2e0bb3c..4c6cee1b 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -1,5 +1,5 @@ test_that("adbo optimizer works", { - #options("bbotk_local" = TRUE) + options("bbotk_local" = TRUE) rush::rush_plan(n_workers = 5) search_space = domain = ps( @@ -31,9 +31,9 @@ test_that("adbo optimizer works", { test_that("adbo tuner works", { - #options("bbotk_local" = TRUE) + # options("bbotk_local" = TRUE) flush_redis() - rush::rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 5) learner = lrn("classif.rpart", minsplit = to_tune(2, 128), @@ -48,7 +48,7 @@ test_that("adbo tuner works", { store_benchmark_result = FALSE ) - optimizer = tnr("adbo", init_design_size = 4) + optimizer = tnr("adbo", design_size = 4) optimizer$optimize(instance) expect_data_table(instance$archive$data, min.rows = 20L) From c8784aad79cdccb349e0932a5ace2b9feb0bbe23 Mon Sep 17 00:00:00 2001 From: be-marc Date: Thu, 22 Feb 2024 09:32:12 +0100 Subject: [PATCH 15/26] feat: add n_worker parameter --- R/OptimizerADBO.R | 3 ++- tests/testthat/test_OptimizerADBO.R | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 380cf1a4..c28c2f00 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -42,7 +42,8 @@ OptimizerADBO = R6Class("OptimizerADBO", period = p_int(lower = 1L, default = 25L), design_size = p_int(lower = 1L), initial_design = p_uty(), - impute_method = p_fct(c("mean", "random"), default = "random") + impute_method = p_fct(c("mean", "random"), default = "random"), + n_workers = p_int(lower = 1L) ) param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L, impute_method = "random") diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 4c6cee1b..51bba643 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -55,6 +55,33 @@ test_that("adbo tuner works", { expect_rush_reset(instance$rush) }) +test_that("adbo tuner works with limited number of workers", { + # options("bbotk_local" = TRUE) + lgr::get_logger("rush")$set_threshold("debug") + + flush_redis() + rush::rush_plan(n_workers = 5) + + learner = lrn("classif.rpart", + minsplit = to_tune(2, 128), + cp = to_tune(1e-04, 1e-1)) + + instance = TuningInstanceRushSingleCrit$new( + task = tsk("pima"), + learner = learner, + resampling = rsmp("cv", folds = 3), + measure = msr("classif.ce"), + terminator = trm("evals", n_evals = 20), + store_benchmark_result = FALSE + ) + + optimizer = tnr("adbo", design_size = 4, n_workers = 2) + optimizer$optimize(instance) + + expect_data_table(instance$archive$data, min.rows = 20L) + expect_rush_reset(instance$rush) +}) + test_that("adbo works with transformation functions", { flush_redis() rush::rush_plan(n_workers = 2) From b97bd18b6f59f7f7c251c4ffc231deae8c2611d7 Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 26 Apr 2024 12:04:54 +0200 Subject: [PATCH 16/26] draft --- R/AcqFunction.R | 2 +- R/AcqFunctionAEI.R | 2 +- R/AcqFunctionCB.R | 2 +- R/AcqFunctionEHVI.R | 4 +- R/AcqFunctionEHVIGH.R | 10 ++-- R/AcqFunctionEI.R | 2 +- R/AcqFunctionEIPS.R | 6 +-- R/AcqFunctionMean.R | 2 +- R/AcqFunctionPI.R | 2 +- R/AcqFunctionSD.R | 2 +- R/AcqFunctionSmsEgo.R | 2 +- R/AcqOptimizer.R | 4 +- R/OptimizerADBO.R | 65 +++++++++++------------- R/OptimizerMbo.R | 4 +- R/ResultAssigner.R | 2 +- R/ResultAssignerArchive.R | 4 +- R/ResultAssignerSurrogate.R | 12 ++--- R/Surrogate.R | 2 +- R/SurrogateLearner.R | 2 +- R/SurrogateLearnerCollection.R | 2 +- R/TunerADBO.R | 4 +- R/TunerMbo.R | 4 +- R/bayesopt_ego.R | 12 ++--- R/bayesopt_emo.R | 10 ++-- R/bayesopt_mpcl.R | 12 ++--- R/bayesopt_parego.R | 14 +++--- R/bayesopt_smsego.R | 12 ++--- R/helper.R | 4 +- R/mbo_defaults.R | 16 +++--- man/AcqOptimizer.Rd | 2 +- man/ResultAssigner.Rd | 2 +- man/SurrogateLearner.Rd | 2 +- man/SurrogateLearnerCollection.Rd | 2 +- man/default_acqoptimizer.Rd | 2 +- man/default_surrogate.Rd | 4 +- man/mlr_acqfunctions_aei.Rd | 2 +- man/mlr_acqfunctions_cb.Rd | 2 +- man/mlr_acqfunctions_ehvi.Rd | 2 +- man/mlr_acqfunctions_ehvigh.Rd | 2 +- man/mlr_acqfunctions_ei.Rd | 2 +- man/mlr_acqfunctions_eips.Rd | 6 +-- man/mlr_acqfunctions_mean.Rd | 2 +- man/mlr_acqfunctions_pi.Rd | 2 +- man/mlr_acqfunctions_sd.Rd | 2 +- man/mlr_acqfunctions_smsego.Rd | 2 +- man/mlr_loop_functions_ego.Rd | 10 ++-- man/mlr_loop_functions_emo.Rd | 8 +-- man/mlr_loop_functions_mpcl.Rd | 10 ++-- man/mlr_loop_functions_parego.Rd | 12 ++--- man/mlr_loop_functions_smsego.Rd | 10 ++-- man/mlr_optimizers_adbo.Rd | 19 ++++--- man/mlr_optimizers_mbo.Rd | 5 +- man/mlr_result_assigners_archive.Rd | 2 +- man/mlr_result_assigners_surrogate.Rd | 4 +- man/mlr_tuners_adbo.Rd | 9 +++- man/mlr_tuners_mbo.Rd | 6 +-- tests/testthat/helper.R | 4 +- tests/testthat/test_AcqOptimizer.R | 2 +- tests/testthat/test_OptimizerADBO.R | 72 ++++++--------------------- tests/testthat/test_bayesopt_ego.R | 2 +- vignettes/mlr3mbo.Rmd | 10 ++-- 61 files changed, 202 insertions(+), 242 deletions(-) diff --git a/R/AcqFunction.R b/R/AcqFunction.R index 6b21f46d..6ac53e03 100644 --- a/R/AcqFunction.R +++ b/R/AcqFunction.R @@ -176,7 +176,7 @@ AcqFunction = R6Class("AcqFunction", stopf("Acquisition function '%s' requires the surrogate to have `\"se\"` as `$predict_type`.", format(self)) } private$.surrogate = rhs - private$.archive = assert_multi_class(rhs$archive, c("Archive", "ArchiveRush")) + private$.archive = assert_archive(rhs$archive) codomain = generate_acq_codomain(rhs, id = self$id, direction = self$direction) self$surrogate_max_to_min = surrogate_mult_max_to_min(rhs) domain = generate_acq_domain(rhs) diff --git a/R/AcqFunctionAEI.R b/R/AcqFunctionAEI.R index 164bdfbd..5521cf98 100644 --- a/R/AcqFunctionAEI.R +++ b/R/AcqFunctionAEI.R @@ -40,7 +40,7 @@ #' codomain = codomain, #' properties = "noisy") #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionCB.R b/R/AcqFunctionCB.R index 06417142..14a980c3 100644 --- a/R/AcqFunctionCB.R +++ b/R/AcqFunctionCB.R @@ -35,7 +35,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionEHVI.R b/R/AcqFunctionEHVI.R index 37e4a6c7..63b73da7 100644 --- a/R/AcqFunctionEHVI.R +++ b/R/AcqFunctionEHVI.R @@ -30,7 +30,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -117,7 +117,7 @@ AcqFunctionEHVI = R6Class("AcqFunctionEHVI", } columns = colnames(self$ys_front_augmented) - + ps = self$surrogate$predict(xdt) means = map_dtc(ps, "mean") diff --git a/R/AcqFunctionEHVIGH.R b/R/AcqFunctionEHVIGH.R index afd9c10c..4ee1ade1 100644 --- a/R/AcqFunctionEHVIGH.R +++ b/R/AcqFunctionEHVIGH.R @@ -41,7 +41,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -175,20 +175,20 @@ adjust_gh_data = function(gh_data, mu, sigma, r) { idx = as.matrix(expand.grid(rep(list(1:n), n_obj))) nodes = matrix(gh_data[idx, 1L], nrow = nrow(idx), ncol = n_obj) weights = apply(matrix(gh_data[idx, 2L], nrow = nrow(idx), ncol = n_obj), MARGIN = 1L, FUN = prod) - - # pruning with pruning rate r + + # pruning with pruning rate r if (r > 0) { weights_quantile = quantile(weights, probs = r) nodes = nodes[weights > weights_quantile, ] weights = weights[weights > weights_quantile] } - + # rotate, scale, translate nodes with error catching # rotation will not have an effect unless we support surrogate models modelling correlated objectives # for now we still support this more general case and scaling is useful anyways nodes = tryCatch( { - eigen_decomp = eigen(sigma) + eigen_decomp = eigen(sigma) rotation = eigen_decomp$vectors %*% diag(sqrt(eigen_decomp$values)) nodes = t(rotation %*% t(nodes) + mu) }, error = function(ec) nodes diff --git a/R/AcqFunctionEI.R b/R/AcqFunctionEI.R index b5e3a1e7..1782b972 100644 --- a/R/AcqFunctionEI.R +++ b/R/AcqFunctionEI.R @@ -30,7 +30,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionEIPS.R b/R/AcqFunctionEIPS.R index 5e5a9b6f..724dd13e 100644 --- a/R/AcqFunctionEIPS.R +++ b/R/AcqFunctionEIPS.R @@ -9,9 +9,9 @@ #' @description #' Expected Improvement per Second. #' -#' It is assumed that calculations are performed on an [bbotk::OptimInstanceSingleCrit]. +#' It is assumed that calculations are performed on an [bbotk::OptimInstanceBatchSingleCrit]. #' Additionally to target values of the codomain that should be minimized or maximized, the -#' [bbotk::Objective] of the [bbotk::OptimInstanceSingleCrit] should return time values. +#' [bbotk::Objective] of the [bbotk::OptimInstanceBatchSingleCrit] should return time values. #' The column names of the target variable and time variable must be passed as `cols_y` in the #' order `(target, time)` when constructing the [SurrogateLearnerCollection] that is being used as a #' surrogate. @@ -37,7 +37,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize"), time = p_dbl(tags = "time")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionMean.R b/R/AcqFunctionMean.R index d4658582..c42e0cc3 100644 --- a/R/AcqFunctionMean.R +++ b/R/AcqFunctionMean.R @@ -27,7 +27,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionPI.R b/R/AcqFunctionPI.R index acce80d1..0bed7196 100644 --- a/R/AcqFunctionPI.R +++ b/R/AcqFunctionPI.R @@ -30,7 +30,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionSD.R b/R/AcqFunctionSD.R index fcbf7b44..2006ebd6 100644 --- a/R/AcqFunctionSD.R +++ b/R/AcqFunctionSD.R @@ -27,7 +27,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqFunctionSmsEgo.R b/R/AcqFunctionSmsEgo.R index fa0ecef7..3e2b18bf 100644 --- a/R/AcqFunctionSmsEgo.R +++ b/R/AcqFunctionSmsEgo.R @@ -40,7 +40,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/AcqOptimizer.R b/R/AcqOptimizer.R index 1f547295..7f37c1a4 100644 --- a/R/AcqOptimizer.R +++ b/R/AcqOptimizer.R @@ -59,7 +59,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -146,7 +146,7 @@ AcqOptimizer = R6Class("AcqOptimizer", logger$set_threshold(self$param_set$values$logging_level) on.exit(logger$set_threshold(old_threshold)) - instance = OptimInstanceSingleCrit$new(objective = self$acq_function, search_space = self$acq_function$domain, terminator = self$terminator, check_values = FALSE, keep_evals = "all") + instance = OptimInstanceBatchSingleCrit$new(objective = self$acq_function, search_space = self$acq_function$domain, terminator = self$terminator, check_values = FALSE) # warmstart if (self$param_set$values$warmstart) { diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index c28c2f00..b994fbf6 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -4,7 +4,7 @@ #' @description #' Asynchronous Decentralized Bayesian Optimization (ADBO). #' -#' @notes +#' @note #' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. #' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. #' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. @@ -28,7 +28,7 @@ #' #' @export OptimizerADBO = R6Class("OptimizerADBO", - inherit = bbotk::Optimizer, + inherit = OptimizerAsync, public = list( @@ -59,33 +59,28 @@ OptimizerADBO = R6Class("OptimizerADBO", #' @description - #' Performs the optimization and writes optimization result into - #' [OptimInstance]. The optimization result is returned but the complete - #' optimization path is stored in [Archive] of [OptimInstance]. + #' Performs the optimization on a [OptimInstanceAsyncSingleCrit] or [OptimInstanceAsyncMultiCrit] until termination. + #' The single evaluations will be written into the [ArchiveAsync]. + #' The result will be written into the instance object. #' - #' @param inst ([OptimInstance]). - #' @return [data.table::data.table]. + #' @param inst ([OptimInstanceAsyncSingleCrit] | [OptimInstanceAsyncMultiCrit]). + #' + #' @return [data.table::data.table()] optimize = function(inst) { - - # generate initial design pv = self$param_set$values + + # initial design design = if (is.null(pv$initial_design)) { + + lg$debug("Generating sobol design with size %s", pv$design_size) generate_design_sobol(inst$search_space, n = pv$design_size)$data } else { + + lg$debug("Using provided initial design with size %s", nrow(pv$initial_design)) pv$initial_design } - # send initial design to workers - inst$rush$push_tasks(transpose_list(design), extra = list(list(timestamp_xs = Sys.time()))) - - # optimize - inst$archive$start_time = Sys.time() - result = optimize_decentralized(inst, self, private) - - # FIXME: kill workers to increase the chance of a fitting the final model - inst$rush$stop_workers(type = "kill") - - result + optimize_async_default(inst, self, design) } ), @@ -94,7 +89,7 @@ OptimizerADBO = R6Class("OptimizerADBO", .optimize = function(inst) { pv = self$param_set$values search_space = inst$search_space - rush = inst$rush + archive = inst$archive # sample lambda from exponential distribution lambda_0 = rexp(1, 1 / pv$lambda) @@ -110,20 +105,14 @@ OptimizerADBO = R6Class("OptimizerADBO", acq_optimizer$acq_function = acq_function lg$debug("Optimizer '%s' evaluates the initial design", self$id) - - # evaluate initial design - while (rush$n_queued_tasks > 0) { - task = rush$pop_task(fields = "xs") - xs_trafoed = trafo_xs(task$xs, inst$search_space) - ys = inst$objective$eval(xs_trafoed) - rush$push_results(task$key, yss = list(ys), extra = list(list(x_domain = list(xs_trafoed), timestamp_ys = Sys.time(), stage = "initial_design"))) - } + evaluate_queue_default(inst) lg$debug("Optimizer '%s' starts the tuning phase", self$id) # actual loop while (!inst$is_terminated) { + # decrease lambda if (pv$exponential_decay) { lambda = lambda_0 * exp(-pv$rate * (t %% pv$period)) t = t + 1 @@ -131,23 +120,25 @@ OptimizerADBO = R6Class("OptimizerADBO", lambda = pv$lambda } + # sample acq_function$constants$set_values(lambda = lambda) acq_function$surrogate$update() acq_function$update() xdt = acq_optimizer$optimize() + + # transpose point xss = transpose_list(xdt) xs = xss[[1]][inst$archive$cols_x] lg$trace("Optimizer '%s' draws %s", self$id, as_short_string(xs)) xs_trafoed = trafo_xs(xs, search_space) - extra = xss[[1]][c("acq_cb", ".already_evaluated")] - keys = rush$push_running_task(list(xs), extra = list(list(timestamp_xs = Sys.time()))) + + # eval + key = archive$push_running_point(xs) ys = inst$objective$eval(xs_trafoed) - rush$push_results(keys, yss = list(ys), extra = list(c(extra, list( - x_domain = list(xs_trafoed), - timestamp_ys = Sys.time(), - stage = "mbo", - lambda_0 = lambda_0, - lambda = lambda)))) + + # push result + extra = c(xss[[1]][c("acq_cb", ".already_evaluated")], list(stage = "mbo", lambda_0 = lambda_0, lambda = lambda)) + archive$push_result(key, ys, x_domain = xs_trafoed, extra = extra) } } ) diff --git a/R/OptimizerMbo.R b/R/OptimizerMbo.R index 9edd164a..c707f2a2 100644 --- a/R/OptimizerMbo.R +++ b/R/OptimizerMbo.R @@ -47,7 +47,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -75,7 +75,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/ResultAssigner.R b/R/ResultAssigner.R index dbbf812c..e558ac0d 100644 --- a/R/ResultAssigner.R +++ b/R/ResultAssigner.R @@ -28,7 +28,7 @@ ResultAssigner = R6Class("ResultAssigner", #' @description #' Assigns the result, i.e., the final point(s) to the instance. #' - #' @param instance ([bbotk::OptimInstanceSingleCrit] | [bbotk::OptimInstanceMultiCrit])\cr + #' @param instance ([bbotk::OptimInstanceBatchSingleCrit] | [bbotk::OptimInstanceBatchMultiCrit])\cr #' The [bbotk::OptimInstance] the final result should be assigned to. assign_result = function(instance) { stop("Abstract.") diff --git a/R/ResultAssignerArchive.R b/R/ResultAssignerArchive.R index aff6c2e8..1c6f9399 100644 --- a/R/ResultAssignerArchive.R +++ b/R/ResultAssignerArchive.R @@ -26,12 +26,12 @@ ResultAssignerArchive = R6Class("ResultAssignerArchive", #' @description #' Assigns the result, i.e., the final point(s) to the instance. #' - #' @param instance ([bbotk::OptimInstanceSingleCrit] | [bbotk::OptimInstanceMultiCrit])\cr + #' @param instance ([bbotk::OptimInstanceBatchSingleCrit] | [bbotk::OptimInstanceBatchMultiCrit])\cr #' The [bbotk::OptimInstance] the final result should be assigned to. assign_result = function(instance) { res = instance$archive$best() xdt = res[, instance$search_space$ids(), with = FALSE] - if (inherits(instance, "OptimInstanceMultiCrit")) { + if (inherits(instance, "OptimInstanceBatchMultiCrit")) { ydt = res[, instance$archive$cols_y, with = FALSE] instance$assign_result(xdt, ydt) } diff --git a/R/ResultAssignerSurrogate.R b/R/ResultAssignerSurrogate.R index 63505b28..0bf824a3 100644 --- a/R/ResultAssignerSurrogate.R +++ b/R/ResultAssignerSurrogate.R @@ -7,7 +7,7 @@ #' Result assigner that chooses the final point(s) based on a surrogate mean prediction of all evaluated points in the [bbotk::Archive]. #' This is especially useful in the case of noisy objective functions. #' -#' In the case of operating on an [bbotk::OptimInstanceMultiCrit] the [SurrogateLearnerCollection] must use as many learners as there are objective functions. +#' In the case of operating on an [bbotk::OptimInstanceBatchMultiCrit] the [SurrogateLearnerCollection] must use as many learners as there are objective functions. #' #' @family Result Assigner #' @export @@ -32,15 +32,15 @@ ResultAssignerSurrogate = R6Class("ResultAssignerSurrogate", #' Assigns the result, i.e., the final point(s) to the instance. #' If `$surrogate` is `NULL`, `default_surrogate(instance)` is used and also assigned to `$surrogate`. #' - #' @param instance ([bbotk::OptimInstanceSingleCrit] | [bbotk::OptimInstanceMultiCrit])\cr + #' @param instance ([bbotk::OptimInstanceBatchSingleCrit] | [bbotk::OptimInstanceBatchMultiCrit])\cr #' The [bbotk::OptimInstance] the final result should be assigned to. assign_result = function(instance) { if (is.null(self$surrogate)) { self$surrogate = default_surrogate(instance) } - if (inherits(instance, "OptimInstanceSingleCrit")) { + if (inherits(instance, "OptimInstanceBatchSingleCrit")) { assert_r6(self$surrogate, classes = "SurrogateLearner") - } else if (inherits(instance, "OptimInstanceMultiCrit")) { + } else if (inherits(instance, "OptimInstanceBatchMultiCrit")) { assert_r6(self$surrogate, classes = "SurrogateLearnerCollection") if (self$surrogate$n_learner != instance$objective$ydim) { stopf("Surrogate used within the result assigner uses %i learners but the optimization instance has %i objective functions", self$surrogate$n_learner, instance$objective$ydim) @@ -62,9 +62,9 @@ ResultAssignerSurrogate = R6Class("ResultAssignerSurrogate", best = archive_tmp$best()[, archive_tmp$cols_x, with = FALSE] # ys are still the ones originally evaluated - best_y = if (inherits(instance, "OptimInstanceSingleCrit")) { + best_y = if (inherits(instance, "OptimInstanceBatchSingleCrit")) { unlist(archive$data[best, on = archive$cols_x][, archive$cols_y, with = FALSE]) - } else if (inherits(instance, "OptimInstanceMultiCrit")) { + } else if (inherits(instance, "OptimInstanceBatchMultiCrit")) { archive$data[best, on = archive$cols_x][, archive$cols_y, with = FALSE] } instance$assign_result(xdt = best, best_y) diff --git a/R/Surrogate.R b/R/Surrogate.R index 506c5f42..1fc998af 100644 --- a/R/Surrogate.R +++ b/R/Surrogate.R @@ -99,7 +99,7 @@ Surrogate = R6Class("Surrogate", if (missing(rhs)) { private$.archive } else { - private$.archive = assert_multi_class(rhs, c("Archive", "ArchiveRush")) + private$.archive = assert_archive(rhs, null_ok = TRUE) invisible(private$.archive) } }, diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index ac88c451..82c92a3e 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -44,7 +44,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' diff --git a/R/SurrogateLearnerCollection.R b/R/SurrogateLearnerCollection.R index fdaa3ef2..bad34526 100644 --- a/R/SurrogateLearnerCollection.R +++ b/R/SurrogateLearnerCollection.R @@ -47,7 +47,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' xdt = generate_design_random(instance$search_space, n = 4)$data diff --git a/R/TunerADBO.R b/R/TunerADBO.R index fc51bbf9..6c89074f 100644 --- a/R/TunerADBO.R +++ b/R/TunerADBO.R @@ -4,7 +4,7 @@ #' @description #' Asynchronous Decentralized Bayesian Optimization (ADBO). #' -#' @notes +#' @note #' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. #' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. #' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. @@ -28,7 +28,7 @@ #' #' @export TunerADBO = R6Class("TunerADBO", - inherit = mlr3tuning::TunerFromOptimizer, + inherit = mlr3tuning::TunerAsyncFromOptimizerAsync, public = list( #' @description diff --git a/R/TunerMbo.R b/R/TunerMbo.R index 13f6615c..5311d005 100644 --- a/R/TunerMbo.R +++ b/R/TunerMbo.R @@ -1,4 +1,4 @@ -#' @title Tuner using Model Based Optimization +#' @title TunerBatch using Model Based Optimization #' #' @name mlr_tuners_mbo #' @@ -50,7 +50,7 @@ #' } #' } TunerMbo = R6Class("TunerMbo", - inherit = mlr3tuning::TunerFromOptimizer, + inherit = mlr3tuning::TunerBatchFromOptimizerBatch, public = list( #' @description diff --git a/R/bayesopt_ego.R b/R/bayesopt_ego.R index 9f8a9618..ca3d5736 100644 --- a/R/bayesopt_ego.R +++ b/R/bayesopt_ego.R @@ -10,8 +10,8 @@ #' In each iteration after the initial design, the surrogate and acquisition function are updated and the next candidate #' is chosen based on optimizing the acquisition function. #' -#' @param instance ([bbotk::OptimInstanceSingleCrit])\cr -#' The [bbotk::OptimInstanceSingleCrit] to be optimized. +#' @param instance ([bbotk::OptimInstanceBatchSingleCrit])\cr +#' The [bbotk::OptimInstanceBatchSingleCrit] to be optimized. #' @param init_design_size (`NULL` | `integer(1)`)\cr #' Size of the initial design. #' If `NULL` and the [bbotk::Archive] contains no evaluations, \code{4 * d} is used with \code{d} being the @@ -34,7 +34,7 @@ #' @note #' * The `acq_function$surrogate`, even if already populated, will always be overwritten by the `surrogate`. #' * The `acq_optimizer$acq_function`, even if already populated, will always be overwritten by `acq_function`. -#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceSingleCrit]. +#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceBatchSingleCrit]. #' #' @return invisible(instance)\cr #' The original instance is modified in-place and returned invisible. @@ -62,7 +62,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -90,7 +90,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize"), time = p_dbl(tags = "time")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -116,7 +116,7 @@ bayesopt_ego = function( ) { # assertions - assert_r6(instance, "OptimInstanceSingleCrit") + assert_r6(instance, "OptimInstanceBatchSingleCrit") assert_r6(surrogate, classes = "Surrogate") # cannot be SurrogateLearner due to EIPS assert_r6(acq_function, classes = "AcqFunction") assert_r6(acq_optimizer, classes = "AcqOptimizer") diff --git a/R/bayesopt_emo.R b/R/bayesopt_emo.R index 1caacd6f..c1e96ec8 100644 --- a/R/bayesopt_emo.R +++ b/R/bayesopt_emo.R @@ -11,8 +11,8 @@ #' In each iteration after the initial design, the surrogate and acquisition function are updated and the next candidate #' is chosen based on optimizing the acquisition function. #' -#' @param instance ([bbotk::OptimInstanceMultiCrit])\cr -#' The [bbotk::OptimInstanceMultiCrit] to be optimized. +#' @param instance ([bbotk::OptimInstanceBatchMultiCrit])\cr +#' The [bbotk::OptimInstanceBatchMultiCrit] to be optimized. #' @param init_design_size (`NULL` | `integer(1)`)\cr #' Size of the initial design. #' If `NULL` and the [bbotk::Archive] contains no evaluations, \code{4 * d} is used with \code{d} being the @@ -34,7 +34,7 @@ #' @note #' * The `acq_function$surrogate`, even if already populated, will always be overwritten by the `surrogate`. #' * The `acq_optimizer$acq_function`, even if already populated, will always be overwritten by `acq_function`. -#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceMultiCrit]. +#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceBatchMultiCrit]. #' #' @return invisible(instance)\cr #' The original instance is modified in-place and returned invisible. @@ -58,7 +58,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -89,7 +89,7 @@ bayesopt_emo = function( ) { # assertions - assert_r6(instance, "OptimInstanceMultiCrit") + assert_r6(instance, "OptimInstanceBatchMultiCrit") assert_r6(surrogate, classes = "SurrogateLearnerCollection") assert_r6(acq_function, classes = "AcqFunction") assert_r6(acq_optimizer, classes = "AcqOptimizer") diff --git a/R/bayesopt_mpcl.R b/R/bayesopt_mpcl.R index edac4cec..59b4850e 100644 --- a/R/bayesopt_mpcl.R +++ b/R/bayesopt_mpcl.R @@ -12,8 +12,8 @@ #' objective function value is obtained by applying the `liar` function to all previously obtained objective function values. #' This is repeated `q - 1` times to obtain a total of `q` candidates that are then evaluated in a single batch. #' -#' @param instance ([bbotk::OptimInstanceSingleCrit])\cr -#' The [bbotk::OptimInstanceSingleCrit] to be optimized. +#' @param instance ([bbotk::OptimInstanceBatchSingleCrit])\cr +#' The [bbotk::OptimInstanceBatchSingleCrit] to be optimized. #' @param init_design_size (`NULL` | `integer(1)`)\cr #' Size of the initial design. #' If `NULL` and the [bbotk::Archive] contains no evaluations, \code{4 * d} is used with \code{d} being the @@ -42,9 +42,9 @@ #' @note #' * The `acq_function$surrogate`, even if already populated, will always be overwritten by the `surrogate`. #' * The `acq_optimizer$acq_function`, even if already populated, will always be overwritten by `acq_function`. -#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceSingleCrit]. +#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceBatchSingleCrit]. #' * To make use of parallel evaluations in the case of `q > 1, the objective -#' function of the [bbotk::OptimInstanceSingleCrit] must be implemented accordingly. +#' function of the [bbotk::OptimInstanceBatchSingleCrit] must be implemented accordingly. #' #' @return invisible(instance)\cr #' The original instance is modified in-place and returned invisible. @@ -72,7 +72,7 @@ #' codomain = ps(y = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceSingleCrit$new( +#' instance = OptimInstanceBatchSingleCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 7)) #' @@ -106,7 +106,7 @@ bayesopt_mpcl = function( ) { # assertions - assert_r6(instance, "OptimInstanceSingleCrit") + assert_r6(instance, "OptimInstanceBatchSingleCrit") assert_r6(surrogate, classes = "Surrogate") # cannot be SurrogateLearner due to EIPS assert_r6(acq_function, classes = "AcqFunction") assert_r6(acq_optimizer, classes = "AcqOptimizer") diff --git a/R/bayesopt_parego.R b/R/bayesopt_parego.R index 62550871..744eecb2 100644 --- a/R/bayesopt_parego.R +++ b/R/bayesopt_parego.R @@ -11,8 +11,8 @@ #' obtained by scalarizing these values via the augmented Tchebycheff function, updating the surrogate with respect to #' these scalarized values and optimizing the acquisition function. #' -#' @param instance ([bbotk::OptimInstanceMultiCrit])\cr -#' The [bbotk::OptimInstanceMultiCrit] to be optimized. +#' @param instance ([bbotk::OptimInstanceBatchMultiCrit])\cr +#' The [bbotk::OptimInstanceBatchMultiCrit] to be optimized. #' @param init_design_size (`NULL` | `integer(1)`)\cr #' Size of the initial design. #' If `NULL` and the [bbotk::Archive] contains no evaluations, \code{4 * d} is used with \code{d} being the @@ -44,11 +44,11 @@ #' @note #' * The `acq_function$surrogate`, even if already populated, will always be overwritten by the `surrogate`. #' * The `acq_optimizer$acq_function`, even if already populated, will always be overwritten by `acq_function`. -#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceMultiCrit]. +#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceBatchMultiCrit]. #' * The scalarizations of the objective function values are stored as the `y_scal` column in the -#' [bbotk::Archive] of the [bbotk::OptimInstanceMultiCrit]. +#' [bbotk::Archive] of the [bbotk::OptimInstanceBatchMultiCrit]. #' * To make use of parallel evaluations in the case of `q > 1, the objective -#' function of the [bbotk::OptimInstanceMultiCrit] must be implemented accordingly. +#' function of the [bbotk::OptimInstanceBatchMultiCrit] must be implemented accordingly. #' #' @return invisible(instance)\cr #' The original instance is modified in-place and returned invisible. @@ -75,7 +75,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -109,7 +109,7 @@ bayesopt_parego = function( ) { # assertions - assert_r6(instance, "OptimInstanceMultiCrit") + assert_r6(instance, "OptimInstanceBatchMultiCrit") assert_r6(surrogate, classes = "SurrogateLearner") assert_r6(acq_function, classes = "AcqFunction") assert_r6(acq_optimizer, classes = "AcqOptimizer") diff --git a/R/bayesopt_smsego.R b/R/bayesopt_smsego.R index 124fcd86..3f7ee08f 100644 --- a/R/bayesopt_smsego.R +++ b/R/bayesopt_smsego.R @@ -10,8 +10,8 @@ #' In each iteration after the initial design, the surrogate and acquisition function ([mlr_acqfunctions_smsego]) are #' updated and the next candidate is chosen based on optimizing the acquisition function. #' -#' @param instance ([bbotk::OptimInstanceMultiCrit])\cr -#' The [bbotk::OptimInstanceMultiCrit] to be optimized. +#' @param instance ([bbotk::OptimInstanceBatchMultiCrit])\cr +#' The [bbotk::OptimInstanceBatchMultiCrit] to be optimized. #' @param init_design_size (`NULL` | `integer(1)`)\cr #' Size of the initial design. #' If `NULL` and the [bbotk::Archive] contains no evaluations, \code{4 * d} is used with \code{d} being the @@ -33,9 +33,9 @@ #' @note #' * The `acq_function$surrogate`, even if already populated, will always be overwritten by the `surrogate`. #' * The `acq_optimizer$acq_function`, even if already populated, will always be overwritten by `acq_function`. -#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceMultiCrit]. +#' * The `surrogate$archive`, even if already populated, will always be overwritten by the [bbotk::Archive] of the [bbotk::OptimInstanceBatchMultiCrit]. #' * Due to the iterative computation of the epsilon within the [mlr_acqfunctions_smsego], requires the [bbotk::Terminator] of -#' the [bbotk::OptimInstanceMultiCrit] to be a [bbotk::TerminatorEvals]. +#' the [bbotk::OptimInstanceBatchMultiCrit] to be a [bbotk::TerminatorEvals]. #' #' @return invisible(instance)\cr #' The original instance is modified in-place and returned invisible. @@ -63,7 +63,7 @@ #' codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) #' objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) #' -#' instance = OptimInstanceMultiCrit$new( +#' instance = OptimInstanceBatchMultiCrit$new( #' objective = objective, #' terminator = trm("evals", n_evals = 5)) #' @@ -94,7 +94,7 @@ bayesopt_smsego = function( ) { # assertions - assert_r6(instance, "OptimInstanceMultiCrit") + assert_r6(instance, "OptimInstanceBatchMultiCrit") assert_r6(instance$terminator, "TerminatorEvals") assert_r6(surrogate, classes = "SurrogateLearnerCollection") assert_r6(acq_function, classes = "AcqFunctionSmsEgo") diff --git a/R/helper.R b/R/helper.R index cc19e336..b327fb9c 100644 --- a/R/helper.R +++ b/R/helper.R @@ -1,5 +1,5 @@ generate_acq_codomain = function(surrogate, id, direction = "same") { - assert_multi_class(surrogate$archive, c("Archive", "ArchiveRush")) + assert_multi_class(surrogate$archive, c("Archive", "ArchiveAsync")) assert_string(id) assert_choice(direction, choices = c("same", "minimize", "maximize")) if (direction == "same") { @@ -18,7 +18,7 @@ generate_acq_codomain = function(surrogate, id, direction = "same") { } generate_acq_domain = function(surrogate) { - assert_multi_class(surrogate$archive, c("Archive", "ArchiveRush")) + assert_archive(surrogate$archive) domain = surrogate$archive$search_space$clone(deep = TRUE)$subset(surrogate$cols_x) domain$trafo = NULL domain diff --git a/R/mbo_defaults.R b/R/mbo_defaults.R index 9d54e411..5aa0dbfe 100644 --- a/R/mbo_defaults.R +++ b/R/mbo_defaults.R @@ -27,9 +27,9 @@ NULL #' @family mbo_defaults #' @export default_loop_function = function(instance) { - if (inherits(instance, "OptimInstanceSingleCrit")) { + if (inherits(instance, "OptimInstanceBatchSingleCrit")) { bayesopt_ego - } else if (inherits(instance, "OptimInstanceMultiCrit")) { + } else if (inherits(instance, "OptimInstanceBatchMultiCrit")) { bayesopt_smsego } } @@ -127,10 +127,10 @@ default_rf = function(noisy = FALSE) { #' In the case of dependencies, the following learner is used as a fallback: #' \code{lrn("regr.featureless")}. #' -#' If the instance is of class [bbotk::OptimInstanceSingleCrit] the learner is wrapped as a +#' If the instance is of class [bbotk::OptimInstanceBatchSingleCrit] the learner is wrapped as a #' [SurrogateLearner]. #' -#' If the instance is of class [bbotk::OptimInstanceMultiCrit] multiple deep clones of the learner are +#' If the instance is of class [bbotk::OptimInstanceBatchMultiCrit] multiple deep clones of the learner are #' wrapped as a [SurrogateLearnerCollection]. #' #' @references @@ -147,7 +147,7 @@ default_rf = function(noisy = FALSE) { #' @family mbo_defaults #' @export default_surrogate = function(instance, learner = NULL, n_learner = NULL) { - assert_multi_class(instance, c("OptimInstance", "OptimInstanceRush")) + assert_multi_class(instance, c("OptimInstance", "OptimInstanceAsync")) assert_r6(learner, "Learner", null.ok = TRUE) assert_int(n_learner, lower = 1L, null.ok = TRUE) noisy = "noisy" %in% instance$objective$properties @@ -211,9 +211,9 @@ default_surrogate = function(instance, learner = NULL, n_learner = NULL) { #' @export default_acqfunction = function(instance) { assert_r6(instance, classes = "OptimInstance") - if (inherits(instance, "OptimInstanceSingleCrit")) { + if (inherits(instance, "OptimInstanceBatchSingleCrit")) { AcqFunctionEI$new() - } else if (inherits(instance, "OptimInstanceMultiCrit")) { + } else if (inherits(instance, "OptimInstanceBatchMultiCrit")) { AcqFunctionSmsEgo$new() } } @@ -222,7 +222,7 @@ default_acqfunction = function(instance) { #' #' @description #' Chooses a default acquisition function optimizer. -#' Defaults to wrapping [bbotk::OptimizerRandomSearch] allowing 10000 function evaluations (with a batch size of 1000) via a [bbotk::TerminatorEvals]. +#' Defaults to wrapping [bbotk::OptimizerBatchRandomSearch] allowing 10000 function evaluations (with a batch size of 1000) via a [bbotk::TerminatorEvals]. #' #' @param acq_function ([AcqFunction]). #' @return [AcqOptimizer] diff --git a/man/AcqOptimizer.Rd b/man/AcqOptimizer.Rd index 0d19908a..f0f8d9b3 100644 --- a/man/AcqOptimizer.Rd +++ b/man/AcqOptimizer.Rd @@ -63,7 +63,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/ResultAssigner.Rd b/man/ResultAssigner.Rd index 28ea502a..a6f5485e 100644 --- a/man/ResultAssigner.Rd +++ b/man/ResultAssigner.Rd @@ -74,7 +74,7 @@ Assigns the result, i.e., the final point(s) to the instance. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{instance}}{(\link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} | \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr +\item{\code{instance}}{(\link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} | \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr The \link[bbotk:OptimInstance]{bbotk::OptimInstance} the final result should be assigned to.} } \if{html}{\out{
}} diff --git a/man/SurrogateLearner.Rd b/man/SurrogateLearner.Rd index 37702fc2..038f9487 100644 --- a/man/SurrogateLearner.Rd +++ b/man/SurrogateLearner.Rd @@ -48,7 +48,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/SurrogateLearnerCollection.Rd b/man/SurrogateLearnerCollection.Rd index 91ae1cc9..954b8ea9 100644 --- a/man/SurrogateLearnerCollection.Rd +++ b/man/SurrogateLearnerCollection.Rd @@ -51,7 +51,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) xdt = generate_design_random(instance$search_space, n = 4)$data diff --git a/man/default_acqoptimizer.Rd b/man/default_acqoptimizer.Rd index 17fb9d42..f5efb42a 100644 --- a/man/default_acqoptimizer.Rd +++ b/man/default_acqoptimizer.Rd @@ -14,7 +14,7 @@ default_acqoptimizer(acq_function) } \description{ Chooses a default acquisition function optimizer. -Defaults to wrapping \link[bbotk:mlr_optimizers_random_search]{bbotk::OptimizerRandomSearch} allowing 10000 function evaluations (with a batch size of 1000) via a \link[bbotk:mlr_terminators_evals]{bbotk::TerminatorEvals}. +Defaults to wrapping \link[bbotk:mlr_optimizers_random_search]{bbotk::OptimizerBatchRandomSearch} allowing 10000 function evaluations (with a batch size of 1000) via a \link[bbotk:mlr_terminators_evals]{bbotk::TerminatorEvals}. } \seealso{ Other mbo_defaults: diff --git a/man/default_surrogate.Rd b/man/default_surrogate.Rd index d2bbeccf..25e416d3 100644 --- a/man/default_surrogate.Rd +++ b/man/default_surrogate.Rd @@ -44,10 +44,10 @@ Out of range imputation makes sense for tree-based methods and is usually hard t In the case of dependencies, the following learner is used as a fallback: \code{lrn("regr.featureless")}. -If the instance is of class \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} the learner is wrapped as a +If the instance is of class \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} the learner is wrapped as a \link{SurrogateLearner}. -If the instance is of class \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} multiple deep clones of the learner are +If the instance is of class \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} multiple deep clones of the learner are wrapped as a \link{SurrogateLearnerCollection}. } \references{ diff --git a/man/mlr_acqfunctions_aei.Rd b/man/mlr_acqfunctions_aei.Rd index 56957d63..7e733f3f 100644 --- a/man/mlr_acqfunctions_aei.Rd +++ b/man/mlr_acqfunctions_aei.Rd @@ -47,7 +47,7 @@ if (requireNamespace("mlr3learners") & codomain = codomain, properties = "noisy") - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_cb.Rd b/man/mlr_acqfunctions_cb.Rd index d94ae789..501ebece 100644 --- a/man/mlr_acqfunctions_cb.Rd +++ b/man/mlr_acqfunctions_cb.Rd @@ -42,7 +42,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_ehvi.Rd b/man/mlr_acqfunctions_ehvi.Rd index 160eb8fa..4301ec08 100644 --- a/man/mlr_acqfunctions_ehvi.Rd +++ b/man/mlr_acqfunctions_ehvi.Rd @@ -26,7 +26,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_ehvigh.Rd b/man/mlr_acqfunctions_ehvigh.Rd index 9d9a2c27..976ffb61 100644 --- a/man/mlr_acqfunctions_ehvigh.Rd +++ b/man/mlr_acqfunctions_ehvigh.Rd @@ -41,7 +41,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_ei.Rd b/man/mlr_acqfunctions_ei.Rd index 0fe783ea..4a12dbda 100644 --- a/man/mlr_acqfunctions_ei.Rd +++ b/man/mlr_acqfunctions_ei.Rd @@ -33,7 +33,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_eips.Rd b/man/mlr_acqfunctions_eips.Rd index 214f654b..4c885b74 100644 --- a/man/mlr_acqfunctions_eips.Rd +++ b/man/mlr_acqfunctions_eips.Rd @@ -7,9 +7,9 @@ \description{ Expected Improvement per Second. -It is assumed that calculations are performed on an \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit}. +It is assumed that calculations are performed on an \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit}. Additionally to target values of the codomain that should be minimized or maximized, the -\link[bbotk:Objective]{bbotk::Objective} of the \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} should return time values. +\link[bbotk:Objective]{bbotk::Objective} of the \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} should return time values. The column names of the target variable and time variable must be passed as \code{cols_y} in the order \verb{(target, time)} when constructing the \link{SurrogateLearnerCollection} that is being used as a surrogate. @@ -40,7 +40,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize"), time = p_dbl(tags = "time")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_mean.Rd b/man/mlr_acqfunctions_mean.Rd index c9d602e2..b09456ba 100644 --- a/man/mlr_acqfunctions_mean.Rd +++ b/man/mlr_acqfunctions_mean.Rd @@ -33,7 +33,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_pi.Rd b/man/mlr_acqfunctions_pi.Rd index cc69d6e0..8f82a67c 100644 --- a/man/mlr_acqfunctions_pi.Rd +++ b/man/mlr_acqfunctions_pi.Rd @@ -33,7 +33,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_sd.Rd b/man/mlr_acqfunctions_sd.Rd index ab434ac9..9fdd0a57 100644 --- a/man/mlr_acqfunctions_sd.Rd +++ b/man/mlr_acqfunctions_sd.Rd @@ -33,7 +33,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_acqfunctions_smsego.Rd b/man/mlr_acqfunctions_smsego.Rd index e5d6c865..78f23dd6 100644 --- a/man/mlr_acqfunctions_smsego.Rd +++ b/man/mlr_acqfunctions_smsego.Rd @@ -39,7 +39,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_loop_functions_ego.Rd b/man/mlr_loop_functions_ego.Rd index 1420a86d..72b7c6fc 100644 --- a/man/mlr_loop_functions_ego.Rd +++ b/man/mlr_loop_functions_ego.Rd @@ -15,8 +15,8 @@ bayesopt_ego( ) } \arguments{ -\item{instance}{(\link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit})\cr -The \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} to be optimized.} +\item{instance}{(\link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit})\cr +The \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} to be optimized.} \item{surrogate}{(\link{Surrogate})\cr \link{Surrogate} to be used as a surrogate. @@ -56,7 +56,7 @@ is chosen based on optimizing the acquisition function. \itemize{ \item The \code{acq_function$surrogate}, even if already populated, will always be overwritten by the \code{surrogate}. \item The \code{acq_optimizer$acq_function}, even if already populated, will always be overwritten by \code{acq_function}. -\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit}. +\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit}. } } \examples{ @@ -76,7 +76,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) @@ -104,7 +104,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize"), time = p_dbl(tags = "time")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_loop_functions_emo.Rd b/man/mlr_loop_functions_emo.Rd index bcb212bc..6ce0885a 100644 --- a/man/mlr_loop_functions_emo.Rd +++ b/man/mlr_loop_functions_emo.Rd @@ -15,8 +15,8 @@ bayesopt_emo( ) } \arguments{ -\item{instance}{(\link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr -The \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} to be optimized.} +\item{instance}{(\link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr +The \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} to be optimized.} \item{surrogate}{(\link{SurrogateLearnerCollection})\cr \link{SurrogateLearnerCollection} to be used as a surrogate.} @@ -56,7 +56,7 @@ is chosen based on optimizing the acquisition function. \itemize{ \item The \code{acq_function$surrogate}, even if already populated, will always be overwritten by the \code{surrogate}. \item The \code{acq_optimizer$acq_function}, even if already populated, will always be overwritten by \code{acq_function}. -\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit}. +\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit}. } } \examples{ @@ -76,7 +76,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_loop_functions_mpcl.Rd b/man/mlr_loop_functions_mpcl.Rd index 7d56c763..1ee43738 100644 --- a/man/mlr_loop_functions_mpcl.Rd +++ b/man/mlr_loop_functions_mpcl.Rd @@ -17,8 +17,8 @@ bayesopt_mpcl( ) } \arguments{ -\item{instance}{(\link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit})\cr -The \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} to be optimized.} +\item{instance}{(\link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit})\cr +The \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} to be optimized.} \item{surrogate}{(\link{Surrogate})\cr \link{Surrogate} to be used as a surrogate. @@ -68,9 +68,9 @@ This is repeated \code{q - 1} times to obtain a total of \code{q} candidates tha \itemize{ \item The \code{acq_function$surrogate}, even if already populated, will always be overwritten by the \code{surrogate}. \item The \code{acq_optimizer$acq_function}, even if already populated, will always be overwritten by \code{acq_function}. -\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit}. +\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit}. \item To make use of parallel evaluations in the case of `q > 1, the objective -function of the \link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} must be implemented accordingly. +function of the \link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} must be implemented accordingly. } } \examples{ @@ -90,7 +90,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 7)) diff --git a/man/mlr_loop_functions_parego.Rd b/man/mlr_loop_functions_parego.Rd index f87fa2a6..8f8606d0 100644 --- a/man/mlr_loop_functions_parego.Rd +++ b/man/mlr_loop_functions_parego.Rd @@ -18,8 +18,8 @@ bayesopt_parego( ) } \arguments{ -\item{instance}{(\link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr -The \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} to be optimized.} +\item{instance}{(\link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr +The \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} to be optimized.} \item{surrogate}{(\link{SurrogateLearner})\cr \link{SurrogateLearner} to be used as a surrogate.} @@ -72,11 +72,11 @@ these scalarized values and optimizing the acquisition function. \itemize{ \item The \code{acq_function$surrogate}, even if already populated, will always be overwritten by the \code{surrogate}. \item The \code{acq_optimizer$acq_function}, even if already populated, will always be overwritten by \code{acq_function}. -\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit}. +\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit}. \item The scalarizations of the objective function values are stored as the \code{y_scal} column in the -\link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit}. +\link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit}. \item To make use of parallel evaluations in the case of `q > 1, the objective -function of the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} must be implemented accordingly. +function of the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} must be implemented accordingly. } } \examples{ @@ -96,7 +96,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_loop_functions_smsego.Rd b/man/mlr_loop_functions_smsego.Rd index 82284754..ab9c3199 100644 --- a/man/mlr_loop_functions_smsego.Rd +++ b/man/mlr_loop_functions_smsego.Rd @@ -15,8 +15,8 @@ bayesopt_smsego( ) } \arguments{ -\item{instance}{(\link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr -The \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} to be optimized.} +\item{instance}{(\link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr +The \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} to be optimized.} \item{surrogate}{(\link{SurrogateLearnerCollection})\cr \link{SurrogateLearnerCollection} to be used as a surrogate.} @@ -55,9 +55,9 @@ updated and the next candidate is chosen based on optimizing the acquisition fun \itemize{ \item The \code{acq_function$surrogate}, even if already populated, will always be overwritten by the \code{surrogate}. \item The \code{acq_optimizer$acq_function}, even if already populated, will always be overwritten by \code{acq_function}. -\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit}. +\item The \code{surrogate$archive}, even if already populated, will always be overwritten by the \link[bbotk:Archive]{bbotk::Archive} of the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit}. \item Due to the iterative computation of the epsilon within the \link{mlr_acqfunctions_smsego}, requires the \link[bbotk:Terminator]{bbotk::Terminator} of -the \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} to be a \link[bbotk:mlr_terminators_evals]{bbotk::TerminatorEvals}. +the \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} to be a \link[bbotk:mlr_terminators_evals]{bbotk::TerminatorEvals}. } } \examples{ @@ -77,7 +77,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) diff --git a/man/mlr_optimizers_adbo.Rd b/man/mlr_optimizers_adbo.Rd index 9b91b3f9..cd883bb8 100644 --- a/man/mlr_optimizers_adbo.Rd +++ b/man/mlr_optimizers_adbo.Rd @@ -7,6 +7,11 @@ \description{ Asynchronous Decentralized Bayesian Optimization (ADBO). } +\note{ +The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. +A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. +ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. +} \section{Parameters}{ \describe{ @@ -26,8 +31,8 @@ Initial design.} } } -\section{Super class}{ -\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{OptimizerADBO} +\section{Super classes}{ +\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{\link[bbotk:OptimizerAsync]{bbotk::OptimizerAsync}} -> \code{OptimizerADBO} } \section{Methods}{ \subsection{Public methods}{ @@ -60,9 +65,9 @@ Creates a new instance of this \link[R6:R6Class]{R6} class. \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-OptimizerADBO-optimize}{}}} \subsection{Method \code{optimize()}}{ -Performs the optimization and writes optimization result into -\link{OptimInstance}. The optimization result is returned but the complete -optimization path is stored in \link{Archive} of \link{OptimInstance}. +Performs the optimization on a \link{OptimInstanceAsyncSingleCrit} or \link{OptimInstanceAsyncMultiCrit} until termination. +The single evaluations will be written into the \link{ArchiveAsync}. +The result will be written into the instance object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{OptimizerADBO$optimize(inst)}\if{html}{\out{
}} } @@ -70,12 +75,12 @@ optimization path is stored in \link{Archive} of \link{OptimInstance}. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{inst}}{(\link{OptimInstance}).} +\item{\code{inst}}{(\link{OptimInstanceAsyncSingleCrit} | \link{OptimInstanceAsyncMultiCrit}).} } \if{html}{\out{
}} } \subsection{Returns}{ -\link[data.table:data.table]{data.table::data.table}. +\code{\link[data.table:data.table]{data.table::data.table()}} } } \if{html}{\out{
}} diff --git a/man/mlr_optimizers_mbo.Rd b/man/mlr_optimizers_mbo.Rd index 82e14a09..f738fdac 100644 --- a/man/mlr_optimizers_mbo.Rd +++ b/man/mlr_optimizers_mbo.Rd @@ -53,7 +53,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) @@ -81,7 +81,7 @@ if (requireNamespace("mlr3learners") & codomain = ps(y1 = p_dbl(tags = "minimize"), y2 = p_dbl(tags = "minimize")) objective = ObjectiveRFun$new(fun = fun, domain = domain, codomain = codomain) - instance = OptimInstanceMultiCrit$new( + instance = OptimInstanceBatchMultiCrit$new( objective = objective, terminator = trm("evals", n_evals = 5)) @@ -152,7 +152,6 @@ Required packages are determined based on the \code{acq_function}, \code{surroga }} diff --git a/man/mlr_result_assigners_archive.Rd b/man/mlr_result_assigners_archive.Rd index 11e3c5a5..aa453a08 100644 --- a/man/mlr_result_assigners_archive.Rd +++ b/man/mlr_result_assigners_archive.Rd @@ -68,7 +68,7 @@ Assigns the result, i.e., the final point(s) to the instance. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{instance}}{(\link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} | \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr +\item{\code{instance}}{(\link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} | \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr The \link[bbotk:OptimInstance]{bbotk::OptimInstance} the final result should be assigned to.} } \if{html}{\out{
}} diff --git a/man/mlr_result_assigners_surrogate.Rd b/man/mlr_result_assigners_surrogate.Rd index 1a0d3251..68d57759 100644 --- a/man/mlr_result_assigners_surrogate.Rd +++ b/man/mlr_result_assigners_surrogate.Rd @@ -8,7 +8,7 @@ Result assigner that chooses the final point(s) based on a surrogate mean prediction of all evaluated points in the \link[bbotk:Archive]{bbotk::Archive}. This is especially useful in the case of noisy objective functions. -In the case of operating on an \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit} the \link{SurrogateLearnerCollection} must use as many learners as there are objective functions. +In the case of operating on an \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit} the \link{SurrogateLearnerCollection} must use as many learners as there are objective functions. } \examples{ result_assigner = ras("surrogate") @@ -82,7 +82,7 @@ If \verb{$surrogate} is \code{NULL}, \code{default_surrogate(instance)} is used \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{instance}}{(\link[bbotk:OptimInstanceSingleCrit]{bbotk::OptimInstanceSingleCrit} | \link[bbotk:OptimInstanceMultiCrit]{bbotk::OptimInstanceMultiCrit})\cr +\item{\code{instance}}{(\link[bbotk:OptimInstanceBatchSingleCrit]{bbotk::OptimInstanceBatchSingleCrit} | \link[bbotk:OptimInstanceBatchMultiCrit]{bbotk::OptimInstanceBatchMultiCrit})\cr The \link[bbotk:OptimInstance]{bbotk::OptimInstance} the final result should be assigned to.} } \if{html}{\out{
}} diff --git a/man/mlr_tuners_adbo.Rd b/man/mlr_tuners_adbo.Rd index adf79f94..a029aa1b 100644 --- a/man/mlr_tuners_adbo.Rd +++ b/man/mlr_tuners_adbo.Rd @@ -7,6 +7,11 @@ \description{ Asynchronous Decentralized Bayesian Optimization (ADBO). } +\note{ +The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. +A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. +ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. +} \section{Parameters}{ \describe{ @@ -27,7 +32,7 @@ Initial design.} } \section{Super classes}{ -\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerFromOptimizer]{mlr3tuning::TunerFromOptimizer}} -> \code{TunerADBO} +\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerAsync]{mlr3tuning::TunerAsync}} -> \code{\link[mlr3tuning:TunerAsyncFromOptimizerAsync]{mlr3tuning::TunerAsyncFromOptimizerAsync}} -> \code{TunerADBO} } \section{Methods}{ \subsection{Public methods}{ @@ -42,7 +47,7 @@ Initial design.}
  • mlr3tuning::Tuner$format()
  • mlr3tuning::Tuner$help()
  • mlr3tuning::Tuner$print()
  • -
  • mlr3tuning::TunerFromOptimizer$optimize()
  • +
  • mlr3tuning::TunerAsyncFromOptimizerAsync$optimize()
  • }} diff --git a/man/mlr_tuners_mbo.Rd b/man/mlr_tuners_mbo.Rd index 36e4c887..b252b1dc 100644 --- a/man/mlr_tuners_mbo.Rd +++ b/man/mlr_tuners_mbo.Rd @@ -3,7 +3,7 @@ \name{mlr_tuners_mbo} \alias{mlr_tuners_mbo} \alias{TunerMbo} -\title{Tuner using Model Based Optimization} +\title{TunerBatch using Model Based Optimization} \description{ \code{TunerMbo} class that implements Model Based Optimization (MBO). This is a minimal interface internally passing on to \link{OptimizerMbo}. @@ -52,7 +52,7 @@ if (requireNamespace("mlr3learners") & } } \section{Super classes}{ -\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerFromOptimizer]{mlr3tuning::TunerFromOptimizer}} -> \code{TunerMbo} +\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerBatch]{mlr3tuning::TunerBatch}} -> \code{\link[mlr3tuning:TunerBatchFromOptimizerBatch]{mlr3tuning::TunerBatchFromOptimizerBatch}} -> \code{TunerMbo} } \section{Active bindings}{ \if{html}{\out{
    }} @@ -108,7 +108,7 @@ Required packages are determined based on the \code{acq_function}, \code{surroga }} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index e2b090b2..0f26a493 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -79,9 +79,9 @@ OBJ_2D_NOISY = ObjectiveRFun$new(fun = FUN_2D_NOISY, domain = PS_2D, properties # Instance helper MAKE_INST = function(objective = OBJ_2D, search_space = PS_2D, terminator = trm("evals", n_evals = 10L)) { if (objective$codomain$length == 1L) { - OptimInstanceSingleCrit$new(objective = objective, search_space = search_space, terminator = terminator) + OptimInstanceBatchSingleCrit$new(objective = objective, search_space = search_space, terminator = terminator) } else { - OptimInstanceMultiCrit$new(objective = objective, search_space = search_space, terminator = terminator) + OptimInstanceBatchMultiCrit$new(objective = objective, search_space = search_space, terminator = terminator) } } diff --git a/tests/testthat/test_AcqOptimizer.R b/tests/testthat/test_AcqOptimizer.R index f86db27b..4881b6ec 100644 --- a/tests/testthat/test_AcqOptimizer.R +++ b/tests/testthat/test_AcqOptimizer.R @@ -4,7 +4,7 @@ test_that("AcqOptimizer API works", { skip_if_not_installed("rgenoud") # EI, random search - instance = OptimInstanceSingleCrit$new(OBJ_1D, terminator = trm("evals", n_evals = 5L)) + instance = OptimInstanceBatchSingleCrit$new(OBJ_1D, terminator = trm("evals", n_evals = 5L)) design = generate_design_grid(instance$search_space, resolution = 4L)$data instance$eval_batch(design) acqfun = AcqFunctionEI$new(SurrogateLearner$new(REGR_KM_DETERM, archive = instance$archive)) diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 51bba643..3bec3b39 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -1,45 +1,31 @@ test_that("adbo optimizer works", { - options("bbotk_local" = TRUE) - rush::rush_plan(n_workers = 5) - - search_space = domain = ps( - x1 = p_dbl(-5, 10), - x2 = p_dbl(0, 15) - ) - - codomain = ps(y = p_dbl(tags = "minimize")) - - fun = function(xs) { - list(y = branin(x1 = xs$x1, x2 = xs$x2)) - } - - objective = ObjectiveRFun$new( - fun = fun, - domain = domain, - codomain = codomain - ) + # options(bbotk_local = TRUE) + skip_on_cran() + skip_if_not_installed("rush") + flush_redis() - instance = OptimInstanceRushSingleCrit$new( - objective = objective, - search_space = search_space, - terminator = trm("evals", n_evals = 100) + rush_plan(n_workers = 2) + instance = oi_async( + objective = OBJ_2D, + search_space = PS_2D, + terminator = trm("evals", n_evals = 100), ) - optimizer = opt("adbo", design_size = 4) optimizer$optimize(instance) }) - test_that("adbo tuner works", { - # options("bbotk_local" = TRUE) + # options(bbotk_local = TRUE) + skip_on_cran() + skip_if_not_installed("rush") flush_redis() - rush::rush_plan(n_workers = 5) learner = lrn("classif.rpart", minsplit = to_tune(2, 128), cp = to_tune(1e-04, 1e-1)) - instance = TuningInstanceRushSingleCrit$new( + rush_plan(n_workers = 2) + instance = ti_async( task = tsk("pima"), learner = learner, resampling = rsmp("cv", folds = 3), @@ -48,39 +34,13 @@ test_that("adbo tuner works", { store_benchmark_result = FALSE ) - optimizer = tnr("adbo", design_size = 4) - optimizer$optimize(instance) + tuner = tnr("adbo", design_size = 4) + tuner$optimize(instance) expect_data_table(instance$archive$data, min.rows = 20L) expect_rush_reset(instance$rush) }) -test_that("adbo tuner works with limited number of workers", { - # options("bbotk_local" = TRUE) - lgr::get_logger("rush")$set_threshold("debug") - - flush_redis() - rush::rush_plan(n_workers = 5) - - learner = lrn("classif.rpart", - minsplit = to_tune(2, 128), - cp = to_tune(1e-04, 1e-1)) - - instance = TuningInstanceRushSingleCrit$new( - task = tsk("pima"), - learner = learner, - resampling = rsmp("cv", folds = 3), - measure = msr("classif.ce"), - terminator = trm("evals", n_evals = 20), - store_benchmark_result = FALSE - ) - - optimizer = tnr("adbo", design_size = 4, n_workers = 2) - optimizer$optimize(instance) - - expect_data_table(instance$archive$data, min.rows = 20L) - expect_rush_reset(instance$rush) -}) test_that("adbo works with transformation functions", { flush_redis() diff --git a/tests/testthat/test_bayesopt_ego.R b/tests/testthat/test_bayesopt_ego.R index d0397dfd..78cb4c11 100644 --- a/tests/testthat/test_bayesopt_ego.R +++ b/tests/testthat/test_bayesopt_ego.R @@ -164,7 +164,7 @@ test_that("bayesopt_ego eips", { terminator = trm("evals", n_evals = 5L) - instance = OptimInstanceSingleCrit$new( + instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = terminator ) diff --git a/vignettes/mlr3mbo.Rmd b/vignettes/mlr3mbo.Rmd index 43066bc8..b76dfb38 100644 --- a/vignettes/mlr3mbo.Rmd +++ b/vignettes/mlr3mbo.Rmd @@ -454,7 +454,7 @@ Note that important fields of an `OptimizerMbo` such as `$param_classes`, `$pack If arguments such as the `surrogate`, `acq_function`, `acq_optimizer` and `result_assigner` were not fully initialized during construction, e.g., the `surrogate` missing the `archive`, or the `acq_function` missing the `surrogate`, lazy initialization is completed prior to the optimizer being used for optimization. -An object of class `OptimizerMbo` can be used to optimize an object of class `r ref("bbotk::OptimInstanceSingleCrit", "OptimInstanceSingleCrit")` or `r ref("bbotk::OptimInstanceMultiCrit", "OptimInstanceMultiCrit")`. +An object of class `OptimizerMbo` can be used to optimize an object of class `r ref("bbotk::OptimInstanceBatchSingleCrit", "OptimInstanceBatchSingleCrit")` or `r ref("bbotk::OptimInstanceBatchMultiCrit", "OptimInstanceBatchMultiCrit")`. For hyperparameter optimization, `r ref("mlr3mbo::mlr_tuners_mbo", "TunerMbo")` should be used (which simply relies on an `OptimizerMbo` that is constructed internally): @@ -536,7 +536,7 @@ objective = ObjectiveRFun$new( domain = domain, codomain = codomain) -instance = OptimInstanceSingleCrit$new( +instance = OptimInstanceBatchSingleCrit$new( objective = objective, terminator = trm("evals", n_evals = 10)) @@ -630,7 +630,7 @@ objective = ObjectiveRFun$new( domain = domain, codomain = codomain) -instance = OptimInstanceSingleCrit$new( +instance = OptimInstanceBatchSingleCrit$new( objective = objective, search_space = domain, terminator = trm("evals", n_evals = 60)) @@ -686,7 +686,7 @@ objective = ObjectiveRFun$new( domain = domain, codomain = codomain) -instance = OptimInstanceMultiCrit$new( +instance = OptimInstanceBatchMultiCrit$new( objective = objective, search_space = domain, terminator = trm("evals", n_evals = 30)) @@ -743,7 +743,7 @@ objective = ObjectiveRFun$new( domain = domain, codomain = codomain) -instance = OptimInstanceMultiCrit$new( +instance = OptimInstanceBatchMultiCrit$new( objective = objective, search_space = domain, terminator = trm("evals", n_evals = 30)) From 3787ec909f555074bb3d5e77a065ae6b5a3026fe Mon Sep 17 00:00:00 2001 From: be-marc Date: Sun, 28 Apr 2024 19:13:46 +0200 Subject: [PATCH 17/26] draft --- .github/workflows/dev-cmd-check.yml | 3 +++ .github/workflows/r-cmd-check.yml | 2 ++ NAMESPACE | 1 + R/OptimizerADBO.R | 3 +-- R/SurrogateLearner.R | 2 +- R/zzz.R | 2 +- man/mlr_optimizers_mbo.Rd | 5 +++-- man/mlr_tuners_mbo.Rd | 4 ++-- tests/testthat/test_TunerADBO.R | 2 +- 9 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dev-cmd-check.yml b/.github/workflows/dev-cmd-check.yml index 4f791969..f9bb2184 100644 --- a/.github/workflows/dev-cmd-check.yml +++ b/.github/workflows/dev-cmd-check.yml @@ -48,3 +48,6 @@ jobs: shell: Rscript {0} - uses: r-lib/actions/check-r-package@v2 + with: + args: 'c("--no-manual")' # "--as-cran" prevents to start external processes + diff --git a/.github/workflows/r-cmd-check.yml b/.github/workflows/r-cmd-check.yml index 25702f8b..c2f640a9 100644 --- a/.github/workflows/r-cmd-check.yml +++ b/.github/workflows/r-cmd-check.yml @@ -42,3 +42,5 @@ jobs: needs: check - uses: r-lib/actions/check-r-package@v2 + with: + args: 'c("--no-manual")' # "--as-cran" prevents to start external processes diff --git a/NAMESPACE b/NAMESPACE index 4a32731a..abd5e315 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -59,6 +59,7 @@ importFrom(R6,R6Class) importFrom(stats,dnorm) importFrom(stats,pnorm) importFrom(stats,quantile) +importFrom(stats,rexp) importFrom(stats,runif) importFrom(stats,setNames) importFrom(utils,bibentry) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index b994fbf6..48cc690e 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -42,8 +42,7 @@ OptimizerADBO = R6Class("OptimizerADBO", period = p_int(lower = 1L, default = 25L), design_size = p_int(lower = 1L), initial_design = p_uty(), - impute_method = p_fct(c("mean", "random"), default = "random"), - n_workers = p_int(lower = 1L) + impute_method = p_fct(c("mean", "random"), default = "random") ) param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L, impute_method = "random") diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index fc6e8ea2..2dc8eda1 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -223,7 +223,7 @@ SurrogateLearner = R6Class("SurrogateLearner", walk(self$cols_y, function(col) { min = min(xydt[[col]], na.rm = TRUE) max = max(xydt[[col]], na.rm = TRUE) - xydt[state %in% c("queued", "running"), (col) := runif(.N, min, max)] + xydt[c("queued", "running"), (col) := runif(.N, min, max), on = "state"] }) set(xydt, j = "state", value = NULL) } else { diff --git a/R/zzz.R b/R/zzz.R index baf57ecf..6ed1197e 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -10,7 +10,7 @@ #' @import mlr3 #' @import mlr3tuning #' @import rush -#' @importFrom stats setNames runif dnorm pnorm quantile +#' @importFrom stats setNames runif dnorm pnorm quantile rexp #' @useDynLib mlr3mbo c_sms_indicator c_eps_indicator "_PACKAGE" diff --git a/man/mlr_optimizers_mbo.Rd b/man/mlr_optimizers_mbo.Rd index e6924fed..6a57a9ca 100644 --- a/man/mlr_optimizers_mbo.Rd +++ b/man/mlr_optimizers_mbo.Rd @@ -95,8 +95,8 @@ if (requireNamespace("mlr3learners") & } } } -\section{Super class}{ -\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{OptimizerMbo} +\section{Super classes}{ +\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{\link[bbotk:OptimizerBatch]{bbotk::OptimizerBatch}} -> \code{OptimizerMbo} } \section{Active bindings}{ \if{html}{\out{
    }} @@ -153,6 +153,7 @@ Required packages are determined based on the \code{acq_function}, \code{surroga }} diff --git a/man/mlr_tuners_mbo.Rd b/man/mlr_tuners_mbo.Rd index 9c0e2828..1e625721 100644 --- a/man/mlr_tuners_mbo.Rd +++ b/man/mlr_tuners_mbo.Rd @@ -24,7 +24,7 @@ if (requireNamespace("mlr3learners") & resampling = rsmp("cv", folds = 3) measure = msr("classif.acc") - instance = TuningInstanceSingleCrit$new( + instance = TuningInstanceBatchSingleCrit$new( task = task, learner = learner, resampling = resampling, @@ -39,7 +39,7 @@ if (requireNamespace("mlr3learners") & resampling = rsmp("cv", folds = 3) measures = msrs(c("classif.acc", "selected_features")) - instance = TuningInstanceMultiCrit$new( + instance = TuningInstanceBatchMultiCrit$new( task = task, learner = learner, resampling = resampling, diff --git a/tests/testthat/test_TunerADBO.R b/tests/testthat/test_TunerADBO.R index 99a4c771..40e14c70 100644 --- a/tests/testthat/test_TunerADBO.R +++ b/tests/testthat/test_TunerADBO.R @@ -7,7 +7,7 @@ test_that("adbo tuner works", { minsplit = to_tune(2, 128), cp = to_tune(1e-04, 1e-1)) - rush_plan(n_workers = 2) + rush_plan(n_workers = 4) instance = ti_async( task = tsk("pima"), learner = learner, From 5a03bf708dd0c7bb6c7118dd9ffd6679e640df69 Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 29 Apr 2024 10:26:41 +0200 Subject: [PATCH 18/26] refactor: remove stage --- R/OptimizerADBO.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 48cc690e..58e4ab66 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -136,7 +136,7 @@ OptimizerADBO = R6Class("OptimizerADBO", ys = inst$objective$eval(xs_trafoed) # push result - extra = c(xss[[1]][c("acq_cb", ".already_evaluated")], list(stage = "mbo", lambda_0 = lambda_0, lambda = lambda)) + extra = c(xss[[1]][c("acq_cb", ".already_evaluated")], list(lambda_0 = lambda_0, lambda = lambda)) archive$push_result(key, ys, x_domain = xs_trafoed, extra = extra) } } From d77fad8567fbc8b839d3cf9c67bdd8249c3b4d1f Mon Sep 17 00:00:00 2001 From: be-marc Date: Mon, 29 Apr 2024 10:34:36 +0200 Subject: [PATCH 19/26] fix: description --- DESCRIPTION | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index be0d7102..d59137ab 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -41,17 +41,16 @@ BugReports: https://github.com/mlr-org/mlr3mbo/issues Depends: R (>= 3.1.0) Imports: - bbotk (>= 0.5.4), + bbotk (>= 0.8.0.9000), checkmate (>= 2.0.0), data.table, lgr (>= 0.3.4), mlr3 (>= 0.14.0), mlr3misc (>= 0.11.0), - mlr3tuning (>= 0.14.0), + mlr3tuning (>= 0.20.0.9000), paradox (>= 0.10.0), spacefillr, - R6 (>= 2.4.1), - rush + R6 (>= 2.4.1) Suggests: DiceKriging, emoa, @@ -65,8 +64,13 @@ Suggests: rgenoud, rmarkdown, rpart, + rush, stringi, - testthat (>= 3.0.0), + testthat (>= 3.0.0) +Remotes: + mlr-org/bbotk, + mlr-org/mlr3tuning, + mlr-org/rush ByteCompile: no Encoding: UTF-8 Config/testthat/edition: 3 From 170d650592f56b024d6b8ea6d1afcc08356daccc Mon Sep 17 00:00:00 2001 From: be-marc Date: Wed, 1 May 2024 08:17:27 +0200 Subject: [PATCH 20/26] feat: add n_worker argument --- R/OptimizerADBO.R | 10 ++++++++-- man/mlr_optimizers_adbo.Rd | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R index 58e4ab66..e4e98fc5 100644 --- a/R/OptimizerADBO.R +++ b/R/OptimizerADBO.R @@ -24,6 +24,11 @@ #' Size of the initial design.} #' \item{`initial_design`}{`data.table`\cr #' Initial design.} +#' \item{`impute_method`}{`character(1)`\cr +#' Imputation method for missing values in the surrogate model.} +#' \item{`n_workers`}{`integer(1)`\cr +#' Number of workers to use. +#' Defaults to the number of workers set by `rush::rush_plan()`} #' } #' #' @export @@ -42,7 +47,8 @@ OptimizerADBO = R6Class("OptimizerADBO", period = p_int(lower = 1L, default = 25L), design_size = p_int(lower = 1L), initial_design = p_uty(), - impute_method = p_fct(c("mean", "random"), default = "random") + impute_method = p_fct(c("mean", "random"), default = "random"), + n_workers = p_int(lower = 1L, default = NULL, special_vals = list(NULL)) ) param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L, impute_method = "random") @@ -79,7 +85,7 @@ OptimizerADBO = R6Class("OptimizerADBO", pv$initial_design } - optimize_async_default(inst, self, design) + optimize_async_default(inst, self, design, n_workers = pv$n_workers) } ), diff --git a/man/mlr_optimizers_adbo.Rd b/man/mlr_optimizers_adbo.Rd index cd883bb8..061a0036 100644 --- a/man/mlr_optimizers_adbo.Rd +++ b/man/mlr_optimizers_adbo.Rd @@ -28,6 +28,11 @@ Period of the exponential decay.} Size of the initial design.} \item{\code{initial_design}}{\code{data.table}\cr Initial design.} +\item{\code{impute_method}}{\code{character(1)}\cr +Imputation method for missing values in the surrogate model.} +\item{\code{n_workers}}{\code{integer(1)}\cr +Number of workers to use. +Defaults to the number of workers set by \code{rush::rush_plan()}} } } From 3bd95b0d7218c1b8d39ad7da33d4f817b3190655 Mon Sep 17 00:00:00 2001 From: be-marc Date: Wed, 1 May 2024 08:27:28 +0200 Subject: [PATCH 21/26] fix: imports --- NAMESPACE | 1 - R/zzz.R | 1 - tests/testthat/test_OptimizerADBO.R | 2 +- tests/testthat/test_TunerADBO.R | 6 +++--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index abd5e315..4ab0552c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -53,7 +53,6 @@ import(mlr3) import(mlr3misc) import(mlr3tuning) import(paradox) -import(rush) import(spacefillr) importFrom(R6,R6Class) importFrom(stats,dnorm) diff --git a/R/zzz.R b/R/zzz.R index 6ed1197e..a0e1e22d 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -9,7 +9,6 @@ #' @import lgr #' @import mlr3 #' @import mlr3tuning -#' @import rush #' @importFrom stats setNames runif dnorm pnorm quantile rexp #' @useDynLib mlr3mbo c_sms_indicator c_eps_indicator "_PACKAGE" diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R index 8aecb5ea..6e8a73a1 100644 --- a/tests/testthat/test_OptimizerADBO.R +++ b/tests/testthat/test_OptimizerADBO.R @@ -3,7 +3,7 @@ test_that("adbo optimizer works", { skip_if_not_installed("rush") flush_redis() - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) instance = oi_async( objective = OBJ_2D, search_space = PS_2D, diff --git a/tests/testthat/test_TunerADBO.R b/tests/testthat/test_TunerADBO.R index 40e14c70..2bc24ba2 100644 --- a/tests/testthat/test_TunerADBO.R +++ b/tests/testthat/test_TunerADBO.R @@ -33,7 +33,7 @@ test_that("adbo works with transformation functions", { minsplit = to_tune(2, 128, logscale = TRUE), cp = to_tune(1e-04, 1e-1, logscale = TRUE)) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) instance = ti_async( task = tsk("pima"), learner = learner, @@ -60,7 +60,7 @@ test_that("search works with dependencies", { cp = to_tune(1e-04, 1e-1), keep_model = to_tune()) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) instance = ti_async( task = tsk("pima"), learner = learner, @@ -92,7 +92,7 @@ test_that("adbo works with branching", { "branch.selection" = to_tune(c("rpart", "debug")) ) - rush_plan(n_workers = 2) + rush::rush_plan(n_workers = 2) instance = ti_async( task = tsk("pima"), learner = graph_learner, From 43c2189896306456ac72f6147ab79796116fe54b Mon Sep 17 00:00:00 2001 From: be-marc Date: Wed, 1 May 2024 08:43:30 +0200 Subject: [PATCH 22/26] fix: tests --- tests/testthat/test_TunerADBO.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test_TunerADBO.R b/tests/testthat/test_TunerADBO.R index 2bc24ba2..5d677bff 100644 --- a/tests/testthat/test_TunerADBO.R +++ b/tests/testthat/test_TunerADBO.R @@ -7,7 +7,7 @@ test_that("adbo tuner works", { minsplit = to_tune(2, 128), cp = to_tune(1e-04, 1e-1)) - rush_plan(n_workers = 4) + rush::rush_plan(n_workers = 4) instance = ti_async( task = tsk("pima"), learner = learner, From 056e50e7a6bbca2729638ba063806657012d38e4 Mon Sep 17 00:00:00 2001 From: be-marc Date: Wed, 1 May 2024 08:45:48 +0200 Subject: [PATCH 23/26] ci: add redis --- .github/workflows/dev-cmd-check.yml | 4 ++++ .github/workflows/r-cmd-check.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/dev-cmd-check.yml b/.github/workflows/dev-cmd-check.yml index f9bb2184..05e89247 100644 --- a/.github/workflows/dev-cmd-check.yml +++ b/.github/workflows/dev-cmd-check.yml @@ -38,6 +38,10 @@ jobs: with: r-version: ${{ matrix.config.r }} + - uses: supercharge/redis-github-action@1.7.0 + with: + redis-version: 7 + - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: any::rcmdcheck diff --git a/.github/workflows/r-cmd-check.yml b/.github/workflows/r-cmd-check.yml index c2f640a9..b6a33022 100644 --- a/.github/workflows/r-cmd-check.yml +++ b/.github/workflows/r-cmd-check.yml @@ -36,6 +36,10 @@ jobs: with: r-version: ${{ matrix.config.r }} + - uses: supercharge/redis-github-action@1.7.0 + with: + redis-version: 7 + - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: any::rcmdcheck From f769c4767d7bd769249bb3a6d11c9874fb5ddea1 Mon Sep 17 00:00:00 2001 From: Lennart Schneider Date: Tue, 18 Jun 2024 08:19:42 +0200 Subject: [PATCH 24/26] drop ADBO for now --- DESCRIPTION | 4 - NAMESPACE | 2 - R/OptimizerADBO.R | 153 ---------------------------- R/TunerADBO.R | 48 --------- man/mlr_optimizers_adbo.Rd | 108 -------------------- man/mlr_tuners_adbo.Rd | 81 --------------- tests/testthat/helper.R | 23 ----- tests/testthat/test_OptimizerADBO.R | 15 --- tests/testthat/test_TunerADBO.R | 110 -------------------- 9 files changed, 544 deletions(-) delete mode 100644 R/OptimizerADBO.R delete mode 100644 R/TunerADBO.R delete mode 100644 man/mlr_optimizers_adbo.Rd delete mode 100644 man/mlr_tuners_adbo.Rd delete mode 100644 tests/testthat/test_OptimizerADBO.R delete mode 100644 tests/testthat/test_TunerADBO.R diff --git a/DESCRIPTION b/DESCRIPTION index d59137ab..07461684 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -64,13 +64,11 @@ Suggests: rgenoud, rmarkdown, rpart, - rush, stringi, testthat (>= 3.0.0) Remotes: mlr-org/bbotk, mlr-org/mlr3tuning, - mlr-org/rush ByteCompile: no Encoding: UTF-8 Config/testthat/edition: 3 @@ -93,7 +91,6 @@ Collate: 'AcqFunctionSmsEgo.R' 'AcqOptimizer.R' 'aaa.R' - 'OptimizerADBO.R' 'OptimizerMbo.R' 'mlr_result_assigners.R' 'ResultAssigner.R' @@ -102,7 +99,6 @@ Collate: 'Surrogate.R' 'SurrogateLearner.R' 'SurrogateLearnerCollection.R' - 'TunerADBO.R' 'TunerMbo.R' 'mlr_loop_functions.R' 'bayesopt_ego.R' diff --git a/NAMESPACE b/NAMESPACE index 4ab0552c..8091417e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,7 +16,6 @@ export(AcqFunctionPI) export(AcqFunctionSD) export(AcqFunctionSmsEgo) export(AcqOptimizer) -export(OptimizerADBO) export(OptimizerMbo) export(ResultAssigner) export(ResultAssignerArchive) @@ -24,7 +23,6 @@ export(ResultAssignerSurrogate) export(Surrogate) export(SurrogateLearner) export(SurrogateLearnerCollection) -export(TunerADBO) export(TunerMbo) export(acqf) export(acqo) diff --git a/R/OptimizerADBO.R b/R/OptimizerADBO.R deleted file mode 100644 index e4e98fc5..00000000 --- a/R/OptimizerADBO.R +++ /dev/null @@ -1,153 +0,0 @@ -#' @title Asynchronous Decentralized Bayesian Optimization -#' @name mlr_optimizers_adbo -#' -#' @description -#' Asynchronous Decentralized Bayesian Optimization (ADBO). -#' -#' @note -#' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. -#' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. -#' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. -#' -#' @section Parameters: -#' \describe{ -#' \item{`lambda`}{`numeric(1)`\cr -#' \eqn{\lambda} value used for the confidence bound. -#' Defaults to `1.96`.} -#' \item{`exponential_decay`}{`lgl(1)`\cr -#' Whether to use periodic exponential decay for \eqn{\lambda}.} -#' \item{`rate`}{`numeric(1)`\cr -#' Rate of the exponential decay.} -#' \item{`t`}{`integer(1)`\cr -#' Period of the exponential decay.} -#' \item{`initial_design_size`}{`integer(1)`\cr -#' Size of the initial design.} -#' \item{`initial_design`}{`data.table`\cr -#' Initial design.} -#' \item{`impute_method`}{`character(1)`\cr -#' Imputation method for missing values in the surrogate model.} -#' \item{`n_workers`}{`integer(1)`\cr -#' Number of workers to use. -#' Defaults to the number of workers set by `rush::rush_plan()`} -#' } -#' -#' @export -OptimizerADBO = R6Class("OptimizerADBO", - inherit = OptimizerAsync, - - public = list( - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - initialize = function() { - param_set = ps( - lambda = p_dbl(lower = 0, default = 1.96), - exponential_decay = p_lgl(default = TRUE), - rate = p_dbl(lower = 0, default = 0.1), - period = p_int(lower = 1L, default = 25L), - design_size = p_int(lower = 1L), - initial_design = p_uty(), - impute_method = p_fct(c("mean", "random"), default = "random"), - n_workers = p_int(lower = 1L, default = NULL, special_vals = list(NULL)) - ) - - param_set$set_values(lambda = 1.96, exponential_decay = TRUE, rate = 0.1, period = 25L, design_size = 1L, impute_method = "random") - - super$initialize("adbo", - param_set = param_set, - param_classes = c("ParamLgl", "ParamInt", "ParamDbl", "ParamFct"), - properties = c("dependencies", "single-crit"), - packages = "mlr3mbo", - label = "Asynchronous Decentralized Bayesian Optimization", - man = "mlr3mbo::OptimizerADBO") - }, - - - #' @description - #' Performs the optimization on a [OptimInstanceAsyncSingleCrit] or [OptimInstanceAsyncMultiCrit] until termination. - #' The single evaluations will be written into the [ArchiveAsync]. - #' The result will be written into the instance object. - #' - #' @param inst ([OptimInstanceAsyncSingleCrit] | [OptimInstanceAsyncMultiCrit]). - #' - #' @return [data.table::data.table()] - optimize = function(inst) { - pv = self$param_set$values - - # initial design - design = if (is.null(pv$initial_design)) { - - lg$debug("Generating sobol design with size %s", pv$design_size) - generate_design_sobol(inst$search_space, n = pv$design_size)$data - } else { - - lg$debug("Using provided initial design with size %s", nrow(pv$initial_design)) - pv$initial_design - } - - optimize_async_default(inst, self, design, n_workers = pv$n_workers) - } - ), - - private = list( - - .optimize = function(inst) { - pv = self$param_set$values - search_space = inst$search_space - archive = inst$archive - - # sample lambda from exponential distribution - lambda_0 = rexp(1, 1 / pv$lambda) - t = 0 - - surrogate = default_surrogate(inst) - surrogate$param_set$set_values(impute_missings = pv$impute_method) - acq_function = acqf("cb", lambda = runif(1, 1 , 3)) - acq_optimizer = acqo(opt("random_search", batch_size = 1000L), terminator = trm("evals", n_evals = 10000L)) - - surrogate$archive = inst$archive - acq_function$surrogate = surrogate - acq_optimizer$acq_function = acq_function - - lg$debug("Optimizer '%s' evaluates the initial design", self$id) - evaluate_queue_default(inst) - - lg$debug("Optimizer '%s' starts the tuning phase", self$id) - - # actual loop - while (!inst$is_terminated) { - - # decrease lambda - if (pv$exponential_decay) { - lambda = lambda_0 * exp(-pv$rate * (t %% pv$period)) - t = t + 1 - } else { - lambda = pv$lambda - } - - # sample - acq_function$constants$set_values(lambda = lambda) - acq_function$surrogate$update() - acq_function$update() - xdt = acq_optimizer$optimize() - - # transpose point - xss = transpose_list(xdt) - xs = xss[[1]][inst$archive$cols_x] - lg$trace("Optimizer '%s' draws %s", self$id, as_short_string(xs)) - xs_trafoed = trafo_xs(xs, search_space) - - # eval - key = archive$push_running_point(xs) - ys = inst$objective$eval(xs_trafoed) - - # push result - extra = c(xss[[1]][c("acq_cb", ".already_evaluated")], list(lambda_0 = lambda_0, lambda = lambda)) - archive$push_result(key, ys, x_domain = xs_trafoed, extra = extra) - } - } - ) -) - -#' @include aaa.R -optimizers[["adbo"]] = OptimizerADBO diff --git a/R/TunerADBO.R b/R/TunerADBO.R deleted file mode 100644 index 6c89074f..00000000 --- a/R/TunerADBO.R +++ /dev/null @@ -1,48 +0,0 @@ -#' @title Asynchronous Decentralized Bayesian Optimization -#' @name mlr_tuners_adbo -#' -#' @description -#' Asynchronous Decentralized Bayesian Optimization (ADBO). -#' -#' @note -#' The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. -#' A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. -#' ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. -#' -#' @section Parameters: -#' \describe{ -#' \item{`lambda`}{`numeric(1)`\cr -#' \eqn{\lambda} value used for the confidence bound. -#' Defaults to `1.96`.} -#' \item{`exponential_decay`}{`lgl(1)`\cr -#' Whether to use periodic exponential decay for \eqn{\lambda}.} -#' \item{`rate`}{`numeric(1)`\cr -#' Rate of the exponential decay.} -#' \item{`t`}{`integer(1)`\cr -#' Period of the exponential decay.} -#' \item{`initial_design_size`}{`integer(1)`\cr -#' Size of the initial design.} -#' \item{`initial_design`}{`data.table`\cr -#' Initial design.} -#' } -#' -#' @export -TunerADBO = R6Class("TunerADBO", - inherit = mlr3tuning::TunerAsyncFromOptimizerAsync, - public = list( - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - initialize = function() { - super$initialize( - optimizer = OptimizerADBO$new(), - man = "mlr3tuning::mlr_tuners_adbo" - ) - } - ) -) - -mlr_tuners$add("adbo", TunerADBO) - -#' @include aaa.R -tuners[["adbo"]] = TunerADBO diff --git a/man/mlr_optimizers_adbo.Rd b/man/mlr_optimizers_adbo.Rd deleted file mode 100644 index 061a0036..00000000 --- a/man/mlr_optimizers_adbo.Rd +++ /dev/null @@ -1,108 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/OptimizerADBO.R -\name{mlr_optimizers_adbo} -\alias{mlr_optimizers_adbo} -\alias{OptimizerADBO} -\title{Asynchronous Decentralized Bayesian Optimization} -\description{ -Asynchronous Decentralized Bayesian Optimization (ADBO). -} -\note{ -The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. -A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. -ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. -} -\section{Parameters}{ - -\describe{ -\item{\code{lambda}}{\code{numeric(1)}\cr -\eqn{\lambda} value used for the confidence bound. -Defaults to \code{1.96}.} -\item{\code{exponential_decay}}{\code{lgl(1)}\cr -Whether to use periodic exponential decay for \eqn{\lambda}.} -\item{\code{rate}}{\code{numeric(1)}\cr -Rate of the exponential decay.} -\item{\code{t}}{\code{integer(1)}\cr -Period of the exponential decay.} -\item{\code{initial_design_size}}{\code{integer(1)}\cr -Size of the initial design.} -\item{\code{initial_design}}{\code{data.table}\cr -Initial design.} -\item{\code{impute_method}}{\code{character(1)}\cr -Imputation method for missing values in the surrogate model.} -\item{\code{n_workers}}{\code{integer(1)}\cr -Number of workers to use. -Defaults to the number of workers set by \code{rush::rush_plan()}} -} -} - -\section{Super classes}{ -\code{\link[bbotk:Optimizer]{bbotk::Optimizer}} -> \code{\link[bbotk:OptimizerAsync]{bbotk::OptimizerAsync}} -> \code{OptimizerADBO} -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-OptimizerADBO-new}{\code{OptimizerADBO$new()}} -\item \href{#method-OptimizerADBO-optimize}{\code{OptimizerADBO$optimize()}} -\item \href{#method-OptimizerADBO-clone}{\code{OptimizerADBO$clone()}} -} -} -\if{html}{\out{ -
    Inherited methods - -
    -}} -\if{html}{\out{
    }} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-OptimizerADBO-new}{}}} -\subsection{Method \code{new()}}{ -Creates a new instance of this \link[R6:R6Class]{R6} class. -\subsection{Usage}{ -\if{html}{\out{
    }}\preformatted{OptimizerADBO$new()}\if{html}{\out{
    }} -} - -} -\if{html}{\out{
    }} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-OptimizerADBO-optimize}{}}} -\subsection{Method \code{optimize()}}{ -Performs the optimization on a \link{OptimInstanceAsyncSingleCrit} or \link{OptimInstanceAsyncMultiCrit} until termination. -The single evaluations will be written into the \link{ArchiveAsync}. -The result will be written into the instance object. -\subsection{Usage}{ -\if{html}{\out{
    }}\preformatted{OptimizerADBO$optimize(inst)}\if{html}{\out{
    }} -} - -\subsection{Arguments}{ -\if{html}{\out{
    }} -\describe{ -\item{\code{inst}}{(\link{OptimInstanceAsyncSingleCrit} | \link{OptimInstanceAsyncMultiCrit}).} -} -\if{html}{\out{
    }} -} -\subsection{Returns}{ -\code{\link[data.table:data.table]{data.table::data.table()}} -} -} -\if{html}{\out{
    }} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-OptimizerADBO-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
    }}\preformatted{OptimizerADBO$clone(deep = FALSE)}\if{html}{\out{
    }} -} - -\subsection{Arguments}{ -\if{html}{\out{
    }} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
    }} -} -} -} diff --git a/man/mlr_tuners_adbo.Rd b/man/mlr_tuners_adbo.Rd deleted file mode 100644 index a029aa1b..00000000 --- a/man/mlr_tuners_adbo.Rd +++ /dev/null @@ -1,81 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/TunerADBO.R -\name{mlr_tuners_adbo} -\alias{mlr_tuners_adbo} -\alias{TunerADBO} -\title{Asynchronous Decentralized Bayesian Optimization} -\description{ -Asynchronous Decentralized Bayesian Optimization (ADBO). -} -\note{ -The \eqn{\lambda} parameter of the upper confidence bound acquisition function controls the trade-off between exploration and exploitation. -A large \eqn{\lambda} value leads to more exploration, while a small \eqn{\lambda} value leads to more exploitation. -ADBO can use periodic exponential decay to reduce \eqn{\lambda} periodically to the exploitation phase. -} -\section{Parameters}{ - -\describe{ -\item{\code{lambda}}{\code{numeric(1)}\cr -\eqn{\lambda} value used for the confidence bound. -Defaults to \code{1.96}.} -\item{\code{exponential_decay}}{\code{lgl(1)}\cr -Whether to use periodic exponential decay for \eqn{\lambda}.} -\item{\code{rate}}{\code{numeric(1)}\cr -Rate of the exponential decay.} -\item{\code{t}}{\code{integer(1)}\cr -Period of the exponential decay.} -\item{\code{initial_design_size}}{\code{integer(1)}\cr -Size of the initial design.} -\item{\code{initial_design}}{\code{data.table}\cr -Initial design.} -} -} - -\section{Super classes}{ -\code{\link[mlr3tuning:Tuner]{mlr3tuning::Tuner}} -> \code{\link[mlr3tuning:TunerAsync]{mlr3tuning::TunerAsync}} -> \code{\link[mlr3tuning:TunerAsyncFromOptimizerAsync]{mlr3tuning::TunerAsyncFromOptimizerAsync}} -> \code{TunerADBO} -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-TunerADBO-new}{\code{TunerADBO$new()}} -\item \href{#method-TunerADBO-clone}{\code{TunerADBO$clone()}} -} -} -\if{html}{\out{ -
    Inherited methods - -
    -}} -\if{html}{\out{
    }} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TunerADBO-new}{}}} -\subsection{Method \code{new()}}{ -Creates a new instance of this \link[R6:R6Class]{R6} class. -\subsection{Usage}{ -\if{html}{\out{
    }}\preformatted{TunerADBO$new()}\if{html}{\out{
    }} -} - -} -\if{html}{\out{
    }} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-TunerADBO-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
    }}\preformatted{TunerADBO$clone(deep = FALSE)}\if{html}{\out{
    }} -} - -\subsection{Arguments}{ -\if{html}{\out{
    }} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
    }} -} -} -} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index e2e91d6f..bf8befeb 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -195,26 +195,3 @@ expect_acqfunction = function(acqf) { expect_man_exists(acqf$man) } -expect_rush_reset = function(rush, type = "kill") { - processes = rush$processes - rush$reset(type = type) - expect_list(rush$connector$command(c("KEYS", "*")), len = 0) - walk(processes, function(p) p$kill()) -} - -flush_redis = function() { - config = redux::redis_config() - r = redux::hiredis(config) - r$FLUSHDB() -} - -sortnames = function(x) { - if (!is.null(names(x))) { - x <- x[order(names(x), decreasing = TRUE)] - } - x -} - -expect_equal_sorted = function(x, y, ...) { - expect_equal(sortnames(x), sortnames(y), ...) -} diff --git a/tests/testthat/test_OptimizerADBO.R b/tests/testthat/test_OptimizerADBO.R deleted file mode 100644 index 6e8a73a1..00000000 --- a/tests/testthat/test_OptimizerADBO.R +++ /dev/null @@ -1,15 +0,0 @@ -test_that("adbo optimizer works", { - skip_on_cran() - skip_if_not_installed("rush") - flush_redis() - - rush::rush_plan(n_workers = 2) - instance = oi_async( - objective = OBJ_2D, - search_space = PS_2D, - terminator = trm("evals", n_evals = 100), - ) - optimizer = opt("adbo", design_size = 4) - optimizer$optimize(instance) -}) - diff --git a/tests/testthat/test_TunerADBO.R b/tests/testthat/test_TunerADBO.R deleted file mode 100644 index 5d677bff..00000000 --- a/tests/testthat/test_TunerADBO.R +++ /dev/null @@ -1,110 +0,0 @@ -test_that("adbo tuner works", { - skip_on_cran() - skip_if_not_installed("rush") - flush_redis() - - learner = lrn("classif.rpart", - minsplit = to_tune(2, 128), - cp = to_tune(1e-04, 1e-1)) - - rush::rush_plan(n_workers = 4) - instance = ti_async( - task = tsk("pima"), - learner = learner, - resampling = rsmp("cv", folds = 3), - measure = msr("classif.ce"), - terminator = trm("evals", n_evals = 20), - store_benchmark_result = FALSE - ) - - tuner = tnr("adbo", design_size = 4) - tuner$optimize(instance) - - expect_data_table(instance$archive$data, min.rows = 20L) - expect_rush_reset(instance$rush) -}) - -test_that("adbo works with transformation functions", { - skip_on_cran() - skip_if_not_installed("rush") - flush_redis() - - learner = lrn("classif.rpart", - minsplit = to_tune(2, 128, logscale = TRUE), - cp = to_tune(1e-04, 1e-1, logscale = TRUE)) - - rush::rush_plan(n_workers = 2) - instance = ti_async( - task = tsk("pima"), - learner = learner, - resampling = rsmp("cv", folds = 3), - measure = msr("classif.ce"), - terminator = trm("evals", n_evals = 20), - store_benchmark_result = FALSE - ) - - optimizer = tnr("adbo", design_size = 4) - optimizer$optimize(instance) - - expect_data_table(instance$archive$data, min.rows = 20) - expect_rush_reset(instance$rush) -}) - -test_that("search works with dependencies", { - skip_on_cran() - skip_if_not_installed("rush") - flush_redis() - - learner = lrn("classif.rpart", - minsplit = to_tune(p_int(2, 128, depends = keep_model == TRUE)), - cp = to_tune(1e-04, 1e-1), - keep_model = to_tune()) - - rush::rush_plan(n_workers = 2) - instance = ti_async( - task = tsk("pima"), - learner = learner, - resampling = rsmp("cv", folds = 3), - measure = msr("classif.ce"), - terminator = trm("evals", n_evals = 20), - store_benchmark_result = FALSE - ) - - optimizer = tnr("adbo", design_size = 4) - optimizer$optimize(instance) - - expect_data_table(instance$archive$data, min.rows = 20) - expect_rush_reset(instance$rush) -}) - -test_that("adbo works with branching", { - skip_on_cran() - skip_if_not_installed("rush") - skip_if_not_installed("mlr3pipelines") - flush_redis() - library(mlr3pipelines) - - graph_learner = as_learner(ppl("branch", graphs = list(rpart = lrn("classif.rpart", id = "rpart"),debug = lrn("classif.debug", id = "debug")))) - graph_learner$param_set$set_values( - "rpart.cp" = to_tune(p_dbl(1e-04, 1e-1, depends = branch.selection == "rpart")), - "rpart.minsplit" = to_tune(p_int(2, 128, depends = branch.selection == "rpart")), - "debug.x" = to_tune(p_dbl(0, 1, depends = branch.selection == "debug")), - "branch.selection" = to_tune(c("rpart", "debug")) - ) - - rush::rush_plan(n_workers = 2) - instance = ti_async( - task = tsk("pima"), - learner = graph_learner, - resampling = rsmp("cv", folds = 3), - measure = msr("classif.ce"), - terminator = trm("evals", n_evals = 20), - store_benchmark_result = FALSE - ) - - optimizer = tnr("adbo", design_size = 4) - optimizer$optimize(instance) - - expect_data_table(instance$archive$data, min.rows = 20) - expect_rush_reset(instance$rush) -}) From 4018fc593df73c94a76e8ffd00ce013886d496e1 Mon Sep 17 00:00:00 2001 From: Lennart Schneider Date: Tue, 18 Jun 2024 22:52:05 +0200 Subject: [PATCH 25/26] do not include partial update changes made to SurrogateLearner --- R/SurrogateLearner.R | 20 ++------------------ R/zzz.R | 2 +- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index 2dc8eda1..17058990 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -87,10 +87,9 @@ SurrogateLearner = R6Class("SurrogateLearner", assert_insample_perf = p_lgl(), perf_measure = p_uty(custom_check = function(x) check_r6(x, classes = "MeasureRegr")), # FIXME: actually want check_measure perf_threshold = p_dbl(lower = -Inf, upper = Inf), - catch_errors = p_lgl(), - impute_missings = p_fct(c("none", "mean", "random")) + catch_errors = p_lgl() ) - ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE, impute_missings = "none") + ps$values = list(assert_insample_perf = FALSE, catch_errors = TRUE) ps$add_dep("perf_measure", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) ps$add_dep("perf_threshold", on = "assert_insample_perf", cond = CondEqual$new(TRUE)) @@ -215,21 +214,6 @@ SurrogateLearner = R6Class("SurrogateLearner", # Train learner with new data. # Also calculates the insample performance based on the `perf_measure` hyperparameter if `assert_insample_perf = TRUE`. .update = function() { - if (self$param_set$values$impute_missings == "mean") { - xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finished"))[, c(self$cols_x, self$cols_y), with = FALSE] - setnafill(xydt, type = "const", fill = mean(xydt[[self$cols_y]], na.rm = TRUE), cols = self$cols_y) - } else if (self$param_set$values$impute_missings == "random") { - xydt = self$archive$rush$fetch_tasks_with_state(states = c("queued", "running", "finished"))[, c(self$cols_x, self$cols_y, "state"), with = FALSE] - walk(self$cols_y, function(col) { - min = min(xydt[[col]], na.rm = TRUE) - max = max(xydt[[col]], na.rm = TRUE) - xydt[c("queued", "running"), (col) := runif(.N, min, max), on = "state"] - }) - set(xydt, j = "state", value = NULL) - } else { - xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] - } - task = TaskRegr$new(id = "surrogate_task", backend = xydt, target = self$cols_y) assert_learnable(task, learner = self$learner) self$learner$train(task) diff --git a/R/zzz.R b/R/zzz.R index a0e1e22d..003b52c1 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -9,7 +9,7 @@ #' @import lgr #' @import mlr3 #' @import mlr3tuning -#' @importFrom stats setNames runif dnorm pnorm quantile rexp +#' @importFrom stats setNames runif dnorm pnorm quantile #' @useDynLib mlr3mbo c_sms_indicator c_eps_indicator "_PACKAGE" From d509304c18bc2ab7d94b932eb1828aa6849fb33d Mon Sep 17 00:00:00 2001 From: Lennart Schneider Date: Tue, 18 Jun 2024 23:24:46 +0200 Subject: [PATCH 26/26] .. --- NAMESPACE | 1 - R/SurrogateLearner.R | 1 + tests/testthat/helper.R | 11 +++++++++++ tests/testthat/test_SurrogateLearner.R | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 8091417e..1a02acdc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -56,7 +56,6 @@ importFrom(R6,R6Class) importFrom(stats,dnorm) importFrom(stats,pnorm) importFrom(stats,quantile) -importFrom(stats,rexp) importFrom(stats,runif) importFrom(stats,setNames) importFrom(utils,bibentry) diff --git a/R/SurrogateLearner.R b/R/SurrogateLearner.R index 17058990..fb5681e4 100644 --- a/R/SurrogateLearner.R +++ b/R/SurrogateLearner.R @@ -214,6 +214,7 @@ SurrogateLearner = R6Class("SurrogateLearner", # Train learner with new data. # Also calculates the insample performance based on the `perf_measure` hyperparameter if `assert_insample_perf = TRUE`. .update = function() { + xydt = self$archive$data[, c(self$cols_x, self$cols_y), with = FALSE] task = TaskRegr$new(id = "surrogate_task", backend = xydt, target = self$cols_y) assert_learnable(task, learner = self$learner) self$learner$train(task) diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index bf8befeb..b3ea492d 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -195,3 +195,14 @@ expect_acqfunction = function(acqf) { expect_man_exists(acqf$man) } +sortnames = function(x) { + if (!is.null(names(x))) { + x = x[order(names(x), decreasing = TRUE)] + } + x +} + +expect_equal_sorted = function(x, y, ...) { + expect_equal(sortnames(x), sortnames(y), ...) +} + diff --git a/tests/testthat/test_SurrogateLearner.R b/tests/testthat/test_SurrogateLearner.R index 8461a757..08f46d7e 100644 --- a/tests/testthat/test_SurrogateLearner.R +++ b/tests/testthat/test_SurrogateLearner.R @@ -50,7 +50,7 @@ test_that("param_set", { inst = MAKE_INST_1D() surrogate = SurrogateLearner$new(learner = REGR_FEATURELESS, archive = inst$archive) expect_r6(surrogate$param_set, "ParamSet") - expect_setequal(surrogate$param_set$ids(), c("assert_insample_perf", "perf_measure", "perf_threshold", "catch_errors", "impute_missings")) + expect_setequal(surrogate$param_set$ids(), c("assert_insample_perf", "perf_measure", "perf_threshold", "catch_errors")) expect_equal(surrogate$param_set$class[["assert_insample_perf"]], "ParamLgl") expect_equal(surrogate$param_set$class[["perf_measure"]], "ParamUty") expect_equal(surrogate$param_set$class[["perf_threshold"]], "ParamDbl")