Skip to content

Commit

Permalink
fixed notebooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Morris committed Jan 6, 2024
1 parent f14bd55 commit db2ef21
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 63 deletions.
48 changes: 30 additions & 18 deletions bloptools/bayesian/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ def __init__(
#
# below are the behaviors of DOFs of each kind and mode:
#
# "read": the agent will read the input on every acquisition (all dofs are always read)
# "move": the agent will try to set and optimize over these (there must be at least one of these)
# "input" means that the agent will use the value to make its posterior
# 'read': the agent will read the input on every acquisition (all dofs are always read)
# 'move': the agent will try to set and optimize over these (there must be at least one of these)
# 'input' means that the agent will use the value to make its posterior
#
#
# not read-only read-only
Expand Down Expand Up @@ -170,7 +170,7 @@ def tell(

elif int(self.n_last_trained / self.train_every) != int(len(self.table) / self.train_every):
if train_models:
self._train_models(a_priori_hypers=hypers)
self._construct_models(train=train_models, a_priori_hypers=hypers)

def _construct_models(self, train=True, skew_dims=None, a_priori_hypers=None):
skew_dims = skew_dims if skew_dims is not None else self.latent_dim_tuples
Expand Down Expand Up @@ -235,11 +235,11 @@ def _construct_models(self, train=True, skew_dims=None, a_priori_hypers=None):
# if self.initialized:
# self._set_hypers(cached_hypers)
# else:
# raise RuntimeError("Could not fit model on initialization!")
# raise RuntimeError('Could not fit model on initialization!')

self.constraint = GenericDeterministicModel(f=lambda x: self.classifier.probabilities(x)[..., -1])

def ask(self, acq_func_identifier="qei", n=1, route=True, sequential=True, upsample=1):
def ask(self, acq_func_identifier="qei", n=1, route=True, sequential=True, upsample=1, **acq_func_kwargs):
"""Ask the agent for the best point to sample, given an acquisition function.
Parameters
Expand All @@ -261,19 +261,21 @@ def ask(self, acq_func_identifier="qei", n=1, route=True, sequential=True, upsam
start_time = ttime.monotonic()

if self.verbose:
print(f'finding points with acquisition function "{acq_func_name}" ...')
print(f"finding points with acquisition function '{acq_func_name}' ...")

if acq_func_type in ["analytic", "monte_carlo"]:
if not all(hasattr(obj, "model") for obj in self.objectives):
raise RuntimeError(
f'Can\'t construct non-trivial acquisition function "{acq_func_identifier}"'
f"Can't construct non-trivial acquisition function '{acq_func_identifier}'"
f" (the agent is not initialized!)"
)

if acq_func_type == "analytic" and n > 1:
raise ValueError("Can't generate multiple design points for analytic acquisition functions.")

acq_func, acq_func_meta = self.get_acquisition_function(identifier=acq_func_identifier, return_metadata=True)
acq_func, acq_func_meta = self.get_acquisition_function(
identifier=acq_func_identifier, return_metadata=True, **acq_func_kwargs
)

NUM_RESTARTS = 8
RAW_SAMPLES = 1024
Expand Down Expand Up @@ -332,7 +334,17 @@ def ask(self, acq_func_identifier="qei", n=1, route=True, sequential=True, upsam
upsampled_idx = np.linspace(0, len(idx) - 1, upsample * len(idx) - 1)
acq_points = sp.interpolate.interp1d(idx, acq_points, axis=0)(upsampled_idx)

return acq_points, acq_func_meta
res = {
"points": acq_points,
"acq_func": acq_func_meta["name"],
"acq_func_kwargs": acq_func_kwargs,
"duration": acq_func_meta["duration"],
"sequential": sequential,
"upsample": upsample,
"read_only_values": acq_func_meta.get("read_only_values"),
}

return res

def acquire(self, acquisition_inputs):
"""Acquire and digest according to the self's acquisition and digestion plans.
Expand Down Expand Up @@ -366,7 +378,7 @@ def acquire(self, acquisition_inputs):
# compute the fitness for each objective
# for index, entry in products.iterrows():
# for obj in self.objectives:
# products.loc[index, objective["key"]] = getattr(entry, objective["key"])
# products.loc[index, objective['key']] = getattr(entry, objective['key'])

except KeyboardInterrupt as interrupt:
raise interrupt
Expand Down Expand Up @@ -405,8 +417,8 @@ def learn(
For example:
RE(agent.learn("qr", n=16))
RE(agent.learn("qei", n=4, iterations=4))
RE(agent.learn('qr', n=16))
RE(agent.learn('qei', n=4, iterations=4))
Parameters
----------
Expand Down Expand Up @@ -435,9 +447,9 @@ def learn(
for i in range(iterations):
print(f"running iteration {i + 1} / {iterations}")
for single_acq_func in np.atleast_1d(acq_func):
acq_points, acq_func_meta = self.ask(n=n, acq_func_identifier=single_acq_func, upsample=upsample)
new_table = yield from self.acquire(acq_points)
new_table.loc[:, "acq_func"] = acq_func_meta["name"]
res = self.ask(n=n, acq_func_identifier=single_acq_func, upsample=upsample)
new_table = yield from self.acquire(res["points"])
new_table.loc[:, "acq_func"] = res["acq_func"]

x = {key: new_table.pop(key).tolist() for key in self.dofs.names}
y = {key: new_table.pop(key).tolist() for key in self.objectives.names}
Expand Down Expand Up @@ -725,8 +737,8 @@ def all_acq_funcs(self):
entries = []
for k, d in acquisition.config.items():
ret = ""
ret += f'{d["pretty_name"].upper()} (identifiers: {d["identifiers"]})\n'
ret += f'-> {d["description"]}'
ret += f"{d['pretty_name'].upper()} (identifiers: {d['identifiers']})\n"
ret += f"-> {d['description']}"
entries.append(ret)

print("\n\n".join(entries))
Expand Down
40 changes: 21 additions & 19 deletions bloptools/bayesian/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def __init__(
self,
num_inputs=1,
skew_dims=True,
diag_prior=True,
priors=True,
scale_output=True,
**kwargs,
):
Expand Down Expand Up @@ -63,21 +63,23 @@ def __init__(

self.n_skew_entries = len(self.skew_matrix_indices[0])

diag_entries_constraint = gpytorch.constraints.Positive()
raw_diag_entries_initial = (
diag_entries_constraint.inverse_transform(torch.tensor(1e-1))
lengthscale_constraint = gpytorch.constraints.Positive()
raw_lengthscale_entries_initial = (
lengthscale_constraint.inverse_transform(torch.tensor(1e-1))
* torch.ones(self.num_outputs, self.num_inputs).double()
)

self.register_parameter(name="raw_diag_entries", parameter=torch.nn.Parameter(raw_diag_entries_initial))
self.register_constraint(param_name="raw_diag_entries", constraint=diag_entries_constraint)
self.register_parameter(
name="raw_lengthscale_entries", parameter=torch.nn.Parameter(raw_lengthscale_entries_initial)
)
self.register_constraint(param_name="raw_lengthscale_entries", constraint=lengthscale_constraint)

if diag_prior:
if priors:
self.register_prior(
name="diag_entries_prior",
name="lengthscale_entries_prior",
prior=gpytorch.priors.GammaPrior(concentration=2, rate=1),
param_or_closure=lambda m: m.diag_entries,
setting_closure=lambda m, v: m._set_diag_entries(v),
param_or_closure=lambda m: m.lengthscale_entries,
setting_closure=lambda m, v: m._set_lengthscale_entries(v),
)

if self.n_skew_entries > 0:
Expand Down Expand Up @@ -105,8 +107,8 @@ def __init__(
)

@property
def diag_entries(self):
return self.raw_diag_entries_constraint.transform(self.raw_diag_entries)
def lengthscale_entries(self):
return self.raw_lengthscale_entries_constraint.transform(self.raw_lengthscale_entries)

@property
def skew_entries(self):
Expand All @@ -116,9 +118,9 @@ def skew_entries(self):
def outputscale(self):
return self.raw_outputscale_constraint.transform(self.raw_outputscale)

@diag_entries.setter
def diag_entries(self, value):
self._set_diag_entries(value)
@lengthscale_entries.setter
def lengthscale_entries(self, value):
self._set_lengthscale_entries(value)

@skew_entries.setter
def skew_entries(self, value):
Expand All @@ -128,10 +130,10 @@ def skew_entries(self, value):
def outputscale(self, value):
self._set_outputscale(value)

def _set_diag_entries(self, value):
def _set_lengthscale_entries(self, value):
if not torch.is_tensor(value):
value = torch.as_tensor(value).to(self.raw_diag_entries)
self.initialize(raw_diag_entries=self.raw_diag_entries_constraint.inverse_transform(value))
value = torch.as_tensor(value).to(self.raw_lengthscale_entries)
self.initialize(raw_lengthscale_entries=self.raw_lengthscale_entries_constraint.inverse_transform(value))

def _set_skew_entries(self, value):
if not torch.is_tensor(value):
Expand All @@ -155,7 +157,7 @@ def skew_matrix(self):
@property
def diag_matrix(self):
D = torch.zeros((self.num_outputs, self.num_inputs, self.num_inputs), dtype=torch.float64)
D[self.diag_matrix_indices] = self.diag_entries.ravel()
D[self.diag_matrix_indices] = self.lengthscale_entries.ravel() ** -1
return D

@property
Expand Down
4 changes: 2 additions & 2 deletions bloptools/bayesian/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self, train_inputs, train_targets, skew_dims=True, *args, **kwargs)
num_inputs=train_inputs.shape[-1],
num_outputs=train_targets.shape[-1],
skew_dims=skew_dims,
diag_prior=True,
priors=True,
scale=True,
**kwargs
)
Expand All @@ -31,7 +31,7 @@ def __init__(self, train_inputs, train_targets, skew_dims=True, *args, **kwargs)
num_inputs=train_inputs.shape[-1],
num_outputs=train_targets.shape[-1],
skew_dims=skew_dims,
diag_prior=True,
priors=True,
scale=True,
**kwargs
)
Expand Down
30 changes: 6 additions & 24 deletions docs/source/tutorials/himmelblau.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"from matplotlib import pyplot as plt\n",
"from bloptools.utils import functions\n",
"\n",
"x1 = x2 = np.linspace(-6, 6, 1024)\n",
"x1 = x2 = np.linspace(-6, 6, 256)\n",
"X1, X2 = np.meshgrid(x1, x2)\n",
"\n",
"F = functions.himmelblau(X1, X2)\n",
Expand Down Expand Up @@ -82,7 +82,7 @@
"id": "54b6f23e",
"metadata": {},
"source": [
"We also need to give the agent something to do. We want our agent to look in the feedback for a variable called \"himmelblau\", and try to minimize it."
"We also need to give the agent something to do. We want our agent to look in the feedback for a variable called 'himmelblau', and try to minimize it."
]
},
{
Expand All @@ -94,7 +94,7 @@
"source": [
"from bloptools.bayesian import Objective\n",
"\n",
"objectives = [Objective(name=\"himmelblau\", target=\"min\")]"
"objectives = [Objective(name=\"himmelblau\", description=\"Himmeblau's function\", target=\"min\")]"
]
},
{
Expand Down Expand Up @@ -170,24 +170,6 @@
"agent.plot_objectives()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "75a6a54f-0140-4bd0-8367-0dd14cdf8116",
"metadata": {},
"outputs": [],
"source": [
"{x % 2 for x in np.arange(10)}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad31b676-8236-4cf8-b9be-c1214d2e8458",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "dc264346-10fb-4c88-9925-4bfcf0dd3b07",
Expand Down Expand Up @@ -264,11 +246,11 @@
},
"outputs": [],
"source": [
"X, _ = agent.ask(\"qei\", n=8, route=True)\n",
"res = agent.ask(\"qei\", n=8, route=True)\n",
"agent.plot_acquisition(acq_func=\"qei\")\n",
"plt.scatter(*X.T, marker=\"d\", facecolor=\"w\", edgecolor=\"k\")\n",
"plt.scatter(*res[\"points\"].T, marker=\"d\", facecolor=\"w\", edgecolor=\"k\")\n",
"plt.plot(\n",
" *X.T,\n",
" *res[\"points\"].T,\n",
" color=\"r\",\n",
")"
]
Expand Down

0 comments on commit db2ef21

Please sign in to comment.