Skip to content

Commit 99661ef

Browse files
committed
correct signatures in function references and add section on embedded Laplace in users guide on GPs.
1 parent 3545625 commit 99661ef

File tree

3 files changed

+218
-20
lines changed

3 files changed

+218
-20
lines changed

src/bibtex/all.bib

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1894,4 +1894,50 @@ @misc{seyboldt:2024
18941894
note="pyro-ppl GitHub repository issue \#1751",
18951895
year = "2024",
18961896
url ="https://github.com/pyro-ppl/numpyro/pull/1751#issuecomment-1980569811"
1897-
}
1897+
}
1898+
1899+
@article{Margossian:2020,
1900+
Author = {Margossian, C. C. and Vehtari, A. and Simpson, D.
1901+
and Agrawal, R.},
1902+
Title = {Hamiltonian Monte Carlo using an adjoint-differentiated Laplace approximation: Bayesian inference for latent Gaussian models and beyond},
1903+
journal = {Advances in Neural Information Processing Systems},
1904+
volume = {34},
1905+
Year = {2020}}
1906+
1907+
@article{Kuss:2005,
1908+
author = {Kuss, Malte and Rasmussen, Carl E},
1909+
title = {Assessing Approximate Inference for Binary {Gaussian} Process Classification},
1910+
journal = {Journal of Machine Learning Research},
1911+
volume = {6},
1912+
pages = {1679 -- 1704},
1913+
year = {2005}}
1914+
1915+
@article{Vanhatalo:2010,
1916+
author = {Jarno Vanhatalo and Ville Pietil\"{a}inen and Aki Vehtari},
1917+
title = {Approximate inference for disease mapping with sparse {Gaussian} processes},
1918+
journal = {Statistics in Medicine},
1919+
year = {2010},
1920+
volume = {29},
1921+
number = {15},
1922+
pages = {1580--1607}
1923+
}
1924+
1925+
@article{Cseke:2011,
1926+
author = {Botond Cseke and Heskes, Tom},
1927+
title = {Approximate marginals in latent {Gaussian} models},
1928+
journal = {Journal of Machine Learning Research},
1929+
volume = {12},
1930+
issue = {2},
1931+
page = {417 -- 454},
1932+
year = {2011}}
1933+
1934+
@article{Vehtari:2016,
1935+
author = {Aki Vehtari and Tommi Mononen and Ville Tolvanen and Tuomas Sivula and Ole Winther},
1936+
title = {Bayesian Leave-One-Out Cross-Validation Approximations for {Gaussian} Latent Variable Models},
1937+
journal = {Journal of Machine Learning Research},
1938+
year = {2016},
1939+
volume = {17},
1940+
number = {103},
1941+
pages = {1--38},
1942+
url = {http://jmlr.org/papers/v17/14-540.html}
1943+
}

src/functions-reference/embedded_laplace.qmd

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -370,21 +370,20 @@ $p(y \mid \theta)$ is a Poisson distribution with a log link
370370
and allows the user to tune the control parameters of the approximation.
371371
{{< since 2.37 >}}
372372

373-
A similar built-in likelihood lets users specify an offset $x_i \in \mathbb R^+$
374-
to the rate parameter of the Poisson. The likelihood is then,
373+
A similar built-in likelihood lets users specify a vector offset
374+
$x \in \mathbb R^N$ with $x_i \ge 0$ to the rate parameter of the Poisson.
375+
The likelihood is then,
375376
$$
376377
p(y \mid \theta, \phi) = \prod_i\text{Poisson} (y_i \mid \exp(\theta_{g(i)}) x_i).
377378
$$
378379

379-
<!-- real; laplace_marginal_poisson_2_log ~; -->
380380
\index{{\tt \bfseries laplace\_marginal\_poisson\_2\_log }!sampling statement|hyperpage}
381381

382382
`y ~ ` **`laplace_marginal_poisson_2_log`**`(y_index, x, theta_init, covariance_function, (...))`<br>\newline
383383

384384
Increment target log probability density with `laplace_marginal_poisson_2_log_lupmf(y | y_index, x, theta_init, covariance_function, (...))`.
385385
{{< since 2.37 >}}
386386

387-
<!-- real; laplace_marginal_tol_poisson_2_log ~; -->
388387
\index{{\tt \bfseries laplace\_marginal\_tol\_poisson\_2\_log }!sampling statement|hyperpage}
389388

390389
`y ~ ` **`laplace_marginal_tol_poisson_2_log`**`(y_index, x, theta_init, covariance_function, (...), tol, max_steps, hessian_block_size, solver, max_steps_linesearch)`<br>\newline
@@ -393,16 +392,14 @@ Increment target log probability density with `laplace_marginal_tol_poisson_2_lo
393392

394393
The signatures for this function are:
395394

396-
<!-- real; laplace_marginal_poisson_2_log_lpmf; (array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...)); -->
397-
\index{{\tt \bfseries laplace\_marginal\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...)): real}|hyperpage}
398-
`real` **`laplace_marginal_poisson_2_log_lpmf`**`(array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...))`<br>\newline
395+
\index{{\tt \bfseries laplace\_marginal\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...)): real}|hyperpage}
396+
`real` **`laplace_marginal_poisson_2_log_lpmf`**`(array[] int y | array[] int y_index, vector x, vector x, vector theta_init, function covariance_function, tuple(...))`<br>\newline
399397
Returns an approximation to the log marginal likelihood $p(y \mid \phi)$
400398
in the special case where the likelihood $p(y \mid \theta)$ is a Poisson
401399
distribution with a log link and an offset.
402400
{{< since 2.37 >}}
403401

404-
<!-- real; laplace_marginal_tol_poisson_2_log_lpmf; (array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch); -->
405-
\index{{\tt \bfseries laplace\_marginal\_tol\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): real}|hyperpage}
402+
\index{{\tt \bfseries laplace\_marginal\_tol\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): real}|hyperpage}
406403

407404
`real` **`laplace_marginal_tol_poisson_2_log_lpmf`**`(array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch)`<br>\newline
408405

@@ -412,17 +409,15 @@ distribution with a log link and an offset
412409
and allows the user to tune the control parameters of the approximation.
413410
{{< since 2.37 >}}
414411

415-
<!-- real; laplace_marginal_poisson_2_log_lupmf; (array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...)); -->
416-
\index{{\tt \bfseries laplace\_marginal\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): real}|hyperpage}
412+
\index{{\tt \bfseries laplace\_marginal\_poisson\_2\_log\_lpmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): real}|hyperpage}
417413
`real` **`laplace_marginal_poisson_2_log_lpmf`**`(array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch)`<br>\newline
418414

419415
Returns an approximation to the log marginal likelihood $p(y \mid \phi)$
420416
in the special case where the likelihood $p(y \mid \theta)$ is a Poisson
421417
distribution with a log link and an offset.
422418
{{< since 2.37 >}}
423419

424-
<!-- real; laplace_marginal_tol_poisson_2_log_lupmf; (array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch); -->
425-
\index{{\tt \bfseries laplace\_marginal\_tol\_poisson\_2\_log\_lupmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...)): real}|hyperpage}
420+
\index{{\tt \bfseries laplace\_marginal\_tol\_poisson\_2\_log\_lupmf }!{\tt (array[] int y \textbar\ array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...)): real}|hyperpage}
426421

427422
`real` **`laplace_marginal_tol_poisson_2_log_lupmf`**`(array[] int y | array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...))`<br>\newline
428423

@@ -432,8 +427,7 @@ distribution with a log link and an offset
432427
and allows the user to tune the control parameters of the approximation.
433428
{{< since 2.37 >}}
434429

435-
<!-- vector; laplace_latent_poisson_2_log_rng; (array[] int y, array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...)); -->
436-
\index{{\tt \bfseries laplace\_latent\_poisson\_2\_log\_rng }!{\tt (array[] int y, array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...)): vector}|hyperpage}
430+
\index{{\tt \bfseries laplace\_latent\_poisson\_2\_log\_rng }!{\tt (array[] int y, array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...)): vector}|hyperpage}
437431

438432
`vector` **`laplace_latent_poisson_2_log_rng`**`(array[] int y, array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...))`<br>\newline
439433

@@ -442,8 +436,7 @@ $p(\theta \mid y, \phi)$ in the special case where the likelihood
442436
$p(y \mid \theta)$ is a Poisson distribution with a log link and an offset.
443437
{{< since 2.37 >}}
444438

445-
<!-- vector; laplace_latent_tol_poisson_2_log_rng; (array[] int y, array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch); -->
446-
\index{{\tt \bfseries laplace\_latent\_tol\_poisson\_2\_log\_rng }!{\tt (array[] int y, array[] int y\_index, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): vector}|hyperpage}
439+
\index{{\tt \bfseries laplace\_latent\_tol\_poisson\_2\_log\_rng }!{\tt (array[] int y, array[] int y\_index, vector x, vector theta\_init, function covariance\_function, tuple(...), real tol, int max\_steps, int hessian\_block\_size, int solver, int max\_steps\_linesearch): vector}|hyperpage}
447440

448441
`vector` **`laplace_latent_tol_poisson_2_log_rng`**`(array[] int y, array[] int y_index, vector x, vector theta_init, function covariance_function, tuple(...), real tol, int max_steps, int hessian_block_size, int solver, int max_steps_linesearch)`<br>\newline
449442

src/stan-users-guide/gaussian-processes.qmd

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,130 @@ model {
486486
}
487487
```
488488

489+
#### Poisson GP using an embedded Laplace approximation {-}
490+
491+
For computational reasons, we may want to integrate out the Gaussian process
492+
$f$, as was done in the normal output model. Unfortunately, exact
493+
marginalization over $f$ is not possible when the outcome model is not normal.
494+
Instead, we may perform *approximate* marginalization with an *embedded
495+
Laplace approximation* [@Rue:2009, @Margossian:2020].
496+
To do so, we first use the function `laplace_marginal` to approximate the marginal
497+
likelihood $p(y \mid \rho, \alpha, a)$ and sample the
498+
hyperparameters with Hamiltonian Monte Carlo sampling. Then, we recover the
499+
integrated out $f$ in the `generated quantities` block using
500+
`laplace_latent_rng`.
501+
502+
The embedded Laplace approximation computes a Gaussian approximation of the
503+
conditional posterior,
504+
$$
505+
\hat p_\mathcal{L}(f \mid \rho, \alpha, a, y) \approx p(f \mid \rho, \alpha, a, y),
506+
$$
507+
where $\hat p_\mathcal{L}$ is a Gaussian that matches the mode and curvature
508+
of $p(f \mid \rho, \alpha, a, y)$. We then obtain an approximation of
509+
the marginal likelihood as follows:
510+
$$
511+
\hat p_\mathcal{L}(y \mid \rho, \alpha, a)
512+
= \frac{p(f^* \mid \alpha, \rho) p(y \mid f^*, a)}{
513+
\hat p_\mathcal{L}(f \mid \rho, \alpha, a, y)},
514+
$$
515+
where $f^*$ is the mode of $p(f \mid \rho, \alpha, a, y)$, obtained via
516+
numerical optimization.
517+
518+
To use Stan's embedded Laplace approximation, we must define the prior covariance
519+
function and the log likelihood function in the functions block.
520+
```{stan}
521+
functions {
522+
// log likelihood function
523+
real ll_function(vector f, real a, array[] int y) {
524+
return poisson_log_lpmf(y | a + f);
525+
}
526+
527+
// covariance function
528+
matrix cov_function(real rho, real alpha, array[] real x, int N, real delta) {
529+
matrix[N, N] K = gp_exp_quad_cov(x, alpha, rho);
530+
return add_diag(K, delta)
531+
}
532+
533+
}
534+
```
535+
536+
Furthermore, we must specify an initial value $f_\text{init}$ for the
537+
numerical optimizer that underlies the Laplace approximation. In our experience,
538+
we have found setting all values to 0 to be a good default.
539+
540+
```{stan}
541+
transformed data {
542+
vector[N] f_init = rep_vector(0, N);
543+
}
544+
```
545+
546+
We then increment `target` in the model block with the approximation to
547+
$\log p(y \mid \rho, \alpha, a)$.
548+
```{stan}
549+
model {
550+
rho ~ inv_gamma(5, 5);
551+
alpha ~ std_normal();
552+
sigma ~ std_normal();
553+
554+
target += laplace_marginal(ll_function, (a, y), f_init,
555+
cov_function, (rho, alpha, x, N, delta));
556+
}
557+
```
558+
Notice that we do not need to construct $f$ explicitly, since it is
559+
marginalized out. Instead, we recover the GP function in `generated quantities`:
560+
```{stan}
561+
generated quantities {
562+
vector[N] f = laplace_latent_rng(ll_function, (a, y), f_init,
563+
cov_function, (rho, alpha, x, N, delta));
564+
}
565+
```
566+
567+
Stan also provides support for a limited menu of built-in functions, including
568+
the Poisson distribution with a log link and an offset $a$. When using such
569+
a built-in function, the user does not need to specify a likelihood in the
570+
`functions` block. However, the user must strictly follow the signature of the
571+
likelihood: in this case, $a$ must be a vector of length $N$ (to allow for
572+
different offsets for each observation $y_i$) and we must indicate which
573+
element of $f$ each component of $y$ matches using the variable $y_\text{index}$.
574+
In our example, there is a simple pairing $(y_i, f_i)$, however we could imagine
575+
a scenario where multiple observations $(y_{j1}, y_{j2}, ...)$ are observed
576+
for a single $f_j$.
577+
578+
```{stan}
579+
transformed data {
580+
// ...
581+
array[n_obs] int y_index;
582+
for (i in 1:n_obs) y_index[i] = i - 1;
583+
}
489584
490-
#### Logistic Gaussian process regression {-}
585+
// ...
586+
587+
transformed parameter {
588+
vector[N] a_vec = rep_vector(a, N);
589+
}
590+
591+
model {
592+
// ...
593+
target += laplace_marginal_poisson_2_log_lpmf(y | y_index, a_vec, f_init,
594+
cov_function, (rho, alpha, x, N, delta));
595+
}
596+
597+
generated quantities {
598+
vector[N] f = laplace_latent_poisson_2_log_rng(y, y_index, a_vec, f_init,
599+
cov_function, (rho, alpha, x, N, delta));
600+
}
601+
602+
```
603+
604+
Marginalization with a Laplace approximation can lead to faster inference,
605+
however it also introduces an approximation error. In practice, this error
606+
is negligible when using a Poisson likelihood and the approximation works well
607+
for log concave likelihoods [@Kuss:2005, @Vanhatalo:2010, @Cseke:2011,
608+
@Vehtari:2016].
609+
Still, users should exercise caution, especially
610+
when trying unconventional likelihoods.
611+
612+
#### Logistic GP regression {-}
491613

492614
For binary classification problems, the observed outputs $z_n \in
493615
\{ 0,1 \}$ are binary. These outputs are modeled using a Gaussian
@@ -514,10 +636,47 @@ data {
514636
// ...
515637
model {
516638
// ...
517-
y ~ bernoulli_logit(a + f);
639+
z ~ bernoulli_logit(a + f);
518640
}
519641
```
520642

643+
#### Logistic GP regression with an embedded Laplace approximation {-}
644+
645+
As with the Poisson GP, we cannot marginalize the GP function exactly,
646+
however we can resort to an embedded Laplace approximation.
647+
648+
```{stan}
649+
functions {
650+
// log likelihood function
651+
real ll_function(vector f, real a, array[] int z) {
652+
return bernoulli_logit_lpmf(z | a + f);
653+
}
654+
655+
// covariance function
656+
matrix cov_function(real rho, real alpha, array[] real x, int N, real delta) {
657+
matrix[N, N] K = gp_exp_quad_cov(x, alpha, rho);
658+
return add_diag(K, delta)
659+
}
660+
}
661+
662+
// ...
663+
664+
model {
665+
target += laplace_marginal(ll_function, (a, z), f_init,
666+
cov_function, (rho, alpha, x, N, delta));
667+
}
668+
669+
generated quantities {
670+
vector[N] f = laplace_latent_rng(ll_function, (a, z), f_init,
671+
cov_function, (rho, alpha, x, N, delta));
672+
}
673+
```
674+
675+
While marginalization with a Laplace approximation can lead to faster inference,
676+
it also introduces an approximation error. In practice, this error may not be
677+
negligable with a Bernoulli likelihood; for more discussion see, e.g.
678+
[@Vehtari:2016, @Margossian:2020].
679+
521680

522681
### Automatic relevance determination {-}
523682

0 commit comments

Comments
 (0)