Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation #153

Merged
merged 25 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b8a3111
added CompositionSampler, RepeatedSampler, MultiSampler together with
torfjelde Mar 2, 2023
ae8588e
added LinearAlgebra as dep
torfjelde Mar 2, 2023
7db1dce
big update but now everything finally works
torfjelde Mar 3, 2023
10905f2
added additional pass-on-methods for meta-samplers and moved the
torfjelde Mar 3, 2023
9e08c3a
renamed state_from_state to state_from and changed the ordering of the
torfjelde Mar 3, 2023
a90845a
added some missing methods and fixed a typo
torfjelde Mar 3, 2023
a77c32a
added model_for_chain and model_for_process similar to other utility
torfjelde Mar 3, 2023
38c0a52
added todo
torfjelde Mar 3, 2023
ad22454
moved bundling back to ordering of defintions
torfjelde Mar 3, 2023
933c0bd
added missing test dep
torfjelde Mar 3, 2023
0b44758
increase number of steps for one of the tests
torfjelde Mar 3, 2023
a4016e1
specialize step for combination of RepeatedSampler and MultiSampler
torfjelde Mar 3, 2023
ef97a94
Update src/sampler.jl
torfjelde Mar 9, 2023
180a928
Introduction of `SwapSampler` + make `TemperedSampler` a fancy versi…
torfjelde Mar 11, 2023
7c6fb75
added docs
torfjelde Mar 11, 2023
3555332
Merge branch 'main' into torfjelde/docs
torfjelde Mar 11, 2023
6947189
added a getting started example with a simple GMM + added another
torfjelde Mar 11, 2023
0b8ff19
removed now redundant compute_tempered_logdensities + added some docs
torfjelde Mar 11, 2023
b75817a
minor improvements to docstrings + removed reference to non-existent …
torfjelde Mar 11, 2023
b46e4b9
fixed typo
torfjelde Mar 11, 2023
a09d981
added deployment and actions for doc deployment
torfjelde Mar 11, 2023
28174f1
fixed issue with GR plotting and headless
torfjelde Mar 11, 2023
c70e5aa
fixed missing renamings
torfjelde Mar 14, 2023
03ff80d
defer design docs
torfjelde Mar 14, 2023
25e19b4
added TODO for later on
torfjelde Mar 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/Docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Documentation

on:
push:
branches:
# Build the master branch.
- master
tags: '*'
pull_request:

concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: '1'
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key
JULIA_DEBUG: Documenter # Print `@debug` statements (https://github.com/JuliaDocs/Documenter.jl/issues/955)
GKSwstype: "100" # https://discourse.julialang.org/t/generation-of-documentation-fails-qt-qpa-xcb-could-not-connect-to-display/60988
run: julia --project=docs/ docs/make.jl
26 changes: 26 additions & 0 deletions .github/workflows/DocsPreviewCleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: DocsPreviewCleanup

on:
pull_request:
types: [closed]

jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v2
with:
ref: gh-pages
- name: Delete preview and history + push changes
run: |
if [ -d "previews/PR$PRNUM" ]; then
git config user.name "Documenter.jl"
git config user.email "documenter@juliadocs.github.io"
git rm -rf "previews/PR$PRNUM"
git commit -m "delete preview"
git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree})
git push --force origin gh-pages-new:gh-pages
fi
env:
PRNUM: ${{ github.event.number }}
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
site/
10 changes: 10 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[deps]
AdvancedMH = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
MCMCTempering = "ce233488-44ea-4441-b732-192676ce2298"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
14 changes: 14 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Documenter
using MCMCTempering

DocMeta.setdocmeta!(MCMCTempering, :DocTestSetup, :(using MCMCTempering); recursive=true)

makedocs(
sitename = "MCMCTempering",
format = Documenter.HTML(),
modules = [MCMCTempering],
pages=["Home" => "index.md", "getting-started.md", "api.md"],
)

# Deply!
deploydocs(; repo="github.com/TuringLang/MCMCTempering.jl.git", push_preview=true)
118 changes: 118 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# API

## Temper samplers

```@docs
MCMCTempering.tempered
MCMCTempering.TemperedSampler
```

Under the hood, [`MCMCTempering.TemperedSampler`](@ref) is actually just a "fancy" representation of a composition (represented using a [`MCMCTempering.CompositionSampler`](@ref)) of a [`MultiSampler`](@ref) and a [`SwapSampler`](@ref).

Roughly speaking, the implementation of `AbstractMCMC.step` for [`MCMCTempering.TemperedSampler`](@ref) is basically

```julia
# 1. Construct the tempered models.
multimodel = MultiModel([make_tempered_model(model, β) for β in tempered_sampler.chain_to_beta])
# 2. Construct the samplers (can be the same one repeated multiple times or different ones)
multisampler = MultiSampler([getsampler(tempered_sampler, i) for i = 1:numtemps])
# 3. Step targeting `multimodel` using a compositoin of `multisampler` and `swapsampler`.
AbstractMCMC.step(rng, multimodel, multisampler ∘ swapsampler, state; kwargs...)
```

which in this case is provided by repeated calls to [`MCMCTempering.make_tempered_model`](@ref).

```@docs
MCMCTempering.make_tempered_model
```

This should be overloaded if you have some custom model-type that does not support the LogDensityProblems.jl-interface.

## Swapping

Swapping is implemented using the somewhat special [`MCMCTempering.SwapSampler`](@ref)

```@docs
MCMCTempering.SwapSampler
MCMCTempering.swapstrategy
```

!!! warning
This is a rather special sampler because, unlike most other implementations of `AbstractMCMC.AbstractSampler`, this is not a valid sampler _on its own_; for this to be sensible it needs to be part of composition (see [`MCMCTempering.CompositionSampler`](@ref)) with _at least_ one other type of (an actually valid) sampler.

### Different swap-strategies

A [`MCMCTempering.SwapSampler`](@ref) can be defined with different swapping strategies:

```@docs
MCMCTempering.AbstractSwapStrategy
MCMCTempering.ReversibleSwap
MCMCTempering.NonReversibleSwap
MCMCTempering.SingleSwap
MCMCTempering.SingleRandomSwap
MCMCTempering.RandomSwap
MCMCTempering.NoSwap
```

```@docs
MCMCTempering.swap_step
```

## Other samplers

```@docs
MCMCTempering.saveall
```

### Compositions of samplers
```@docs
MCMCTempering.CompositionSampler
```

This sampler also has its own transition- and state-type

```@docs
MCMCTempering.CompositionTransition
MCMCTempering.CompositionState
```

#### Repeated sampler / composition with itself

Large compositions can have unfortunate effects on the compilation times in Julia.

To alleviate this issue we also have the [`RepeatedSampler`](@ref):

```@docs
MCMCTempering.RepeatedSampler
```

In the case where [`saveall`](@ref) returns `false`, `step` for a [`MCMCTempering.RepeatedSampler`](@ref) simply returns the last transition and state; if it returns `true`, then the transition is of type [`MCMCTempering.SequentialTransitions`](@ref) and the state is of type [`MCMCTempering.SequentialStates`](@ref).

```@docs
MCMCTempering.SequentialTransitions
MCMCTempering.SequentialStates
```

This effectively allows you to specify whether or not the "intermediate" states should be kept or not.

!!! note
You will rarely see [`MCMCTempering.SequentialTransitions`](@ref) and [`MCMCTempering.SequentialStates`](@ref) as a user because `AbstractMCMC.bundle_samples` has been overloaded to these to return the flattened representation, i.e. we "un-roll" the transitions in every [`MCMCTempering.SequentialTransitions`](@ref).

### Multiple or product of samplers

```@docs
MCMCTempering.MultiSampler
```

where the tempered models are represented using a [`MCMCTempering.MultiModel`](@ref)

```@docs
MCMCTempering.MultiModel
```

The `step` for a [`MCMCTempering.MultiSampler`](@ref) and a [`MCMCTempering.MultiModel`] is a transition of type [`MCMCTempering.MultipleTransitions`](@ref) and a state of type [`MCMCTempering.MultipleStates`](@ref)

```@docs
MCMCTempering.MultipleTransitions
MCMCTempering.MultipleStates
```
151 changes: 151 additions & 0 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Getting started

## Mixture of Gaussians

Suppose we have a mixture of Gaussians, e.g. something like

```@example gmm
using Distributions
target_distribution = MixtureModel(
Normal,
[(-3, 1.5), (3, 1.5), (20, 1.5)], # parameters
[0.5, 0.3, 0.2] # weights
)
```

This is a simple 1-dimensional distribution, so let's visualize it:

```@example gmm
using StatsPlots
figsize = (800, 400)
plot(target_distribution; components=false, label=nothing, size=figsize)
```

We can convert a `Distribution` from [Distributions.jl](https://github.com/JuliaStats/Distributions.jl) into something we can pass to `sample` for many different samplers by implementing the [LogDensityProblems.jl](https://github.com/tpapp/LogDensityProblems.jl) interface:

```@example gmm
using LogDensityProblems: LogDensityProblems

struct DistributionLogDensity{D}
d::D
end

LogDensityProblems.logdensity(d::DistributionLogDensity, x) = loglikelihood(d.d, x)
LogDensityProblems.dimension(d::DistributionLogDensity) = length(d.d)
LogDensityProblems.capabilities(::Type{<:DistributionLogDensity}) = LogDensityProblems.LogDensityOrder{0}()

# Wrap our target distribution.
target_model = DistributionLogDensity(target_distribution)
```

Immediately one might reach for a standard sampler, e.g. a random-walk Metropolis-Hastings (RWMH) from [`AdvancedMH.jl`](https://github.com/TuringLang/AdvancedMH.jl) and start sampling using `sample`:

```@example gmm
using AdvancedMH, MCMCChains, LinearAlgebra

using StableRNGs
rng = StableRNG(42) # To ensure reproducbility across devices.

sampler = RWMH(MvNormal(zeros(1), I))
num_iterations = 10_000
chain = sample(
rng,
target_model, sampler, num_iterations;
chain_type=MCMCChains.Chains,
param_names=["x"]
)
```

```@example gmm
plot(chain; size=figsize)
```

This doesn't look quite like what we're expecting.

```@example gmm
plot(target_distribution; components=false, linewidth=2)
density!(chain)
plot!(size=figsize)
```

Notice how `chain` has zero probability mass in the left-most component of the mixture!

Let's instead try to use a _tempered_ version of `RWMH`. _But_ before we do that, we need to make sure that AdvancedMH.jl is compatible with MCMCTempering.jl.

To do that we need to implement two methods. First we need to tell MCMCTempering how to extract the parameters, and potentially the log-probabilities, from a `AdvancedMH.Transition`:

```@docs
MCMCTempering.getparams_and_logprob
```

And similarly, we need a way to _update_ the parameters and the log-probabilities of a `AdvancedMH.Transition`:

```@docs
MCMCTempering.setparams_and_logprob!!
```

Luckily, implementing these is quite easy:

```@example gmm
using MCMCTempering

MCMCTempering.getparams_and_logprob(transition::AdvancedMH.Transition) = transition.params, transition.lp
function MCMCTempering.setparams_and_logprob!!(transition::AdvancedMH.Transition, params, lp)
return AdvancedMH.Transition(params, lp)
end
```

Now that this is done, we can wrap `sampler` in a [`MCMCTempering.TemperedSampler`](@ref)

```@example gmm
inverse_temperatures = 0.90 .^ (0:20)
sampler_tempered = TemperedSampler(sampler, inverse_temperatures)
```

aaaaand `sample`!

```@example gmm
chain_tempered = sample(
rng, target_model, sampler_tempered, num_iterations;
chain_type=MCMCChains.Chains,
param_names=["x"]
)
```

Let's see how this looks

```@example gmm
plot(chain_tempered)
plot!(size=figsize)
```

```@example gmm
plot(target_distribution; components=false, linewidth=2)
density!(chain)
density!(chain_tempered)
plot!(size=figsize)
```

Neato; we've indeed captured the target distribution much better!

We can even inspect _all_ of the tempered chains if we so desire

```@example gmm
chain_tempered_all = sample(
rng,
target_model, sampler_tempered, num_iterations;
chain_type=Vector{MCMCChains.Chains}, # Different!
param_names=["x"]
);
```

```@example gmm
plot(target_distribution; components=false, linewidth=2)
density!(chain)
# Tempered ones.
for chain_tempered in chain_tempered_all[2:end]
density!(chain_tempered, color="green", alpha=inv(sqrt(length(chain_tempered_all))))
end
density!(chain_tempered_all[1], color="green", size=figsize)
plot!(size=figsize)
```
5 changes: 5 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# MCMCTempering.jl

*Tempering methods and more for Markov chain Monte Carlo methods.*

MCMCTempering provides implementations of different ways to define tempered samplers and models, in addition to other ways of composing and mixing samplers.
Loading