From 90997dba35cde7a3587fde33cccf1c11cd77adc6 Mon Sep 17 00:00:00 2001 From: Sam Daulton Date: Thu, 5 Jan 2023 12:13:46 -0800 Subject: [PATCH] fix chebyshev scalariztaion Summary: See https://github.com/pytorch/botorch/issues/1614 Differential Revision: D42373368 fbshipit-source-id: 0a1417d8865c943851430866df4f9369d0e21bf0 --- botorch/utils/multi_objective/scalarization.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/botorch/utils/multi_objective/scalarization.py b/botorch/utils/multi_objective/scalarization.py index 9ca69ebf9f..c2f92d7287 100644 --- a/botorch/utils/multi_objective/scalarization.py +++ b/botorch/utils/multi_objective/scalarization.py @@ -32,13 +32,15 @@ def get_chebyshev_scalarization( Augmented Chebyshev scalarization: objective(y) = min(w * y) + alpha * sum(w * y) - Outcomes are first normalized to [0,1] for maximization (or [-1,0] for minimization) + Outcomes are multiplied by -1, then normalized to [0,1] for maximization (or [-1,0] for minimization) and then an augmented Chebyshev scalarization is applied. + Since typically the augmented chebyshev scalarization is minimized, we multiply the resulting quantity by -1. + Note: this assumes maximization of the augmented Chebyshev scalarization. Minimizing/Maximizing an objective is supported by passing a negative/positive weight for that objective. To make all w * y's have positive sign - such that they are comparable when computing min(w * y), outcomes of minimization + such that they are comparable when computing max(w * y), outcomes of minimization objectives are shifted from [0,1] to [-1,0]. See [Knowles2005]_ for details. @@ -61,6 +63,7 @@ def get_chebyshev_scalarization( >>> weights = torch.tensor([0.75, -0.25]) >>> transform = get_aug_chebyshev_scalarization(weights, Y) """ + Y = -Y if weights.shape != Y.shape[-1:]: raise BotorchTensorDimensionError( "weights must be an `m`-dim tensor where Y is `... x m`." @@ -71,7 +74,7 @@ def get_chebyshev_scalarization( def chebyshev_obj(Y: Tensor, X: Optional[Tensor] = None) -> Tensor: product = weights * Y - return product.min(dim=-1).values + alpha * product.sum(dim=-1) + return product.max(dim=-1).values + alpha * product.sum(dim=-1) if Y.shape[-2] == 0: # If there are no observations, we do not need to normalize the objectives @@ -90,10 +93,10 @@ def chebyshev_obj(Y: Tensor, X: Optional[Tensor] = None) -> Tensor: def obj(Y: Tensor, X: Optional[Tensor] = None) -> Tensor: # scale to [0,1] - Y_normalized = normalize(Y, bounds=Y_bounds) + Y_normalized = normalize(-Y, bounds=Y_bounds) # If minimizing an objective, convert Y_normalized values to [-1,0], # such that min(w*y) makes sense, we want all w*y's to be positive Y_normalized[..., minimize] = Y_normalized[..., minimize] - 1 - return chebyshev_obj(Y=Y_normalized) + return -chebyshev_obj(Y=Y_normalized) return obj