Skip to content

Commit 20445d8

Browse files
authored
Add mode estimation page (#470)
* Add mode estimation page * Improvements to mode estimation docs
1 parent 06e22fc commit 20445d8

File tree

6 files changed

+1697
-111
lines changed

6 files changed

+1697
-111
lines changed

_quarto.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ website:
5353
- text: "Quick Start"
5454
href: tutorials/docs-14-using-turing-quick-start/index.qmd
5555
- tutorials/docs-12-using-turing-guide/index.qmd
56+
- text: "Mode Estimation"
57+
href: tutorials/docs-17-mode-estimation/index.qmd
5658
- tutorials/docs-09-using-turing-advanced/index.qmd
5759
- tutorials/docs-10-using-turing-autodiff/index.qmd
5860
- tutorials/docs-13-using-turing-performance-tips/index.qmd
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
[deps]
22
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
3-
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
43
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
54
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
65
Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0"

tutorials/docs-12-using-turing-guide/index.qmd

Lines changed: 4 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -418,120 +418,14 @@ loglikelihood(model, chn)
418418

419419
### Maximum likelihood and maximum a posterior estimates
420420

421-
Turing provides support for two mode estimation techniques, [maximum likelihood estimation](https://en.wikipedia.org/wiki/Maximum_likelihood_estimation) (MLE) and [maximum a posterior](https://en.wikipedia.org/wiki/Maximum_a_posteriori_estimation) (MAP) estimation. Optimization is performed by the [Optim.jl](https://github.com/JuliaNLSolvers/Optim.jl) package. Mode estimation is currently a optional tool, and will not be available to you unless you have manually installed Optim and loaded the package with a `using` statement. To install Optim, run `import Pkg; Pkg.add("Optim")`.
422-
423-
Mode estimation only works when all model parameters are continuous -- discrete parameters cannot be estimated with MLE/MAP as of yet.
424-
425-
To understand how mode estimation works, let us first load Turing and Optim to enable mode estimation, and then declare a model:
426-
427-
```{julia}
428-
# Note that loading Optim explicitly is required for mode estimation to function,
429-
# as Turing does not load the opimization suite unless Optim is loaded as well.
430-
using Turing
431-
using Optim
432-
433-
@model function gdemo(x)
434-
s² ~ InverseGamma(2, 3)
435-
m ~ Normal(0, sqrt(s²))
436-
437-
for i in eachindex(x)
438-
x[i] ~ Normal(m, sqrt(s²))
439-
end
440-
end
441-
```
442-
443-
Once the model is defined, we can construct a model instance as we normally would:
444-
445-
```{julia}
446-
# Create some data to pass to the model.
447-
data = [1.5, 2.0]
448-
449-
# Instantiate the gdemo model with our data.
450-
model = gdemo(data)
451-
```
452-
453-
Mode estimation is typically quick and easy at this point. Turing extends the function `Optim.optimize` and accepts the structs `MLE()` or `MAP()`, which inform Turing whether to provide an MLE or MAP estimate, respectively. By default, the [LBFGS optimizer](https://julianlsolvers.github.io/Optim.jl/stable/#algo/lbfgs/) is used, though this can be changed. Basic usage is:
421+
Turing also has functions for estimating the maximum aposteriori and maximum likelihood parameters of a model. This can be done with
454422

455423
```{julia}
456-
# Generate a MLE estimate.
457-
mle_estimate = optimize(model, MLE())
458-
459-
# Generate a MAP estimate.
460-
map_estimate = optimize(model, MAP())
424+
mle_estimate = maximum_likelihood(model)
425+
map_estimate = maximum_a_posteriori(model)
461426
```
462427

463-
If you wish to change to a different optimizer, such as `NelderMead`, simply place your optimizer in the third argument slot:
464-
465-
```{julia}
466-
#| eval: false
467-
# Use NelderMead
468-
mle_estimate = optimize(model, MLE(), NelderMead())
469-
470-
# Use SimulatedAnnealing
471-
mle_estimate = optimize(model, MLE(), SimulatedAnnealing())
472-
473-
# Use ParticleSwarm
474-
mle_estimate = optimize(model, MLE(), ParticleSwarm())
475-
476-
# Use Newton
477-
mle_estimate = optimize(model, MLE(), Newton())
478-
479-
# Use AcceleratedGradientDescent
480-
mle_estimate = optimize(model, MLE(), AcceleratedGradientDescent())
481-
```
482-
483-
Some methods may have trouble calculating the mode because not enough iterations were allowed, or the target function moved upwards between function calls. Turing will warn you if Optim fails to converge by running `Optim.converge`. A typical solution to this might be to add more iterations, or allow the optimizer to increase between function iterations:
484-
485-
```{julia}
486-
#| eval: false
487-
# Increase the iterations and allow function eval to increase between calls.
488-
mle_estimate = optimize(
489-
model, MLE(), Newton(), Optim.Options(; iterations=10_000, allow_f_increases=true)
490-
)
491-
```
492-
493-
More options for Optim are available [here](https://julianlsolvers.github.io/Optim.jl/stable/#user/config/).
494-
495-
#### Analyzing your mode estimate
496-
497-
Turing extends several methods from `StatsBase` that can be used to analyze your mode estimation results. Methods implemented include `vcov`, `informationmatrix`, `coeftable`, `params`, and `coef`, among others.
498-
499-
For example, let's examine our ML estimate from above using `coeftable`:
500-
501-
```{julia}
502-
#| eval: false
503-
# Import StatsBase to use it's statistical methods.
504-
using StatsBase
505-
506-
# Print out the coefficient table.
507-
coeftable(mle_estimate)
508-
```
509-
510-
511-
<!-- table -->
512-
```{.cell-bg}
513-
─────────────────────────────
514-
estimate stderror tstat
515-
─────────────────────────────
516-
s 0.0625 0.0625 1.0
517-
m 1.75 0.176777 9.8995
518-
─────────────────────────────
519-
```
520-
521-
Standard errors are calculated from the Fisher information matrix (inverse Hessian of the log likelihood or log joint). t-statistics will be familiar to frequentist statisticians. Warning -- standard errors calculated in this way may not always be appropriate for MAP estimates, so please be cautious in interpreting them.
522-
523-
#### Sampling with the MAP/MLE as initial states
524-
525-
You can begin sampling your chain from an MLE/MAP estimate by extracting the vector of parameter values and providing it to the `sample` function with the keyword `initial_params`. For example, here is how to sample from the full posterior using the MAP estimate as the starting point:
526-
527-
```{julia}
528-
#| eval: false
529-
# Generate an MAP estimate.
530-
map_estimate = optimize(model, MAP())
531-
532-
# Sample with the MAP estimate as the starting point.
533-
chain = sample(model, NUTS(), 1_000; initial_params=map_estimate.values.array)
534-
```
428+
For more details see the [mode estimation page](../docs-17-mode-estimation/index.qmd).
535429

536430
## Beyond the Basics
537431

0 commit comments

Comments
 (0)