Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove BoTorch Workaround (old) #88

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
AdrianSosic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# NOTES:
Scienfitz marked this conversation as resolved.
Show resolved Hide resolved
# - The map syntax used for matrix is flagged red but actually works
# - This runs everything in Python 3.11, except the fulltest which is also run in 3.8
# - This runs everything in Python 3.11, except the fulltest which is also run in 3.9
# - Only coretest and fulltest environments are cached due to space limit

name: Continuous Integration
Expand Down Expand Up @@ -114,7 +114,7 @@ jobs:
needs: [typecheck, audit]
strategy:
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'} ]
py-version: [ {semantic: '3.11', tox: 'py311'} ]
name: Core Tests ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand All @@ -136,7 +136,7 @@ jobs:
needs: [typecheck, audit]
strategy:
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.11', tox: 'py311'} ]
name: Full Tests ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/regular.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# NOTES:
# - The map syntax used for matrix is flagged red but actually works
# - This runs everything in Python 3.8, 3.9, 3.10 and 3.11
# - This runs everything in Python 3.9, 3.10 and 3.11
# - No environments are cached due to space limit

name: Regular Checks
Expand Down Expand Up @@ -40,7 +40,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
name: Lint ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand All @@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
name: Type Check ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand All @@ -78,7 +78,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
name: Audit ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand All @@ -97,7 +97,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
name: Core Tests ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand All @@ -120,7 +120,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py-version: [ {semantic: '3.8', tox: 'py38'}, {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
py-version: [ {semantic: '3.9', tox: 'py39'}, {semantic: '3.10', tox: 'py310'}, {semantic: '3.11', tox: 'py311'} ]
name: Full Tests ${{ matrix.py-version.semantic }}
runs-on: ubuntu-latest
steps:
Expand Down
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ build

# Testing
.tox
.coverage
.coverage.*
.hypothesis/
.coverage*
.hypothesis
.pytest_cache
.mypy_cache
.ruff_cache
htmlcov

# Pictures created by backtesting
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- BoTorch dependency bumped to `>=0.9.3`

### Removed
- Workaround for BoTorch hybrid recommender data type
- Support for Python 3.8

## [0.7.2] - 2024-01-24
### Added
- Target enums
Expand Down Expand Up @@ -46,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Specifying target configs without explicit type information is deprecated
- Specifying parameters/constraints at the top level of a campaign configuration JSON is
deprecated. Instead, an explicit `searchspace` field must be provided with an optional
`constructor` entry.
`constructor` entry

## [0.7.1] - 2023-12-07
### Added
Expand Down
46 changes: 16 additions & 30 deletions baybe/recommenders/bayesian.py
AdrianSosic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from functools import partial
from typing import Any, Callable, ClassVar, Literal, Optional

import numpy as np
import pandas as pd
from attrs import define, field, validators
from botorch.acquisition import (
Expand All @@ -18,7 +17,6 @@
qUpperConfidenceBound,
)
from botorch.optim import optimize_acqf, optimize_acqf_discrete, optimize_acqf_mixed
from sklearn.metrics import pairwise_distances_argmin

from baybe.acquisition import PartialAcquisitionFunction, debotorchize
from baybe.exceptions import NoMCAcquisitionFunctionError
Expand Down Expand Up @@ -295,7 +293,6 @@ def _recommend_discrete(
on=list(candidates_comp),
)["index"]
)
assert len(points) == len(idxs)

return idxs

Expand Down Expand Up @@ -382,7 +379,8 @@ def _recommend_hybrid(
# format expected by BoTorch
# TODO: Currently assumes that discrete parameters are first and continuous
# second. Once parameter redesign [11611] is completed, we might adjust this.
candidates_comp.columns = list(range(len(candidates_comp.columns)))
num_comp_columns = len(candidates_comp.columns)
candidates_comp.columns = list(range(num_comp_columns))
fixed_features_list = candidates_comp.to_dict("records")

# Actual call of the BoTorch optimization routine
Expand All @@ -397,15 +395,15 @@ def _recommend_hybrid(
equality_constraints=[
c.to_botorch(
searchspace.continuous.parameters,
idx_offset=len(candidates_comp.columns),
idx_offset=num_comp_columns,
)
for c in searchspace.continuous.constraints_lin_eq
]
or None, # TODO: https://github.com/pytorch/botorch/issues/2042
inequality_constraints=[
c.to_botorch(
searchspace.continuous.parameters,
idx_offset=len(candidates_comp.columns),
idx_offset=num_comp_columns,
)
for c in searchspace.continuous.constraints_lin_ineq
]
Expand All @@ -417,40 +415,28 @@ def _recommend_hybrid(
f"acquisition functions."
) from ex

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
AdrianSosic marked this conversation as resolved.
Show resolved Hide resolved
# TODO [14819]: The following code is necessary due to floating point
# inaccuracies introduced by BoTorch (potentially due to some float32
# conversion?). The current workaround is the match the recommendations back
# to the closest candidate points.

# Split discrete and continuous parts
disc_points = points[:, : len(candidates_comp.columns)]
cont_points = points[:, len(candidates_comp.columns) :]

# Find the closest match with the discrete candidates
candidates_comp_np = candidates_comp.to_numpy()
disc_points_np = disc_points.numpy()
if not disc_points_np.flags["C_CONTIGUOUS"]:
disc_points_np = np.ascontiguousarray(disc_points_np)
if not candidates_comp_np.flags["C_CONTIGUOUS"]:
candidates_comp_np = np.ascontiguousarray(candidates_comp_np)
disc_idxs_iloc = pairwise_distances_argmin(
disc_points_np, candidates_comp_np, metric="manhattan"
)
disc_points = points[:, :num_comp_columns]
cont_points = points[:, num_comp_columns:]

# Get the actual search space dataframe indices
disc_idxs_loc = candidates_comp.iloc[disc_idxs_iloc].index
# Get selected candidate indices
idxs = pd.Index(
pd.merge(
candidates_comp.reset_index(),
pd.DataFrame(disc_points, columns=candidates_comp.columns),
on=list(candidates_comp),
)["index"]
)

# Get experimental representation of discrete and continuous parts
rec_disc_exp = searchspace.discrete.exp_rep.loc[disc_idxs_loc]
rec_disc_exp = searchspace.discrete.exp_rep.loc[idxs]
rec_cont_exp = pd.DataFrame(
cont_points, columns=searchspace.continuous.param_names
)

# Adjust the index of the continuous part and concatenate both
# Adjust the index of the continuous part and create overall recommendations
rec_cont_exp.index = rec_disc_exp.index
rec_exp = pd.concat([rec_disc_exp, rec_cont_exp], axis=1)
# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

return rec_exp

Expand Down
1 change: 0 additions & 1 deletion baybe/recommenders/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ def _recommend_hybrid(
replace=len(disc_candidates) < batch_quantity,
)

cont_random.reset_index(drop=True)
cont_random.index = disc_random.index
return pd.concat([disc_random, cont_random], axis=1)

Expand Down
2 changes: 1 addition & 1 deletion examples/Serialization/basic_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
# We next serialize the campaign to JSON.
# This yields a JSON representation in string format.
# Since it is rather complex, we do not print this string here.
# Note: Dataframes are encoded via binary parquet and are hence not human-readable.
# Note: Dataframes are binary-encoded and are hence not human-readable.
string = campaign.to_json()


Expand Down
9 changes: 4 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ authors = [
]
readme = "README.md"
license = { text = "Apache-2.0" }
requires-python =">=3.8,<3.12"
requires-python =">=3.9,<3.12"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand All @@ -30,20 +29,20 @@ keywords = [
dynamic = ['version']
dependencies = [
"attrs>=22.2.0",
"botorch>=0.8.1",
"botorch>=0.9.3",
"cattrs>=23.2.0",
"exceptiongroup",
"funcy>=1.17",
"gpytorch>=1.9.1",
"ngboost>=0.3.12",
"numpy>=1.24.1",
"pandas[parquet]>=1.4.2",
"pandas>=1.4.2",
AdrianSosic marked this conversation as resolved.
Show resolved Hide resolved
"protobuf<=3.20.3",
"scikit-learn>=1.1.1",
"scikit-learn-extra>=0.3.0",
"scipy>=1.10.1",
"setuptools-scm>=7.1.0",
"torch>=1.11.0",
"torch>=1.13.1",
"baybe[telemetry]",
]

Expand Down
9 changes: 4 additions & 5 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pytest --cov=baybe

This will produce something like this:
```
---------- coverage: platform darwin, python 3.8.6-final-0 -----------
Name Stmts Miss Cover
--------------------------------------------------------
baybe/acquisition.py 58 0 100%
Expand All @@ -59,8 +58,8 @@ possibility to test different python variants as well.

### Environments
In `tox.ini`, we have configured several environments for running different actions
(`fulltest`, `coretest`, `lint`, `audit`) against different versions of python (e.g. `py38`, `py39`, .
..).
(`fulltest`, `coretest`, `lint`, `audit`) against different versions of python
(e.g. `py310`, `py311`, ...).
You can specify both in `tox` to call a certain combination.

For instance
Expand All @@ -85,13 +84,13 @@ tox -l
### Shortcuts
In case you want to run several combinations, you can specify them like
```bash
tox -e audit-py38,audit-py311
tox -e audit-py310,audit-py311
```

If you omit the python version from the environment, `tox` will use the version
from the command-executing environment:
```bash
tox -e coretest # runs like '-e coretest-py38' if called from a python 3.8 environment
tox -e coretest # runs like '-e coretest-py310' if called from a python 3.10 environment
```

If you simply want to run all combinations, you can use
Expand Down
14 changes: 7 additions & 7 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
[tox]
min_version = 4.9
env_list = {fulltest,coretest,lint,mypy,audit}-py{38,39,310,311}
env_list = {fulltest,coretest,lint,mypy,audit}-py{39,310,311}
isolated_build = True

[testenv:fulltest,fulltest-py{38,39,310,311}]
[testenv:fulltest,fulltest-py{39,310,311}]
description = Run PyTest with all extra functionality
extras = test,chem,examples,simulation,onnx
passenv = CI
commands =
python --version
pytest -p no:warnings --cov=baybe --durations=5 {posargs}

[testenv:coretest,coretest-py{38,39,310,311}]
[testenv:coretest,coretest-py{39,310,311}]
description = Run PyTest with core functionality
extras = test,examples
passenv = CI
commands =
python --version
pytest -p no:warnings --cov=baybe --durations=5 {posargs}

[testenv:lint,lint-py{38,39,310,311}]
[testenv:lint,lint-py{39,310,311}]
description = Run linters and format checkers
extras = lint,examples
skip_install = True
Expand All @@ -28,7 +28,7 @@ commands =
python --version
pre-commit run --all-files {posargs:--show-diff-on-failure}

[testenv:mypy,mypy-py{38,39,310,311}]
[testenv:mypy,mypy-py{39,310,311}]
description = Run mypy
extras = mypy
setenv =
Expand All @@ -37,7 +37,7 @@ commands =
python --version
mypy

[testenv:audit,audit-py{38,39,310,311}]
[testenv:audit,audit-py{39,310,311}]
description = Run pip-audit
extras = dev # audit entire environment
setenv =
Expand All @@ -47,7 +47,7 @@ commands =
python --version
pip-audit {env:EXCLUDES:}

[testenv:docs,docs-py{38,39,310,311}]
[testenv:docs,docs-py{39,310,311}]
description = Build documentation
extras = docs
passenv = BAYBE_DOCS_LINKCHECK_IGNORE
Expand Down