ENV["GKS_ENCODING"] = "utf-8" # Allows the use of unicode characters in Plots.jl
using Plots
using StatsPlots
using Turing
using Random
using Bijectors
# Set a seed.
Random.seed!(0)
# Define a strange model.
@model function gdemo(x)
~ InverseGamma(2, 3)
s² ~ Normal(0, sqrt(s²))
m = sin(m) + cos(m)
bumps = m + 5 * bumps
m for i in eachindex(x)
~ Normal(m, sqrt(s²))
x[i] end
return s², m
end
# Define our data points.
= [1.5, 2.0, 13.0, 2.1, 0.0]
x
# Set up the model call, sample from the prior.
= gdemo(x)
model
# Evaluate surface at coordinates.
evaluate(m1, m2) = logjoint(model, (m=m2, s²=invlink.(Ref(InverseGamma(2, 3)), m1)))
function plot_sampler(chain; label="")
# Extract values from chain.
= get(chain, [:s², :m, :lp])
val = link.(Ref(InverseGamma(2, 3)), val.s²)
ss = val.m
ms = val.lp
lps
# How many surface points to sample.
= 100
granularity
# Range start/stop points.
= 0.5
spread = minimum(ss) - spread * std(ss)
σ_start = maximum(ss) + spread * std(ss)
σ_stop = minimum(ms) - spread * std(ms)
μ_start = maximum(ms) + spread * std(ms)
μ_stop = collect(range(σ_start; stop=σ_stop, length=granularity))
σ_rng = collect(range(μ_start; stop=μ_stop, length=granularity))
μ_rng
# Make surface plot.
= surface(
p
σ_rng,
μ_rng,
evaluate;=(30, 65),
camera# ticks=nothing,
=false,
colorbar=:inferno,
color=label,
title
)
= 1:length(ms)
line_range
scatter3d!(
ss[line_range],
ms[line_range],
lps[line_range];=:viridis,
mc=collect(line_range),
marker_z=0,
msw=false,
legend=false,
colorbar=0.5,
alpha="σ",
xlabel="μ",
ylabel="Log probability",
zlabel=label,
title
)
return p
end;
Sampler Visualization
Introduction
The Code
For each sampler, we will use the same code to plot sampler paths. The block below loads the relevant libraries and defines a function for plotting the sampler’s trajectory across the posterior.
The Turing model definition used here is not especially practical, but it is designed in such a way as to produce visually interesting posterior surfaces to show how different samplers move along the distribution.
setprogress!(false)
Samplers
Gibbs
Gibbs sampling tends to exhibit a “jittery” trajectory. The example below combines HMC
and PG
sampling to traverse the posterior.
= sample(model, Gibbs(HMC(0.01, 5, :s²), PG(20, :m)), 1000)
c plot_sampler(c)
HMC
Hamiltonian Monte Carlo (HMC) sampling is a typical sampler to use, as it tends to be fairly good at converging in a efficient manner. It can often be tricky to set the correct parameters for this sampler however, and the NUTS
sampler is often easier to run if you don’t want to spend too much time fiddling with step size and and the number of steps to take. Note however that HMC
does not explore the positive values μ very well, likely due to the leapfrog and step size parameter settings.
= sample(model, HMC(0.01, 10), 1000)
c plot_sampler(c)