Getting started in Ask-Tell Mode (Python)

 

The ask-tell interface in Dragonfly enables step-by-step optimization by directly exposing the next point to be evaluated in an iteration of Bayesian optimization.

Two main components are required in this interface: a function caller and an optimizer.

There are two different types of function callers: EuclideanFunctionCaller and CPFunctionCaller. If the domain is limited to Euclidean spaces, use a EuclideanFunctionCaller, otherwise use a CPFunctionCaller. For Cartesian product spaces, you may also need to define orderings for the domain, which can be passed in with the domain_orderings argument in CPFunctionCaller. It is important to note that no objective function is passed in to the function caller. See the example below for more details.

There are three different optimizers, similar to how the main API allows specification of the optimization method using the opt_method argument. In this interface, the optimizer is explicitly created via <domain>GPBandit, <domain>GAOptimiser, or <domain>RandomOptimiser, where <domain> is replaced by Euclidean or CP depending on the domain used. This domain should be consistent with the function caller created. Here, ask_tell_mode should be set to True to activate the ask-tell interface.

Finally, call initialise() on the created optimizer to begin using the interface.

You can import the necessary components in python code via,

from dragonfly.exd import domains
from dragonfly.exd.experiment_caller import CPFunctionCaller, EuclideanFunctionCaller
from dragonfly.opt import random_optimiser, cp_ga_optimiser, gp_bandit

max_capital = 100
objective = lambda x: x[0] ** 4 - x[0]**2 + 0.1 * x[0]
domain = domains.EuclideanDomain([[-10, 10]])
func_caller = EuclideanFunctionCaller(None, domain)
opt = gp_bandit.EuclideanGPBandit(func_caller, ask_tell_mode=True)
opt.initialise()

for i in range(max_capital):
    x = opt.ask()
    y = objective(x)
    print("x:", x, ", y:", y)
    opt.tell([(x, y)])

Here, objective is the function to be maximised, domain is the domain over which objective is to be optimised, and max_capital is the capital available for optimisation. In this interface, max_capital is simply the maximum number of evaluations to objective.

To minimise the function, simply take the negative of the objective and perform the same procedure above.

ask returns the next point to be evaluated in a numpy array. Once the point is evaluated by calling the objective function, tell the point back to the optimiser. Note that tell takes one argument, where x and y are organized into a tuple wrapped by a list.

As with the main API, the domain can be specified via a JSON file or in code. See the following example for more details. You can run it via, for example,

$ python examples/detailed_use_cases/in_code_demo_ask_tell.py

 

Multifidelity optimisation

The flow for multifidelity optimisation is very similar. In addition to the required components mentioned above, a fidelity space and a fidelity value to optimise on is required as well. When the objective is evaluated on both the fidelity coordinate z and the domain coordinate x, the fidelity argument must also be specified by calling opt.tell([z, x, y]).