Manually Defining a Model

Traditionally, models in Turing are defined using the @model macro:

using Turing

@model function gdemo(x)
    # Set priors.
~ InverseGamma(2, 3)
    m ~ Normal(0, sqrt(s²))

    # Observe each value of x.
    @. x ~ Normal(m, sqrt(s²))
end

model = gdemo([1.5, 2.0])
DynamicPPL.Model{typeof(gdemo), (:x,), (), (), Tuple{Vector{Float64}}, Tuple{}, DynamicPPL.DefaultContext}(Main.Notebook.gdemo, (x = [1.5, 2.0],), NamedTuple(), DynamicPPL.DefaultContext())

The @model macro accepts a function definition and rewrites it such that call of the function generates a Model struct for use by the sampler.

However, models can be constructed by hand without the use of a macro. Taking the gdemo model above as an example, the macro-based definition can be implemented also (a bit less generally) with the macro-free version

# Create the model function.
function gdemo2(model, varinfo, context, x)
    # Assume s² has an InverseGamma distribution.
    s², varinfo = DynamicPPL.tilde_assume!!(
        context, InverseGamma(2, 3), Turing.@varname(s²), varinfo
    )

    # Assume m has a Normal distribution.
    m, varinfo = DynamicPPL.tilde_assume!!(
        context, Normal(0, sqrt(s²)), Turing.@varname(m), varinfo
    )

    # Observe each value of x[i] according to a Normal distribution.
    return DynamicPPL.dot_tilde_observe!!(
        context, Normal(m, sqrt(s²)), x, Turing.@varname(x), varinfo
    )
end
gdemo2(x) = Turing.Model(gdemo2, (; x))

# Instantiate a Model object with our data variables.
model2 = gdemo2([1.5, 2.0])
DynamicPPL.Model{typeof(gdemo2), (:x,), (), (), Tuple{Vector{Float64}}, Tuple{}, DynamicPPL.DefaultContext}(Main.Notebook.gdemo2, (x = [1.5, 2.0],), NamedTuple(), DynamicPPL.DefaultContext())

We can sample from this model in the same way:

chain = sample(model2, NUTS(), 1000; progress=false)
┌ Info: Found initial step size
└   ϵ = 0.9
Chains MCMC chain (1000×14×1 Array{Float64, 3}):

Iterations        = 501:1:1500
Number of chains  = 1
Samples per chain = 1000
Wall duration     = 6.39 seconds
Compute duration  = 6.39 seconds
parameters        = s², m
internals         = lp, n_steps, is_accept, acceptance_rate, log_density, hamiltonian_energy, hamiltonian_energy_error, max_hamiltonian_energy_error, tree_depth, numerical_error, step_size, nom_step_size

Summary Statistics
  parameters      mean       std      mcse   ess_bulk   ess_tail      rhat   e ⋯
      Symbol   Float64   Float64   Float64    Float64    Float64   Float64     ⋯

          s²    2.0373    1.8131    0.0740   527.8451   438.9933    0.9997     ⋯
           m    1.1916    0.7359    0.0319   536.8176   502.0240    1.0003     ⋯
                                                                1 column omitted

Quantiles
  parameters      2.5%     25.0%     50.0%     75.0%     97.5%
      Symbol   Float64   Float64   Float64   Float64   Float64

          s²    0.4991    1.0306    1.4872    2.3427    6.4998
           m   -0.2767    0.7437    1.1514    1.6473    2.6784

The subsequent pages in this section will show how the @model macro does this behind-the-scenes.

Back to top