Library / SDK
hyperopt/hyperopt avatar
hyperopt/hyperopt

Hyperopt: hyperparameter search spaces with conditionals, run in serial or parallel

Distributed Asynchronous Hyperparameter Optimization in Python

7,596 stars1,076 forksPythonNOASSERTION

At a glance

What is it?
A Python library for serial and parallel optimization over awkward search spaces that include real valued, discrete and conditional dimensions, with TPE, random search, and Spark or MongoDB for distributed evaluation.
Who is it for?
Hyperopt earns its place when your search space genuinely branches, because expressing a dimension that only exists when another one takes a certain value is the thing it does better than a flat grid or a sampler that assumes fixed parameters. It is a poor fit if you want a modern, actively developed tuning framework with a growing sampler library, since version 0.3.0, published 2026-07-24, was the first release since 2021 and the package itself is still classified as alpha.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 14, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Search spaces that can contain conditionals

The README describes Hyperopt as a library for serial and parallel optimization over awkward search spaces, which may include real-valued, discrete and conditional dimensions. That word awkward is doing real work. Most tuning APIs assume your parameter set is fixed: the same keys exist whether you are training on one dataset or another. Hyperopt's space description is a program, so a dimension can be conditional on the value of another one, and the search only ever sees points that are actually valid.

The example in the README makes the shape concrete. A space is built with `hp.choice` over a list of cases, each case pairing a label with its own parameters, one of which is a lognormal draw and the other a uniform draw over a range. Because the two cases carry different labels, an optimizer that lands in one of them needs to know which parameters exist, which is what `space_eval` is for: it turns the best result dictionary back into the tuple the space describes.

The distinction matters for real models. If switching to a convolutional architecture disables a learning rate parameter entirely, or a dropout rate only exists when a flag is set, a flat parameter vector either carries dead entries or silently ignores them. That is the class of problem this library was built for.

The fmin example, line by line

Install comes from PyPI, and the README gives both pip and uv paths:

bash
pip install hyperopt
# or with uv
uv add hyperopt

The tutorial example is short enough to read as the whole API. The objective takes a single argument and unpacks a case label and a value, returning either the value directly or its square, so the surface is genuinely minimal. Minimizing it is one call:

python
from hyperopt import fmin, tpe, space_eval
best = fmin(objective, space, algo=tpe.suggest, max_evals=100)

print(best)
print(space_eval(space, best))

Three parameters carry the weight. `algo` selects the search strategy, here `tpe.suggest`. `max_evals` is the budget, here 100, and it is the number of evaluations rather than a time limit or a convergence criterion, which means you are choosing the wall clock budget implicitly by how expensive one evaluation is. And the return value is a dict, so you print it and then convert it back through `space_eval` to get the value your objective actually saw.

That last detail is the one that trips people up when adapting the example. `best` contains the internal labels, and the commented output in the README shows the value differing slightly from the printed sample, because each run samples new points. Treat the printed numbers as an illustration of the shape, not a result.

Random search, TPE and adaptive TPE

Three algorithms are implemented, and the README is candid that the set is small. Random Search is the baseline, cited to the JMLR paper. Tree of Parzen Estimators, cited to the NIPS paper, is the default choice in practice. Adaptive TPE is a variant of TPE.

What is not implemented matters just as much. The README states that Hyperopt has been designed to accommodate Bayesian optimization algorithms based on Gaussian processes and regression trees, but that these are not currently implemented. That is the honest boundary of the project: the architecture was meant to hold more samplers than it ships, and after a long gap between releases it still ships three. The `hyperopt-gpsmso` link in the related projects section exists because the Gaussian process sampler lives outside the core library.

The practical consequence is that choosing Hyperopt means choosing TPE or random search. If your tuning problem needs an ensemble of samplers, or a specific acquisition function you have read about, or a default-constructed study with good Bayesian behaviour out of the box, this library will not grow into that while you wait. Related projects fill some gaps: hyperopt-sklearn wraps it for scikit-learn estimators, hyperas adapts it to Keras, and hyperopt-convent targets convolutional networks.

Parallelizing through Spark, MongoDB and the extras system

Hyperopt is distributed asynchronous optimization, and the README names the two mechanisms: Apache Spark and MongoDB. The design is straightforward in principle, since a trials backend records every evaluation centrally while workers pull the next suggestion, so you can scale evaluation across machines that do not share memory.

The mechanism is selected through packaging extras rather than being on by default, which is the right call given the dependency weight. The extras are named `SparkTrials`, `MongoTrials` and `ATPE`, and pyproject.toml spells out what each pulls in:

toml
SparkTrials = ["pyspark", "py4j"]
MongoTrials = ["pymongo>=4.0.0"]
ATPE = ["lightgbm", "scikit-learn"]

That third extra is the one to notice. Adaptive TPE needs LightGBM, because it fits a gradient boosted model to the observed trials, so installing it means taking on a tree library as well as scikit-learn. Spark users should note the 0.3.0 change requiring py4j only for Spark, which came alongside unpinned pyspark in CI and the removal of Travis, so the Spark path is maintained but no longer carries a pinned version in its own test matrix.

Version 0.3.0-pre on 2026-07-15 was explicitly released as a non-production release with a promise of a production follow-up, and 0.3.0 landed on 2026-07-24. Both notes open by saying a lot has changed since the last release in 2021, including the release process itself and many dependencies, and that the main user-facing change is improved compatibility with modern numpy.

Packaging, Python floor, and a documentation split

The build moved to hatchling with hatch-vcs, so the version is derived from tags rather than written by hand, and the core dependencies are numpy, scipy, networkx, tqdm and cloudpickle. That is a modest dependency list, and the presence of cloudpickle is the tell for how parallel evaluation works: your objective function has to be serializable to be sent to a worker.

pyproject.toml requires Python 3.10 or newer, and the 0.3.0 release notes say Hyperopt is now only tested with Python versions at or above 3.10. The classifier list in the same file still mentions Python 3.8 and 3.9, which is a leftover rather than a real supported version. Treat 3.10 as the real floor and ignore the classifiers. The package metadata also classifies hyperopt as Development Status 3 - Alpha, which is a more reliable signal of maturity than the release number suggests.

Documentation is the weakest part of the project and the README says so itself, noting that the documentation can be found at hyperopt.github.io but is partly still hosted on the wiki. The three quick links it gives are the fmin tutorial, installation notes and the MongoDB parallelization page, all on the wiki. So a reader has to move between a docs site and a wiki, and the wiki pages are the older ones. The repository tree reflects the same split, with `docs/`, `tutorial/` and `noxfile.py` alongside the `hyperopt/` package, and the contributing instructions show a uv-based workflow with nox for testing across Python versions.

When Hyperopt is the wrong choice

There are three reasonable reasons to pick something else, and they are not all about features.

The first is maturity and sampler breadth. If you want a tuning framework that has gained new algorithms steadily over the last few years, and one where the default experience is already Bayesian rather than random, a newer tool will get you there with less assembly. Hyperopt's own metadata calls it alpha, and its three samplers have been the same set for years.

The second is the parameter-shape mismatch. If your parameters are flat and numeric, Hyperopt's conditional spaces buy you nothing, and you pay for the abstraction. Random search alone, or a plain grid, will serve you fine and has fewer moving parts.

The third is operational. The MongoDB path requires a running MongoDB instance and the Spark path requires a Spark cluster, which for a small tuning job is a lot of infrastructure to stand up for what amounts to a few hundred model fits. If your evaluations are slow and you have many of them, that infrastructure may pay for itself, and the design is genuinely built for it. If your evaluations take seconds, running them in a loop is the sensible thing and the distributed backends are pure overhead.

None of that makes Hyperopt a bad choice. It makes it a specific answer to a specific shape of problem: awkward, conditional, expensive spaces where the number of evaluations you can afford is small.

Editorial conclusion

Hyperopt earns its place when your search space genuinely branches, because expressing a dimension that only exists when another one takes a certain value is the thing it does better than a flat grid or a sampler that assumes fixed parameters. It is a poor fit if you want a modern, actively developed tuning framework with a growing sampler library, since version 0.3.0, published 2026-07-24, was the first release since 2021 and the package itself is still classified as alpha. Start with the README's fmin example to confirm the API works in your environment, then read the tutorial wiki page for anything past the basics, because the documentation is split between a docs site and a set of wiki pages. Before committing to it, verify the Python floor, because pyproject.toml requires 3.10 or newer while its own classifier list still mentions 3.8 and 3.9.

Frequently asked questions

What are the key differences between Optuna and Hyperopt in Python?

Hyperopt describes the search space as a program using functions such as hp.choice, so dimensions can be conditional on each other, and it ships three algorithms: random search, TPE and adaptive TPE. Optuna, by contrast, presents the search space as a declarative object built from suggest calls inside the objective. Hyperopt's README also notes that Gaussian process and regression tree samplers were designed for but not implemented, which bounds how many algorithms you can choose from.

How do I install Hyperopt and run a first search?

Install it from PyPI with `pip install hyperopt`, or add it with uv using `uv add hyperopt`. Then call `fmin(objective, space, algo=tpe.suggest, max_evals=100)` to minimize your objective over the space, where max_evals is the number of evaluations rather than a time limit.

How do I run Hyperopt searches in parallel?

Through a trials backend, selected with packaging extras. `SparkTrials` pulls in pyspark and py4j, `MongoTrials` pulls in pymongo 4.0 or newer, and both backends let workers pull the next suggestion from a shared record of past evaluations rather than sharing memory.

What is the current Hyperopt release and what Python version does it need?

Version 0.3.0, published 2026-07-24, after a pre-release on 2026-07-15 and a gap since 2021. pyproject.toml sets requires-python to 3.10 or newer and the release notes say the project is only tested on 3.10 and above, although older Python versions still appear in the classifier list.

What licence is Hyperopt released under?

pyproject.toml declares the project licence as BSD-3-Clause and the repository carries a LICENSE.txt file. The version is derived from git tags using hatch-vcs rather than hard-coded.

Official sources

  1. hyperopt/hyperopt on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hyperopt-hyperopt.svg)](https://hysenlabs.com/projects/hyperopt-hyperopt)