-
Notifications
You must be signed in to change notification settings - Fork 223
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
parameters
macro for specifying trace manually (aka Turing's VarInfo
)
#2492
Comments
As discussed previously, I like this proposal as long as we can find a way to make most I wonder what the best syntax is for connecting a particular parameter struct with the variables of a model. With @model function (gdemo::Demo)()
(;m, s², x) = gdemo
m ~ Normal(0, sqrt(s²))
s² ~ InverseGamma(2, 3)
x .~ Normal(m, sqrt(s²))
end it's not obvious to me how we would match e.g. the @model function (gdemo::Demo)()
gdemo.m ~ Normal(0, sqrt(s²))
gdemo.s² ~ InverseGamma(2, 3)
gdemo.x .~ Normal(m, sqrt(s²))
end would work but gets a bit verbose. |
A quick note for future discussion: we could use a type similar to ForwardDiff's |
It turns out the following is valid (see JuliaLang/julia#39285 and docs ) julia> struct A
x
y
end
julia> foo((; x, y)::A) = x + y
foo (generic function with 1 method)
julia> foo(A(1, 2))
3 So, we could write: @parameters struct Demo{T}
m::T
s²::T
x::Vector{T}
end
@model function model((;m, s², x)::Demo)
m ~ Normal(0, sqrt(s²))
s² ~ InverseGamma(2, 3)
x .~ Normal(m, sqrt(s²))
end This would avoid the use of |
It has been known for a while that one can write Turing models as callable objects/functors, in the form of
Suppose one further assumes that all model parameters (i.e. LHS of tilde) have to be a field of
MyModel
. In that case, the type definition ofMyModel
manually specifies the tracing data structure for Turing models.However, the above example doesn't yet use
MyModel
as a substitute forTypedVarInfo
. For that to happen, one can introduce a new@parameters
macro to manually specifyTypedVarInfo
for models. Here is an example:Here, all the model parameters are passed to models transparently via the
(;m, s², x) = gdemo
. This avoids the use ofVarInfo
ultimately (we will needVarInfo
for other purposes in a lightweight manner, e.g. for accumulatinglogp
. If a sampler opts to leave a parameter unspecified (i.e.sample_from_prior
/sample_from_proposal
), the model evaluator can still sample these parameters from their conditional prior. Otherwise, samplers must specify each parameter with a concrete value or mark it asmissing
orpredict
so the model evaluator handles them accordingly. In addition, users could manually specify parameter constraints and bijector transforms onstruct Demo
(note this happens without running the model once). All these properties allow more clarity, reduce the complexity of DynamicPPL, and improve robustness by avoiding edge cases ofVarInfo
.This approach offers many advantages, e.g.
TypedVarInfo
(see Simplify the context mechanism in DynamicPPL #2424 and Significantly simplify the tilde-pipeline in DynamicPPL #2422), which requires running the model oncefix
/condition
/biject_transform
/missing
/predict
/sample_from_prior
: we could mark fields ofMyModel
as one of these operations without requiring DynamicPPL's model evaluation context (see, e.g. Convenience macros to use within@model
DynamicPPL.jl#714).A note on the practicals for DynamicPPL: as I mentioned in a previous meeting, one could refactor the DynamicPPL functionality for building
TypedVarInfo
and provide an API for users to define@parameters struct Demo{T}
automatically. This would involve running the model once, collecting all the model parameters and their support constraints, and then automatically generating a Julia struct definition.This new design (passing tracing data structure explicitly and assume it is immutable) will resolve the following:
missing
is thread-unsafe DynamicPPL.jl#641parameters
definition, for example:The text was updated successfully, but these errors were encountered: