# DeepHyper: Massively Parallel Hyperparameter Optimization in Python

> DeepHyper is a Python HPO library from Argonne researchers that binds a black-box run function to a process, Ray or MPI evaluator and searches with a centralized Bayesian optimizer. The tutorial path is short; the distributed path is where the design decisions show.

**deephyper/deephyper** — DeepHyper: A Python Package for Massively Parallel Hyperparameter Optimization in Machine Learning

- Repository: https://github.com/deephyper/deephyper
- Website: https://deephyper.readthedocs.io
- Stars: 310 · Forks: 66
- Language: Python
- License: BSD-3-Clause
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/deephyper-deephyper

## The problem DeepHyper targets: too many evaluations, not enough wall clock

Most hyperparameter search code written in a notebook assumes one evaluation at a time. A loop suggests a configuration, trains, records a score, and repeats. That model breaks down the moment a model takes hours to train or the search space has categorical and discrete dimensions that interact. DeepHyper is built around the opposite assumption: evaluations are expensive and should be running concurrently, on a laptop or across a cluster, while a single search algorithm decides what to try next.

The intended user is not someone tuning a random forest on 10,000 rows. The project description and its HPC topic tags point at machine learning workloads where the objective is a training run, and where the README's own framing is "massively parallel" and "distributed across multiple machines." The README also states that DeepHyper is "first and foremost a hyperparameter optimization (HPO) library," with neural architecture search, multi-fidelity and ensembles built on that core. That ordering matters: NAS and multi-fidelity are described as capabilities layered on the HPO engine, not as separate products.

One thing to be clear about before going further: the README's quickstart maximizes the return value of run(job). If your instinct is to minimize a loss, you will need to account for that sign convention in your objective function, not in the search configuration.

## How the run function, the evaluator and CBO fit together

The architecture has three moving parts, and the README's quickstart shows all three in roughly forty lines.

The first is the black-box function. It takes a single argument named job, and the values the search is proposing are read from job.parameters, a dictionary keyed by hyperparameter name. The function returns a number.

The second is the evaluator. Evaluator.create binds the run function to an execution strategy. The README uses method="process" with method_kwargs={"num_workers": 2}, which means the evaluations run in local worker processes rather than in the calling process. This is the boundary where distribution happens, and it is deliberately separated from the search logic. Swapping the evaluator changes where the computation runs without rewriting the objective.

The third is the search. CBO, the centralized Bayesian optimizer, is constructed from an HpProblem and a log_dir, and given a random_state. Calling search.search(evaluator, max_evals=100) drives the loop.

The returned object is a pandas DataFrame, and the column naming carries information. Suggested parameters appear with a p: prefix (p:x, p:b, p:function). The objective column holds the value returned by run. Metadata columns record job_id, job_status, and timestamps for submit and gather. There is also a family of sol.* columns (sol.p:b, sol.p:function, sol.p:x, sol.objective) that track the incumbent solution as the search progresses. In the README's printed output, the sol.* columns stay fixed at the best configuration found so far while the p:* columns change with each new suggestion. Reading that table is how you tell whether the search is exploring or has settled.

## Installing DeepHyper and running the README quickstart

The README gives one installation command, and it is the plain PyPI install:

```bash
pip install deephyper
```

The README points to the online installation documentation for anything beyond that. The optional dependency groups in pyproject.toml are where the real choices live: jax-cpu, jax-cuda, torch, mpi, ray, redis and redis-hiredis are declared as extras, and the core extra bundles deephyper[torch] with deephyper[jax-cpu]. The base install does not pull in MPI, Ray or Redis, so a distributed setup needs an extra chosen deliberately. Note also that requires-python is ">=3.10", and the classifiers list 3.10 through 3.14.

For a first real use, the README's quickstart is the honest starting point. It defines a problem with three hyperparameters of three different kinds: a real interval, a discrete integer range, and a categorical choice.

```python
from deephyper.evaluator import Evaluator
from deephyper.hpo import HpProblem, CBO

problem = HpProblem()
problem.add_hyperparameter((-10.0, 10.0), "x")
problem.add_hyperparameter((0, 10), "b")
problem.add_hyperparameter(["linear", "cubic"], "function")
```

The objective function reads those values back out of job.parameters and returns a number. In the README example the function branches on the categorical parameter, computing x + b or x**3 + b:

```python
def run(job):
    x = job.parameters["x"]
    b = job.parameters["b"]
    if job.parameters["function"] == "linear":
        y = x + b
    elif job.parameters["function"] == "cubic":
        y = x**3 + b
    return y
```

Binding and running is three calls. The evaluator takes the run function and the distribution method; the search takes the problem and a log directory.

```python
evaluator = Evaluator.create(
    run,
    method="process",
    method_kwargs={"num_workers": 2},
)
search = CBO(problem, log_dir=tmp_path, random_state=42)
results = search.search(evaluator, max_evals=100)
print(results)
```

The README reports that this run converges on function == "cubic" with x near 9.99 and b == 10, because the cubic branch dominates the linear one on the positive end of the x range. The printed DataFrame has 101 rows and 12 columns, and the assertion in the README's test checks that the maximum objective exceeds 1000. If you reproduce it, expect the first rows to look exploratory and the later rows to cluster near the boundary of x.

## Where DeepHyper gets awkward: alpha status, evaluator choice and the sign convention

Three limitations are visible without running anything.

The first is maturity. pyproject.toml declares "Development Status :: 3 - Alpha" in the classifiers. That is the project's own label, and it sits alongside a 0.13.x release line. Alpha status does not mean the package is broken, but it does mean the API surface is not frozen, and code written against 0.13.0 may need attention at 0.13.2 and beyond. Pin the version in your environment file.

The second is that the evaluator is not a detail. The README's quickstart uses the process method with two workers, which is a single-machine story. The extras list mpi, ray and redis as separate installs, which tells you the distributed paths require their own dependencies and their own operational knowledge. If you skip that and run the process evaluator on a cluster login node, you have not distributed anything. The README does not document what happens when a worker dies mid-evaluation, nor does it document rollback behavior for a partially completed search, so treat failure recovery as something you must verify against the evaluator you choose.

The third is the maximization convention. The README states in bold that CBO finds values which MAXIMIZE the return value of run(job). Every objective you write must be phrased as a maximization, which usually means returning the negative of a loss. This is a small thing that produces silently wrong searches when forgotten, because a search that maximizes a loss will still converge, just on the worst configuration.

A fourth point is scope. DeepHyper is a Python package with a Python objective function. If your training pipeline is a shell script or a compiled binary, you are writing a Python wrapper around it before any of this applies.

## DeepHyper compared with Optuna and Ray Tune

The obvious comparison is Optuna, and the difference is architectural rather than cosmetic. Optuna's core abstraction is a study with trials, and its storage layer (SQLite or a database) coordinates workers that each run their own sampler. DeepHyper's README describes CBO as a centralized Bayesian optimizer: the search logic sits in one place and the evaluator distributes evaluations out to workers. That centralization is what makes the MPI and Ray backends meaningful for HPC jobs, and it is also why the evaluator is a first-class object in the API rather than an implicit detail.

Ray Tune is the other reference point, and the split is similar. Ray Tune assumes you are already inside the Ray ecosystem and its schedulers are designed around Ray actors. DeepHyper treats Ray as one evaluator option among several, alongside process, MPI and Redis, which means the same search code can move between a laptop and a supercomputer without a rewrite. The cost is that DeepHyper carries its own abstractions for problems, evaluators and searches, and you learn those instead of reusing whatever you already know from Ray.

There is a second axis worth naming: multi-fidelity. The README lists multi-fidelity as a capability built on the HPO core, and the repository has a dedicated examples/examples_uq/ directory alongside examples_hpo/, examples_bbo/ and examples_parallelism/. The examples tree is the most reliable map of what the project actually demonstrates, since the README itself only walks through one CBO example.

## Maintenance, licence and what an upgrade actually costs

The repository is not archived, and the last push was on 2026-03-27. The most recent release listed is 0.13.2 from 2026-01-05, following 0.13.1 on 2025-12-17 and 0.13.0 on 2025-12-02. That is a tight release cadence across three patch and minor versions in about a month, and the gap between the last release and the last push suggests ongoing work on master that has not yet been tagged.

Licensing is BSD-3-Clause, declared in the LICENSE file and referenced from pyproject.toml via license = { file = "LICENSE" }. BSD-3-Clause is permissive and permits commercial use, modification and redistribution provided the copyright notice and disclaimer are retained. That is a description of the licence text, not legal advice; if you are embedding DeepHyper in a product, have your own counsel read the LICENSE file.

Upgrade cost has two components. The dependency list in pyproject.toml is long and pins lower bounds rather than exact versions: ConfigSpace>=1.1.1, numpy>=1.26.0, scikit-learn>=0.23.1, scipy>=1.10, pydantic>=2.10, pymoo>=0.6.0, and others. Any of those moving underneath you is a potential source of behavior change. The optional extras add more surface: jax, torch, mpi4py and ray each have their own compatibility constraints, and a CUDA build of JAX is not something you want to rediscover during an upgrade. Pin the extras you install, not just deephyper itself.

## Conclusion

Adopt DeepHyper when you already have a Python objective function and you need many evaluations running at once on one machine or across nodes, and when you are willing to install the optional extras for the backend you actually use. Do not adopt it for a handful of sequential scikit-learn fits, and do not assume the process evaluator will scale to a cluster: the README's quickstart uses method="process" with num_workers=2, while mpi, ray and redis are separate optional dependency groups listed in pyproject.toml. Before committing, verify three things: that your Python version satisfies requires-python = ">=3.10", that the evaluator method you intend to use is the one your infrastructure supports, and that the search method you pick matches the multi-fidelity or multi-objective behavior you need, since the README only demonstrates CBO.

## FAQ

### What does DeepHyper do?

It is a Python hyperparameter optimization library. The README describes it as first and foremost an HPO library, with neural architecture search, multi-fidelity and ensemble capabilities built on that core, runnable on one machine or distributed across several.

### How do I install DeepHyper?

The README gives a single command, pip install deephyper, and points to the online installation documentation for more detail. Distributed backends such as MPI, Ray and Redis are separate optional extras declared in pyproject.toml.

### Does DeepHyper maximize or minimize the objective?

It maximizes. The README states that the CBO search finds values which MAXIMIZE the return value of run(job), so a loss you want to minimize has to be negated before it is returned.

### What Python version does DeepHyper require?

The pyproject.toml declares requires-python = ">=3.10" and lists classifiers for Python 3.10 through 3.14.

### What licence is DeepHyper released under?

BSD-3-Clause, declared in the LICENSE file and referenced from pyproject.toml. That is a permissive licence, but the repository does not offer legal advice about your use case.

## Sources

- [deephyper/deephyper on GitHub](https://github.com/deephyper/deephyper)
- [License: BSD-3-Clause](https://github.com/deephyper/deephyper/blob/master/LICENSE)
- [Project website](https://deephyper.readthedocs.io)
- [README](https://github.com/deephyper/deephyper/blob/master/README.md)
- [Releases](https://github.com/deephyper/deephyper/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/deephyper-deephyper
