theogf / ThermodynamicIntegration.jl

Thermodynamic Integration for Turing models and more
MIT License
13 stars 1 forks source link

Automate bounds of Turing models #22

Open itsdfish opened 2 years ago

itsdfish commented 2 years ago

Hello,

As we discussed on Slack, the end user must manually transform parameters and densities when parameters have restrictions. For example, the parameter sigma of the normal distribution must be non-negative. The need to transform parameters is quite common, as many distributions in the exponential family have restrictions, including the normal, binomial, beta, Poisson, and Gamma distributions. Unfortunately, this added step is cumbersome for the end user. Turing appears to handle these transformations automatically. Given that Turing models can be passed to alg, I wonder if it would be possible to tap into those capabilities. Having this capability would make the package much easier to use.

theogf commented 2 years ago

I don't think I would have time to implement such a process. This is basically asking to start implementing a new probabilistic programming language. In any case, have you considered passing a Turing model directly to the TI algorithm?

itsdfish commented 2 years ago

I completely understand. I want to clarify that I was not suggesting that you implement a new PPL. Instead, I was wondering whether it would be possible to make a small change in your code that would allow Turing to automate the transformations as it typically does outside of your package.

As you suggested, I was hoping that using a Turing model would solve the problem, but unfortunately it still persists.

Here is a MWE:

Code

using Turing, ThermodynamicIntegration, Distributions
# data
n = 30
k = 12

@model function turing_model(n, k)
    θ ~ Beta(5, 5)
    k ~ Binomial(n, θ)
end

model = turing_model(n, k)

alg = ThermInt(n_samples=1000) 
logZ = alg(model) 

Error

ERROR: LoadError: DomainError with Dual{ForwardDiff.Tag{ThermodynamicIntegration.var"#f#38"{DynamicPPL.Model{typeof(turing_model), (:n, :k), (), (), Tuple{Int64, Int64}, Tuple{}, DynamicPPL.DefaultContext}, DynamicPPL.TypedVarInfo{NamedTuple{(:θ,), Tuple{DynamicPPL.Metadata{Dict{AbstractPPL.VarName{:θ, Setfield.IdentityLens}, Int64}, Vector{Beta{Float64}}, Vector{AbstractPPL.VarName{:θ, Setfield.IdentityLens}}, Vector{Float64}, Vector{Set{DynamicPPL.Selector}}}}}, Float64}, DynamicPPL.SampleFromPrior, DynamicPPL.MiniBatchContext{DynamicPPL.DefaultContext, Float64}}, Float64}}(1.4480301908301867,1.0):
Binomial: the condition zero(p) <= p <= one(p) is not satisfied.

Version Info

  [31c24e10] Distributions v0.25.49
  [1022446e] ThermodynamicIntegration v0.2.4
  [84d833dd] TransformVariables v0.6.0
  [fce5fe82] Turing v0.20.4

If I ran the model with sample, it would respect the parameter bounds. But as you can see, this does not happen with your code unfortunately.

theogf commented 2 years ago

Ah ok thanks, yeah it looks like calling the functions from the model does not use the reparametrization. This is something I could look at.