leanhebo 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- leanhebo-0.1.0/CHANGELOG.md +15 -0
- leanhebo-0.1.0/CITATION.cff +46 -0
- leanhebo-0.1.0/LICENSE +22 -0
- leanhebo-0.1.0/NOTICE.md +14 -0
- leanhebo-0.1.0/ORIGIN.md +23 -0
- leanhebo-0.1.0/PKG-INFO +192 -0
- leanhebo-0.1.0/README.md +162 -0
- leanhebo-0.1.0/examples/adapters.py +22 -0
- leanhebo-0.1.0/examples/basic.py +40 -0
- leanhebo-0.1.0/examples/contextual_checkpoint.py +20 -0
- leanhebo-0.1.0/pyproject.toml +120 -0
- leanhebo-0.1.0/pyproject.toml.orig +102 -0
- leanhebo-0.1.0/src/leanhebo/__init__.py +27 -0
- leanhebo-0.1.0/src/leanhebo/acquisition/__init__.py +8 -0
- leanhebo-0.1.0/src/leanhebo/acquisition/mace.py +91 -0
- leanhebo-0.1.0/src/leanhebo/acquisition/posterior.py +119 -0
- leanhebo-0.1.0/src/leanhebo/checkpoint.py +73 -0
- leanhebo-0.1.0/src/leanhebo/config.py +263 -0
- leanhebo-0.1.0/src/leanhebo/data/__init__.py +29 -0
- leanhebo-0.1.0/src/leanhebo/data/adapters/__init__.py +11 -0
- leanhebo-0.1.0/src/leanhebo/data/adapters/numpy.py +30 -0
- leanhebo-0.1.0/src/leanhebo/data/adapters/pandas.py +15 -0
- leanhebo-0.1.0/src/leanhebo/data/adapters/polars.py +15 -0
- leanhebo-0.1.0/src/leanhebo/data/adapters/registry.py +125 -0
- leanhebo-0.1.0/src/leanhebo/data/batch.py +255 -0
- leanhebo-0.1.0/src/leanhebo/data/store.py +355 -0
- leanhebo-0.1.0/src/leanhebo/diagnostics.py +134 -0
- leanhebo-0.1.0/src/leanhebo/errors.py +23 -0
- leanhebo-0.1.0/src/leanhebo/gp/__init__.py +8 -0
- leanhebo-0.1.0/src/leanhebo/gp/exact.py +742 -0
- leanhebo-0.1.0/src/leanhebo/gp/kernel.py +130 -0
- leanhebo-0.1.0/src/leanhebo/gp/optimizer.py +127 -0
- leanhebo-0.1.0/src/leanhebo/gp/reports.py +7 -0
- leanhebo-0.1.0/src/leanhebo/optimizer.py +628 -0
- leanhebo-0.1.0/src/leanhebo/py.typed +1 -0
- leanhebo-0.1.0/src/leanhebo/runtime/__init__.py +8 -0
- leanhebo-0.1.0/src/leanhebo/runtime/process.py +44 -0
- leanhebo-0.1.0/src/leanhebo/runtime/rng.py +82 -0
- leanhebo-0.1.0/src/leanhebo/search/__init__.py +82 -0
- leanhebo-0.1.0/src/leanhebo/search/duplicates.py +228 -0
- leanhebo-0.1.0/src/leanhebo/search/nsga2.py +599 -0
- leanhebo-0.1.0/src/leanhebo/search/operators.py +451 -0
- leanhebo-0.1.0/src/leanhebo/search/repair.py +307 -0
- leanhebo-0.1.0/src/leanhebo/search/sorting.py +187 -0
- leanhebo-0.1.0/src/leanhebo/search/survival.py +127 -0
- leanhebo-0.1.0/src/leanhebo/space/__init__.py +22 -0
- leanhebo-0.1.0/src/leanhebo/space/compiled.py +732 -0
- leanhebo-0.1.0/src/leanhebo/space/keys.py +92 -0
- leanhebo-0.1.0/src/leanhebo/space/parameters.py +488 -0
- leanhebo-0.1.0/src/leanhebo/space/space.py +101 -0
- leanhebo-0.1.0/src/leanhebo/transforms/__init__.py +53 -0
- leanhebo-0.1.0/src/leanhebo/transforms/power.py +957 -0
- leanhebo-0.1.0/src/leanhebo/transforms/scalers.py +362 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to LeanHEBO will be documented here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-08-09
|
|
6
|
+
|
|
7
|
+
- Establish the independent `uv` project and provenance boundary.
|
|
8
|
+
- Implement the initial exact-GP LeanHEBO optimization path.
|
|
9
|
+
- Fit and checkpoint the HEBO-compatible observed-range input scaler used by the exact GP.
|
|
10
|
+
- Preserve append-only observation state, reserved duplicate keys, diagnostics, search history,
|
|
11
|
+
and exact version counters across safe checkpoints.
|
|
12
|
+
- Raise a typed exhaustion error instead of silently returning duplicate suggestions.
|
|
13
|
+
- Retry numerical fit or posterior failures once with a clean full GP refit.
|
|
14
|
+
- Add a pinned, dependency-locked upstream benchmark environment and a fail-closed paired
|
|
15
|
+
comparison harness with actual-work checks and bootstrap confidence intervals.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use LeanHEBO, cite both LeanHEBO and the original HEBO work."
|
|
3
|
+
title: "LeanHEBO"
|
|
4
|
+
type: software
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
date-released: 2026-08-09
|
|
7
|
+
license: MIT
|
|
8
|
+
authors:
|
|
9
|
+
- name: "LeanHEBO contributors"
|
|
10
|
+
repository-code: "https://github.com/dimitrismoustakas/LeanHEBO"
|
|
11
|
+
references:
|
|
12
|
+
- type: article
|
|
13
|
+
title: "HEBO: Pushing the Limits of Sample-Efficient Hyperparameter Optimisation"
|
|
14
|
+
authors:
|
|
15
|
+
- family-names: Cowen-Rivers
|
|
16
|
+
given-names: Alexander I.
|
|
17
|
+
- family-names: Lyu
|
|
18
|
+
given-names: Wenlong
|
|
19
|
+
- family-names: Tutunov
|
|
20
|
+
given-names: Rasul
|
|
21
|
+
- family-names: Wang
|
|
22
|
+
given-names: Zhi
|
|
23
|
+
- family-names: Grosnit
|
|
24
|
+
given-names: Antoine
|
|
25
|
+
- family-names: Griffiths
|
|
26
|
+
given-names: Ryan-Rhys
|
|
27
|
+
- family-names: Maravel
|
|
28
|
+
given-names: Alexandre M.
|
|
29
|
+
- family-names: Hao
|
|
30
|
+
given-names: Jianye
|
|
31
|
+
- family-names: Wang
|
|
32
|
+
given-names: Jun
|
|
33
|
+
- family-names: Peters
|
|
34
|
+
given-names: Jan
|
|
35
|
+
- family-names: Bou-Ammar
|
|
36
|
+
given-names: Haitham
|
|
37
|
+
journal: "Journal of Artificial Intelligence Research"
|
|
38
|
+
volume: 74
|
|
39
|
+
year: 2022
|
|
40
|
+
doi: "10.1613/jair.1.13643"
|
|
41
|
+
- type: software
|
|
42
|
+
title: "HEBO"
|
|
43
|
+
authors:
|
|
44
|
+
- name: "Huawei Technologies Co., Ltd."
|
|
45
|
+
repository-code: "https://github.com/huawei-noah/HEBO"
|
|
46
|
+
version: "ee6112d39d1a9e9703fecaf9057193e1ec9dae72"
|
leanhebo-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved.
|
|
4
|
+
Copyright (c) 2026 LeanHEBO contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
leanhebo-0.1.0/NOTICE.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Notice
|
|
2
|
+
|
|
3
|
+
LeanHEBO is an independent implementation derived in part from the HEBO project by
|
|
4
|
+
Huawei Technologies Co., Ltd. It is not affiliated with, sponsored by, or endorsed by
|
|
5
|
+
Huawei.
|
|
6
|
+
|
|
7
|
+
- Upstream project: <https://github.com/huawei-noah/HEBO>
|
|
8
|
+
- Audited package: `HEBO/`
|
|
9
|
+
- Audited commit: `ee6112d39d1a9e9703fecaf9057193e1ec9dae72`
|
|
10
|
+
- Upstream license: MIT
|
|
11
|
+
|
|
12
|
+
The HEBO method is described by Cowen-Rivers et al., “HEBO: Pushing the Limits of
|
|
13
|
+
Sample-Efficient Hyperparameter Optimisation,” *Journal of Artificial Intelligence
|
|
14
|
+
Research*, volume 74, 2022.
|
leanhebo-0.1.0/ORIGIN.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Code origin
|
|
2
|
+
|
|
3
|
+
LeanHEBO reimplements the main single-objective exact-GP path of Huawei's HEBO package,
|
|
4
|
+
audited at commit `ee6112d39d1a9e9703fecaf9057193e1ec9dae72`.
|
|
5
|
+
|
|
6
|
+
## Reimplemented components
|
|
7
|
+
|
|
8
|
+
- mixed-variable design-space encoding and Sobol sampling;
|
|
9
|
+
- output standardization and Box-Cox/Yeo-Johnson transformation behavior;
|
|
10
|
+
- exact Gaussian-process regression and HEBO-compatible kernel construction;
|
|
11
|
+
- the three-objective MACE acquisition calculation;
|
|
12
|
+
- HEBO-style batch candidate selection.
|
|
13
|
+
|
|
14
|
+
## Independently implemented components
|
|
15
|
+
|
|
16
|
+
- immutable compiled-space metadata and `CandidateBatch` boundary;
|
|
17
|
+
- append-only tensor observation storage and incremental duplicate membership;
|
|
18
|
+
- persistent GP/model/optimizer lifecycle;
|
|
19
|
+
- tensor-native mixed-variable NSGA-II;
|
|
20
|
+
- configuration, diagnostics, checkpointing, and optional table adapters.
|
|
21
|
+
|
|
22
|
+
Files that substantially copy upstream implementation text must retain Huawei copyright
|
|
23
|
+
headers. New implementations use SPDX identifiers and refer to `NOTICE.md`.
|
leanhebo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: leanhebo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tensor-native, low-latency implementation of the HEBO method
|
|
5
|
+
Keywords: bayesian-optimization,gaussian-process,hebo,pytorch
|
|
6
|
+
Author: LeanHEBO contributors
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: NOTICE.md
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Dist: gpytorch>=1.14
|
|
18
|
+
Requires-Dist: numpy>=2.0
|
|
19
|
+
Requires-Dist: torch>=2.5
|
|
20
|
+
Requires-Dist: pandas>=2.2 ; extra == 'pandas'
|
|
21
|
+
Requires-Dist: polars>=1.0 ; extra == 'polars'
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Project-URL: Homepage, https://github.com/dimitrismoustakas/LeanHEBO
|
|
24
|
+
Project-URL: Repository, https://github.com/dimitrismoustakas/LeanHEBO
|
|
25
|
+
Project-URL: Issues, https://github.com/dimitrismoustakas/LeanHEBO/issues
|
|
26
|
+
Project-URL: Changelog, https://github.com/dimitrismoustakas/LeanHEBO/blob/main/CHANGELOG.md
|
|
27
|
+
Provides-Extra: pandas
|
|
28
|
+
Provides-Extra: polars
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# LeanHEBO
|
|
32
|
+
|
|
33
|
+
LeanHEBO is a tensor-native, low-latency implementation of the established HEBO Bayesian
|
|
34
|
+
optimization strategy. It focuses on the single-objective exact-GP path, persistent model
|
|
35
|
+
state, mixed-variable search, and explicit CPU or CUDA execution.
|
|
36
|
+
|
|
37
|
+
LeanHEBO is an independent project. It is not affiliated with or endorsed by Huawei and
|
|
38
|
+
does not claim a new optimization algorithm. See
|
|
39
|
+
[NOTICE.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/NOTICE.md) and
|
|
40
|
+
[ORIGIN.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/ORIGIN.md) for provenance.
|
|
41
|
+
|
|
42
|
+
The package is under active initial development. Its first release targets continuous,
|
|
43
|
+
log-continuous, integer, stepped-integer, power/exponent-integer, Boolean, and categorical
|
|
44
|
+
variables; batch and contextual suggestions; HEBO output warping; MACE acquisition; and a
|
|
45
|
+
tensor-native NSGA-II search.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
LeanHEBO requires Python 3.11 or newer; the initial release is tested on Python 3.11 through
|
|
50
|
+
3.13. Install the released package with either pip or uv:
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
python -m pip install leanhebo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
uv add leanhebo
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Pandas and Polars adapters are optional extras:
|
|
61
|
+
|
|
62
|
+
```console
|
|
63
|
+
python -m pip install "leanhebo[pandas,polars]"
|
|
64
|
+
# or: uv add "leanhebo[pandas,polars]"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
CPU is the primary supported path for the initial alpha release. CUDA execution is available,
|
|
68
|
+
but accelerator support depends on the Torch build and the local CUDA stack. Install the
|
|
69
|
+
appropriate Torch build using the [PyTorch installation guide](https://pytorch.org/get-started/locally/)
|
|
70
|
+
before installing LeanHEBO; the package does not silently switch between CPU and CUDA.
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
LeanHEBO minimizes the objective values supplied to `observe`. This complete example optimizes
|
|
75
|
+
a small mixed-variable loss:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import numpy as np
|
|
79
|
+
|
|
80
|
+
from leanhebo import LeanHEBO
|
|
81
|
+
from leanhebo.config import GPConfig, LeanHEBOConfig, RuntimeConfig, SearchConfig
|
|
82
|
+
from leanhebo.space import Bool, Categorical, Float, Integer, Space
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def objective(row: dict[str, object]) -> float:
|
|
86
|
+
"""Return a loss: LeanHEBO minimizes the values passed to observe."""
|
|
87
|
+
x = float(row["x"])
|
|
88
|
+
depth = int(row["depth"])
|
|
89
|
+
activation_penalty = 0.0 if row["activation"] == "gelu" else 0.25
|
|
90
|
+
bias_penalty = 0.0 if bool(row["use_bias"]) else 0.1
|
|
91
|
+
return (x - 0.3) ** 2 + (depth - 6) ** 2 / 25 + activation_penalty + bias_penalty
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
space = Space(
|
|
95
|
+
Float("x", -2.0, 2.0),
|
|
96
|
+
Integer("depth", 1, 12),
|
|
97
|
+
Categorical("activation", ("relu", "gelu", "silu")),
|
|
98
|
+
Bool("use_bias"),
|
|
99
|
+
)
|
|
100
|
+
config = LeanHEBOConfig(
|
|
101
|
+
runtime=RuntimeConfig(seed=7),
|
|
102
|
+
# Small settings keep this example quick; use the defaults for real optimization.
|
|
103
|
+
gp=GPConfig(initial_steps=15, update_steps=3),
|
|
104
|
+
search=SearchConfig(population_size=32, generations=15),
|
|
105
|
+
)
|
|
106
|
+
optimizer = LeanHEBO(space, config=config)
|
|
107
|
+
|
|
108
|
+
for _ in range(3):
|
|
109
|
+
candidates = optimizer.suggest(3)
|
|
110
|
+
losses = np.asarray([objective(row) for row in candidates.to_records()])
|
|
111
|
+
optimizer.observe(candidates, losses)
|
|
112
|
+
|
|
113
|
+
print(optimizer.best_x.to_records()[0], optimizer.best_y)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Passing the original `CandidateBatch` to `observe` avoids re-encoding; the observation store takes
|
|
117
|
+
one owned tensor snapshot so later caller mutation cannot rewrite history. Records, NumPy arrays,
|
|
118
|
+
Pandas DataFrames, and Polars DataFrames are also accepted at the boundary and encoded once.
|
|
119
|
+
|
|
120
|
+
Contextual values are fixed without a DataFrame round trip:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
candidates = optimizer.suggest(8, fix_input={"use_bias": True})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
candidates = optimizer.suggest(3)
|
|
128
|
+
frame = candidates.to_polars() # or candidates.to_pandas()
|
|
129
|
+
losses = np.asarray([objective(row) for row in candidates.to_records()])
|
|
130
|
+
optimizer.observe(frame, losses)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Runtime behavior
|
|
134
|
+
|
|
135
|
+
Runtime code keeps encoded observations, transforms, GP state, acquisition evaluation, random
|
|
136
|
+
streams, and evolutionary populations in Torch. NumPy and optional table libraries are boundary
|
|
137
|
+
formats only. The GP and likelihood survive ordinary updates; new training data are installed
|
|
138
|
+
with GPyTorch's persistent exact-GP API and receive the configured short update schedule.
|
|
139
|
+
|
|
140
|
+
CPU is the default. CUDA is selected explicitly with `RuntimeConfig(device="cuda")`; LeanHEBO
|
|
141
|
+
does not silently move work between devices. Both `float32` and `float64` are supported. The
|
|
142
|
+
project is currently alpha software: CPU behavior receives the broadest release validation,
|
|
143
|
+
while CUDA compatibility can vary across Torch, driver, and device combinations.
|
|
144
|
+
|
|
145
|
+
Importing LeanHEBO does not change Torch or BLAS thread counts. Applications that want an
|
|
146
|
+
explicit process-wide policy should call the startup helper before other Torch work:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from leanhebo.runtime import configure_process
|
|
150
|
+
|
|
151
|
+
configure_process(torch_num_threads=1, torch_num_interop_threads=1)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Every configuration group has one documented set of defaults and serializes with
|
|
155
|
+
`optimizer.config.to_dict()`. There are no hidden execution modes or preset profiles.
|
|
156
|
+
|
|
157
|
+
## Checkpointing
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
optimizer.save("run.leanhebo")
|
|
161
|
+
restored = LeanHEBO.load("run.leanhebo", map_location="cpu")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The versioned checkpoint contains only LeanHEBO-defined state, tensors, and primitive schema
|
|
165
|
+
values. It restores observations, transforms, model and likelihood parameters, optimizer state,
|
|
166
|
+
Sobol progress, and independent Torch generator states. User functions are never pickled.
|
|
167
|
+
|
|
168
|
+
## Scope
|
|
169
|
+
|
|
170
|
+
The initial implementation is intentionally narrow: one user objective, an exact Gaussian
|
|
171
|
+
process, MACE, and mixed-variable NSGA-II. Random forests, CatBoost, neural ensembles, sparse
|
|
172
|
+
GPs, constrained user objectives, and general multi-objective user objectives are not part of
|
|
173
|
+
the first release.
|
|
174
|
+
|
|
175
|
+
No performance or quality claim should be made without the pinned, matched-work benchmark and
|
|
176
|
+
multi-seed quality suite described in
|
|
177
|
+
[benchmarks/README.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/benchmarks/README.md).
|
|
178
|
+
|
|
179
|
+
## Development
|
|
180
|
+
|
|
181
|
+
```console
|
|
182
|
+
uv sync --all-groups --all-extras
|
|
183
|
+
uv run pytest
|
|
184
|
+
uv run ruff check .
|
|
185
|
+
uv run ruff format --check .
|
|
186
|
+
uv run mypy src/leanhebo
|
|
187
|
+
uv build
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The repository uses Python 3.11+, a `src/` layout, the pure-Python `uv_build` backend, and a
|
|
191
|
+
committed CPU development lock. Optional accelerator environments should override only the
|
|
192
|
+
explicit Torch package index.
|
leanhebo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# LeanHEBO
|
|
2
|
+
|
|
3
|
+
LeanHEBO is a tensor-native, low-latency implementation of the established HEBO Bayesian
|
|
4
|
+
optimization strategy. It focuses on the single-objective exact-GP path, persistent model
|
|
5
|
+
state, mixed-variable search, and explicit CPU or CUDA execution.
|
|
6
|
+
|
|
7
|
+
LeanHEBO is an independent project. It is not affiliated with or endorsed by Huawei and
|
|
8
|
+
does not claim a new optimization algorithm. See
|
|
9
|
+
[NOTICE.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/NOTICE.md) and
|
|
10
|
+
[ORIGIN.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/ORIGIN.md) for provenance.
|
|
11
|
+
|
|
12
|
+
The package is under active initial development. Its first release targets continuous,
|
|
13
|
+
log-continuous, integer, stepped-integer, power/exponent-integer, Boolean, and categorical
|
|
14
|
+
variables; batch and contextual suggestions; HEBO output warping; MACE acquisition; and a
|
|
15
|
+
tensor-native NSGA-II search.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
LeanHEBO requires Python 3.11 or newer; the initial release is tested on Python 3.11 through
|
|
20
|
+
3.13. Install the released package with either pip or uv:
|
|
21
|
+
|
|
22
|
+
```console
|
|
23
|
+
python -m pip install leanhebo
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```console
|
|
27
|
+
uv add leanhebo
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Pandas and Polars adapters are optional extras:
|
|
31
|
+
|
|
32
|
+
```console
|
|
33
|
+
python -m pip install "leanhebo[pandas,polars]"
|
|
34
|
+
# or: uv add "leanhebo[pandas,polars]"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
CPU is the primary supported path for the initial alpha release. CUDA execution is available,
|
|
38
|
+
but accelerator support depends on the Torch build and the local CUDA stack. Install the
|
|
39
|
+
appropriate Torch build using the [PyTorch installation guide](https://pytorch.org/get-started/locally/)
|
|
40
|
+
before installing LeanHEBO; the package does not silently switch between CPU and CUDA.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
LeanHEBO minimizes the objective values supplied to `observe`. This complete example optimizes
|
|
45
|
+
a small mixed-variable loss:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import numpy as np
|
|
49
|
+
|
|
50
|
+
from leanhebo import LeanHEBO
|
|
51
|
+
from leanhebo.config import GPConfig, LeanHEBOConfig, RuntimeConfig, SearchConfig
|
|
52
|
+
from leanhebo.space import Bool, Categorical, Float, Integer, Space
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def objective(row: dict[str, object]) -> float:
|
|
56
|
+
"""Return a loss: LeanHEBO minimizes the values passed to observe."""
|
|
57
|
+
x = float(row["x"])
|
|
58
|
+
depth = int(row["depth"])
|
|
59
|
+
activation_penalty = 0.0 if row["activation"] == "gelu" else 0.25
|
|
60
|
+
bias_penalty = 0.0 if bool(row["use_bias"]) else 0.1
|
|
61
|
+
return (x - 0.3) ** 2 + (depth - 6) ** 2 / 25 + activation_penalty + bias_penalty
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
space = Space(
|
|
65
|
+
Float("x", -2.0, 2.0),
|
|
66
|
+
Integer("depth", 1, 12),
|
|
67
|
+
Categorical("activation", ("relu", "gelu", "silu")),
|
|
68
|
+
Bool("use_bias"),
|
|
69
|
+
)
|
|
70
|
+
config = LeanHEBOConfig(
|
|
71
|
+
runtime=RuntimeConfig(seed=7),
|
|
72
|
+
# Small settings keep this example quick; use the defaults for real optimization.
|
|
73
|
+
gp=GPConfig(initial_steps=15, update_steps=3),
|
|
74
|
+
search=SearchConfig(population_size=32, generations=15),
|
|
75
|
+
)
|
|
76
|
+
optimizer = LeanHEBO(space, config=config)
|
|
77
|
+
|
|
78
|
+
for _ in range(3):
|
|
79
|
+
candidates = optimizer.suggest(3)
|
|
80
|
+
losses = np.asarray([objective(row) for row in candidates.to_records()])
|
|
81
|
+
optimizer.observe(candidates, losses)
|
|
82
|
+
|
|
83
|
+
print(optimizer.best_x.to_records()[0], optimizer.best_y)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Passing the original `CandidateBatch` to `observe` avoids re-encoding; the observation store takes
|
|
87
|
+
one owned tensor snapshot so later caller mutation cannot rewrite history. Records, NumPy arrays,
|
|
88
|
+
Pandas DataFrames, and Polars DataFrames are also accepted at the boundary and encoded once.
|
|
89
|
+
|
|
90
|
+
Contextual values are fixed without a DataFrame round trip:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
candidates = optimizer.suggest(8, fix_input={"use_bias": True})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
candidates = optimizer.suggest(3)
|
|
98
|
+
frame = candidates.to_polars() # or candidates.to_pandas()
|
|
99
|
+
losses = np.asarray([objective(row) for row in candidates.to_records()])
|
|
100
|
+
optimizer.observe(frame, losses)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Runtime behavior
|
|
104
|
+
|
|
105
|
+
Runtime code keeps encoded observations, transforms, GP state, acquisition evaluation, random
|
|
106
|
+
streams, and evolutionary populations in Torch. NumPy and optional table libraries are boundary
|
|
107
|
+
formats only. The GP and likelihood survive ordinary updates; new training data are installed
|
|
108
|
+
with GPyTorch's persistent exact-GP API and receive the configured short update schedule.
|
|
109
|
+
|
|
110
|
+
CPU is the default. CUDA is selected explicitly with `RuntimeConfig(device="cuda")`; LeanHEBO
|
|
111
|
+
does not silently move work between devices. Both `float32` and `float64` are supported. The
|
|
112
|
+
project is currently alpha software: CPU behavior receives the broadest release validation,
|
|
113
|
+
while CUDA compatibility can vary across Torch, driver, and device combinations.
|
|
114
|
+
|
|
115
|
+
Importing LeanHEBO does not change Torch or BLAS thread counts. Applications that want an
|
|
116
|
+
explicit process-wide policy should call the startup helper before other Torch work:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from leanhebo.runtime import configure_process
|
|
120
|
+
|
|
121
|
+
configure_process(torch_num_threads=1, torch_num_interop_threads=1)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Every configuration group has one documented set of defaults and serializes with
|
|
125
|
+
`optimizer.config.to_dict()`. There are no hidden execution modes or preset profiles.
|
|
126
|
+
|
|
127
|
+
## Checkpointing
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
optimizer.save("run.leanhebo")
|
|
131
|
+
restored = LeanHEBO.load("run.leanhebo", map_location="cpu")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The versioned checkpoint contains only LeanHEBO-defined state, tensors, and primitive schema
|
|
135
|
+
values. It restores observations, transforms, model and likelihood parameters, optimizer state,
|
|
136
|
+
Sobol progress, and independent Torch generator states. User functions are never pickled.
|
|
137
|
+
|
|
138
|
+
## Scope
|
|
139
|
+
|
|
140
|
+
The initial implementation is intentionally narrow: one user objective, an exact Gaussian
|
|
141
|
+
process, MACE, and mixed-variable NSGA-II. Random forests, CatBoost, neural ensembles, sparse
|
|
142
|
+
GPs, constrained user objectives, and general multi-objective user objectives are not part of
|
|
143
|
+
the first release.
|
|
144
|
+
|
|
145
|
+
No performance or quality claim should be made without the pinned, matched-work benchmark and
|
|
146
|
+
multi-seed quality suite described in
|
|
147
|
+
[benchmarks/README.md](https://github.com/dimitrismoustakas/LeanHEBO/blob/main/benchmarks/README.md).
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```console
|
|
152
|
+
uv sync --all-groups --all-extras
|
|
153
|
+
uv run pytest
|
|
154
|
+
uv run ruff check .
|
|
155
|
+
uv run ruff format --check .
|
|
156
|
+
uv run mypy src/leanhebo
|
|
157
|
+
uv build
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The repository uses Python 3.11+, a `src/` layout, the pure-Python `uv_build` backend, and a
|
|
161
|
+
committed CPU development lock. Optional accelerator environments should override only the
|
|
162
|
+
explicit Torch package index.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""Optional table adapters remain outside the optimization hot path."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from leanhebo import LeanHEBO
|
|
10
|
+
from leanhebo.config import LeanHEBOConfig, RuntimeConfig
|
|
11
|
+
from leanhebo.space import Categorical, Float, Space
|
|
12
|
+
|
|
13
|
+
space = Space(Float("x", -1.0, 1.0), Categorical("kind", ("left", "right")))
|
|
14
|
+
optimizer = LeanHEBO(space, config=LeanHEBOConfig(runtime=RuntimeConfig(seed=3)))
|
|
15
|
+
|
|
16
|
+
candidates = optimizer.suggest(4)
|
|
17
|
+
pandas_frame = candidates.to_pandas()
|
|
18
|
+
polars_frame = candidates.to_polars()
|
|
19
|
+
assert pandas_frame.shape == polars_frame.shape
|
|
20
|
+
|
|
21
|
+
values = np.square(pandas_frame["x"].to_numpy())
|
|
22
|
+
optimizer.observe(candidates, values) # reuses CandidateBatch tensors
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""A small mixed-variable LeanHEBO loop."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from leanhebo import LeanHEBO
|
|
10
|
+
from leanhebo.config import GPConfig, LeanHEBOConfig, RuntimeConfig, SearchConfig
|
|
11
|
+
from leanhebo.space import Bool, Categorical, Float, Integer, Space
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def objective(row: dict[str, object]) -> float:
|
|
15
|
+
x = float(row["x"])
|
|
16
|
+
depth = int(row["depth"])
|
|
17
|
+
category_penalty = 0.0 if row["activation"] == "gelu" else 0.25
|
|
18
|
+
bias_penalty = 0.0 if bool(row["use_bias"]) else 0.1
|
|
19
|
+
return (x - 0.3) ** 2 + (depth - 6) ** 2 / 25 + category_penalty + bias_penalty
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
space = Space(
|
|
23
|
+
Float("x", -2.0, 2.0),
|
|
24
|
+
Integer("depth", 1, 12),
|
|
25
|
+
Categorical("activation", ("relu", "gelu", "silu")),
|
|
26
|
+
Bool("use_bias"),
|
|
27
|
+
)
|
|
28
|
+
config = LeanHEBOConfig(
|
|
29
|
+
runtime=RuntimeConfig(seed=7),
|
|
30
|
+
gp=GPConfig(initial_steps=30, update_steps=5),
|
|
31
|
+
search=SearchConfig(population_size=64, generations=30),
|
|
32
|
+
)
|
|
33
|
+
optimizer = LeanHEBO(space, config=config)
|
|
34
|
+
|
|
35
|
+
for _ in range(12):
|
|
36
|
+
batch = optimizer.suggest(3)
|
|
37
|
+
y = np.asarray([objective(record) for record in batch.to_records()])
|
|
38
|
+
optimizer.observe(batch, y)
|
|
39
|
+
|
|
40
|
+
print(optimizer.best_x.to_records()[0], optimizer.best_y)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""Contextual suggestions and deterministic checkpoint continuation."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from leanhebo import LeanHEBO
|
|
8
|
+
from leanhebo.config import LeanHEBOConfig, RuntimeConfig
|
|
9
|
+
from leanhebo.space import Categorical, Float, Space
|
|
10
|
+
|
|
11
|
+
space = Space(Float("dose", 0.0, 1.0), Categorical("site", ("north", "south")))
|
|
12
|
+
optimizer = LeanHEBO(space, config=LeanHEBOConfig(runtime=RuntimeConfig(seed=19)))
|
|
13
|
+
|
|
14
|
+
south_batch = optimizer.suggest(4, fix_input={"site": "south"})
|
|
15
|
+
assert all(record["site"] == "south" for record in south_batch.to_records())
|
|
16
|
+
|
|
17
|
+
optimizer.save("contextual.leanhebo")
|
|
18
|
+
restored = LeanHEBO.load("contextual.leanhebo", map_location="cpu")
|
|
19
|
+
next_batch = restored.suggest(2, fix_input={"site": "south"})
|
|
20
|
+
print(next_batch.to_records())
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "leanhebo"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A tensor-native, low-latency implementation of the HEBO method"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = [
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"NOTICE.md",
|
|
11
|
+
]
|
|
12
|
+
keywords = [
|
|
13
|
+
"bayesian-optimization",
|
|
14
|
+
"gaussian-process",
|
|
15
|
+
"hebo",
|
|
16
|
+
"pytorch",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"gpytorch>=1.14",
|
|
29
|
+
"numpy>=2.0",
|
|
30
|
+
"torch>=2.5",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[[project.authors]]
|
|
34
|
+
name = "LeanHEBO contributors"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/dimitrismoustakas/LeanHEBO"
|
|
38
|
+
Repository = "https://github.com/dimitrismoustakas/LeanHEBO"
|
|
39
|
+
Issues = "https://github.com/dimitrismoustakas/LeanHEBO/issues"
|
|
40
|
+
Changelog = "https://github.com/dimitrismoustakas/LeanHEBO/blob/main/CHANGELOG.md"
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
pandas = ["pandas>=2.2"]
|
|
44
|
+
polars = ["polars>=1.0"]
|
|
45
|
+
|
|
46
|
+
[dependency-groups]
|
|
47
|
+
dev = [
|
|
48
|
+
"hypothesis>=6.100",
|
|
49
|
+
"mypy>=1.11",
|
|
50
|
+
"pandas>=2.2",
|
|
51
|
+
"polars>=1.0",
|
|
52
|
+
"pre-commit>=3.7",
|
|
53
|
+
"pymoo>=0.6",
|
|
54
|
+
"pytest>=8",
|
|
55
|
+
"pytest-cov>=5",
|
|
56
|
+
"ruff>=0.6",
|
|
57
|
+
"scikit-learn>=1.5",
|
|
58
|
+
"scipy>=1.14",
|
|
59
|
+
]
|
|
60
|
+
bench = [
|
|
61
|
+
"asv>=0.6",
|
|
62
|
+
"psutil>=6",
|
|
63
|
+
"py-spy>=0.4",
|
|
64
|
+
"pytest-benchmark>=4",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[build-system]
|
|
68
|
+
requires = ["uv_build>=0.12.0,<0.13"]
|
|
69
|
+
build-backend = "uv_build"
|
|
70
|
+
|
|
71
|
+
[tool.uv.build-backend]
|
|
72
|
+
module-name = "leanhebo"
|
|
73
|
+
module-root = "src"
|
|
74
|
+
source-include = [
|
|
75
|
+
"CHANGELOG.md",
|
|
76
|
+
"CITATION.cff",
|
|
77
|
+
"ORIGIN.md",
|
|
78
|
+
"examples/**",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.pytest.ini_options]
|
|
82
|
+
addopts = "-ra --strict-config --strict-markers"
|
|
83
|
+
testpaths = ["tests"]
|
|
84
|
+
markers = [
|
|
85
|
+
"gpu: requires a CUDA-capable Torch installation",
|
|
86
|
+
"performance: structural or timing performance tests",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[tool.coverage.run]
|
|
90
|
+
branch = true
|
|
91
|
+
source = ["leanhebo"]
|
|
92
|
+
|
|
93
|
+
[tool.coverage.report]
|
|
94
|
+
show_missing = true
|
|
95
|
+
skip_covered = true
|
|
96
|
+
|
|
97
|
+
[tool.ruff]
|
|
98
|
+
line-length = 100
|
|
99
|
+
target-version = "py311"
|
|
100
|
+
|
|
101
|
+
[tool.ruff.lint]
|
|
102
|
+
select = [
|
|
103
|
+
"E",
|
|
104
|
+
"F",
|
|
105
|
+
"I",
|
|
106
|
+
"UP",
|
|
107
|
+
"B",
|
|
108
|
+
"SIM",
|
|
109
|
+
"RUF",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint.per-file-ignores]
|
|
113
|
+
"tests/**/*.py" = ["S101"]
|
|
114
|
+
|
|
115
|
+
[tool.mypy]
|
|
116
|
+
python_version = "3.11"
|
|
117
|
+
strict = true
|
|
118
|
+
warn_unreachable = true
|
|
119
|
+
packages = ["leanhebo"]
|
|
120
|
+
mypy_path = "src"
|