Turing.jl icon indicating copy to clipboard operation
Turing.jl copied to clipboard

Turing Sampling specified parameters

Open astro-kevin opened this issue 3 years ago • 3 comments

Copied from https://discourse.julialang.org/t/turing-sampling-specified-parameters/90360

In my model, I have

@model function runmodel(stuff, parameters)
parameters ~ Product([Uniform(0,5),
            Uniform(0, 1),
...])
predictions, otherstuff = model(stuff, parameters)
obs, var = findobsvar(stuff, otherstuff)
obs ~ MvNormal(predictions, Diagonal(var))

where findobsvar is a function which takes in stuff and returns my observations and variances which I need for my multivariate normal distribution.

However, when I run my model using sample, I find that it has obs as a parameter in addition to parameters.

How do I stop that? I only want parameters as my variable since I’m only trying to constrain parameters of my model. findobsvar is just a helper function in getting the values of obs and var within the model.

Edit: I have added how I define my priors for parameters.

astro-kevin avatar Nov 16 '22 18:11 astro-kevin

How do you run sample and what exactly do you want to do? If you want to perform Bayesian inference of parameters you would have to specify a prior for parameters, it seems? Or do you want to perform only maximum likelihood estimation?

Generally, in a standard Turing model everything on the left hand side of a ~ statement is a (observed or unobserved) parameter of the model. And every LHS that is not a literal or appears as a model argument is considered an unobserved variable.

devmotion avatar Nov 16 '22 19:11 devmotion

I'm trying to run an MCMC, so I'm calling sample like this.

chain = sample(runmodel(stuff, parameters)), MH(), num_iter)

stuff and num_iter are variables defined outside.

I have

parameters ~ Product([Uniform(0,5),
            Uniform(0, 1),
...])
            

inside runmodel (edited to add in OP).

A previous version I had worked because I had obs as a variable of runmodel. However, my current version of my code have my data in bins, and which bin I go into to look for obs depends on the result of model. But clearly I'm not trying to infer anything about obs, it's just my storage variable for my data, which I'm getting from findobsvar.

astro-kevin avatar Nov 16 '22 21:11 astro-kevin

But clearly I'm not trying to infer anything about obs, it's just my storage variable for my data, which I'm getting from findobsvar.

Well, it's not clear from the line obs ~ MvNormal(...) - Turing will always make the LHS a model parameter. One way around it would be to replace this line with

Turing.@addlogprob! logpdf(MvNormal(...), obs)

That will just add the log probability to the accumulated log density without adding any new variables. But there are some drawbacks to that approach (e.g. https://github.com/TuringLang/DynamicPPL.jl/issues/390) and, I think, should only be used if there is no better alternative. Maybe that's the case here.

Another workaround - which relies on even more internals if it works at all, I haven't tested it - would be to keep the model but add something like

DynamicPPL.inargnames(::VarName{:obs}, ::Model{typeof(runmodel)}) = true

The idea is that Turing checks if the LHS is an argument to the model, and if it is, then it is treated as an observation (if it is not missing...). So maybe in that way one could avoid that Turing treats it as an unobserved model parameter. But as I said, it's a quite dangerous workaround (IMO) as it relies on the internals - which might change.

devmotion avatar Nov 16 '22 21:11 devmotion