Unconstrained Example
This example demonstrates how to use qPOTS for a simple unconstrained multi-objective optimization workflow. It is a non-HPC implementation designed for local execution.
Overview
Optimizes a 2-dimensional, 2-objective problem.
Uses Pareto Optimal Thompson Sampling (QPOTS) for acquisition.
Evaluates hypervolume (HV) at each step.
Saves training data, hypervolume values, and computational times for analysis.
Script Details
unconstrained_branin.py
1"""
2This example demonstrates how to use qPOTS on a BoTorch multiobjective test function called BraninCurrin.
3This is not an HPC implementation.
4"""
5import warnings
6import os
7import time
8import numpy as np
9
10warnings.filterwarnings('ignore')
11
12from qpots.acquisition import Acquisition
13from qpots.config import DEFAULT_DEVICE, DEFAULT_DTYPE
14from qpots.config import DEFAULT_DEVICE, DEFAULT_DTYPE
15from qpots.model_object import ModelObject
16from qpots.utils.utils import expected_hypervolume
17
18import torch
19from qpots.function import Function
20from botorch.utils.transforms import unnormalize
21from botorch.test_functions.synthetic import Branin
22
23device = DEFAULT_DEVICE
24args = dict(
25 {
26 "ntrain": 20,
27 "iters": 100,
28 "reps": 20,
29 "q": 1,
30 "wd": ".",
31 "ref_point": torch.tensor([-300.0, -18.0], device=device, dtype=DEFAULT_DTYPE),
32 "dim": 2,
33 "nobj": 2,
34 "ncons": 0,
35 "nystrom": 0,
36 "nychoice": "pareto",
37 "ngen": 10,
38 }
39)
40
41def custom_func(x):
42 f = Branin(negate=True)
43
44 return f(x).unsqueeze(1).repeat(1, 2)
45
46# Set up problem
47bounds = torch.tensor([(-5, 10.), (0., 15.)], device=device, dtype=DEFAULT_DTYPE)
48tf = Function(dim=args["dim"], nobj=args["nobj"], custom_func=custom_func, bounds=bounds)
49f = tf.evaluate
50bounds = tf.get_bounds()
51
52os.makedirs(args["wd"], exist_ok=True)
53torch.manual_seed(1023)
54
55# set up the training points
56train_x = torch.rand([args["ntrain"], args["dim"]], device=device, dtype=DEFAULT_DTYPE)
57train_y = f(unnormalize(train_x, bounds))
58
59# fit the GP models
60gps = ModelObject(train_x, train_y, bounds, args["nobj"], args["ncons"], device=device)
61gps.fit_gp(single_objective=True)
62
63# initialize
64acq = Acquisition(tf, gps, device=device, q=args["q"])
65
66times, hvs = [], []
67for i in range(args["iters"]):
68 t1 = time.time() # tracking time
69 newx = acq.qpots(bounds, i, **args)
70 t2 = time.time()
71 times.append(t2 - t1)
72
73 newy = f(unnormalize(newx.reshape(-1, args["dim"]), bounds))
74 hv, _ = expected_hypervolume(gps, ref_point=args['ref_point'])
75 hvs.append(hv)
76
77 print(f"Iteration: {i}, New candidate: {newx}, Time: {t2 - t1}, HV: {hv}")
78
79 train_x = torch.row_stack([train_x, newx.view(-1, args["dim"])])
80 train_y = torch.row_stack([train_y, newy])
81 gps = ModelObject(train_x, train_y, bounds, args["nobj"], args["ncons"], device=device)
82 gps.fit_gp(single_objective=True)
83
84 np.save(f"{args['wd']}/train_x.npy", train_x.detach().cpu().numpy())
85 np.save(f"{args['wd']}/train_y.npy", train_y.detach().cpu().numpy())
86 np.save(f"{args['wd']}/hv.npy", hvs)
87 np.save(f"{args['wd']}/times.npy", times)
88
89
90
Example Output
Iteration: 0, New candidate: tensor([...]), Time: 0.12s, HV: 4478.89
Iteration: 1, New candidate: tensor([...]), Time: 0.14s, HV: 4480.92
...
Iteration: 49, New candidate: tensor([...]), Time: 0.20s, HV: 4997.88
Usage
To run the script locally, use:
python examples/unconstrained_branin.py
Ensure dependencies such as BoTorch, PyTorch, and qPOTS are installed.