Map DynamicPPL samples back to original space#20
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the DynamicPPL/Turing integration so samples produced in linked/unconstrained space are postprocessed back into the model’s original parameter space (including original-shaped parameters and names), primarily targeting MCMCChains.Chains outputs.
Changes:
- Introduces a
postprocess_samplehook and applies it inAbstractMCMC.stepimplementations to allow remapping transitions after sampling steps. - Adds dispatchable wrappers for LogDensityProblems primal/gradient callables to enable DynamicPPL-specific postprocessing.
- Extends chain construction/bundling paths (notably for
ParallelMALASampler+MCMCChains) and updates tests + compat/version.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/interface.jl |
Adds postprocessing hook and threads it through sampler steps; refactors ParallelMALASampler chain construction to allow specialization. |
ext/LogDensityProblemsExt.jl |
Wraps LDP objects in dispatchable callable structs; extends constructor to forward hvp. |
ext/DynamicPPLExt.jl |
Implements DynamicPPL-specific postprocessing and MCMCChains bundling/chain construction based on ParamsWithStats. |
test/test-Turing-Integration.jl |
Adds coverage for constrained + structured parameters mapping back to original space and names. |
test/test-DEER-Turing-Logistic.jl |
Adjusts Turing/DEER tests for the updated naming/mapping behavior. |
Project.toml |
Bumps package version and expands DynamicPPL compatibility bounds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Thanks so much for getting this started! I'll take a look this week as time permits :)
by any chance could you send me an example error? I thought i had just got this fixed...might have to call in an AD expert if this ends up being that brittle. On my machine at home I was able to get it working without error so it's unfortunate to hear its broken elsewhere... |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (89.28%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #20 +/- ##
==========================================
- Coverage 88.89% 88.65% -0.25%
==========================================
Files 6 6
Lines 1045 1040 -5
==========================================
- Hits 929 922 -7
- Misses 116 118 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
No rush at all :) Yes, I'll file a separate issue for Enzyme. |
rsenne
left a comment
There was a problem hiding this comment.
Overall looks great, just one point and one quick question for you :)
|
Sorry it took a while! This week turned out to be pretty busy for me. DynamicPPLExt basically now has one overload mirroring each overload in I added a couple sentences to the docs. |
|
@all-contributors please add @rsenne for code,maintenance,test,ideas,review,docs Just getting this up-to-date as i forgot to do this |
|
@all-contributors please add @penelopeysm for code,test,ideas,review,docs |
|
I've put up a pull request to add @penelopeysm! 🎉 |
rsenne
left a comment
There was a problem hiding this comment.
LGTM. Thanks so much for your work and thanks for being the first contributor :)
Ooh, it is my honour! |
Hello! So it turns out I did manage to work on this a little bit. This PR just takes care of mapping parameter values back into the 'original' space and getting back their name.
I think it's easiest to demonstrate this with the following model, which I snuck a variation of into the test suite. There are a couple of things here: firstly, the transformed Dirichlet will only have two variables, but in the chain the result should have three. Secondly, the parameter names should take their cue from the distributions:
xis a length-3 vector, andyis a NamedTuple with keys:aand:b.The way this works is by reevaluating the model:
What this PR does is slightly different for the different samplers:
AbstractMCMC.step, we inject this reevaluation at the end of the step via a new function_postprocess_sample.ParallelMALASampler+MCMCChains.Chains, because you've currently overloadedAbstractMCMC.mcmcsampledirectly, we inject it via a new function_construct_chains.bundle_samplesdirectly :(. Ugly, but well.All of these new functions are overloaded in DynamicPPLExt. However, we have to make sure to only overload them for
DensityModels which ultimately wrap aDynamicPPL.LogDensityFunction. To make this possible, we have to thread through some extra structs that allow us to dispatch on this, namely theLogDensityProblemPrimalandLogDensityProblemGradientstructs (previously thelogpandgradlogpfield would be anonymous functions which can't be dispatched on).Overall, this means that the following works nicely (this goes via
AbstractMCMC.step):The DEER model in the test suite also works correctly too, however I couldn't get ParallelMALASampler to work nicely on Turing models out of the box because Enzyme's hvp errorred in various forms. I assume that the test suite works because you supply an analytical hvp...
As for FlexiChains, the fact that we overload
AbstractMCMC.stepmeans that things sometimes Just Work:However,
discard_warmup=truedoesn't work: that's because we haven't overloadedbundle_samplesfor FlexiChains yet. I haven't put in too much effort into this yet, because I think that that should be separate -- we can at least get MCMCChains working for now.