This vignette is supposed to give a short introduction to the key features of mlrMBO
. The main goal of mlrMBO
is to optimize Expensive Black-Box Functions through Model-Based Optimization and to provide a unified interface for different MBO flavours and optimization tasks. Supported are, among other things:
This guide gives an overview of the typical optimization workflow with mlrMBO.
With the installation of mlrMBO
the dependencies mlr
, ParamHelpers
, and smoof
will be installed and also loaded when you load mlrMBO
. For this tutorial, you will need the additional packages DiceKriging
and randomForest
.
library(mlrMBO)
The following steps are needed to start the optimization:
smoof
.mlr
learner for the surrogate model (optional).mbo()
.For a simple example we minimize a cosine mixture function with an initial design of 5 points and 10 sequential MBO iterations. Thus, the optimizer gets in total 15 evaluations of the objective function to find the optimum.
Instead of writing the objective function by hand, we use the smoof package which offers many single objective functions frequently used for benchmarking of optimizers. smoof is a dependency and gets automatically attached with mlrMBO
.
Note: You are not limited to these test functions but can define arbitrary objective functions with smoof. Check ?smoof::makeSingleObjectiveFunction
for an example.
obj.fun = makeCosineMixtureFunction(1)
obj.fun = convertToMinimization(obj.fun)
print(obj.fun)
## Single-objective function
## Name: Cosine Mixture Function
## Description: no description
## Tags: single-objective, discontinuous, non-differentiable, separable, scalable, multimodal
## Noisy: FALSE
## Minimize: TRUE
## Constraints: TRUE
## Number of parameters: 1
## Type len Def Constr Req Tunable Trafo
## x numericvector 1 - -1 to 1 - TRUE -
## Global optimum objective value of -0.1000 at
## x
## 1 0
ggplot2::autoplot(obj.fun)
Before the MBO algorithm can starts it needs a set of already evaluated points - the inital design. If no design is given (i.e. design = NULL
), mbo()
will use a Maximin Latin Hypercube lhs::maximinLHS()
design with n = 4 * getNumberOfParameters(obj.fun)
points. If the design does not include function outcomes mbo()
will evaluate the design first before starting with the MBO algorithm. In this example we generate our own design.
des = generateDesign(n = 5, par.set = getParamSet(obj.fun), fun = lhs::randomLHS)
We will also precalculate the results:
des$y = apply(des, 1, obj.fun)
Note: mlrMBO uses y
as a default name for the outcome of the objective function. This can be changed in the control object.
We decide to use Kriging as our surrogate model because it has proven to be quite effective for numerical domains. The surrogate must be specified as a mlr regression learner:
surr.km = makeLearner("regr.km", predict.type = "se", covtype = "matern3_2", control = list(trace = FALSE))
Note: If no surrogate learner is defined, mbo()
automatically uses Kriging for a numerical domain, otherwise random forest regression.
The MBOControl
object contains all further settings for mbo()
. It is created with makeMBOControl()
. For further customization there are the following functions:
setMBOControlTermination()
: It is obligatory to define a termination criterion like the number of MBO iterations.setMBOControlInfill()
: It is recommended to set the infill criterion. For learners that support predict.type = "se"
the Confidence Bound "cb"
and the Expected Improvement "ei"
are a good choice.setMBOControlMultiPoint()
: Needed, in case you want to evaluate more then just one point per MBO-Iteration you can control this process here. This makes sense for parallelization.setMBOControlMultiObj()
: Needed, in case you want to optimize a multi-objective target function.control = makeMBOControl()
control = setMBOControlTermination(control, iters = 10)
control = setMBOControlInfill(control, crit = makeMBOInfillCritEI())
Finally, we start the optimization process and print the result object, which gives us the best found solution and the reached objective value.
run = mbo(obj.fun, design = des, learner = surr.km, control = control, show.info = TRUE)
## [mbo] 1: x=-0.161 : y = -0.0557 : 0.0 secs : infill_ei
## [mbo] 2: x=-0.186 : y = -0.063 : 0.0 secs : infill_ei
## [mbo] 3: x=-0.453 : y = 0.273 : 0.0 secs : infill_ei
## [mbo] 4: x=-0.179 : y = -0.0626 : 0.0 secs : infill_ei
## [mbo] 5: x=-0.194 : y = -0.062 : 0.0 secs : infill_ei
## [mbo] 6: x=-0.183 : y = -0.063 : 0.0 secs : infill_ei
## [mbo] 7: x=-0.188 : y = -0.0629 : 0.0 secs : infill_ei
## [mbo] 8: x=-0.185 : y = -0.063 : 0.0 secs : infill_ei
## [mbo] 9: x=-0.185 : y = -0.063 : 0.0 secs : infill_ei
## [mbo] 10: x=-0.184 : y = -0.063 : 0.0 secs : infill_ei
print(run)
## Recommended parameters:
## x=-0.185
## Objective: y = -0.063
##
## Optimization path
## 5 + 10 entries in total, displaying last 10 (or less):
## x y dob eol error.message exec.time ei
## 6 -0.1606555 -0.05569243 1 NA <NA> 0.000 -2.544066e-02
## 7 -0.1855267 -0.06300664 2 NA <NA> 0.000 -3.965762e-03
## 8 -0.4530156 0.27250626 3 NA <NA> 0.000 -8.941899e-04
## 9 -0.1791857 -0.06259511 4 NA <NA> 0.001 -4.302329e-04
## 10 -0.1936351 -0.06200608 5 NA <NA> 0.000 -1.493771e-04
## 11 -0.1833775 -0.06298321 6 NA <NA> 0.000 -5.596284e-05
## 12 -0.1877692 -0.06290288 7 NA <NA> 0.000 -2.664588e-05
## 13 -0.1846145 -0.06301134 8 NA <NA> 0.000 -1.413386e-05
## 14 -0.1849927 -0.06301202 9 NA <NA> 0.000 -3.516386e-06
## 15 -0.1842604 -0.06300733 10 NA <NA> 0.000 -1.292013e-06
## error.model train.time prop.type propose.time se mean
## 6 <NA> 0.031 infill_ei 0.053 7.674768e-02 -0.007966397
## 7 <NA> 0.019 infill_ei 0.056 1.247202e-02 -0.053522488
## 8 <NA> 0.020 infill_ei 0.052 1.534806e-01 0.265081259
## 9 <NA> 0.021 infill_ei 0.054 1.523041e-03 -0.062611157
## 10 <NA> 0.020 infill_ei 0.053 1.583207e-03 -0.061528160
## 11 <NA> 0.021 infill_ei 0.054 1.669101e-04 -0.062984191
## 12 <NA> 0.025 infill_ei 0.052 1.545918e-04 -0.062915952
## 13 <NA> 0.025 infill_ei 0.064 2.933588e-05 -0.063011220
## 14 <NA> 0.023 infill_ei 0.054 7.823809e-06 -0.063012096
## 15 <NA> 0.022 infill_ei 0.057 7.784748e-06 -0.063007267
To get better insight into the MBO process, we can start the previous optimization with the function exampleRun()
instead of mbo()
. This specialized function augments the results of mbo()
with additional information for plotting. Here, we plot the optimization state at iterations 1, 2, and 10.
run = exampleRun(obj.fun, learner = surr.km, control = control, show.info = FALSE)
print(run)
## MBOExampleRun
## Number of parameters : 1
## Parameter names : x
## Parameter types : numericvector
## Global Opt (known) : -1.0000e-01
## Gap for best point : 3.7022e-02
## True points per dim. : 50
## Objectives : 1
## Points proposed per iter : 1
##
## Infill criterion : Expected improvement (ei)
## Direction of optimization : maximize
## Requirement : SE estimation
## Components : se, mean
## Parameters : se.threshold=1e-06
## Infill optimizer : focussearch
## Infill optimizer restarts : 1
## Final point by : best.true.y
## Learner : regr.km
## Learner settings:
## jitter=FALSE,covtype=matern3_2,control=<list>
## Recommended parameters:
## x=-0.186
## Objective: y = -6.298e-02
plotExampleRun(run, iters = c(1L, 2L, 10L), pause = FALSE)