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

SNPE_C won't draw samples from the posterior #1287

Closed
paarth-dudani opened this issue Sep 30, 2024 · 5 comments
Closed

SNPE_C won't draw samples from the posterior #1287

paarth-dudani opened this issue Sep 30, 2024 · 5 comments

Comments

@paarth-dudani
Copy link

Describe the bug
I have implemented SNPE_C with a uniform prior and a sine simulator with noise. However, it randomly won't sample/sample very slowly from the posterior, even after the network converges.

To Reproduce
1.
Python version: 3.9.13
SBI version: 0.23.1
2. Minimal code example:

n = 100
t = np.linspace(0,10,n)

num_sims = 100
num_rounds = 2
scale_true = torch.tensor([2.5])

class WrappedUniform(Uniform):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def log_prob(*args, **kwargs):
        log_probs = Uniform.log_prob(*args, **kwargs)
        return log_probs.squeeze()

prior_mod = WrappedUniform(torch.tensor([0.1]),torch.tensor([5.0]))

## Function to introduce noise into the exponential:
def noisy_sine(scale, input, initial_cond):
    x_noise = np.zeros((len(input)),)
    for i in range(len(input)):
        value = 1/(scale)*torch.sin(scale*t[i]) + initial_cond + 0.05*np.random.normal(0,1)
        x_noise[i] = value
    return torch.tensor(x_noise).float()

simulator = lambda theta: ((1/scale_true)*torch.sin(-t/scale_true) + 0.05*torch.rand_like(theta)).float()
x_o = noisy_sine(scale_true,t,1)

inference = NPE(prior=prior_mod, density_estimator='made')
proposal = prior_mod

# Later rounds use the APT loss.
for _ in range(num_rounds):
    theta = proposal.sample((num_sims,))
    print(np.shape(theta))
    x = simulator(theta)
    x[x>10] = 10
    _ = inference.append_simulations(theta, x, proposal=proposal).train(validation_fraction=0.1,use_combined_loss = True, retrain_from_scratch = True)
    posterior = inference.build_posterior().set_default_x(x_o)
    proposal = posterior

posterior_samples_exp = posterior.sample((500,), x=x_o)

_ = pairplot(
    posterior_samples_exp, limits=[[0, 10]], figsize=(5, 5),
    labels=[r"$\theta$"],
    points=theta_true # add ground truth thetas
)
  1. There is no error message but the algorithm just won't sample from the posterior in some iterations.

Example 1:
Screenshot 2024-09-30 at 15 22 33

Example 2:

Screenshot 2024-09-30 at 15 29 02

Expected behavior

Sampling from the posterior in a few seconds.

@paarth-dudani paarth-dudani added the bug Something isn't working label Sep 30, 2024
@michaeldeistler
Copy link
Contributor

michaeldeistler commented Oct 1, 2024

Can you try using truncated proposals?

from sbi.inference import NPE
from sbi.utils import RestrictedPrior, get_density_thresholder

inference = NPE(prior)
proposal = prior
for _ in range(num_rounds):
    theta = proposal.sample((num_sims,))
    x = simulator(theta)
    _ = inference.append_simulations(theta, x).train(force_first_round_loss=True)
    posterior = inference.build_posterior().set_default_x(x_o)

    accept_reject_fn = get_density_thresholder(posterior, quantile=1e-4)
    proposal = RestrictedPrior(prior, accept_reject_fn, sample_with="rejection")

@paarth-dudani
Copy link
Author

paarth-dudani commented Oct 3, 2024

I made the changes by using the truncated proposals as you have suggested.

I have a couple of questions.

  1. As I added the density estimator: 'mdn'. I am getting the same issue as before:

inference = NPE(prior=prior_mod, density_estimator='mdn')

Screenshot 2024-10-03 at 10 51 21

Similarly for other density estimator specifications such as 'made'.

inference = NPE(prior=prior_mod, density_estimator='made')

Screenshot 2024-10-03 at 10 56 10

Why would this happen?

  1. What does the user warning in the first image mean, since I have gotten it on numerous occasions?

@michaeldeistler
Copy link
Contributor

  1. If it works for MAF and NSF then just use those, they are generally better than MDN and MADE.

  2. I am not sure and would have to have a look, my guess that this has to do with newer pytorch versions.

@manuelgloeckler
Copy link
Contributor

manuelgloeckler commented Oct 4, 2024

To expand on this a bit:

  1. Especially in the 1d case MAF and MADE will only be able to model Gaussian, which probably are a bad proxy for what you want to learn.

The "issue" lies within accept_reject sampling. The posterior for NPE given a prior on a constrained domain will perform rejection sampling for this domain. If the acceptance rate is too low, then the sampling progress will be slow/get stuck (there normally should be a UserWarning for that; I have to check why/if this stopped working).

The issue in your case actually is your code:

simulator = lambda theta: ((1/scale_true)*torch.sin(-t/scale_true) + 0.05*torch.rand_like(theta)).float()

Note that in your simulator, the parameters theta are just used here, torch.rand_like(theta), so do not have any effect on the simulation output, which remains constant from the global variable scale_true.

In the end this leads to the estimator learning "non-sense" because the data you give it is "non-sense". For certain input it then just predicts stuff outside the prior domains, which all gets rejected.

@manuelgloeckler
Copy link
Contributor

Closing this issue, in favor of #1292

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

3 participants