v0.38.0
DynamicPPL v0.38.0
Breaking changes
Introduction of InitContext
DynamicPPL 0.38 introduces a new evaluation context, InitContext.
It is used to generate fresh values for random variables in a model.
Evaluation contexts are stored inside a DynamicPPL.Model object, and control what happens with tilde-statements when a model is run.
The two major leaf (basic) contexts are DefaultContext and, now, InitContext.
DefaultContext is the default context, and it simply uses the values that are already stored in the VarInfo object passed to the model evaluation function.
On the other hand, InitContext ignores values in the VarInfo object and inserts new values obtained from a specified source.
(It follows also that the VarInfo being used may be empty, which means that InitContext is now also the way to obtain a fresh VarInfo for a model.)
DynamicPPL 0.38 provides three flavours of initialisation strategies, which are specified as the second argument to InitContext:
- InitContext(rng, InitFromPrior()): New values are sampled from the prior distribution (on the right-hand side of the tilde).
- InitContext(rng, InitFromUniform(a, b)): New values are sampled uniformly from the interval- [a, b], and then invlinked to the support of the distribution on the right-hand side of the tilde.
- InitContext(rng, InitFromParams(p, fallback)): New values are obtained by indexing into the- pobject, which can be a- NamedTupleor- Dict{<:VarName}. If a variable is not found in- p, then the- fallbackstrategy is used, which is simply another of these strategies. In particular,- InitFromParamsenables the case where different variables are to be initialised from different sources.
(It is possible to define your own initialisation strategy; users who wish to do so are referred to the DynamicPPL API documentation and source code.)
The main impact on the upcoming Turing.jl release is that, instead of providing initial values for sampling, the user will be expected to provide an initialisation strategy instead.
This is a more flexible approach, and not only solves a number of pre-existing issues with initialisation of Turing models, but also improves the clarity of user code.
In particular:
- When providing a set of fixed parameters (i.e. InitFromParams(p)),pmust now either be a NamedTuple or a Dict. Previously Vectors were allowed, which is error-prone because the ordering of variables in a VarInfo is not obvious.
- The parameters in pmust now always be provided in unlinked space (i.e., in the space of the distribution on the right-hand side of the tilde). Previously, whether a parameter was expected to be in linked or unlinked space depended on whether the VarInfo was linked or not, which was confusing.
Removal of SamplingContext
For developers working on DynamicPPL, InitContext now completely replaces what used to be SamplingContext, SampleFromPrior, and SampleFromUniform.
Evaluating a model with SamplingContext(SampleFromPrior()) (e.g. with DynamicPPL.evaluate_and_sample!!(model, VarInfo(), SampleFromPrior()) has a direct one-to-one replacement in DynamicPPL.init!!(model, VarInfo(), InitFromPrior()).
Please see the docstring of init!! for more details.
Likewise SampleFromUniform() can be replaced with InitFromUniform().
InitFromParams() provides new functionality which was previously implemented in the roundabout way of manipulating the VarInfo (e.g. using unflatten, or even more hackily by directly modifying values in the VarInfo), and then evaluating using DefaultContext.
The main change that this is likely to create is for those who are implementing samplers or inference algorithms.
The exact way in which this happens will be detailed in the Turing.jl changelog when a new release is made.
Broadly speaking, though, SamplingContext(MySampler()) will be removed so if your sampler needs custom behaviour with the tilde-pipeline you will likely have to define your own context.
Removal of DynamicPPL.Sampler
DynamicPPL.Sampler and all associated interface functions have also been removed entirely.
If you were using these, the corresponding replacements are:
- DynamicPPL.Sampler(S): just don't wrap- S; but make sure- Ssubtypes- AbstractMCMC.AbstractSampler
- DynamicPPL.initialstep: directly implement- AbstractMCMC.stepand- AbstractMCMC.step_warmupas per the AbstractMCMC interface
- DynamicPPL.loadstate:- Turing.loadstate(will be introduced in the next version)
- DynamicPPL.default_chain_type: removed, just use the- chain_typekeyword argument directly
- DynamicPPL.initialsampler:- Turing.Inference.init_strategy(will be introduced in the next version; note that this function must return an- AbstractInitStrategy, see above for explanation)
- DynamicPPL.default_varinfo:- Turing.Inference.default_varinfo(will be introduced in the next version)
- DynamicPPL.TestUtils.test_samplerand related methods: removed, please implement your own testing utilities as needed
Simplification of the tilde-pipeline
There are now only two functions in the tilde-pipeline that need to be overloaded to change the behaviour of tilde-statements, namely, tilde_assume!! and tilde_observe!!.
Other functions such as tilde_assume and assume (and their observe counterparts) have been removed.
Note that this was effectively already the case in DynamicPPL 0.37 (where they were just wrappers around each other).
The separation of these functions was primarily implemented to avoid performing extra work where unneeded (e.g. to not calculate the log-likelihood when PriorContext was being used). This functionality has since been replaced with accumulators (see the 0.37 changelog for more details).
Removal of the "del" flag
Previously VarInfo (or more correctly, the Metadata object within a VarInfo), had a flag called "del" for all variables. If it was set to true the variable was to be overwritten with a new value at the next evaluation. The new InitContext and related changes above make this flag unnecessary, and it has been removed.
The only flag other than "del" that Metadata ever used was "trans". Thus the generic functions set_flag!, unset_flag! and is_flagged! have also been removed in favour of more specific ones. We've also used this opportunity to name the "trans" flag and the corresponding istrans function to be more explicit. The new, exported interface consists of the is_transformed and set_transformed!! functions.
Removal of resume_from
The resume_from=chn keyword argument to sample has been removed; please use the initial_state argument instead.
loadstate will be exported from Turing in the next release of Turing.
Change of output type for pointwise_logdensities
The functions pointwise_prior_logdensities, pointwise_logdensities, and pointwise_loglikelihoods when called on MCMCChains.Chains objects, now return new MCMCChains.Chains objects by default, instead of dictionaries of matrices.
If you want the old behaviour, you can pass OrderedDict as the third argument, i.e., pointwise_logdensities(model, chain, OrderedDict).
Other changes
predict(model, chain; include_all)
The include_all keyword argument for predict now works even when no RNG is specified (previously it would only work when an RNG was explicitly passed).
DynamicPPL.setleafcontext(model, context)
This convenience method has been added to quickly modify the leaf context of a model.
Reimplementation of functions using InitContext
A number of functions have been reimplemented and unified with the help of InitContext.
In particular, this release brings substantial performance improvements for returned and predict.
Their APIs are the same.
Upstreaming of VarName functionality
The implementation of the varname_leaves and varname_and_value_leaves functions have been moved to AbstractPPL.jl.
Their behaviour is otherwise identical, and they are still accessible from the DynamicPPL module (though still not exported).
Merged pull requests:
- v0.38 (#1018) (@penelopeysm)
- Remove Samplerand its interface (#1037) (@penelopeysm)
- Separate context code into smaller files; remove some dead code (#1050) (@penelopeysm)
- add Enzyme benchmarks and incorporate some CompatHelper bits (#1056) (@penelopeysm)
- Fixes for Turing 0.41 (#1057) (@penelopeysm)
- Delete the "del"flag (#1058) (@mhauru)
- no coveralls (#1059) (@penelopeysm)
- Replace Metadata.flagswithMetadata.trans(#1060) (@mhauru)
- Remove resume_fromanddefault_chain_type(#1061) (@penelopeysm)
- Allow more flexible initial_params(#1064) (@penelopeysm)
- Bump JET and SpecialFunctions test compat (#1065) (@penelopeysm)
- Fix CI for 1.12 (#1067) (@penelopeysm)
- fix include_all kwarg for predict, improve perf (#1068) (@penelopeysm)
- don't run Turing integration test on 1.12.0 (#1069) (@penelopeysm)
- Change pointwise_logdensities default key type to VarName (#1071) (@mhauru)
- Remove VarInfo internal docs from navigation (#1073) (@mhauru)
- Fix DynamicPPL / MCMCChains methods (#1076) (@penelopeysm)
Closed issues:
- Add scale parameter to SampleFromUniform (#375)
- Removed ignorableargument fromset_flag!(#683)
- Return an AbstractChains object from appliying pointwise_logdensities to Abstractchains? (#688)
- Usage of VarNameas keys (#712)
- Support using OrderedDictfor initialization, also improve error message (#774)
- Inline (and more carefully use) islinkedinsideinitialize_parameters!!(#797)
- SampleFromPrior, etc. cleanup (#859)
- toveccausing an error when sampling a Product named tuple distribution (#933)
- del "del": remove- delflag (#982)
- setleafcontext(::Model, ::AbstractContext)(#993)
- improve implementation of predict(...; include_all)(#1042)
- loadstatedoesn't differentiate between single-chain sampling and multi-chain sampling with n_chains = 1 (#1049)
- make pointwise_logdensities return a dict of varname (#1070)
- chains methods claim to be generic but only work on MCMCChains (#1072)