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}(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}(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
└   ϵ = 1.6
Chains MCMC chain (1000×14×1 Array{Float64, 3}):

Iterations        = 501:1:1500
Number of chains  = 1
Samples per chain = 1000
Wall duration     = 7.39 seconds
Compute duration  = 7.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.0981    1.7491    0.0735   546.7820   540.5783    1.0005     ⋯
           m    1.2104    0.8233    0.0373   517.0032   518.3267    1.0032     ⋯
                                                                1 column omitted

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

          s²    0.6023    1.0588    1.5689    2.4419    6.7994
           m   -0.3834    0.7167    1.1967    1.6596    2.9164

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

Back to top