Open-source project
hyperactive-project/Hyperactive avatar
hyperactive-project/Hyperactive

Hyperactive: one experiment object, 31 optimizers behind it

A unified interface for optimization algorithms and experiments

549 stars73 forksPythonMIT

At a glance

What is it?
Hyperactive wraps GFO, Optuna and scikit-learn search methods behind a single experiment-based API so you can swap optimizers without rewriting your objective. The abstraction is the product here, and it is also where the sharp edges are.
Who is it for?
Adopt Hyperactive if you already have several optimizers in play and want one objective function plus one search space dict to serve all of them, or if you want GFO's algorithm set without adopting a second API. Do not adopt it if you need custom samplers, distributed multi-machine search, or a scheduler you control, since the README does not describe any of those.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day 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 September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem is optimizer lock-in, not missing algorithms

Most tuning code is written against one library. You pick Optuna, you write study.optimize, and your objective function grows a trial argument that only Optuna understands. Two years later a paper describes a method you want to try, and trying it means rewriting the objective, the search space definition, and the result handling. Hyperactive's answer is to invert that: the README states the library "separates optimization problems from algorithms, enabling you to swap optimizers without changing your experiment code." The target reader is someone running model selection or hyperparameter tuning who wants to compare search strategies rather than commit to one. The README names hyperparameter tuning, model selection and black-box optimization as the intended uses, with native integrations for scikit-learn, sktime, skpro and PyTorch. That list matters, because a generic optimizer interface with no framework hooks is a toy. The integration packages are shipped as extras rather than pulled in by default, which keeps a plain pip install hyperactive light.

What the experiment abstraction actually holds

The README's diagram shows the data flow in three blocks. On the left is your code: a function def objective(params): return score, and a search space dict such as {'x': np.arange(...), 'y': [1, 2, 3]}. In the middle is an Optimizer object that dispatches to one of the backends. On the right is a single value, best_params. Everything the library does sits between those two ends. The search space is expressed in plain NumPy arrays and Python lists, which the README describes as supporting discrete, continuous and mixed parameter types. That is a deliberate simplification: there is no separate parameter-type class hierarchy to learn, and no distribution objects to import. The cost is that you describe a space by enumerating values rather than by declaring a distribution, so a continuous range becomes np.arange(-5, 5, 0.1) with a fixed step rather than a float distribution with bounds. For hyperparameter tuning that is usually fine. For high-dimensional continuous search it is a real constraint, since the granularity of the grid is now your decision, not the sampler's. The objective function is equally plain. It receives a params mapping and returns a score, and the README's example uses a negated paraboloid so that maximization finds the minimum. That sign convention is the kind of detail that bites people, and the example is honest about it.

Three backends, and what the split implies

The library exposes 31 algorithms across three backends. GFO contributes 21, Optuna contributes 8, and scikit-learn contributes 2, according to the README's own counts and its diagram. The README also lists the algorithm families as local, global, population-based and model-based methods. The import path in the Quick Start is the tell for how this is organized: from hyperactive.opt.gfo import HillClimbing. The backend is a namespace under hyperactive.opt, so an Optuna sampler and a GFO algorithm are siblings in the module tree even though they share almost nothing underneath. This is the design that makes swapping cheap and also the design that caps what you can do. A unified interface can only expose the intersection of what its backends support. If a backend has a feature the others lack, either the interface grows a backend-specific escape hatch or the feature stays unreachable. The README does not describe such escape hatches, so treat the 31 algorithms as 31 configurations of a common contract rather than 31 fully featured tools. The diagram's "... more to come" node under Backends suggests the set is expected to grow, which cuts both ways: more coverage, and more surface for the common contract to strain against.

Getting it running, and the extras you will probably need

The base install is one line: pip install hyperactive. Three optional extras are documented. pip install hyperactive[sklearn-integration] adds the scikit-learn integration, pip install hyperactive[sktime-integration] adds sktime and skpro, and pip install hyperactive[all_extras] pulls in everything including Optuna. Note the naming asymmetry: the Optuna backend has no dedicated extra, so if you want those 8 algorithms you either take all_extras or install Optuna yourself. The Quick Start is short enough to reproduce in full. You define objective, build search_space with np.arange calls, then construct HillClimbing(search_space=search_space, n_iter=100, experiment=objective) and call optimizer.solve(). The README shows the printed result as {'x': 0.0, 'y': 0.0} for a paraboloid whose optimum is at the origin. Two constructor arguments are doing the work here: n_iter caps the budget, and experiment is the name the library gives to the objective you pass in. That keyword is worth remembering, because it is the seam the abstraction is built around. If you are migrating existing tuning code, the mechanical change is renaming your objective's parameter handling to accept a params dict and moving your search space into the dict form the README shows.

The abstraction tax, and when it makes Hyperactive the wrong pick

A common interface over three backends has to normalize their differences, and normalization loses information. The clearest case is the search space. Optuna's own API is built around suggest_float, suggest_int and suggest_categorical calls made inside the objective, which lets the sampler adapt its proposal distribution as the study progresses. Hyperactive's search space is declared up front as arrays and lists. Declaring it up front is what makes the space portable across backends, and it is also what prevents a backend from doing anything the declared representation cannot express. If your work depends on conditional or nested search spaces, where the presence of one parameter depends on the value of another, the README does not describe support for that, and the flat dict example suggests it is not the model. The second gap is scale. The README's topics list includes parallel-computing, but the documented Quick Start runs a single optimizer with n_iter=100 and returns best_params. There is no described mechanism for coordinating workers across machines, no storage URL, no study database. If you need a shared study that several processes or several people append to, that is Optuna's territory and Hyperactive's uniform contract is not obviously the right layer for it. The third gap is budget control. n_iter is a fixed count. The README does not describe time-based stopping, early termination callbacks, or pruning of unpromising trials, which are standard in the tuning libraries this wraps.

Optuna is the alternative, and the difference is where the search space lives

The honest comparison is with Optuna used directly, since Optuna is one of Hyperactive's own backends. In Optuna, the search space lives inside the objective function as suggest_* calls, and the study object owns the trial history, the sampler, the pruner and the storage backend. That arrangement gives you pruning, distributed studies via a storage URL, and per-trial control over what gets proposed. In Hyperactive, the search space is a data structure you pass to the optimizer, and the objective is a function of a params dict with no knowledge of trials at all. That is the actual difference in approach: Hyperactive treats the space as data and the objective as a pure function, Optuna treats the objective as a program that queries a study. The data-and-pure-function model is what makes swapping to HillClimbing or to a scikit-learn search method a one-line change. It is also what makes conditional spaces and adaptive pruning hard to express. If your tuning is a fixed grid of independent parameters and you want to try several search strategies, Hyperactive's model fits better. If your tuning is a long-running study with pruning and shared state, Optuna's model fits better, and you would be using Hyperactive to reach a subset of Optuna through an extra layer.

Maintenance, licence and what to check before adopting

The project is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is the standard permissive arrangement; it is not legal advice, and if you are embedding the library in a distributed product you should read the LICENSE file in the repository rather than this summary. On maintenance, the release history shows v5.0.2 in September 2025, v5.0.3 in December 2025 and v5.0.4 in March 2026, with the last push to the default branch in August 2026. The README claims active maintenance since 2019 and 5+ years of development. Three patch releases inside roughly six months is a steady cadence, and the version numbering says the project is on its fifth major line, which means the API has broken across majors before. Pin your version. The upgrade cost is concentrated in two places: the optimizer constructor signatures, which is where n_iter, search_space and experiment live, and the backend import paths under hyperactive.opt. Both are visible in the Quick Start, so a version bump that touches either will show up immediately in that example. Run it against your pinned version before upgrading.

Editorial conclusion

Adopt Hyperactive if you already have several optimizers in play and want one objective function plus one search space dict to serve all of them, or if you want GFO's algorithm set without adopting a second API. Do not adopt it if you need custom samplers, distributed multi-machine search, or a scheduler you control, since the README does not describe any of those. Before you commit, install with pip install hyperactive[all_extras], reproduce the HillClimbing example in the Quick Start, then swap the optimizer class for an Optuna-backed one and confirm that your objective function runs unchanged. That single swap is the whole value proposition, and it is the first thing worth verifying.

Official sources

  1. hyperactive-project/Hyperactive on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes