Skip to content

Commit 1fb8895

Browse files
committed
Expand 'Getting Started' page
- Bump the minimum version of Julia. - Explain the significance of parameters to @model function. - Explain how to obtain the actual samples in the chain. - Expand on the maths involved in the analytical posterior calculation (otherwise, to someone who hasn't seen it before, the formulas look too magic).
1 parent 0b3bb94 commit 1fb8895

File tree

1 file changed

+86
-33
lines changed

1 file changed

+86
-33
lines changed

tutorials/docs-00-getting-started/index.qmd

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,96 +16,149 @@ Pkg.instantiate();
1616

1717
To use Turing, you need to install Julia first and then install Turing.
1818

19-
### Install Julia
19+
You will need to install Julia 1.7 or greater, which you can get from [the official Julia website](http://julialang.org/downloads/).
2020

21-
You will need to install Julia 1.3 or greater, which you can get from [the official Julia website](http://julialang.org/downloads/).
22-
23-
### Install Turing.jl
24-
25-
Turing is an officially registered Julia package, so you can install a stable version of Turing by running the following in the Julia REPL:
21+
Turing is officially registered in the [Julia General package registry](https://github.com/JuliaRegistries/General), which means that you can install a stable version of Turing by running the following in the Julia REPL:
2622

2723
```{julia}
2824
#| output: false
2925
using Pkg
3026
Pkg.add("Turing")
3127
```
3228

33-
You can check if all tests pass by running `Pkg.test("Turing")` (it might take a long time)
29+
### Example usage
3430

35-
### Example
31+
Here is a simple example showing Turing in action.
3632

37-
Here's a simple example showing Turing in action.
38-
39-
First, we can load the Turing and StatsPlots modules
33+
First, we load the Turing and StatsPlots modules.
34+
The latter is required for visualising the results.
4035

4136
```{julia}
4237
using Turing
4338
using StatsPlots
4439
```
4540

46-
Then, we define a simple Normal model with unknown mean and variance
41+
Then, we define a simple Normal model with unknown mean and variance.
42+
Here, both `x` and `y` are observed values (since they are function parameters), whereas `m` and `` are the parameters to be inferred.
4743

4844
```{julia}
4945
@model function gdemo(x, y)
5046
s² ~ InverseGamma(2, 3)
5147
m ~ Normal(0, sqrt(s²))
5248
x ~ Normal(m, sqrt(s²))
53-
return y ~ Normal(m, sqrt(s²))
49+
y ~ Normal(m, sqrt(s²))
5450
end
5551
```
5652

57-
Then we can run a sampler to collect results. In this case, it is a Hamiltonian Monte Carlo sampler
53+
Suppose we have some data `x` and `y` that we want to infer the mean and variance for.
54+
We can pass these data as arguments to the `gdemo` function, and run a sampler to collect the results.
55+
In this specific example, we collect 1000 samples using the No U-Turn Sampler (NUTS) algorithm, which is a Hamiltonian Monte Carlo method.
5856

5957
```{julia}
6058
chn = sample(gdemo(1.5, 2), NUTS(), 1000, progress=false)
6159
```
6260

63-
We can plot the results
61+
We can plot the results:
6462

6563
```{julia}
6664
plot(chn)
6765
```
6866

69-
In this case, because we use the normal-inverse gamma distribution as a conjugate prior, we can compute its updated mean as follows:
67+
and obtain summary statistics by indexing the chain:
68+
69+
```{julia}
70+
mean(chn[:m]), mean(chn[:s²])
71+
```
72+
73+
74+
### Verifying the results
75+
76+
To verify the results of this example, we can analytically solve for the posterior distribution.
77+
Our prior is a normal-inverse gamma distribution:
78+
79+
$$\begin{align}
80+
P(s^2) &= \Gamma^{-1}(s^2 | \alpha = 2, \beta = 3) \\
81+
P(m) &= \mathcal{N}(m | \mu = 0, \sigma^2 = s^2) \\
82+
\implies P(m, s^2) &= \text{N-}\Gamma^{-1}(m, s^2 | \mu = 0, \lambda = 1, \alpha = 2, \beta = 3).
83+
\end{align}$$
84+
85+
This is a conjugate prior for a normal distribution with unknown mean and variance.
86+
So, the posterior distribution given some data $\mathbf{x}$ is also a normal-inverse gamma distribution, which we can compute analytically:
87+
88+
$$P(m, s^2 | \mathbf{x}) = \text{N-}\Gamma^{-1}(m, s^2 | \mu', \lambda', \alpha', \beta').$$
89+
90+
The four updated parameters are given respectively (see for example [Wikipedia](https://en.wikipedia.org/wiki/Normal-gamma_distribution#Posterior_distribution_of_the_parameters)) by
91+
92+
$$\begin{align}
93+
\mu' &= \frac{\lambda\mu + n\bar{x}}{\lambda + n}; &
94+
\lambda' &= \lambda + n; \\[0.3cm]
95+
\alpha' &= \alpha + \frac{n}{2}; &
96+
\beta' &= \beta + \frac{1}{2}\left(nv + \frac{\lambda n(\bar{x} - \mu)^2}{\lambda + n}\right),
97+
\end{align}$$
98+
99+
where $n$ is the number of data points, $\bar{x}$ the mean of the data, and $v$ the uncorrected sample variance of the data.
70100

71101
```{julia}
72102
s² = InverseGamma(2, 3)
73-
m = Normal(0, 1)
103+
α, β = shape(s²), scale(s²)
104+
105+
# We defined m ~ Normal(0, sqrt(s²)), and the normal-inverse gamma
106+
# distribution is defined by m ~ Normal(µ, sqrt(s²/λ)), which lets
107+
# us identify the following
108+
µ, λ = 0, 1
109+
74110
data = [1.5, 2]
75111
x_bar = mean(data)
76-
N = length(data)
112+
n = length(data)
113+
v = var(data; corrected=false)
114+
115+
µ´ = ((λ * µ) + (n * x_bar)) / (λ + n)
116+
λ´ = λ + n
117+
α´ = α + n / 2
118+
β´ = β + ((n * v) + ((λ * n * (x_bar - µ)^2) / (λ + n))) / 2
77119
78-
mean_exp = (m.σ * m.μ + N * x_bar) / (m.σ + N)
120+
(µ´, λ´, α´, β´)
79121
```
80122

81-
We can also compute the updated variance
123+
We can use these to analytically calculate, for example, the expectation values of the mean and variance parameters in the posterior distribution: $E[m] = \mu'$, and $E[s^2] = \beta'/(\alpha
124+
- 1)$.
82125

83126
```{julia}
84-
updated_alpha = shape(s²) + (N / 2)
85-
updated_beta =
86-
scale(s²) +
87-
(1 / 2) * sum((data[n] - x_bar)^2 for n in 1:N) +
88-
(N * m.σ) / (N + m.σ) * ((x_bar)^2) / 2
89-
variance_exp = updated_beta / (updated_alpha - 1)
127+
mean_exp = µ´
128+
variance_exp = β´ / (α´ - 1)
129+
130+
(mean_exp, variance_exp)
90131
```
91132

92-
Finally, we can check if these expectations align with our HMC approximations from earlier. We can compute samples from a normal-inverse gamma following the equations given [here](https://en.wikipedia.org/wiki/Normal-inverse-gamma_distribution#Generating_normal-inverse-gamma_random_variates).
133+
Alternatively, we can compare the two distributions visually (one parameter at a time).
134+
To do so, we will directly sample from the analytical posterior distribution using the procedure described in [Wikipedia](https://en.wikipedia.org/wiki/Normal-inverse-gamma_distribution#Generating_normal-inverse-gamma_random_variates).
93135

94136
```{julia}
95-
function sample_posterior(alpha, beta, mean, lambda, iterations)
137+
function sample_posterior_analytic(µ´, λ´, α´, β´, iterations)
96138
samples = []
97139
for i in 1:iterations
98-
sample_variance = rand(InverseGamma(alpha, beta), 1)
99-
sample_x = rand(Normal(mean, sqrt(sample_variance[1]) / lambda), 1)
100-
samples = append!(samples, sample_x)
140+
sampled_s² = rand(InverseGamma(α´, β'))
141+
sampled_m = rand(Normal(µ´, sqrt(sampled_s² / λ´)))
142+
samples = push!(samples, (sampled_m, sampled_s²))
101143
end
102144
return samples
103145
end
104146
105-
analytical_samples = sample_posterior(updated_alpha, updated_beta, mean_exp, 2, 1000);
147+
analytical_samples = sample_posterior_analytic(µ´, λ´, α´, β´, 1000);
106148
```
107149

150+
Comparing the distribution of the mean:
151+
108152
```{julia}
109-
density(analytical_samples; label="Posterior (Analytical)")
153+
density([s[1] for s in analytical_samples]; label="Posterior (Analytical)")
110154
density!(chn[:m]; label="Posterior (HMC)")
111155
```
156+
157+
and the distribution of the variance:
158+
159+
```{julia}
160+
density([s[2] for s in analytical_samples]; label="Posterior (Analytical)")
161+
density!(chn[:s²]; label="Posterior (HMC)")
162+
```
163+
164+
we see that our HMC sampler has given us a good representation of the posterior distribution.

0 commit comments

Comments
 (0)