InferenceReport
Summary
InferenceReport
is a Julia package to automatically create reports based on MCMC inference methods.
Installing InferenceReport
- If you have not done so, install Julia. Julia 1.9 and higher are supported.
- Install
InferenceReport
using
using Pkg; Pkg.add("InferenceReport")
Usage
InferenceReport's main function is report
. It takes one mandatory argument, which at the moment can be either Pigeons' Parallel Tempering (PT) output, or MCMCChains' Chains struct.
We provide an example of each in the next two sections.
From Pigeons
First, run Parallel Tempering (PT) via Pigeons.
Then call report()
on the resulting PT struct:
using InferenceReport
using Pigeons
pt = pigeons(
target = toy_mvn_target(2),
n_rounds = 4,
record = [traces; round_trip; record_default()])
report(pt)
───────────────────────────────────────────────────────────────────────────────────────
scans restarts Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0 0.609 4.53e-05 1.16e+04 -1.68 0.705 0.932
4 0 1.28 5.5e-05 1.84e+04 -1.86 0.527 0.858
8 0 1.39 6.15e-05 3.34e+04 -2.29 0.458 0.845
16 1 1.55 0.000101 5.82e+04 -2.27 0.646 0.828
───────────────────────────────────────────────────────────────────────────────────────
target_description...[skipped: no description provided]
pair_plot... ✓
trace_plot... ✓
moments... ✓
trace_plot_cumulative... ✓
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress... ✓
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-02-55-bFzIKdoX
This will generate an HTML report with various useful diagnostic plots and open it in your default browser.
See Examples
in the left side bar to see examples of such reports.
See report
for more information on the options available.
You may also generate a TeX/PDF version using Documenter.jl's TeX support as follows:
report(pt; writer=InferenceReport.Documenter.LaTeX(platform = "docker"))
target_description...[skipped: no description provided]
pair_plot... ✓
trace_plot... ✓
moments... ✓
trace_plot_cumulative... ✓
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress... ✓
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-03-01-1L7BkYVX
From MCMCChains
MCMCChains.jl is used to store MCMC samples in packages such as Turing.jl.
Simply pass it into report
to generate and open an HTML report:
using InferenceReport
using Turing
using MCMCChains
# example from Turing.jl's webpage
@model function coinflip(; N::Int)
p ~ Beta(1, 1)
y ~ filldist(Bernoulli(p), N)
return y
end;
y = Bool[1, 1, 1, 0, 0, 1]
model = coinflip(; N=length(y)) | (; y)
chain = sample(model, NUTS(), 100; progress=false)
report(chain)
┌ Info: Found initial step size
└ ϵ = 3.2
target_description...[skipped: no description provided]
pair_plot... ✓
trace_plot... ✓
moments... ✓
trace_plot_cumulative... ✓
mpi_standard_out...[skipped: only applies to Pigeons]
lcb...[skipped: only applies to Pigeons]
gcb_progress...[skipped: only applies to Pigeons]
logz_progress...[skipped: only applies to Pigeons]
round_trip_progress...[skipped: only applies to Pigeons]
swaps_plot...[skipped: only applies to Pigeons]
pigeons_summary...[skipped: only applies to Pigeons]
pigeons_inputs...[skipped: only applies to Pigeons]
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-07-52-E2xtzfEw
Target descriptions
Two methods are available to specify descriptions for target distributions.
First, a TargetDescription
can be passed in as argument:
using InferenceReport
using Pigeons
target = toy_mvn_target(2)
pt = pigeons(; target, n_rounds = 2)
target_description = TargetDescription(
text = """
The model description can use math: ``x^2``.
""")
report(pt; target_description)
┌ Info: Neither traces, disk, nor online recorders included.
│ You may not have access to your samples (unless you are using a custom recorder, or maybe you just want log(Z)).
└ To add recorders, use e.g. pigeons(target = ..., record = [traces; record_default()])
────────────────────────────────────────────────────────────────────────────
scans Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0.609 4.23e-05 1.14e+04 -1.68 0.705 0.932
4 1.28 5.23e-05 1.8e+04 -1.86 0.527 0.858
────────────────────────────────────────────────────────────────────────────
Could not build traces: ErrorException("type NamedTuple has no field traces")
target_description... ✓
pair_plot...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
trace_plot...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
moments...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
trace_plot_cumulative...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress...[skipped: number restarts not recorded]
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-11-39-lHedHob4
Sometimes we may have a family of targets (e.g., in the above example, normals indexed by their dimensionality) and would like the documentation to be automatically generated based on the parameters.
To do so, implement your own pigeons_target_description
as done in the following example:
using InferenceReport
using Pigeons
target = toy_mvn_target(2)
pt = pigeons(; target, n_rounds = 2)
const MyTargetType = typeof(target)
InferenceReport.pigeons_target_description(target::MyTargetType) = TargetDescription(
text = """
Some description.
It can use information in the target, e.g. here
to report that its dimension is: $(target.dim)
"""
)
┌ Info: Neither traces, disk, nor online recorders included.
│ You may not have access to your samples (unless you are using a custom recorder, or maybe you just want log(Z)).
└ To add recorders, use e.g. pigeons(target = ..., record = [traces; record_default()])
────────────────────────────────────────────────────────────────────────────
scans Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0.609 2.1e-05 1.14e+04 -1.68 0.705 0.932
4 1.28 2.27e-05 1.8e+04 -1.86 0.527 0.858
────────────────────────────────────────────────────────────────────────────
Adding references to a bibliography
To create a bibliography, we provide automatic integration with DocumenterCitations.
In the target description's text, use a syntax like
[bib_key](@citet)
to include a citation (see DocumenterCitations for more citation styles). Then pass include the contents of bibtex file to pigeons_target_description
's bibliography
argument.
using InferenceReport
using Pigeons
target = toy_mvn_target(2)
pt = pigeons(; target, n_rounds = 2)
report(pt;
target_description = TargetDescription(
text = """
The model description can use math: ``x^2``.
Citation: [neal_slice_2003](@citet)
""",
bibliography = InferenceReport.example_bib()
))
┌ Info: Neither traces, disk, nor online recorders included.
│ You may not have access to your samples (unless you are using a custom recorder, or maybe you just want log(Z)).
└ To add recorders, use e.g. pigeons(target = ..., record = [traces; record_default()])
────────────────────────────────────────────────────────────────────────────
scans Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0.609 1.51e-05 1.14e+04 -1.68 0.705 0.932
4 1.28 2.02e-05 1.8e+04 -1.86 0.527 0.858
────────────────────────────────────────────────────────────────────────────
Could not build traces: ErrorException("type NamedTuple has no field traces")
target_description... ✓
pair_plot...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
trace_plot...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
moments...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
trace_plot_cumulative...[skipped: no traces provided (in Pigeons, use 'record = [traces])]
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress...[skipped: number restarts not recorded]
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-11-43-u3lKE7fZ
See funnel_model
and Bibliography
in the navigation bar to see examples of linked bibliographic items.
Reproducibility instructions
Simple Pigeons reproducibility instructions can be added to the generated page. This is done via the reproducibility_command
argument to report
. This should be a string showing how to create an Inputs struct. When reproducibility_command
is provided, InferenceReport
will combine it to information queried in the current git repository to attempt to string together a mini-script that can be used to reproduce the result.
To help filling reproducibility_command
, we provide a macro, @reproducible
, which, given an expression, produces a pair containing the verbatim expression as well as its string value. Here his an example:
using InferenceReport
using Pigeons
inputs, reproducibility_command =
@reproducible Inputs(
target = toy_mvn_target(1), n_rounds = 4, record = [traces])
pt = pigeons(inputs)
report(pt; reproducibility_command)
──────────────────────────────────────────────────────
scans Λ log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ──────────
2 0.417 -1.56 0.782 0.954
4 0.564 -0.653 0.61 0.937
8 0.597 -0.833 0.869 0.934
16 0.686 -1.35 0.729 0.924
──────────────────────────────────────────────────────
target_description... ✓
pair_plot... ✓
trace_plot... ✓
moments... ✓
trace_plot_cumulative... ✓
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress...[skipped: number restarts not recorded]
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info... ✓
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-11-46-hFomjP6f
Adding postprocessors
Calling report()
triggers a list of postprocessors, each creating a section in the generated report.
To add a custom section in the report, first, create a function taking as input the PostprocessContext
which contains all required information such as the MCMC traces.
Here is an example of postprocessor outputting the number of dimensions:
using InferenceReport
using MCMCChains
import InferenceReport: get_chains, default_postprocessors, add_table, add_plot, add_markdown
function report_dim(context)
chns = get_chains(context)
params = names(chns, :parameters)
n_params = length(params)
add_markdown(context;
title = "Dimension",
contents = "The target has $n_params parameters."
)
end
report_dim (generic function with 1 method)
Various utilities are available to generate contents, see for example add_table
, add_plot
, add_markdown
.
Then, to use the custom postprocessor, add it to the postprocessors
argument:
using Pigeons
pt = pigeons(
target = toy_mvn_target(2),
n_rounds = 4,
record = [traces; round_trip; record_default()])
report(pt; postprocessors = [report_dim; default_postprocessors()])
───────────────────────────────────────────────────────────────────────────────────────
scans restarts Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α)
────────── ────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0 0.609 4.11e-05 1.16e+04 -1.68 0.705 0.932
4 0 1.28 5.85e-05 1.84e+04 -1.86 0.527 0.858
8 0 1.39 6.22e-05 3.34e+04 -2.29 0.458 0.845
16 1 1.55 7.1e-05 5.82e+04 -2.27 0.646 0.828
───────────────────────────────────────────────────────────────────────────────────────
report_dim... ✓
target_description... ✓
pair_plot... ✓
trace_plot... ✓
moments... ✓
trace_plot_cumulative... ✓
mpi_standard_out...[skipped: no MPI std out files found]
lcb... ✓
gcb_progress... ✓
logz_progress... ✓
round_trip_progress... ✓
swaps_plot... ✓
pigeons_summary... ✓
pigeons_inputs... ✓
reproducibility_info...[skipped: missing reproducibility_command]
Report generated at: /home/runner/work/InferenceReport.jl/InferenceReport.jl/docs/build/results/all/2024-09-20-19-11-49-ITIFgSZQ
Pull requests for additional postprocessors are welcome.
Documenter.jl integration
Note: at the moment, this feature is supported on Julia 1.10+ only.
See our Documenter.jl make file to see how to integrate InferenceReport into a broader documentation page. The key functions used are headless
, report_to_docs
and as_doc_page
.