Home

Awesome

<p align="center"> <a href="https://github.com/SimonBlanke/Hyperactive"><img src="./docs/images/logo.png" height="250"></a> </p> <br>
<h2 align="center">An optimization and data collection toolbox for convenient and fast prototyping of computationally expensive models.</h2> <br> <table> <tbody> <tr align="left" valign="center"> <td> <strong>Master status:</strong> </td> <td> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_ubuntu.yml/badge.svg?branch=master" alt="img not loaded: try F5 :)"> </a> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_windows.yml/badge.svg?branch=master" alt="img not loaded: try F5 :)"> </a> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_macos.yml/badge.svg?branch=master" alt="img not loaded: try F5 :)"> </a> <a href="https://app.codecov.io/gh/SimonBlanke/Hyperactive"> <img src="https://img.shields.io/codecov/c/github/SimonBlanke/Hyperactive/master" alt="img not loaded: try F5 :)"> </a> </td> </tr> <tr align="left" valign="center"> <td> <strong>Dev status:</strong> </td> <td> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_ubuntu.yml/badge.svg?branch=dev" alt="img not loaded: try F5 :)"> </a> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_windows.yml/badge.svg?branch=dev" alt="img not loaded: try F5 :)"> </a> <a href="https://github.com/SimonBlanke/Hyperactive/actions"> <img src="https://github.com/SimonBlanke/Hyperactive/actions/workflows/tests_macos.yml/badge.svg?branch=dev" alt="img not loaded: try F5 :)"> </a> <a href="https://app.codecov.io/gh/SimonBlanke/Hyperactive"> <img src="https://img.shields.io/codecov/c/github/SimonBlanke/Hyperactive/dev" alt="img not loaded: try F5 :)"> </a> </td> </tr> <tr align="left" valign="center"> <td> <strong>Code quality:</strong> </td> <td> <a href="https://codeclimate.com/github/SimonBlanke/Hyperactive"> <img src="https://img.shields.io/codeclimate/maintainability/SimonBlanke/Hyperactive?style=flat-square&logo=code-climate" alt="img not loaded: try F5 :)"> </a> <a href="https://scrutinizer-ci.com/g/SimonBlanke/Hyperactive/"> <img src="https://img.shields.io/scrutinizer/quality/g/SimonBlanke/Hyperactive?style=flat-square&logo=scrutinizer-ci" alt="img not loaded: try F5 :)"> </a> </td> </tr> <tr align="left" valign="center"> <td> <strong>Latest versions:</strong> </td> <td> <a href="https://pypi.org/project/gradient_free_optimizers/"> <img src="https://img.shields.io/pypi/v/Hyperactive?style=flat-square&logo=PyPi&logoColor=white&color=blue" alt="img not loaded: try F5 :)"> </a> </td> </tr> </tbody> </table> <br> <img src="./docs/images/bayes_convex.gif" align="right" width="500">

Hyperactive:

<br> <br> <br>

As its name suggests Hyperactive started as a hyperparameter optimization package, but it has been generalized to solve expensive gradient-free optimization problems. It uses the Gradient-Free-Optimizers package as an optimization-backend and expands on it with additional features and tools.

<br>
<div align="center"><a name="menu"></a> <h3> <a href="https://github.com/SimonBlanke/Hyperactive#overview">Overview</a> • <a href="https://github.com/SimonBlanke/Hyperactive#installation">Installation</a> • <a href="https://simonblanke.github.io/hyperactive-documentation/4.5/">API reference</a> • <a href="https://github.com/SimonBlanke/Hyperactive#roadmap">Roadmap</a> • <a href="https://github.com/SimonBlanke/Hyperactive#citing-hyperactive">Citation</a> • <a href="https://github.com/SimonBlanke/Hyperactive#license">License</a> </h3> </div>
<br>

Overview

<h3 align="center"> Hyperactive features a collection of optimization algorithms that can be used for a variety of optimization problems. The following table shows examples of its capabilities: </h3> <br> <table> <tbody> <tr align="center" valign="center"> <td> <strong>Optimization Techniques</strong> <img src="./docs/images/blue.jpg"/> </td> <td> <strong>Tested and Supported Packages</strong> <img src="./docs/images/blue.jpg"/> </td> <td> <strong>Optimization Applications</strong> <img src="./docs/images/blue.jpg"/> </td> </tr> <tr/> <tr valign="top"> <td> <a><b>Local Search:</b></a> <ul> <li><a href="./examples/optimization_techniques/hill_climbing.py">Hill Climbing</a></li> <li><a href="./examples/optimization_techniques/repulsing_hill_climbing.py">Repulsing Hill Climbing</a></li> <li><a href="./examples/optimization_techniques/simulated_annealing.py">Simulated Annealing</a></li> <li><a href="./examples/optimization_techniques/downhill_simplex.py">Downhill Simplex Optimizer</a></li> </ul><br> <a><b>Global Search:</b></a> <ul> <li><a href="./examples/optimization_techniques/random_search.py">Random Search</a></li> <li><a href="./examples/optimization_techniques/grid_search.py">Grid Search</a></li> <li><a href="./examples/optimization_techniques/rand_rest_hill_climbing.py">Random Restart Hill Climbing</a></li> <li><a href="./examples/optimization_techniques/random_annealing.py">Random Annealing</a> [<a href="#/./overview#experimental-algorithms">*</a>] </li> <li><a href="./examples/optimization_techniques/pattern_search.py">Powell's Method</a></li> <li><a href="./examples/optimization_techniques/powells_method.py">Pattern Search</a></li> </ul><br> <a><b>Population Methods:</b></a> <ul> <li><a href="./examples/optimization_techniques/parallel_tempering.py">Parallel Tempering</a></li> <li><a href="./examples/optimization_techniques/particle_swarm_optimization.py">Particle Swarm Optimizer</li> <li><a href="./examples/optimization_techniques/spiral_optimization.py">Spiral Optimization</li> <li>Genetic Algorithm</a></li> <li><a href="./examples/optimization_techniques/evolution_strategy.py">Evolution Strategy</a></li> <li>Differential Evolution</a></li> </ul><br> <a><b>Sequential Methods:</b></a> <ul> <li><a href="./examples/optimization_techniques/bayesian_optimization.py">Bayesian Optimization</a></li> <li><a href="./examples/optimization_techniques/lipschitz_optimization.py">Lipschitz Optimization</a></li> <li><a href="./examples/optimization_techniques/direct_algorithm.py">Direct Algorithm</a></li> <li><a href="./examples/optimization_techniques/tpe.py">Tree of Parzen Estimators</a></li> <li><a href="./examples/optimization_techniques/forest_optimization.py">Forest Optimizer</a> [<a href="#/./overview#references">dto</a>] </li> </ul> </td> <td> <a><b>Machine Learning:</b></a> <ul> <li><a href="./examples/tested_and_supported_packages/sklearn_example.py">Scikit-learn</a></li> <li><a href="./examples/tested_and_supported_packages/xgboost_example.py">XGBoost</a></li> <li><a href="./examples/tested_and_supported_packages/lightgbm_example.py">LightGBM</a></li> <li><a href="./examples/tested_and_supported_packages/catboost_example.py">CatBoost</a></li> <li><a href="./examples/tested_and_supported_packages/rgf_example.py">RGF</a></li> <li><a href="./examples/tested_and_supported_packages/mlxtend_example.py">Mlxtend</a></li> </ul><br> <a><b>Deep Learning:</b></a> <ul> <li><a href="./examples/tested_and_supported_packages/tensorflow_example.py">Tensorflow</a></li> <li><a href="./examples/tested_and_supported_packages/keras_example.py">Keras</a></li> <li><a href="./examples/tested_and_supported_packages/pytorch_example.py">Pytorch</a></li> </ul><br> <a><b>Parallel Computing:</b></a> <ul> <li><a href="./examples/tested_and_supported_packages/multiprocessing_example.py">Multiprocessing</a></li> <li><a href="./examples/tested_and_supported_packages/joblib_example.py">Joblib</a></li> <li>Pathos</li> </ul> </td> <td> <a><b>Feature Engineering:</b></a> <ul> <li><a href="./examples/optimization_applications/feature_transformation.py">Feature Transformation</a></li> <li><a href="./examples/optimization_applications/feature_selection.py">Feature Selection</a></li> </ul> <a><b>Machine Learning:</b></a> <ul> <li><a href="./examples/optimization_applications/hyperpara_optimize.py">Hyperparameter Tuning</a></li> <li><a href="./examples/optimization_applications/model_selection.py">Model Selection</a></li> <li><a href="./examples/optimization_applications/sklearn_pipeline_example.py">Sklearn Pipelines</a></li> <li><a href="./examples/optimization_applications/ensemble_learning_example.py">Ensemble Learning</a></li> </ul> <a><b>Deep Learning:</b></a> <ul> <li><a href="./examples/optimization_applications/neural_architecture_search.py">Neural Architecture Search</a></li> <li><a href="./examples/optimization_applications/pretrained_nas.py">Pretrained Neural Architecture Search</a></li> <li><a href="./examples/optimization_applications/transfer_learning.py">Transfer Learning</a></li> </ul> <a><b>Data Collection:</b></a> <ul> <li><a href="./examples/optimization_applications/meta_data_collection.py">Search Data Collection</a></li> <li><a href="./examples/optimization_applications/meta_optimization.py">Meta Optimization</a></li> <li><a href="./examples/optimization_applications/meta_learning.py">Meta Learning</a></li> </ul> <a><b>Miscellaneous:</b></a> <ul> <li><a href="./examples/optimization_applications/test_function.py">Test Functions</a></li> <li>Fit Gaussian Curves</li> <li><a href="./examples/optimization_applications/multiple_scores.py">Managing multiple objectives</a></li> <li><a href="./examples/optimization_applications/search_space_example.py">Managing objects in search space</a></li> <li><a href="./examples/optimization_applications/constrained_optimization.py">Constrained Optimization</a></li> <li><a href="./examples/optimization_applications/memory.py">Memorize evaluations</a></li> </ul> </td> </tr> </tbody> </table>

The examples above are not necessarily done with realistic datasets or training procedures. The purpose is fast execution of the solution proposal and giving the user ideas for interesting usecases.

<br>

Sideprojects and Tools

The following packages are designed to support Hyperactive and expand its use cases.

PackageDescription
Search-Data-CollectorSimple tool to save search-data during or after the optimization run into csv-files.
Search-Data-ExplorerVisualize search-data with plotly inside a streamlit dashboard.

If you want news about Hyperactive and related projects you can follow me on twitter.

<br>

Notebooks and Tutorials

<br>

Installation

The most recent version of Hyperactive is available on PyPi:

pyversions PyPI version PyPI version

pip install hyperactive
<br>

Example

from sklearn.model_selection import cross_val_score
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.datasets import load_diabetes
from hyperactive import Hyperactive

data = load_diabetes()
X, y = data.data, data.target

# define the model in a function
def model(opt):
    # pass the suggested parameter to the machine learning model
    gbr = GradientBoostingRegressor(
        n_estimators=opt["n_estimators"], max_depth=opt["max_depth"]
    )
    scores = cross_val_score(gbr, X, y, cv=4)

    # return a single numerical value
    return scores.mean()

# search space determines the ranges of parameters you want the optimizer to search through
search_space = {
    "n_estimators": list(range(10, 150, 5)),
    "max_depth": list(range(2, 12)),
}

# start the optimization run
hyper = Hyperactive()
hyper.add_search(model, search_space, n_iter=50)
hyper.run()

<br>

Hyperactive API reference

<br>

Basic Usage

<details> <summary><b> Hyperactive(verbosity, distribution, n_processes)</b></summary> </details> <details> <summary><b> .add_search(objective_function, search_space, n_iter, optimizer, n_jobs, initialize, pass_through, callbacks, catch, max_score, early_stopping, random_state, memory, memory_warm_start)</b></summary> </details> <details> <summary><b> .run(max_time)</b></summary> </details> <br>

Special Parameters

<details> <summary><b> Objective Function</b></summary>

Each iteration consists of two steps:

The objective function has one argument that is often called "para", "params", "opt" or "access". This argument is your access to the parameter set that the optimizer has selected in the corresponding iteration.

def objective_function(opt):
    # get x1 and x2 from the argument "opt"
    x1 = opt["x1"]
    x2 = opt["x2"]

    # calculate the score with the parameter set
    score = -(x1 * x1 + x2 * x2)

    # return the score
    return score

The objective function always needs a score, which shows how "good" or "bad" the current parameter set is. But you can also return some additional information with a dictionary:

def objective_function(opt):
    x1 = opt["x1"]
    x2 = opt["x2"]

    score = -(x1 * x1 + x2 * x2)

    other_info = {
      "x1 squared" : x1**2,
      "x2 squared" : x2**2,
    }

    return score, other_info

When you take a look at the results (a pandas dataframe with all iteration information) after the run has ended you will see the additional information in it. The reason we need a dictionary for this is because Hyperactive needs to know the names of the additonal parameters. The score does not need that, because it is always called "score" in the results. You can run this example script if you want to give it a try.

</details> <details> <summary><b> Search Space Dictionary</b></summary>

The search space defines what values the optimizer can select during the search. These selected values will be inside the objective function argument and can be accessed like in a dictionary. The values in each search space dimension should always be in a list. If you use np.arange you should put it in a list afterwards:

search_space = {
    "x1": list(np.arange(-100, 101, 1)),
    "x2": list(np.arange(-100, 101, 1)),
}

A special feature of Hyperactive is shown in the next example. You can put not just numeric values into the search space dimensions, but also strings and functions. This enables a very high flexibility in how you can create your studies.

def func1():
  # do stuff
  return stuff
  

def func2():
  # do stuff
  return stuff


search_space = {
    "x": list(np.arange(-100, 101, 1)),
    "str": ["a string", "another string"],
    "function" : [func1, func2],
}

If you want to put other types of variables (like numpy arrays, pandas dataframes, lists, ...) into the search space you can do that via functions:

def array1():
  return np.array([1, 2, 3])
  

def array2():
  return np.array([3, 2, 1])


search_space = {
    "x": list(np.arange(-100, 101, 1)),
    "str": ["a string", "another string"],
    "numpy_array" : [array1, array2],
}

The functions contain the numpy arrays and returns them. This way you can use them inside the objective function.

</details> <details> <summary><b> Optimizer Classes</b></summary>

Each of the following optimizer classes can be initialized and passed to the "add_search"-method via the "optimizer"-argument. During this initialization the optimizer class accepts only optimizer-specific-paramters (no random_state, initialize, ... ):

optimizer = HillClimbingOptimizer(epsilon=0.1, distribution="laplace", n_neighbours=4)

for the default parameters you can just write:

optimizer = HillClimbingOptimizer()

and pass it to Hyperactive:

hyper = Hyperactive()
hyper.add_search(model, search_space, optimizer=optimizer, n_iter=100)
hyper.run()

So the optimizer-classes are different from Gradient-Free-Optimizers. A more detailed explanation of the optimization-algorithms and the optimizer-specific-paramters can be found in the Optimization Tutorial.

</details> <br>

Result Attributes

<details> <summary><b> .best_para(objective_function)</b></summary> </details> <details> <summary><b> .best_score(objective_function)</b></summary> </details> <details> <summary><b> .search_data(objective_function, times=False)</b></summary> </details> <br>

Roadmap

<details> <summary><b>v2.0.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v2.1.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v2.2.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v2.3.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v3.0.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v3.1.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v3.2.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v3.3.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.0.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.1.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.2.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.3.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.4.0</b> :heavy_check_mark: </summary> </details> <details> <summary><b>v4.5.0</b> :heavy_check_mark: </summary> </details> <details> <summary><b>v4.6.0</b> :heavy_check_mark: </summary> </details> <details> <summary><b>v4.7.0</b> :heavy_check_mark: </summary> </details> <details> <summary><b>v4.8.0</b> :heavy_check_mark:</summary> </details> <details> <summary><b>v4.9.0</b> </summary> </details> <details> <summary><b>Future releases</b> </summary> </details> <br>

FAQ

Known Errors + Solutions

<details> <summary><b> Read this before opening a bug-issue </b></summary> <br> </details> <details> <summary> MemoryError: Unable to allocate ... for an array with shape (...) </summary> <br>

This is expected of the current implementation of smb-optimizers. For all Sequential model based algorithms you have to keep your eyes on the search space size:

search_space_size = 1
for value_ in search_space.values():
    search_space_size *= len(value_)
    
print("search_space_size", search_space_size)

Reduce the search space size to resolve this error.

</details> <details> <summary> TypeError: cannot pickle '_thread.RLock' object </summary> <br>

This is because you have classes and/or non-top-level objects in the search space. Pickle (used by multiprocessing) cannot serialize them. Setting distribution to "joblib" or "pathos" may fix this problem:

hyper = Hyperactive(distribution="joblib")
</details> <details> <summary> Command line full of warnings </summary> <br>

Very often warnings from sklearn or numpy. Those warnings do not correlate with bad performance from Hyperactive. Your code will most likely run fine. Those warnings are very difficult to silence.

It should help to put this at the very top of your script:

def warn(*args, **kwargs):
    pass


import warnings

warnings.warn = warn
</details> <details> <summary> Warning: Not enough initial positions for population size </summary> <br>

This warning occurs because Hyperactive needs more initial positions to choose from to generate a population for the optimization algorithm: The number of initial positions is determined by the initialize-parameter in the add_search-method.

# This is how it looks per default
initialize = {"grid": 4, "random": 2, "vertices": 4}
  
# You could set it to this for a maximum population of 20
initialize = {"grid": 4, "random": 12, "vertices": 4}
</details> <br>

References

[dto] Scikit-Optimize

<br>

Citing Hyperactive

@Misc{hyperactive2021,
  author =   {{Simon Blanke}},
  title =    {{Hyperactive}: An optimization and data collection toolbox for convenient and fast prototyping of computationally expensive models.},
  howpublished = {\url{https://github.com/SimonBlanke}},
  year = {since 2019}
}
<br>

License

LICENSE