-
Notifications
You must be signed in to change notification settings - Fork 158
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
Sampler interface #573
Sampler interface #573
Conversation
913ac84
to
05525a5
Compare
05525a5
to
4528f3d
Compare
Codecov Report
@@ Coverage Diff @@
## main #573 +/- ##
==========================================
- Coverage 66.92% 66.79% -0.13%
==========================================
Files 56 67 +11
Lines 4193 4186 -7
==========================================
- Hits 2806 2796 -10
- Misses 1387 1390 +3
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
724fb58
to
bca182d
Compare
bca182d
to
ee32bd1
Compare
Great work, this should be very helpful down the road! I think the most crucial design decision to discuss is this one: "Currently, x can not be changed after instantiation -> one has to rerun .build_posterior() with the new x.". Should it stay this way, or do we want to support this? As I understand it, the main difficulty doing this within the proposed design is that the posterior class would need to rebuild or change its potential function to support this. I was wondering whether it would be advantageous to pass a potential function builder rather than the fully-built potential to the init of the posterior instead. Since all potential function builders are treated the same way (https://github.com/mackelab/sbi/blob/sampler/sbi/inference/potentials/likelihood_based_potential.py#L36-L41, https://github.com/mackelab/sbi/blob/sampler/sbi/inference/potentials/posterior_based_potential.py#L39-L44, https://github.com/mackelab/sbi/blob/sampler/sbi/inference/potentials/ratio_based_potential.py#L36-L41), couldn't calling the builder function happen inside the posterior class instead, e.g., in a method of the posterior base class? About the proposed change to the simple interface: I would strongly favor keeping things down to a single line of code -- e.g., by keeping support for setting With respect to naming things:
|
Thanks for the feedback JM!
I'm also still unsure about whether this is ok or not. One thing to keep in mind though: at least for SNPE, the
My main reason for having the
yes, that would be possible with the
if we go for a
Agreed!
I like it, but it's quite verbose. How about |
Exactly :) This is what got me thinking about passing the builder.
I think being verbose is okay if it helps avoid confusion. To me, the essential bit to get across is that we are building potential functions (always the same quantity -- likelihood x prior) based on different estimators (estimators of posterior/likelihood/likelihood-to-evidence ratio etc.).
We could still support this case by keeping the functions for the two-step build process. I think, ultimately support for external samplers would need to be documented in a tutorial or FAQ entry, where we'd explain this. I think being able to keep a single line |
I think you convinced me regarding the |
Yes, this looks great already! I agree with keeping the names I would vote for a more descriptive name for the function that returns the potential function, e.g., More detailed comments in the review below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great effort!
I added some comments and questions.
Overall, I suggest to rename {likelihood, posterior, ratio}_model
back to ``{likelihood, posterior, ratio}_estimator`, and to simplify to construction and naming of the potential functions as commented.
440c1b8
to
ef63641
Compare
58d00ac
to
ae673c0
Compare
ae673c0
to
cb61d3b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great -- think the interface turned out very well! So much fewer API changes now. Only left a few brief comments. If there remains something to be discussed, let me know :)
221aafb
to
d7f123a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall great work! Looks good to. me now, except for some small comments, some of which we can move to issues and future PRs.
|
||
return samples | ||
|
||
def map( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, but then one could just have this method like it is here and in DirectPosterior
(there are almost the same no?) and let the child method call the base method with appropriate default args? e.g., init_method="prior"
here, and init_method="posterior"
in the DirectPosterior
?
|
||
return samples | ||
|
||
def map( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could also be sth for an issue and future PR
f78cf2a
to
5bf8e57
Compare
5bf8e57
to
cf4bd15
Compare
Main API remains unchanged
The sampler interface
The
.build_posterior()
method is a wrapper around the sampler interface:Other available samplers are:
For devs: how we deal with
default_x()
When not using the sampler interface:
x_o
is always passed as before: either viaposterior.set_default_x(xo)
or viaposterior.sample((1,), x=xo)
.set_default_x()
saves the value as the.default_x
property of theposterior
classes.When using the sampler interface:
x_o
(to avoid API changes). Therefore, thex_o
argument to thelikelihood_estimator_based_potential()
method can beNone
(type isOptional[Tensor]
), but it has no default value. The following works:x_o
can also be passed to thelikelihood_estimator_based_potential()
. In that case, thedefault_x
property of theposterior
is directly set to whatever was used in thepotential_fn
. The following works:potential_fn.x_o
is always the most recently used data. It is not the same as posterior.default_xAPI changes
.sample(..., sample_with="mcmc")
is no longer supportedThe posteriors are now sampler specific, e.g.
MCMCPosterior
. Thus, one can not change whether one samples the posterior with MCMC or rejection sampling (or vi) at.sample()
. We give an explicit error in that case. The user has to rerun.build_posterior(sample_with="mcmc")
..sample_conditional()
is no longer part of theposterior
.sample_conditional
requires using the sampler-interface. The new API is:Posterior is no longer aware of how many rounds it has been trained on
The posterior no longer has the attribute
_num_trained_rounds
. This affects theprint(posterior)
statement: before, it printed whether the posterior is amortized or not. This is no longer done.Changes in code-base structure
The main change is that the
posterior
classes are no longer specific to the inference method (e.g.LikelihoodBasedPosterior
), but instead to the sampler (e.g.MCMCPosterior
). What is specific to the inference method are the potentials (e.g.likelihood_potential()
). These potentials all lie in a new foldersbi/inference/potentials
.Notes