Purpose

This Vignette will give you a short overview on how to warm-start your optimization. It will consider three kinds of warm starting. First, you can warm-start your optimization on any pre-evaluated design. Second, you can continue optimizing a terminated optimization. Third, you can continue any failed optimization if you took the right precautions.

Prerequisites

First, we will construct our problem that will be used for the following examples

library(mlrMBO)
obj.fun = makeSixHumpCamelFunction()
ggplot2::autoplot(obj.fun, render.levels = TRUE, show.optimum = TRUE)

Warm Start on a Design

First we create the pre-evaluated design.

design = generateGridDesign(getParamSet(obj.fun), resolution = 3)
design$y = apply(design, 1, obj.fun)
design
##   x1 x2     y
## 1 -3 -2 162.9
## 2  0 -2  48.0
## 3  3 -2 150.9
## 4 -3  0 108.9
## 5  0  0   0.0
## 6  3  0 108.9
## 7 -3  2 150.9
## 8  0  2  48.0
## 9  3  2 162.9

Now we define out MBO Settings.

ctrl = makeMBOControl()
ctrl = setMBOControlInfill(ctrl, crit.ei)
ctrl = setMBOControlTermination(ctrl, iters = 4)

To warm start the Bayesian optimization we simply call mbo() and pass the pre-evaluated design.

res = mbo(obj.fun, design = design, control = ctrl)
## [mbo] 1: x=-0.54,0.0443 : y = 0.966 : 0.0 secs : infill_ei
## [mbo] 2: x=-0.256,-0.258 : y = 0.0701 : 0.0 secs : infill_ei
## [mbo] 3: x=-0.243,0.106 : y = 0.159 : 0.0 secs : infill_ei
## [mbo] 4: x=-0.21,-0.0831 : y = 0.163 : 0.0 secs : infill_ei
plot(res$final.opt.state, scale.panels = TRUE)

Continue a Terminated Optimization

Now, we will continue our above optimization. Here we have two options. First, we can convert the opt.path from the result to a data.frame, which will then serve as the pre-evaluated design. This pre-evaluated design can be passed to mbo() just as in the previous example.

op = as.data.frame(res$opt.path)
design = op[, c("x1", "x2", "y")]
res2 = mbo(obj.fun, design = design, control = ctrl)
## [mbo] 1: x=0.452,-0.233 : y = 0.422 : 0.0 secs : infill_ei
## [mbo] 2: x=0.222,-0.23 : y = -0.0592 : 0.0 secs : infill_ei
## [mbo] 3: x=0.306,-0.504 : y = -0.555 : 0.0 secs : infill_ei
## [mbo] 4: x=0.0967,-0.427 : y = -0.599 : 0.0 secs : infill_ei
plot(res2$final.opt.state, scale.panels = TRUE)

Second, we can use mboContinue() on the final.opt.state. In this case we have to change the state of the opt.state object from "term.iter" to "iter" so MBO does not assume the optimization is already terminated. Furthermore we have to redefine the termination criterion to 8 because we want run 4 further iterations from the 4 we already did in the beginning.

opt.state = res$final.opt.state
opt.state$opt.problem$control = setMBOControlTermination(opt.state$opt.problem$control, iters = 8)
opt.state$state = "iter"
res3 = mboContinue(res$final.opt.state)
## [mbo] 5: x=0.454,-0.235 : y = 0.422 : 0.0 secs : infill_ei
## [mbo] 6: x=0.229,-0.227 : y = -0.0433 : 0.0 secs : infill_ei
## [mbo] 7: x=0.309,-0.506 : y = -0.554 : 0.0 secs : infill_ei
## [mbo] 8: x=-0.355,0.649 : y = -0.734 : 0.0 secs : infill_ei
plot(res3$final.opt.state, scale.panels = TRUE)

The first approach has the advantage that it is more transparent. Also you have to pass an MBOControl object which gives you an easy ability to refine your MBO settings for the further iterations. The second approach is a bit more hacky but has the advantage that you do not have to construct the design from the opt.path.

Continue a Failed Optimization

If you run long MBO optimization tasks it is especially frustrating if some part crashes and your optimization progress is gone. Luckily MBO has the capabilities to continue failed optimization runs if you configure the MBOControl object right.

But first, for this example we have to construct a function that fails. This function will throw an error the 12th time it is called.

counter = 0
f = makeSingleObjectiveFunction(
  fn = function(x) {
    counter <<- counter + 1
    if (counter == 12L)
      stop("fail")
    sum(x^2)
  },
  par.set = makeNumericParamSet(len = 2L, lower = -2, upper = 1)
)

To be able to continue a failed optimization run we have to set save.on.disk.at.time or save.on.disk.at. The first defines a time frame that has to pass until the current state is saved to disk again (e.g. all 30 seconds). The second defines a vector of iterations, when to save the current state to disk (e.g. c(10,20,30)). Additionally you can set the location where the state is saved with save.file.path. It defaults to getwd()/mlrMBO_run.RData.

ctrl = makeMBOControl(save.on.disk.at = c(2,4))
ctrl = setMBOControlInfill(ctrl, crit.ei)
ctrl = setMBOControlTermination(ctrl, iters = 8L)
or = mbo(f, control = ctrl)
## Computing y column(s) for design. Not provided.
## [mbo] 0: x=-0.587,-0.903 : y = 1.16 : 0.0 secs : initdesign
## [mbo] 0: x=0.303,-0.37 : y = 0.229 : 0.0 secs : initdesign
## [mbo] 0: x=-1.08,0.621 : y = 1.55 : 0.0 secs : initdesign
## [mbo] 0: x=-1.74,0.151 : y = 3.03 : 0.0 secs : initdesign
## [mbo] 0: x=0.17,-1.45 : y = 2.14 : 0.0 secs : initdesign
## [mbo] 0: x=0.732,-0.79 : y = 1.16 : 0.0 secs : initdesign
## [mbo] 0: x=-1.59,-1.76 : y = 5.64 : 0.0 secs : initdesign
## [mbo] 0: x=-0.298,0.928 : y = 0.949 : 0.0 secs : initdesign
## [mbo] 1: x=-0.134,-0.108 : y = 0.0295 : 0.0 secs : infill_ei
## Saved the current state after iteration 2 in the file /home/runner/work/mlrMBO/mlrMBO/vignettes/supplementary/mlrMBO_run.RData.
## [mbo] 2: x=0.12,0.131 : y = 0.0315 : 0.0 secs : infill_ei
## [mbo] 3: x=0.0353,-0.0343 : y = 0.00242 : 0.0 secs : infill_ei
## Saved the current state after iteration 4 in the file /home/runner/work/mlrMBO/mlrMBO/vignettes/supplementary/mlrMBO_run.RData.
## Error in fn(unlist(x), ...): fail

As expected the process failed. Luckily we can use the saved opt.state to continue the optimization.

counter = 13 # set counter to not trigger the error
or = mboContinue("mlrMBO_run.RData")
## [mbo] 4: x=-0.0394,0.0483 : y = 0.00389 : 0.0 secs : infill_ei
## [mbo] 5: x=-0.339,0.0209 : y = 0.115 : 0.0 secs : infill_ei
## [mbo] 6: x=0.00141,-0.168 : y = 0.0283 : 0.0 secs : infill_ei
## [mbo] 7: x=-0.00765,-0.... : y = 6.45e-05 : 0.0 secs : infill_ei
## [mbo] 8: x=0.0729,0.0184 : y = 0.00566 : 0.0 secs : infill_ei
file.remove("mlrMBO_run.RData") # remove the saved state
## [1] TRUE

Note: It is possible to continue an optimization that was saved to disk and terminated using the same approach as in the previous chapter. You can access the opt.state by calling load("mlrMBO_run.RData").