Skip to content

INLA ​

INLA is Latte's default inference engine. Given a latent Gaussian model, inla computes posterior marginals for the latent field and the hyperparameters without any MCMC. It does this by nesting two approximations.

How it works ​

INLA never builds the full joint posterior. It goes after each marginal directly, in two steps.

The first step is the latent field at a fixed value of the hyperparameters θ. The conditional p(x∣y,θ) is approximated by a Gaussian centred at its mode. When the observations are Gaussian this is exact; otherwise it is a Laplace approximation, and how accurately you take it is the main accuracy setting (see Tuning below).

The second step is the hyperparameters. The marginal posterior p(θ∣y)∝p(θ)p(y∣θ) is reconstructed by evaluating it at a handful of θ points, where the marginal likelihood p(y∣θ) comes from the first step, and fitting a smooth surface through them. Each latent marginal then falls out as a weighted mixture of the Gaussians from the first step, one per θ point.

So there are two things you actually control: how accurately the inner marginals are taken, and where the θ points are placed. Drag the grid in the picture below to see the second one at work.

the hyperparameter posterior p(θ|y)
θ = log τ  ·  3 grid points
→
a latent marginal p(xᵢ|y) = weighted mix of per-θ Gaussians
xᵢ
per-θ GaussianINLA marginalexact (fine grid)

Tuning ​

The defaults work well for most models. Here is what to reach for when one doesn't.

Latent marginal accuracy (latent_marginalization_method) ​

The inner Gaussian is symmetric, but real latent marginals are often skewed. This sets how much of that skew you recover.

  • GaussianMarginal(): just the inner Gaussian. Fastest, but symmetric.

  • SimplifiedLaplace(), the default: a cheap correction that adds the skewness back. Accurate enough for most models.

  • LaplaceMarginal(): a full Laplace approximation for each component. The most accurate and the most expensive. Worth it when the simplified correction isn't enough, for instance with strongly non-Gaussian likelihoods or very few observations behind each latent value.

julia
inla(model, y; latent_marginalization_method = LaplaceMarginal())

Hyperparameter exploration (exploration_strategy) ​

This decides where the θ points go.

  • AutoExplorationStrategy(), the default: a dense grid when there are only a few hyperparameters, switching to a central composite design (CCD) as the count grows.

  • GridExplorationStrategy(integration_step_z = …, max_log_drop = …): an explicit grid. Lowering integration_step_z packs in more points. The default grid is fairly coarse, and a denser one noticeably sharpens skewed hyperparameter tails (the Validation page measures exactly this). Each extra point costs about one more inner solve.

  • CCDExplorationStrategy(): forces the CCD design. The practical choice once you have several hyperparameters and a full grid gets too expensive.

julia
inla(model, y; exploration_strategy = GridExplorationStrategy(integration_step_z = 0.5))

Mode finding (mode_init, mode_diagnostic) ​

The θ points are placed around the mode of p(θ∣y). On difficult posteriors (multimodal, very skewed, nearly degenerate) the optimiser can settle on a poor mode. Latte checks for this afterwards and, by default, warns you if it finds a better point on the grid (mode_diagnostic = :warn). When that happens, give the search a better starting point, or a few of them, through mode_init.

Other knobs ​

  • latent_indices computes marginals only for the components you ask for, which saves a lot of time on large latent fields.

  • DIC, WAIC, CPO and the marginal likelihood are computed along the way by default, through accumulators.

Reference ​

Latte.inla Function
julia
inla(model::LatentGaussianModel, y::AbstractVector; kwargs...)

Unified INLA inference with automatic parameter selection and progress tracking.

This function provides a simplified interface for INLA inference, automatically selecting sensible defaults while supporting advanced customization.

Arguments

  • model::LatentGaussianModel: The INLA model specification

  • y::AbstractVector: Observed data

Keyword Arguments

  • latent_marginalization_method = nothing: Method for latent marginalization. nothing resolves per model via default_marginalization: compact LTM models get the VBC mean correction (VBCMarginal), everything else simplified Laplace (SimplifiedLaplace).

  • hyperparameter_marginalization_method::HyperparameterMarginalizationMethod = AutoHyperparameterMarginal(): Method for hyperparameter marginalization (GridSum for D=1, CCD interpolant for D≥2)

  • latent_indices::Union{Nothing, AbstractVector{<:Integer}} = nothing: Indices to marginalize (default: all)

  • exploration_strategy::ExplorationStrategy = AutoExplorationStrategy(): Hyperparameter exploration strategy. AutoExplorationStrategy() uses grid for D ≤ 2, CCD for D ≥ 3. Can also pass GridExplorationStrategy(...) or CCDExplorationStrategy(...) directly.

  • mode_method = nothing: Optimization method for mode finding. The default resolves to NewtonTrustRegion() for AD gradients, dim(θ) ≤ 6, and non-augmented models (a trust-region model Hessian from AD gradients), and BFGS + backtracking otherwise; see find_hyperparameter_mode.

  • mode_iterations::Int = 1000: Maximum iterations for mode finding

  • progress::Bool = true: Enable progress tracking

  • accumulators::Tuple = (DICStrategy(), MarginalLogLikelihoodStrategy(), WAICStrategy(), CPOStrategy()): Tuple of PosteriorStrategy configs for model comparison metrics. Each strategy is materialised into a fresh accumulator per call, so the tuple can be safely reused across multiple inla() runs. Pass e.g. WAICStrategy(n_nodes=25) to tune knobs.

Returns

  • INLAResult: Complete INLA inference results with marginals and diagnostics

Examples

julia
# Basic usage with default settings
result = inla(model, y)

# Custom exploration parameters
result = inla(model, y, exploration_strategy=GridExplorationStrategy(max_log_drop=3.0, interpolation_subdivisions=3))

# Disable progress tracking
result = inla(model, y, progress=false)

# Opt into the heavier adaptive latent marginalization
result = inla(model, y,
    latent_marginalization_method=AdaptiveMarginal(),
    latent_indices=1:100)

# Force CCD exploration on a 2D model
result = inla(model, y,
    exploration_strategy=CCDExplorationStrategy())

Progress Tracking

When progress=true, displays a 3-phase progress bar:

  • Phase 1 (33%): Mode finding with iteration tracking

  • Phase 2 (66%): Exploration with grid point evaluation

  • Phase 3 (100%): Hyperparameter marginalization (may include adaptive expansion)

Each phase shows detailed real-time information about the computation.

source

Limits ​

The Validation page measures all of these.

  • Skewed hyperparameter tails. The coarse default grid does not resolve them well; densify it with GridExplorationStrategy(integration_step_z = …). For non-Gaussian likelihoods a small gap survives even then, and that part comes from the inner Laplace approximation rather than the grid.

  • Non-identified hyperparameters. When the data only pin down a combination of hyperparameters (say σ2+1/τ in a Gaussian-Gaussian IID model), the outer surface cannot follow the degenerate ridge, so those marginals drift even though the inner Laplace matches the exact posterior. A sampler like HMC-Laplace handles this case.

  • Many hyperparameters. The full grid grows exponentially in their number. The Auto/CCD path softens that, and HMC-Laplace scales better when θ is large.

References ​

See also ​