Library / SDK
EmuKit/emukit avatar
EmuKit/emukit

Emukit: a model-agnostic toolkit for decision making under uncertainty

A Python-based toolbox of various methods in decision making, uncertainty quantification and statistical emulation: multi-fidelity, experimental design, Bayesian optimisation, Bayesian quadrature, etc.

675 stars135 forksPythonApache-2.0

At a glance

What is it?
Emukit packages multi-fidelity emulation, Bayesian optimisation, experimental design, sensitivity analysis and Bayesian quadrature behind a framework-agnostic interface. The catch is that its most-used acquisition functions still route through GPy, which lags NumPy 2.
Who is it for?
Adopt Emukit if you need multi-fidelity emulation or Bayesian quadrature alongside optimisation, and you are willing to pin a working NumPy and GPy combination. Do not adopt it if your only goal is single-fidelity hyperparameter tuning on a scikit-learn model, where the emukit[sklearn] extra plus an existing tuner is less machinery than you need.
Can I use it commercially?
Yes. Apache-2.0 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 16 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 September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Emukit targets: decisions when each data point is expensive

Emukit is aimed at a specific situation the README describes as complex systems where data is scarce or difficult to acquire. That framing matters, because it separates the library from general-purpose machine learning tooling. If your dataset already exists and fits in memory, the design loop Emukit builds around is overhead. If each observation costs a simulation run, a lab experiment, or a week of compute, then deciding where to sample next is the actual problem, and the model is only one component of it.

The audience is therefore narrower than the topic list suggests. Practitioners running physical experiments, tuning expensive simulation codes, or integrating expensive functions are the intended users. The README also names tuning parameters of machine learning algorithms as a Bayesian optimisation use case, but that is the crowded end of the market and not where the library's other components add anything.

The five advertised feature areas (multi-fidelity emulation, Bayesian optimisation, experimental design and active learning, sensitivity analysis, Bayesian quadrature) share one premise: a surrogate model stands in for something costly, and an acquisition rule decides what to evaluate next. Emukit supplies the second half of that pattern and lets you bring your own model for the first half.

The model-agnostic wrapper layer is the architectural bet

The design decision that shapes everything else is stated plainly in the README: Emukit is agnostic to the underlying modelling framework, so you can use any tool in the Python ecosystem to build the model and still use Emukit. Concretely, the library is split into model wrappers and the decision-making machinery that consumes them. The wrappers are packaged as optional extras precisely because they drag in third-party dependencies: emukit[gpy] adds GPy, emukit[bnn] adds pybnn and torch, emukit[sklearn] adds scikit-learn.

This is a real architectural commitment, not marketing. A core install pulls only NumPy, SciPy, matplotlib and emcee. The acquisition functions, multi-fidelity models and Bayesian quadrature code live behind the gpy extra. The Bayesian neural network meta-surrogates (Bohamiann, Profet) live behind bnn. That split means the decision logic is nominally reusable across model families, but in practice the GPy path is the one the majority of the library's functionality is wired against, since the README notes that most acquisition functions need GPy.

The consequence for anyone evaluating the framework-agnostic claim: it is true at the level of interfaces, and less true at the level of what is actually exercised. If you plan to plug in a non-GPy model, expect to write an adapter and to check which acquisition functions assume a Gaussian posterior.

Installing Emukit and choosing the right extras

The base install is a single command:

pip install emukit

The extras are where the real dependency decisions happen, and the README lists them explicitly:

pip install emukit[gpy] pip install emukit[bnn] pip install emukit[sklearn] pip install emukit[docs] pip install emukit[examples] pip install emukit[full]

The examples extra bundles GPy, pybnn, torch and scikit-learn for running most example scripts. The full extra adds docs and test tooling on top. The README states that legacy pinned requirement files remain in the requirements/ directory for reference, but that extras are the preferred installation mechanism going forward. If you are reproducing an older environment, those pinned files are the thing to read before assuming the extras resolve to the same versions.

For a first evaluation, emukit[gpy] plus emukit[sklearn] covers the widest surface without pulling torch. The tutorial notebooks are the documented starting point; the README points at the notebooks/index.ipynb index on nbviewer rather than describing a quickstart inline.

The GPy and NumPy 2 constraint is the first thing to verify

The README carries an explicit notice on this, and it is the most operationally important paragraph in the document. Core Emukit functionality works with NumPy 2.0 and above. However, some parts of Emukit, described as most acquisition functions, need GPy, which the README says is a bit behind on NumPy 2. The stated mitigation is to consider installing earlier versions of Emukit if GPy is essential to you.

Read that as a compatibility triangle rather than a bug. You are choosing among three things: a recent Emukit, a recent NumPy, and GPy-based acquisition functions. The README does not state which combination resolves cleanly, and I cannot confirm from the supplied material which GPy release, if any, closes the gap. That is the single item to test before you build anything on top.

The practical shape of the failure is a dependency resolution error or an import error at the point you construct an acquisition function, not a silent numerical problem. That is at least diagnosable. But it means the framework-agnostic pitch and the NumPy 2 support claim are in tension: the agnostic interfaces work, and the GPy-backed implementations of them are the part with the version ceiling.

Where Emukit is the wrong tool

Two cases stand out. The first is single-fidelity hyperparameter search on a model you already have. Emukit's Bayesian optimisation will do it, but the value it adds over a simpler tuner comes from the pieces around optimisation: multi-fidelity sources, quadrature, sensitivity analysis. If none of those are in play and you are not already invested in GPy, the extra dependency surface buys you nothing.

The second case is any workflow where you cannot tolerate the GPy ceiling. If your project is committed to NumPy 2 across the board and you need acquisition functions, the README's own advice points you backward to earlier Emukit releases. Running an older Emukit to satisfy a newer NumPy is a maintenance posture, not a stable one, and it should be a deliberate choice rather than something you discover after wiring the library into a pipeline.

A third, softer limitation: the README does not describe a serialisation format, a persistence layer, or a serving story. Emukit is a library you call inside a loop you control. If you need a managed optimisation service with a job queue, look elsewhere.

How Emukit differs from BoTorch and from a plain scikit-learn loop

BoTorch is the closest comparison in the Bayesian optimisation space, and the difference is in what the framework assumes about your model. BoTorch is built on PyTorch and its acquisition functions are written against PyTorch tensors and autograd, which makes custom acquisition functions and GPU execution natural but ties you to that stack. Emukit inverts this: the README's stated position is that you can use any modelling tool in the Python ecosystem, with GPy, pybnn/torch and scikit-learn wrappers shipped as optional extras. The cost of that flexibility is that Emukit does not give you a single tensor abstraction across all models, and the most complete code path is the GPy one rather than a neutral one.

Against a plain scikit-learn loop, the difference is scope rather than speed. A hand-rolled loop gives you a model, a fit call and an argmax over an acquisition score. Emukit adds multi-fidelity emulation, Bayesian quadrature and sensitivity analysis as first-class components, and it separates the model wrapper from the decision logic so the same loop can be pointed at a different surrogate. If your problem only ever has one fidelity level and one objective, that separation is structure you pay for without using.

Maintenance cost, release cadence and licence terms

The release history shows 0.5.1, 0.5.0 and 0.4.11, all dated 2026-02-22 in the supplied metadata, with the last push to main on 2026-08-30. The repository is not archived. Three releases landing on the same day suggests a batch publication rather than a steady drip, so do not read the version numbers as a signal about how quickly fixes arrive.

The upgrade cost is dominated by the dependency triangle rather than by Emukit's own API. Every time you move NumPy or GPy, you are re-testing the combination described in the NumPy 2 notice. The extras mechanism helps here: because gpy, bnn and sklearn are separable, a project that only needs the scikit-learn wrapper can avoid GPy entirely, at the cost of the acquisition functions that require it. Keep the requirements/ pinned files in mind as the reference point if you need to reconstruct an environment that predates the extras.

On licensing: Emukit is Apache-2.0, and the README directs readers to LICENSE and NOTICE for further information. Apache-2.0 is permissive and includes an explicit patent grant, but the NOTICE file exists for a reason and should be read before redistribution. If you vendor Emukit into a product, check what the NOTICE file requires you to carry forward. That is a question for your own legal review, not something the README answers.

Editorial conclusion

Adopt Emukit if you need multi-fidelity emulation or Bayesian quadrature alongside optimisation, and you are willing to pin a working NumPy and GPy combination. Do not adopt it if your only goal is single-fidelity hyperparameter tuning on a scikit-learn model, where the emukit[sklearn] extra plus an existing tuner is less machinery than you need. Before committing, run pip install emukit[gpy] on your target Python and NumPy version and confirm the acquisition functions you plan to use import cleanly, because the README states that GPy is behind on NumPy 2 and that earlier Emukit versions are the fallback if GPy is essential to you.

Official sources

  1. EmuKit/emukit on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes