Skip to content

Commit cb93c5d

Browse files
saitcakmakfacebook-github-bot
authored andcommitted
Clean up float32 defaults in Sobol utils & test functions (#2346)
Summary: Pull Request resolved: #2346 We recommend using double/float64 in BoTorch but seem to default to float32 in some Sobol utilities and test function code. I searched through the code base and updated float32 defaults in a few ways: - Either removed them and left them to use whatever default torch sees fit. - Set them to `torch.get_default_dtype`, to explicitly match the dtype used by torch. - Updated them to use the dtype of another tensor from the same class. Some added `dtype=torch.get_default_dtype()` is unnecessarily verbose, as torch will default to it whenever the input is `List[Union[int, float]]` or `List[float]` -- but it will default to `torch.long` if the input is `List[int]`. I think being verbose here helps avoid confusion. Found while investigating #2264. Also made some minor updates in these files to make pyre happier (or less upset, whichever fits). Reviewed By: Balandat Differential Revision: D57473132 fbshipit-source-id: cf98b792f8f34abf20d8e4b7bbf714fdc73b764e
1 parent 425b1db commit cb93c5d

File tree

7 files changed

+142
-130
lines changed

7 files changed

+142
-130
lines changed

botorch/sampling/qmc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ def __init__(
5858
self._sobol_engine = SobolEngine(dimension=sobol_dim, scramble=True, seed=seed)
5959

6060
def draw(
61-
self, n: int = 1, out: Optional[Tensor] = None, dtype: torch.dtype = torch.float
61+
self,
62+
n: int = 1,
63+
out: Optional[Tensor] = None,
64+
dtype: Optional[torch.dtype] = None,
6265
) -> Optional[Tensor]:
6366
r"""Draw `n` qMC samples from the standard Normal.
6467
@@ -67,10 +70,12 @@ def draw(
6770
out: An option output tensor. If provided, draws are put into this
6871
tensor, and the function returns None.
6972
dtype: The desired torch data type (ignored if `out` is provided).
73+
If None, uses `torch.get_default_dtype()`.
7074
7175
Returns:
7276
A `n x d` tensor of samples if `out=None` and `None` otherwise.
7377
"""
78+
dtype = torch.get_default_dtype() if dtype is None else dtype
7479
# get base samples
7580
samples = self._sobol_engine.draw(n, dtype=dtype)
7681
if self._inv_transform:

botorch/test_functions/base.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
from __future__ import annotations
1212

1313
from abc import ABC, abstractmethod
14-
from typing import List, Tuple, Union
14+
from typing import List, Optional, Tuple, Union
1515

1616
import torch
17-
1817
from botorch.exceptions.errors import InputDataError
1918
from torch import Tensor
2019
from torch.nn import Module
@@ -146,16 +145,16 @@ def evaluate_slack_true(self, X: Tensor) -> Tensor:
146145
pass # pragma: no cover
147146

148147

149-
class MultiObjectiveTestProblem(BaseTestProblem):
150-
r"""Base class for test multi-objective test functions.
148+
class MultiObjectiveTestProblem(BaseTestProblem, ABC):
149+
r"""Base class for multi-objective test functions.
151150
152151
TODO: add a pareto distance function that returns the distance
153152
between a provided point and the closest point on the true pareto front.
154153
"""
155154

156155
num_objectives: int
157156
_ref_point: List[float]
158-
_max_hv: float
157+
_max_hv: Optional[float] = None
159158

160159
def __init__(
161160
self,
@@ -176,16 +175,16 @@ def __init__(
176175
f"must match the number of objectives ({len(self._ref_point)})"
177176
)
178177
super().__init__(noise_std=noise_std, negate=negate)
179-
ref_point = torch.tensor(self._ref_point, dtype=torch.float)
178+
ref_point = torch.tensor(self._ref_point, dtype=torch.get_default_dtype())
180179
if negate:
181180
ref_point *= -1
182181
self.register_buffer("ref_point", ref_point)
183182

184183
@property
185184
def max_hv(self) -> float:
186-
try:
185+
if self._max_hv is not None:
187186
return self._max_hv
188-
except AttributeError:
187+
else:
189188
raise NotImplementedError(
190189
f"Problem {self.__class__.__name__} does not specify maximal "
191190
"hypervolume."

botorch/test_functions/multi_fidelity.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ class AugmentedBranin(SyntheticTestFunction):
4646
def evaluate_true(self, X: Tensor) -> Tensor:
4747
t1 = (
4848
X[..., 1]
49-
- (5.1 / (4 * math.pi**2) - 0.1 * (1 - X[:, 2])) * X[:, 0] ** 2
49+
- (5.1 / (4 * math.pi**2) - 0.1 * (1 - X[:, 2])) * X[:, 0].pow(2)
5050
+ 5 / math.pi * X[..., 0]
5151
- 6
5252
)
5353
t2 = 10 * (1 - 1 / (8 * math.pi)) * torch.cos(X[..., 0])
54-
return t1**2 + t2 + 10
54+
return t1.pow(2) + t2 + 10
5555

5656

5757
class AugmentedHartmann(SyntheticTestFunction):
@@ -93,15 +93,15 @@ def __init__(self, noise_std: Optional[float] = None, negate: bool = False) -> N
9393
[1312, 1696, 5569, 124, 8283, 5886],
9494
[2329, 4135, 8307, 3736, 1004, 9991],
9595
[2348, 1451, 3522, 2883, 3047, 6650],
96-
[4047, 8828, 8732, 5743, 1091, 381],
96+
[4047, 8828, 8732, 5743, 1091, 381.0],
9797
]
98-
self.register_buffer("A", torch.tensor(A, dtype=torch.float))
99-
self.register_buffer("P", torch.tensor(P, dtype=torch.float))
98+
self.register_buffer("A", torch.tensor(A))
99+
self.register_buffer("P", torch.tensor(P))
100100

101101
def evaluate_true(self, X: Tensor) -> Tensor:
102102
self.to(device=X.device, dtype=X.dtype)
103103
inner_sum = torch.sum(
104-
self.A * (X[..., :6].unsqueeze(-2) - 0.0001 * self.P) ** 2, dim=-1
104+
self.A * (X[..., :6].unsqueeze(-2) - 0.0001 * self.P).pow(2), dim=-1
105105
)
106106
alpha1 = self.ALPHA[0] - 0.1 * (1 - X[..., 6])
107107
H = (
@@ -147,6 +147,6 @@ def __init__(
147147
def evaluate_true(self, X: Tensor) -> Tensor:
148148
X_curr = X[..., :-3]
149149
X_next = X[..., 1:-2]
150-
t1 = 100 * (X_next - X_curr**2 + 0.1 * (1 - X[..., -2:-1])) ** 2
151-
t2 = (X_curr - 1 + 0.1 * (1 - X[..., -1:]) ** 2) ** 2
150+
t1 = 100 * (X_next - X_curr.pow(2) + 0.1 * (1 - X[..., -2:-1])).pow(2)
151+
t2 = (X_curr - 1 + 0.1 * (1 - X[..., -1:]).pow(2)).pow(2)
152152
return -((t1 + t2).sum(dim=-1))

botorch/test_functions/multi_objective.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
import math
7777
from abc import ABC, abstractmethod
7878
from math import pi
79-
from typing import List, Union
79+
from typing import List, Tuple, Union
8080

8181
import torch
8282
from botorch.exceptions.errors import UnsupportedError
@@ -170,7 +170,7 @@ class DH(MultiObjectiveTestProblem, ABC):
170170
"""
171171

172172
num_objectives = 2
173-
_ref_point: float = [1.1, 1.1]
173+
_ref_point: List[float] = [1.1, 1.1]
174174
_x_1_lb: float
175175
_area_under_curve: float
176176
_min_dim: int
@@ -286,7 +286,7 @@ class DH3(DH):
286286
_min_dim = 3
287287

288288
@staticmethod
289-
def _exp_args(x: Tensor) -> Tensor:
289+
def _exp_args(x: Tensor) -> Tuple[Tensor, Tensor]:
290290
exp_arg_1 = -((x - 0.35) / 0.25).pow(2)
291291
exp_arg_2 = -((x - 0.85) / 0.03).pow(2)
292292
return exp_arg_1, exp_arg_2
@@ -1078,7 +1078,7 @@ def gen_pareto_front(self, n: int) -> Tensor:
10781078
torch.linspace(
10791079
left + self._eps,
10801080
right - self._eps,
1081-
n_per_part[i],
1081+
int(n_per_part[i]),
10821082
dtype=self.bounds.dtype,
10831083
device=self.bounds.device,
10841084
)
@@ -1195,12 +1195,12 @@ class BNH(MultiObjectiveTestProblem, ConstrainedBaseTestProblem):
11951195

11961196
def evaluate_true(self, X: Tensor) -> Tensor:
11971197
return torch.stack(
1198-
[4.0 * (X**2).sum(dim=-1), ((X - 5.0) ** 2).sum(dim=-1)], dim=-1
1198+
[4.0 * X.pow(2).sum(dim=-1), (X - 5.0).pow(2).sum(dim=-1)], dim=-1
11991199
)
12001200

12011201
def evaluate_slack_true(self, X: Tensor) -> Tensor:
1202-
c1 = 25.0 - (X[..., 0] - 5.0) ** 2 - X[..., 1] ** 2
1203-
c2 = (X[..., 0] - 8.0) ** 2 + (X[..., 1] + 3.0) ** 2 - 7.7
1202+
c1 = 25.0 - (X[..., 0] - 5.0).pow(2) - X[..., 1].pow(2)
1203+
c2 = (X[..., 0] - 8.0).pow(2) + (X[..., 1] + 3.0).pow(2) - 7.7
12041204
return torch.stack([c1, c2], dim=-1)
12051205

12061206

@@ -1256,7 +1256,9 @@ def __init__(
12561256
negate: If True, negate the function.
12571257
"""
12581258
super().__init__(noise_std=noise_std, negate=negate)
1259-
con_bounds = torch.tensor(self._con_bounds, dtype=torch.float).transpose(-1, -2)
1259+
con_bounds = torch.tensor(self._con_bounds, dtype=self.bounds.dtype).transpose(
1260+
-1, -2
1261+
)
12601262
self.register_buffer("con_bounds", con_bounds)
12611263
self.constraint_noise_std = constraint_noise_std
12621264

@@ -1373,7 +1375,7 @@ def __init__(
13731375
super().__init__(noise_std=noise_std, negate=negate)
13741376
self.constraint_noise_std = constraint_noise_std
13751377

1376-
def LA2(self, A, B, C, D, theta):
1378+
def LA2(self, A, B, C, D, theta) -> Tensor:
13771379
return A * torch.sin(B * theta.pow(C)).pow(D)
13781380

13791381
def evaluate_true(self, X: Tensor) -> Tensor:
@@ -1420,22 +1422,22 @@ class OSY(MultiObjectiveTestProblem, ConstrainedBaseTestProblem):
14201422

14211423
def evaluate_true(self, X: Tensor) -> Tensor:
14221424
f1 = -(
1423-
25 * (X[..., 0] - 2) ** 2
1424-
+ (X[..., 1] - 2) ** 2
1425-
+ (X[..., 2] - 1) ** 2
1426-
+ (X[..., 3] - 4) ** 2
1427-
+ (X[..., 4] - 1) ** 2
1425+
25 * (X[..., 0] - 2).pow(2)
1426+
+ (X[..., 1] - 2).pow(2)
1427+
+ (X[..., 2] - 1).pow(2)
1428+
+ (X[..., 3] - 4).pow(2)
1429+
+ (X[..., 4] - 1).pow(2)
14281430
)
1429-
f2 = (X**2).sum(-1)
1431+
f2 = X.pow(2).sum(-1)
14301432
return torch.stack([f1, f2], dim=-1)
14311433

14321434
def evaluate_slack_true(self, X: Tensor) -> Tensor:
14331435
g1 = X[..., 0] + X[..., 1] - 2.0
14341436
g2 = 6.0 - X[..., 0] - X[..., 1]
14351437
g3 = 2.0 - X[..., 1] + X[..., 0]
14361438
g4 = 2.0 - X[..., 0] + 3.0 * X[..., 1]
1437-
g5 = 4.0 - (X[..., 2] - 3.0) ** 2 - X[..., 3]
1438-
g6 = (X[..., 4] - 3.0) ** 2 + X[..., 5] - 4.0
1439+
g5 = 4.0 - (X[..., 2] - 3.0).pow(2) - X[..., 3]
1440+
g6 = (X[..., 4] - 3.0).pow(2) + X[..., 5] - 4.0
14391441
return torch.stack([g1, g2, g3, g4, g5, g6], dim=-1)
14401442

14411443

@@ -1453,12 +1455,12 @@ class SRN(MultiObjectiveTestProblem, ConstrainedBaseTestProblem):
14531455
_ref_point = [0.0, 0.0] # TODO: Determine proper reference point
14541456

14551457
def evaluate_true(self, X: Tensor) -> Tensor:
1456-
obj1 = 2.0 + ((X - 2.0) ** 2).sum(dim=-1)
1457-
obj2 = 9.0 * X[..., 0] - (X[..., 1] - 1.0) ** 2
1458+
obj1 = 2.0 + (X - 2.0).pow(2).sum(dim=-1)
1459+
obj2 = 9.0 * X[..., 0] - (X[..., 1] - 1.0).pow(2)
14581460
return torch.stack([obj1, obj2], dim=-1)
14591461

14601462
def evaluate_slack_true(self, X: Tensor) -> Tensor:
1461-
c1 = 225.0 - ((X**2) ** 2).sum(dim=-1)
1463+
c1 = 225.0 - (X.pow(2)).pow(2).sum(dim=-1)
14621464
c2 = -10.0 - X[..., 0] + 3 * X[..., 1]
14631465
return torch.stack([c1, c2], dim=-1)
14641466

@@ -1490,8 +1492,8 @@ def evaluate_true(self, X: Tensor) -> Tensor:
14901492
# different numbers (see below).
14911493
# f1 = WeldedBeam.evaluate_true(self, X)
14921494
x1, x2, x3, x4 = X.unbind(-1)
1493-
f1 = 1.10471 * (x1**2) * x2 + 0.04811 * x3 * x4 * (14.0 + x2)
1494-
f2 = 2.1952 / (x4 * x3**3)
1495+
f1 = 1.10471 * x1.pow(2) * x2 + 0.04811 * x3 * x4 * (14.0 + x2)
1496+
f2 = 2.1952 / (x4 * x3.pow(3))
14951497
return torch.stack([f1, f2], dim=-1)
14961498

14971499
def evaluate_slack_true(self, X: Tensor) -> Tensor:
@@ -1509,17 +1511,17 @@ def evaluate_slack_true(self, X: Tensor) -> Tensor:
15091511
# g3 = 1 / (5 - 0.125) * g3_
15101512
# g4 = 1 / P * g6_
15111513

1512-
R = torch.sqrt(0.25 * (x2**2 + (x1 + x3) ** 2))
1514+
R = torch.sqrt(0.25 * (x2.pow(2) + (x1 + x3).pow(2)))
15131515
M = P * (L + x2 / 2)
15141516
# This `J` is different than the one in [CoelloCoello2002constraint]_
15151517
# by a factor of 2 (sqrt(2) instead of sqrt(0.5))
1516-
J = 2 * math.sqrt(0.5) * x1 * x2 * (x2**2 / 12 + 0.25 * (x1 + x3) ** 2)
1518+
J = 2 * math.sqrt(0.5) * x1 * x2 * (x2.pow(2) / 12 + 0.25 * (x1 + x3).pow(2))
15171519
t1 = P / (math.sqrt(2) * x1 * x2)
15181520
t2 = M * R / J
1519-
t = torch.sqrt(t1**2 + t1 * t2 * x2 / R + t2**2)
1520-
s = 6 * P * L / (x4 * x3**2)
1521+
t = torch.sqrt(t1.pow(2) + t1 * t2 * x2 / R + t2.pow(2))
1522+
s = 6 * P * L / (x4 * x3.pow(2))
15211523
# These numbers are also different from [CoelloCoello2002constraint]_
1522-
P_c = 64746.022 * (1 - 0.0282346 * x3) * x3 * x4**3
1524+
P_c = 64746.022 * (1 - 0.0282346 * x3) * x3 * x4.pow(3)
15231525

15241526
g1 = (t - t_max) / t_max
15251527
g2 = (s - s_max) / s_max

0 commit comments

Comments
 (0)