Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JAX implementation of emcee #499

Open
amifalk opened this issue Jan 26, 2024 · 5 comments
Open

JAX implementation of emcee #499

amifalk opened this issue Jan 26, 2024 · 5 comments

Comments

@amifalk
Copy link

amifalk commented Jan 26, 2024

Greetings!

I've ported a subset of emcee functionality to the NumPyro project under the sampler name AIES.

(For the uninitiated, NumPyro uses JAX, a library with an interface to numpy and additional features like JIT compiling and GPU support, in the backend. The upshot is that if you're using currently using emcee, switching to NumPyro may give you a dramatic inference speedup!)

I've tried my best to match the existing API. You can use either the NumPyro model specification language

import jax
import jax.numpy as jnp

import numpyro
from numpyro.infer import MCMC, AIES
import numpyro.distributions as dist

n_dim, num_chains = 5, 100
mu, sigma = jnp.zeros(n_dim), jnp.ones(n_dim)

def model(mu, sigma):
    with numpyro.plate('n_dim', n_dim):
        numpyro.sample("x", dist.Normal(mu, sigma))

kernel = AIES(model, moves={AIES.DEMove() : 0.5,
                            AIES.StretchMove() : 0.5})

mcmc = MCMC(kernel, 
            num_warmup=1000,
            num_samples=2000, 
            num_chains=num_chains, 
            chain_method='vectorized')

mcmc.run(jax.random.PRNGKey(0), mu, sigma)
mcmc.print_summary()

or provide your own potential function.

def potential_fn(z):
    return 0.5 * jnp.sum(((z - mu) / sigma) ** 2)

kernel = AIES(potential_fn=potential_fn, 
              moves={AIES.DEMove() : 0.5,
                     AIES.StretchMove() : 0.5})
mcmc = MCMC(kernel, 
            num_warmup=1000,
            num_samples=2000, 
            num_chains=num_chains, 
            chain_method='vectorized')

init_params = jax.random.normal(jax.random.PRNGKey(0), 
                                (num_chains, n_dim))

mcmc.run(jax.random.PRNGKey(1), mu, sigma, init_params=init_params)
mcmc.print_summary()

Hope this is helpful to some folks!

@dfm
Copy link
Owner

dfm commented Jan 26, 2024

Very cool! Thanks for sharing.

@jcblemai
Copy link

jcblemai commented Apr 5, 2024

@amifalk Do you have some idea of the speedup ?

@amifalk
Copy link
Author

amifalk commented Apr 5, 2024

It depends on how many chains you run, whether or not you have a gpu, the amount of native python code in your model, etc., but it can often be a few orders of magnitude faster.

@kaiserls
Copy link

@amifalk Is the functionality of emcee to calculate and store additional data for each step supported? In emcee you can return a tuple in the potential_fn, and the rest is handled mostly automatically. I found the get_extra_fields function in numpyro, but I am not sure how to generate these extra fields.

@amifalk
Copy link
Author

amifalk commented Nov 18, 2024

get_extra_fields currently only allows you to extract internal metadata generated by the sampler at each step. If want to access some intermediate value of your likelihood function, you can recompute it after the run.

By the way, the Pyro forum is a great place to ask these kinds of questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants