Skip to content

Commit

Permalink
fix merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Morris committed Nov 8, 2023
2 parents 2a91cce + 30d6710 commit 932dd12
Show file tree
Hide file tree
Showing 21 changed files with 565 additions and 299 deletions.
30 changes: 15 additions & 15 deletions bloptools/bayesian/acquisition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,35 @@
config[acq_func_name]["identifiers"].append(acq_func_name)


def parse_acq_func(acq_func_identifier):
def parse_acq_func_identifier(identifier):
acq_func_name = None
for _acq_func_name in config.keys():
if acq_func_identifier.lower() in config[_acq_func_name]["identifiers"]:
if identifier.lower() in config[_acq_func_name]["identifiers"]:
acq_func_name = _acq_func_name

if acq_func_name is None:
raise ValueError(f'Unrecognized acquisition function identifier "{acq_func_identifier}".')
raise ValueError(f'Unrecognized acquisition function identifier "{identifier}".')

return acq_func_name


def get_acquisition_function(agent, acq_func_identifier="qei", return_metadata=True, verbose=False, **acq_func_kwargs):
"""
Generates an acquisition function from a supplied identifier.
def get_acquisition_function(agent, identifier="qei", return_metadata=True, verbose=False, **acq_func_kwargs):
"""Generates an acquisition function from a supplied identifier. A list of acquisition functions and
their identifiers can be found at `agent.all_acq_funcs`.
"""

acq_func_name = parse_acq_func(acq_func_identifier)
acq_func_config = agent.acq_func_config["upper_confidence_bound"]
acq_func_name = parse_acq_func_identifier(identifier)
acq_func_config = config["upper_confidence_bound"]

if agent.acq_func_config[acq_func_name]["multitask_only"] and (agent.num_tasks == 1):
if config[acq_func_name]["multitask_only"] and (agent.num_tasks == 1):
raise ValueError(f'Acquisition function "{acq_func_name}" is only for multi-task optimization problems!')

# there is probably a better way to structure this
if acq_func_name == "expected_improvement":
acq_func = analytic.ConstrainedLogExpectedImprovement(
constraint=agent.constraint,
model=agent.model,
best_f=agent.best_scalarized_objective,
best_f=agent.max_scalarized_objective,
posterior_transform=ScalarizedPosteriorTransform(weights=agent.objective_weights_torch, offset=0),
)
acq_func_meta = {"name": acq_func_name, "args": {}}
Expand All @@ -55,7 +55,7 @@ def get_acquisition_function(agent, acq_func_identifier="qei", return_metadata=T
acq_func = monte_carlo.qConstrainedExpectedImprovement(
constraint=agent.constraint,
model=agent.model,
best_f=agent.best_scalarized_objective,
best_f=agent.max_scalarized_objective,
posterior_transform=ScalarizedPosteriorTransform(weights=agent.objective_weights_torch, offset=0),
)
acq_func_meta = {"name": acq_func_name, "args": {}}
Expand All @@ -64,7 +64,7 @@ def get_acquisition_function(agent, acq_func_identifier="qei", return_metadata=T
acq_func = analytic.ConstrainedLogProbabilityOfImprovement(
constraint=agent.constraint,
model=agent.model,
best_f=agent.best_scalarized_objective,
best_f=agent.max_scalarized_objective,
posterior_transform=ScalarizedPosteriorTransform(weights=agent.objective_weights_torch, offset=0),
)
acq_func_meta = {"name": acq_func_name, "args": {}}
Expand All @@ -73,7 +73,7 @@ def get_acquisition_function(agent, acq_func_identifier="qei", return_metadata=T
acq_func = monte_carlo.qConstrainedProbabilityOfImprovement(
constraint=agent.constraint,
model=agent.model,
best_f=agent.best_scalarized_objective,
best_f=agent.max_scalarized_objective,
posterior_transform=ScalarizedPosteriorTransform(weights=agent.objective_weights_torch, offset=0),
)
acq_func_meta = {"name": acq_func_name, "args": {}}
Expand Down Expand Up @@ -119,11 +119,11 @@ def get_acquisition_function(agent, acq_func_identifier="qei", return_metadata=T
acq_func_meta = {"name": acq_func_name, "args": {"beta": beta}}

elif acq_func_name == "expected_mean":
acq_func = get_acquisition_function(agent, acq_func_identifier="ucb", beta=0, return_metadata=False)
acq_func = get_acquisition_function(agent, identifier="ucb", beta=0, return_metadata=False)
acq_func_meta = {"name": acq_func_name, "args": {}}

elif acq_func_name == "monte_carlo_expected_mean":
acq_func = get_acquisition_function(agent, acq_func_identifier="qucb", beta=0, return_metadata=False)
acq_func = get_acquisition_function(agent, identifier="qucb", beta=0, return_metadata=False)
acq_func_meta = {"name": acq_func_name, "args": {}}

return (acq_func, acq_func_meta) if return_metadata else acq_func
43 changes: 37 additions & 6 deletions bloptools/bayesian/acquisition/analytic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@


class ConstrainedUpperConfidenceBound(UpperConfidenceBound):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Upper confidence bound, but scaled by some constraint.
NOTE: Because the UCB can be negative, we constrain it by adjusting the Gaussian quantile.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
Expand All @@ -26,17 +37,37 @@ def forward(self, x):


class ConstrainedLogExpectedImprovement(LogExpectedImprovement):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Log expected improvement, but scaled by some constraint.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
return (super().forward(x) + self.constraint(x).log().squeeze(-1)).exp()


class ConstrainedLogProbabilityOfImprovement(LogProbabilityOfImprovement):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Log probability of improvement acquisition function, but scaled by some constraint.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
Expand Down
2 changes: 1 addition & 1 deletion bloptools/bayesian/acquisition/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ monte_carlo_probability_of_improvement:
type: monte_carlo

random:
description: A uniform random sampel of the parameters.
description: Uniformly-sampled random points.
identifiers:
- r
multitask_only: false
Expand Down
72 changes: 62 additions & 10 deletions bloptools/bayesian/acquisition/monte_carlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@


class qConstrainedUpperConfidenceBound(qUpperConfidenceBound):
def __init__(self, constraint, beta=4, *args, **kwargs):
super().__init__(beta=beta, *args, **kwargs)
"""Monte Carlo expected improvement, but scaled by some constraint.
NOTE: Because the UCB can be negative, we constrain it by adjusting the Gaussian quantile.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, constraint, beta=4, **kwargs):
super().__init__(beta=beta, **kwargs)
self.constraint = constraint
self.beta = torch.tensor(beta)

Expand All @@ -30,35 +41,76 @@ def forward(self, x):


class qConstrainedExpectedImprovement(qExpectedImprovement):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Monte Carlo expected improvement, but scaled by some constraint.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
return super().forward(x) * self.constraint(x).squeeze(-1)


class qConstrainedProbabilityOfImprovement(qProbabilityOfImprovement):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Monte Carlo probability of improvement, but scaled by some constraint.
Parameters
----------
model:
A BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
return super().forward(x) * self.constraint(x).squeeze(-1)


class qConstrainedNoisyExpectedHypervolumeImprovement(qNoisyExpectedHypervolumeImprovement):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""Monte Carlo noisy expected hypervolume improvement, but scaled by some constraint.
Only works with multi-objective models.
Parameters
----------
model:
A multi-objective BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
return super().forward(x) * self.constraint(x).squeeze(-1)


class qConstrainedLowerBoundMaxValueEntropy(qLowerBoundMaxValueEntropy):
def __init__(self, constraint, *args, **kwargs):
super().__init__(*args, **kwargs)
"""GIBBON (General-purpose Information-Based Bayesian OptimisatioN), but scaled by some constraint.
Parameters
----------
model:
A multi-objective BoTorch model over which to compute the acquisition function.
constraint:
A callable which when evaluated on inputs returns the probability of feasibility.
"""

def __init__(self, model, constraint, **kwargs):
super().__init__(model=model, **kwargs)
self.constraint = constraint

def forward(self, x):
Expand Down
Loading

0 comments on commit 932dd12

Please sign in to comment.