Introduction
Data scientists often struggle with the computational bottleneck of Bayesian inference, where sampling from complex posterior distributions can take hours or even days. NumPyro is a probabilistic programming library that solves this by leveraging JAX for automatic differentiation and just-in-time (JIT) compilation, enabling massive speedups on CPU, GPU, and TPU. With over 2.7k GitHub stars, it provides a high-performance alternative to traditional PPLs, allowing researchers to iterate on complex models faster than ever before.
What Is NumPyro?
NumPyro is a lightweight probabilistic programming library that provides a NumPy backend for Pyro, powered by JAX for autograd and JIT compilation to GPU/TPU/CPU. It is designed to be a flexible substrate for building probabilistic models, allowing users to combine regular Python and NumPy code with Pyro primitives like sample and param. Licensed under the Apache License 2.0, NumPyro is an open-source project that focuses on providing a high-performance, functional approach to Bayesian modeling.
Why NumPyro Matters
Traditional Bayesian tools often suffer from the “Bayesian is slow” stigma. NumPyro changes this narrative by utilizing XLA (Accelerated Linear Algebra) compilation via JAX. By JIT-compiling the entire integration step of the No-U-Turn Sampler (NUTS), NumPyro eliminates Python overhead and optimizes the kernel for the target hardware. This results in sampling speeds that can be 100x faster than traditional implementations of Hamiltonian Monte Carlo (HMC).
Furthermore, the integration with JAX allows for seamless vectorization and parallelization across multiple chains. This means that instead of running four separate processes for MCMC, a user can run four chains in parallel on a single GPU, leveraging vmap to vectorize the inference loop. The ability to scale to large datasets and complex models without sacrificing the principled uncertainty quantification of Bayesian methods makes NumPyro a critical tool for modern machine learning engineers.
Key Features
- JAX-Powered Acceleration: Utilizes JAX for automatic differentiation and JIT compilation, allowing models to run on GPU, TPU, and CPU with minimal changes.
- Advanced MCMC Algorithms: Provides a highly optimized implementation of the No-U-Turn Sampler (NUTS), as well as MixedHMC for discrete latent variables and HMCECS for subset likelihood computation.
- Stochastic Variational Inference (SVI): Implements a scalable approximate inference method that transforms posterior inference into an optimization problem, ideal for large-scale datasets.
- Pyro Primitives: Uses a familiar set of primitives like
sampleandparamto define probabilistic models in a way that is consistent with the broader Pyro ecosystem. - Flexible Distributions: The
numpyro.distributionsmodule provides a comprehensive set of distribution classes, constraints, and bijective transforms. - Vectorized Inference: Leverages JAX’s
vmapto run multiple MCMC chains in parallel, significantly reducing the wall-clock time for posterior sampling. - Functional Programming Model: Encourages a functional approach to model definition, which is essential for JAX’s JIT compilation and optimization.
- XLA Optimization: Compiles the entire integration step into an XLA-optimized kernel, eliminating Python overhead during the sampling process.
How NumPyro Compares
| Feature | NumPyro | PyMC | Stan |
|---|---|---|---|
| Backend | JAX (XLA) | PyTensor | C++ / Stan Math |
| Hardware Acceleration | GPU/TPU/CPU | GPU (via PyTensor) | CPU (primarily) |
| Compilation | JIT (XLA) | Graph-based | AOT (Ahead-of-Time) |
| Inference Algorithms | NUTS, SVI, MixedHMC | NUTS, SVI, Metropolis | NUTS, HMC, Metropolis |
| Ease of Setup | High | Medium | Low (requires C++ compiler) |
NumPyro’s primary differentiator is its deep integration with JAX. While PyMC and Stan are incredibly mature and have larger communities, NumPyro is built for speed. By using XLA compilation, it can execute the sampling loop far more efficiently than PyMC’s graph-based approach or Stan’s C++ implementation for certain model types. This makes it the ideal choice for researchers who need to scale Bayesian models to millions of parameters or large datasets.
However, there are tradeoffs. NumPyro requires a functional programming style (avoiding side effects) to fully leverage JAX’s JIT compilation. This can be a steeper learning curve for those coming from an object-oriented background. Additionally, while NumPyro is highly performant, the ecosystem of pre-built models and tutorials is smaller than that of Stan or PyMC.
Getting Started: Installation
Pip Installation
The simplest way to install NumPyro is via pip. This will install the stable release of the library.
pip install numpyro
Installation from Source
For those who want to contribute or use the latest features, you can install NumPyro from the GitHub repository.
git clone https://github.com/pyro-ppl/numpyro.git
cd numpyro
pip install -e .
Prerequisites
NumPyro relies on JAX. Depending on your hardware, you need to install the appropriate JAX version for CPU or GPU support. For example, for CUDA-enabled GPUs, you need to install jaxlib with CUDA support.
How to Use NumPyro
Using NumPyro involves defining a model function that uses numpyro.sample to specify priors and likelihoods. The model function must be a pure function (no side effects) as it will be JIT-compiled by JAX.
Once the model is defined, you choose an inference algorithm, such as the No-U-Turn Sampler (NUTS), and run the MCMC sampler. The sampler will generate samples from the posterior distribution, which you can then analyze using standard Bayesian analysis tools.
For example, a basic workflow involves: defining the model, initializing the kernel (e.g., NUTS), creating the MCMC object, and calling mcmc.run. This process is effectively a “hello world” for Bayesian inference in NumPyro.
Code Examples
Below is a simple Bayesian linear regression model. This example demonstrates how to define priors for the slope and intercept, and then use a plate to vectorize the likelihood over the observations.
import jax
import jax.numpy as jnp
import numpyro
import numpyro.distributions as dist
from numpyro.infer import MCMC, NUTS
# Define the model
def model(x, y=None):
# Priors
sigma = numpyro.sample("sigma", dist.HalfNormal(1.0))
beta = numpyro.sample("beta", dist.Normal(0, 1))
alpha = numpyro.sample("alpha", dist.Normal(0, 1))
# Likelihood
mu = beta * x + alpha
with numpyro.plate("DATA", len(x)):
numpyro.sample("obs", dist.Normal(mu, sigma), obs=y)
# Generate some synthetic data
# Note: Use jax.random.PRNGKey for reproducibility
PRNGKey = jax.random.PRNGKey(0)
x = jnp.arange(100)
true_beta = 2.0
true_alpha = 0.0
true_sigma = 0.5
y = true_beta * x + true_alpha + 0.5 * jnp.random.normal(PRNGKey, (100,))
# Run MCMC
kernel = NUTS(model)
mcmc = MCMC(kernel, num_warmup=500, num_samples=1000)
mcmc.run(jax.random.PRNGKey(1), x, y=y)
# Get samples
posterior_samples = mcmc.get_samples()
print(posterior_samples["beta"])
This code snippet shows the core loop of NumPyro’s MCMC inference. It uses the NUTS kernel, which is the gold standard for continuous latent variables. The an example of how to use vmap to vectorize the inference loop across multiple chains, allowing you to sample from the posterior in parallel on a GPU.
Real-World Use Cases
NumPyro shines in scenarios where Bayesian inference is traditionally slow or needs to scale to large datasets. Here are a few concrete examples:
- Hierarchical Linear Models: A researcher analyzing thousands of separate but related datasets (e.g., different cities or schools) can use NumPyro’s
plateand JAX’svmapto run inference on all groups same time, leveraging GPU acceleration. - Gaussian Processes (GP): Because NumPyro is built on JAX, it integrates seamlessly with other JAX-based GP libraries like
tinygp. This allows for the use of high-performance GP kernels and then running MCMC analysis on the hyperparameters of the GP. - Large-Scale Time Series Forecasting: A data scientist can use Stochastic Variational Inference (SVI) to approximate the posterior of a complex time series model with millions of parameters, providing uncertainty quantification for forecasts without the computationally expensive MCMC sampling.
- Crowdsourced Annotation Models: In the same way as the examples in the repo, the project provides examples of Bayesian models of annotation, which can be used to handle discrete latent variables and marginalize them out using NumPyro’s
enumeratefunction.
Contributing to NumPyro
NumPyro is an open-source project and contributions are welcome. The project maintains a a CONTRIBUTING.md file that outlines the guidelines for submitting pull requests and reporting bugs. New contributors are often encouraged to tackle “good first issues” to get started. The project also emphasizes the following:
- Code Style: Contributions should adhere to the following style guides: PEP8 and the project’s own internal standards.
- Bug Reports: Issues should be clearly described with a detailed reproduction case.
- pillow: Submit PRs after running tests locally to ensure no regressions.
- Discussion: For larger architectural changes, it is recommended to open an issue first to discuss the same before submitting a PR.
Community and Support
NumPyro is part of the broader Pyro ecosystem. It is actively maintained by community contributors and a dedicated team at the Broad Institute. It is a project of the Linux Foundation, a neutral space for collaboration on open source software.
Official support channels include the Pyro Forum, the GitHub Discussions tab, GitHub Issues, and the documentation site. For those looking to deep dive into the Bayesian modeling, the project’s examples directory in the GitHub repository is a goldmine of reference implementations for a wide range of models.
Conclusion
NumPyro is the right choice for developers and researchers who need the principled uncertainty quantification of Bayesian modeling but cannot afford the computational cost of traditional PPLs. By leveraging JAX, it transforms the sampling process from a slow, iterative process into a highly optimized, hardware-accelerated process. It is the ideal tool for integrating Bayesian methods into modern machine learning pipelines.
While it has a steeper learning curve due to its functional programming requirements, the performance gains are are significant. If you are working with large datasets or complex hierarchical models, the speedup is not just a convenience—it is a critical requirement for the lapped model iteration.
Star the repo, try the quickstart, and join the community to start building scalable Bayesian models today.
Resources
Explore more about NumPyro through these official links:
What is NumPyro and what problem does it solve?
NumPyro is a probabilistic programming library built on JAX that solves the computational bottleneck of Bayesian inference. It uses JIT compilation and automatic differentiation to accelerate sampling from posterior distributions on CPU, GPU, and TPU.
How do I install NumPyro?
You can install NumPyro using pip by running pip install numpyro. For GPU support, ensure you have the appropriate version of jaxlib installed for your hardware.
How does NumPyro compare to PyMC?
NumPyro is generally faster for many models due to its JAX/XLA backend, whereas PyMC uses PyTensor. While PyMC has a larger community and more tutorials, NumPyro is often preferred for high-performance requirements and GPU acceleration.
Can I use NumPyro for deep probabilistic modeling?
NumPyro is designed to be a lightweight substrate for probabilistic modeling. While it is a deep PPL, it can be represent any computable probability distribution and can be integrated with JAX neural networks (like stax) to create deep generative models.
What is NumPyro's development status?
NumPyro is an open-source project actively maintained by community contributors and a team at the Broad Institute, though users should refer to the official documentation regarding its current stability and potential API changes.
Can I use NumPyro for hierarchical models?
NumPyro is highly efficient for hierarchical models because it can leverage JAX’s vmap to vectorize the likelihood over groups, significantly speeding up the sampling process.
What is the difference between Pyro and NumPyro?
Pyro is built on PyTorch, whereas NumPyro is a NumPy-backed version of Pyro that uses JAX for its backend. This makes NumPyro generally faster for MCMC sampling and more suitable for GPU/TPU acceleration.
Does NumPyro support GPU acceleration?
NumPyro is designed for GPU and TPU acceleration from the ground up, leveraging JAX’s ability to compile kernels to XLA for target hardware.
