Skip to content

Commit

Permalink
Migrate tensor to ndarray in searchspace
Browse files Browse the repository at this point in the history
  • Loading branch information
rjavadi committed Feb 27, 2024
1 parent 35a23f4 commit c16cc57
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
module
- `strategy` keyword of `Campaign` renamed to `recommender`
- `NaiveHybridRecommender` renamed to `NaiveHybridSpaceRecommender`
- `SearchSpace`s now use `ndarray` instead of `Tensor`

### Fixed
- Unhandled exception in telemetry when username could not be inferred on Windows
Expand Down
8 changes: 6 additions & 2 deletions baybe/recommenders/pure/bayesian/sequential_greedy.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ def _recommend_continuous(
batch_size: int,
) -> pd.DataFrame:
# See base class.
import torch

try:
points, _ = optimize_acqf(
acq_function=self._acquisition_function,
bounds=subspace_continuous.param_bounds_comp,
bounds=torch.from_numpy(subspace_continuous.param_bounds_comp),
q=batch_size,
num_restarts=5, # TODO make choice for num_restarts
raw_samples=10, # TODO make choice for raw_samples
Expand Down Expand Up @@ -162,6 +163,8 @@ def _recommend_hybrid(
NoMCAcquisitionFunctionError: If a non Monte Carlo acquisition function
is chosen.
"""
import torch

if len(candidates_comp) > 0:
# Calculate the number of samples from the given percentage
n_candidates = int(self.sampling_percentage * len(candidates_comp.index))
Expand All @@ -186,9 +189,10 @@ def _recommend_hybrid(

# Actual call of the BoTorch optimization routine
try:
# TODO Roya convert
points, _ = optimize_acqf_mixed(
acq_function=self._acquisition_function,
bounds=searchspace.param_bounds_comp,
bounds=torch.from_numpy(searchspace.param_bounds_comp),
q=batch_size,
num_restarts=5, # TODO make choice for num_restarts
raw_samples=10, # TODO make choice for raw_samples
Expand Down
15 changes: 7 additions & 8 deletions baybe/searchspace/continuous.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import numpy as np
import pandas as pd
import torch
from attr import define, field

from baybe.constraints import (
Expand All @@ -18,7 +17,7 @@
from baybe.searchspace.validation import validate_parameter_names
from baybe.serialization import SerialMixin, converter, select_constructor_hook
from baybe.utils.dataframe import pretty_print_df
from baybe.utils.numerical import DTypeFloatTorch
from baybe.utils.numerical import DTypeFloatNumpy


@define
Expand Down Expand Up @@ -145,11 +144,11 @@ def param_names(self) -> List[str]:
return [p.name for p in self.parameters]

@property
def param_bounds_comp(self) -> torch.Tensor:
"""Return bounds as tensor."""
def param_bounds_comp(self) -> np.ndarray:
"""Return bounds as numpy array."""
if not self.parameters:
return torch.empty(2, 0, dtype=DTypeFloatTorch)
return torch.stack([p.bounds.to_tensor() for p in self.parameters]).T
return np.empty((2, 0), dtype=DTypeFloatNumpy)
return np.stack([p.bounds.to_ndarray() for p in self.parameters]).T

def transform(
self,
Expand Down Expand Up @@ -180,12 +179,12 @@ def samples_random(self, n_points: int = 1) -> pd.DataFrame:
"""
if not self.parameters:
return pd.DataFrame()

import torch
from botorch.utils.sampling import get_polytope_samples

points = get_polytope_samples(
n=n_points,
bounds=self.param_bounds_comp,
bounds=torch.from_numpy(self.param_bounds_comp),
equality_constraints=[
c.to_botorch(self.parameters) for c in self.constraints_lin_eq
],
Expand Down
6 changes: 3 additions & 3 deletions baybe/searchspace/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from enum import Enum
from typing import List, Optional, cast

import numpy as np
import pandas as pd
import torch
from attr import define, field

from baybe.constraints import (
Expand Down Expand Up @@ -232,9 +232,9 @@ def contains_rdkit(self) -> bool:
)

@property
def param_bounds_comp(self) -> torch.Tensor:
def param_bounds_comp(self) -> np.ndarray:
"""Return bounds as tensor."""
return torch.hstack(
return np.hstack(
[self.discrete.param_bounds_comp, self.continuous.param_bounds_comp]
)

Expand Down
7 changes: 3 additions & 4 deletions baybe/searchspace/discrete.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import numpy as np
import pandas as pd
import torch
from attr import define, field
from cattrs import IterableValidationError

Expand Down Expand Up @@ -467,14 +466,14 @@ def is_empty(self) -> bool:
return len(self.parameters) == 0

@property
def param_bounds_comp(self) -> torch.Tensor:
def param_bounds_comp(self) -> np.ndarray:
"""Return bounds as tensor.
Take bounds from the parameter definitions, but discards bounds belonging to
columns that were filtered out during the creation of the space.
"""
if not self.parameters:
return torch.empty(2, 0)
return np.empty((2, 0))
bounds = np.hstack(
[
np.vstack([p.comp_df[col].min(), p.comp_df[col].max()])
Expand All @@ -483,7 +482,7 @@ def param_bounds_comp(self) -> torch.Tensor:
if col in self.comp_rep.columns
]
)
return torch.from_numpy(bounds)
return bounds

def mark_as_measured(
self,
Expand Down
2 changes: 1 addition & 1 deletion baybe/surrogates/gaussian_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _fit(self, searchspace: SearchSpace, train_x: Tensor, train_y: Tensor) -> No
numeric_idxs = [i for i in range(train_x.shape[1]) if i != task_idx]

# get the input bounds from the search space in BoTorch Format
bounds = searchspace.param_bounds_comp
bounds = torch.from_numpy(searchspace.param_bounds_comp)
# TODO: use target value bounds when explicitly provided

# define the input and outcome transforms
Expand Down
4 changes: 2 additions & 2 deletions tests/test_continuous.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test for continuous parameters."""
import numpy as np
import pytest
import torch


@pytest.mark.parametrize(
Expand All @@ -16,6 +16,6 @@ def test_valid_configs(campaign):
print(campaign.searchspace.continuous.param_bounds_comp.flatten())

assert all(
torch.is_floating_point(itm)
np.issubdtype(type(itm), np.floating)
for itm in campaign.searchspace.continuous.param_bounds_comp.flatten()
)
12 changes: 6 additions & 6 deletions tests/test_searchspace.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for the searchspace module."""
import numpy as np
import pandas as pd
import pytest
import torch

from baybe.constraints import (
ContinuousLinearEqualityConstraint,
Expand Down Expand Up @@ -41,8 +41,8 @@ def test_bounds_order():
NumericalContinuousParameter(name="B_cont", bounds=(10.0, 12.0)),
]
searchspace = SearchSpace.from_product(parameters=parameters)
expected = torch.tensor([[1.0, 7.0, 4.0, 10.0], [3.0, 9.0, 6.0, 12.0]]).double()
assert torch.equal(
expected = np.array([[1.0, 7.0, 4.0, 10.0], [3.0, 9.0, 6.0, 12.0]])
assert np.array_equal(
searchspace.param_bounds_comp,
expected,
)
Expand All @@ -56,9 +56,9 @@ def test_empty_parameter_bounds():
parameters = []
searchspace_discrete = SubspaceDiscrete.from_product(parameters=parameters)
searchspace_continuous = SubspaceContinuous(parameters=parameters)
expected = torch.empty(2, 0)
assert torch.equal(searchspace_discrete.param_bounds_comp, expected)
assert torch.equal(searchspace_continuous.param_bounds_comp, expected)
expected = np.empty((2, 0))
assert np.array_equal(searchspace_discrete.param_bounds_comp, expected)
assert np.array_equal(searchspace_continuous.param_bounds_comp, expected)


def test_discrete_searchspace_creation_from_dataframe():
Expand Down

0 comments on commit c16cc57

Please sign in to comment.