-
Notifications
You must be signed in to change notification settings - Fork 32
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
Support transformed RVs & track expressions #94
Comments
Even if that might be a way to solve the problem, I'm not sure that's how we should actually do it (sorry 😛). Adding a deterministic distribution and an identity bijector for a transformation seems like a bit of a hack to me (and the AD part seems to be focused on HMC?). It seems the main purpose of If it's (mainly) about the interesting variables ending up in the chain, maybe @model function test(x)
m1 ~ Normal()
m2 = f(m1) # some differentiable transformation
x ~ Normal(m2, 1.0)
return m1, m2
end and respecting the |
Cool idea to have the return statement determine what is stored "additionally" in the chain. |
That said, I find the use of an |
What do you guys think about using the return statement (as described by @devmotion) in general to define the set of variables that should be tracked? This idea is kinda growing on me. :) @model function gmm(x, K)
m ~ filldist(Normal(), K)
v ~ filldist(InverseGamma(2, 3), K)
s = sqrt.(v)
w ~ Dirichlet(K, 1.0)
z ~ filldist(Categorical(w), length(x))
x .~ Normal.(m[z] s[z])
return m, s, w
end Then the resulting chain has only states for |
So just a heads up: I've already implemented a In this case you could then just do: @model function gmm(x, K)
m ~ filldist(Normal(), K)
v ~ filldist(InverseGamma(2, 3), K)
s = sqrt.(v)
w ~ Dirichlet(K, 1.0)
z ~ filldist(Categorical(w), length(x))
x .~ Normal.(m[z] s[z])
return m, s, w
end
m = gmm(x, K)
chain = sample(m, sampler, n)
return_values = generated_quantities(m, chain) This is a fairly good temporary-fix for tackling this issue + it has additional use-cases:
Not suggesting this is as a solution to the problem, but it can in many cases be a good fix + it provides some additional functionality. For completeness: function generated_quantities(m::Turing.Model, c::MCMCChains.Chains)
# if `c` is multiple chains we pool them into a single chain
chain = length(chains(c)) == 1 ? c : MCMCChains.pool_chain(c)
varinfo = Turing.DynamicPPL.VarInfo(m)
return map(1:length(chain)) do i
Turing.DynamicPPL._setval!(varinfo, chain[i])
m(varinfo)
end
end |
Nice! IMO both approaches try to address a different problem (which we should both solve in some way). The approach with Additionally, I think we should just have some convenience function for running models with NamedTuple instead of VarInfo, instead of letting users rewrite the same hacks over and over again. IMO it would be good to use NamedTuples in |
👍
Hooold up; what do you mean when you say "reordering of the columns"? Do you mean that |
You're absolutely right - I assumed |
+1 for using the |
Something I've always wondered about this is why we don't just track these generated quantities in |
I think using the |
Ref: TuringLang/Turing.jl#1335 Thanks to the most recent updates to DPPL (in particular @devmotion's PR with the new impl of
Thoughts? |
This is essentially a post-processing step, right? I think this is a nice approach, but a more integrated solution that uses the return statement during inference would be great too, as it could help in figuring out possible ways to collapse out parameters. Maybe we can have your solution implemented for now and add the functionality that I proposed later on. This way one can make use of both 1) possible collapsed sampling, 2) obtaining transformed variables after sampling. What do you think? |
Re-running the model on a big dataset could be expensive. I think what @torfjelde proposes can be considered a separate feature. It is helpful to have a |
I wonder if we can just do away entirely with @model function f()
m ~ Normal(0, 1)
z = m + 1
return z
end to something where the return value is a @model function f()
m ~ Normal(0, 1)
z = m + 1
return (z=z,)
end Then, when we run the model through Turing, we just bundle up the |
I thought about Tor’s approach also as an additional functionality. It would also be nice to have a similar function to obtain the log prob values of each datum at each iteration after inference. |
I 100% agree that it would be nice with a more integrated approach where we keep track of the quantities during sampling, but I also 100% disagree with this meaning that
Now, if anyone still disagrees; fight me! I'll be near the fountain behind the gray building at 6pm. No brass knuckles allowed. (I'm kidding; I've just always wanted to say that. Please continue the discussion in a civil way.) EDIT: Also, in my original comment I should have emphasized that I did not mean that my proposal was a replacement for tracking during sampling! My bad. But rather an addition + it would provide a temporary "solution" to the problem in most basic use-cases, which I think is important too, given the number of times people have brought this up in our Slack-channel. EDIT 2: The above is mainly a response to the:
|
Well, I think we all agree that it’s very useful to have, and I think we should provide it as functionally. We should simply not have this as the only solution. I think best would be both, as pointed out earlier. |
I think those are all great points, particularly the idea about using different models. The memory constraints thing is not that big an issue though, since I was also thinking of a keyword argument to exclude/include generated quantities during sampling. I think also there's not really that much data that gets thrown around in most common models, so we probably shouldn't be running into memory issues. We could by default just not store any Maybe the short-term solution here is to give a keyword |
I like @devmotion's proposal above: a clean syntax for specifying tracked variables would be via the return statement: @model test(x) = begin
m1 ~ Normal()
m2 = f(m1) # some differentiable transformation
x ~ Normal(m2, 1.0)
return m2 # store returned values in the `AbstractMCMC.bundle_samples` function
end |
This is a summary issue of something floating around for quite some time.
We would like to be able to do this:
The resulting chain should contain states for
m1, m2
respectively.Comments by @mohamed82008 how to approach this:
The text was updated successfully, but these errors were encountered: