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

custom prior #581

Closed
alessiospuriomancini opened this issue Jan 17, 2022 · 10 comments · Fixed by #595 or #602
Closed

custom prior #581

alessiospuriomancini opened this issue Jan 17, 2022 · 10 comments · Fixed by #595 or #602
Assignees

Comments

@alessiospuriomancini
Copy link

First of all congratulations for this amazing software!

My issue: I have a custom prior that I would like to sample from

import scipy.special as sp
import numpy as np
a_0 = 3.0
b_0 = 2.0 * 300**2
def prior(alpha, tau):
        return  = a_0 * np.log(tau) - b_0 * tau - sp.gammaln(a_0) - tau

Is there a way to write this in a way that can be read by sbi, without using Torch distributions? Thanks

@michaeldeistler
Copy link
Contributor

Hi there! It's a bit unclear to me what your prior is doing. This line seems to have a bug:

return  = a_0 * np.log(tau) - b_0 * tau - sp.gammaln(a_0) - tau # see the "=" after "return"

Anyways:
If you are using SNPE, you can simply not pass any prior in the flexible interface:

from sbi.inference import SNPE
inference = SNPE()
_ = inference.append_simulations(theta, x).train()  # theta are samples from your custom prior
posterior = inference.build_posterior()

If you are using SNLE or SNRE, you need to specify a prior. The prior must have a .log_prob() method.

Does this answer you question?

@alessiospuriomancini
Copy link
Author

alessiospuriomancini commented Jan 17, 2022 via email

@janfb
Copy link
Contributor

janfb commented Jan 18, 2022

Hi @alessiospuriomancini and thanks for bringing this up!

Yes, if you pass a class that mimics the behaviour of a torch distributions, then sbi will wrap it as a torch distribution and can use it from there.

Essentially, the class needs

  • a .sample(sample_shape) method, where sample_shape is a shape tuple, e.g., (n,), and .sample needs to return a batch of n samples, e.g., in your case with two parameter the return shape should be (n, 2);
  • and it needs a log_prob(value) method that returns the "log probs" of parameters under the prior, e.g., for a batch of parameters with shape (n, 2) it should return a log probs array of shape (n,).

I think you are the first person we know about using this feature, that's great!

Let us know if there are any problems.

@psteinb
Copy link
Contributor

psteinb commented Jan 18, 2022

A comment from the side lines: if @alessiospuriomancini sees that this works, it might be an idea to contribute a unit test for exactly this feature to sbi - in case something like this doesn't exist yet. This might also serve as a starting point for other users in the future.

@janfb
Copy link
Contributor

janfb commented Jan 18, 2022

@alessiospuriomancini
Copy link
Author

Thanks everyone for your help. I can confirm that:

  • creating a class called, for example, Custom_Prior
  • containing methods .sample(sample_shape) and log_prob(value), as described by @janfb above,

works smoothly with the SNLE method.

@alessiospuriomancini
Copy link
Author

Unfortunately I have to reopen this issue. In my last post I incorrectly said that writing the Custom_prior class with methods .sample and .log_prob allows one to run with the SNLE method. Apologies, I was incorrect: this trick works when using SN P E.

When running with SN L E, instead, with the same prior setup previously described, I get the following error:

Traceback (most recent call last):
  File "examples/sbi_examples.py", line 46, in <module>
    samples         = posterior.sample((1000,), x=observed_data).numpy()
  File "/home/alessio/anaconda2/envs/sbi-env/lib/python3.8/site-packages/sbi/inference/posteriors/likelihood_based_posterior.py", line 187, in sample
    transform = mcmc_transform(
  File "/home/alessio/anaconda2/envs/sbi-env/lib/python3.8/site-packages/sbi/utils/sbiutils.py", line 918, in mcmc_transform
    if hasattr(prior.support, "base_constraint") and hasattr(
  File "/home/alessio/anaconda2/envs/sbi-env/lib/python3.8/site-packages/torch/distributions/distribution.py", line 107, in support
    raise NotImplementedError
NotImplementedError 

The call to SBI in my script sbi_examples.py is:

from sbi import utils as utils
from sbi.inference.base import infer

def simulator(parameters):
    return experiment.simulator(parameters)

posterior = infer(simulator, prior, method='SNLE', num_simulations=1000)

samples         = posterior.sample((1000,), x=observed_data).numpy()
log_probability = posterior.log_prob(samples, x=observed_data).numpy()

prior is an instantiation of the Custom_Prior class described above.

@janfb
Copy link
Contributor

janfb commented Jan 18, 2022

thanks for the good error documentation!

Alright, this is probably due to the new support constraints since pytorch 1.5 or so. We will have to look into this in more detail adapt the prior wrapper class accordingly. Mostly likely we will have the time for that next week already, we will let you know.

@michaeldeistler
Copy link
Contributor

This is a bug in our code, I recently encountered it as well. It is fixed on the current main branch via this fix, but we have not made a release yet.

@michaeldeistler
Copy link
Contributor

michaeldeistler commented Jan 18, 2022

A simple fix might be to add a support method to your prior class, sth like:

class MyPrior:
    ....
    ....
    def support():
        pass

(I did not test this though, no guarantees)

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

Successfully merging a pull request may close this issue.

4 participants