Bayesian Optimization
Part II: Gaussian Processes
中文

Gaussian Process Regression

Chapter 7 ended with a prior: a Gaussian process that assigns a probability to every function before any data arrives. This chapter adds the data. We evaluate the unknown function at a few inputs, and ask what the prior, together with those values, says about the function everywhere else.

The answer needs no new machinery. A Gaussian process says that any finite set of function values is jointly Gaussian, and Section 4.5 showed how to condition a joint Gaussian on some of its coordinates. Gaussian process regression is that one formula, applied with the observed inputs on one side and the inputs we want to predict on the other. Everything else in the chapter is about reading the result: what the posterior mean does between and beyond the data, why the uncertainty depends on where we looked but not on what we saw, what changes when observations are noisy, and how to compute all of it without numerical trouble.

The posterior uncertainty is the quantity the rest of the book spends. Every acquisition function in Chapter 12 is a rule for turning it into the next query, so it is worth knowing its shape well.

8.1 Conditioning on observations #

Write ff for the unknown function on an input domain X\X, and suppose it has a Gaussian process prior with mean zero and kernel kk:

f∼GP(0,k).f \sim \GP(0, k).

We observe ff at nn inputs x1,…,xn\vx_1, \dots, \vx_n, collected in a set XX, and for now the observations are exact: yi=f(xi)y_i = f(\vx_i). Stack the values into a vector y=(y1,…,yn)⊤\vy = (y_1, \dots, y_n)^\T. We want the distribution of ff at mm new inputs X∗X_*, whose unknown values we stack into f∗\vf_*.

The smallest case was worked in Example 4.3: two function values with correlation 0.8, one of them observed at 1.2, and a belief about the other that moved to mean 0.96 and standard deviation 0.6. What follows is that computation with nn observed values, any number of unobserved ones, and a kernel supplying the correlations.

By the definition of a Gaussian process, y\vy and f∗\vf_* are jointly Gaussian. Their covariance is built entry by entry from the kernel, so it has four blocks: covariances among the observed inputs, between observed and new inputs, and among the new inputs.

[yf∗]∼N ⁣(0,  [KK∗K∗⊤K∗∗]).\begin{bmatrix} \vy \\ \vf_* \end{bmatrix} \sim \N\!\left( \mathbf{0},\; \begin{bmatrix} \mK & \mK_* \\ \mK_*^\T & \mK_{**} \end{bmatrix} \right).
(8.1)

Here [K]ij=k(xi,xj)[\mK]_{ij} = k(\vx_i, \vx_j) holds the covariances among observed inputs, [K∗]ij=k(xi,x∗j)[\mK_*]_{ij} = k(\vx_i, \vx_{*j}) those between observed and new inputs, and [K∗∗]ij=k(x∗i,x∗j)[\mK_{**}]_{ij} = k(\vx_{*i}, \vx_{*j}) those among new inputs.

Conditioning on y\vy is now the operation from Section 4.5.

Derivation The predictive distribution

By Equation (4.15), for a joint Gaussian with blocks μa,μb\vmu_a, \vmu_b and Σaa,Σab,Σbb\mSigma_{aa}, \mSigma_{ab}, \mSigma_{bb}, the conditional of b\mathbf{b} given a\mathbf{a} is Gaussian with mean μb+Σab⊤Σaa−1(a−μa)\vmu_b + \mSigma_{ab}^\T \mSigma_{aa}^{-1}(\mathbf{a} - \vmu_a) and covariance Σbb−Σab⊤Σaa−1Σab\mSigma_{bb} - \mSigma_{ab}^\T \mSigma_{aa}^{-1} \mSigma_{ab}.

  1. Take a=y\mathbf{a} = \vy and b=f∗\mathbf{b} = \vf_*. Both prior means are zero, so μa=μb=0\vmu_a = \vmu_b = \mathbf{0}.
  2. Read the blocks from Equation (8.1): Σaa=K\mSigma_{aa} = \mK, Σab=K∗\mSigma_{ab} = \mK_*, Σbb=K∗∗\mSigma_{bb} = \mK_{**}.
  3. Substitute. The conditional mean is K∗⊤K−1y\mK_*^\T \mK^{-1} \vy and the conditional covariance is K∗∗−K∗⊤K−1K∗\mK_{**} - \mK_*^\T \mK^{-1} \mK_*.

So the posterior over the new values is

f∗∣X,y,X∗∼N ⁣(K∗⊤K−1y,  K∗∗−K∗⊤K−1K∗).\vf_* \mid X, \vy, X_* \sim \N\!\left(\mK_*^\T \mK^{-1} \vy,\; \mK_{**} - \mK_*^\T \mK^{-1} \mK_*\right).
(8.2)

Nothing in this derivation depended on how many new inputs we chose, or which. The posterior is again a Gaussian process: for any finite set of new inputs, the predictions are jointly Gaussian with the mean and covariance above. That closure is what makes the method practical. The data are absorbed once, and the result can be queried anywhere.

For a single new input x\vx, the blocks become a vector and two numbers. Write k(x)=(k(x,x1),…,k(x,xn))⊤\vk(\vx) = (k(\vx, \vx_1), \dots, k(\vx, \vx_n))^\T for the covariances between x\vx and the observed inputs. Then the posterior mean and variance are

μ(x)=k(x)⊤K−1y,σ2(x)=k(x,x)−k(x)⊤K−1k(x).\mu(\vx) = \vk(\vx)^\T \mK^{-1} \vy, \qquad \sigma^2(\vx) = k(\vx, \vx) - \vk(\vx)^\T \mK^{-1} \vk(\vx).
(8.3)

These two lines are the working form of the whole chapter. The rest of the book writes μn(x)\mu_n(\vx) and σn(x)\sigma_n(\vx), always with their argument, when the number nn of observations matters. They are not to be confused with the noise standard deviation σn\sigma_n of Section 8.3, which has no argument and whose subscript stands for noise.

Key idea Uncertainty depends on where, not on what

The variance in Equation (8.3) contains the inputs and the kernel but not the observed values y\vy. With the kernel fixed, how uncertain the model is at x\vx depends only on where we have looked, never on what we found there. The values enter only through the mean. When the kernel's hyperparameters are fitted to the data (Chapter 9), the values reach the variance indirectly, through the fitted lengthscale and amplitude.

8.2 Reading the posterior #

The figure below computes Equation (8.3) on a grid of 160 inputs. The blue line is the posterior mean; the shaded band covers the mean plus and minus 1.96 posterior standard deviations, which holds 95% of the posterior probability at each input. The strip underneath plots the standard deviation by itself.

posterior mean95% credible bandobservations−2−1012f(x)0.00.51.00.00.20.40.60.81.0input xposterior sd
posterior mean95% credible bandobservations−2−1012f(x)0.00.51.00.00.20.40.60.81.0input xposterior sd
Figure 8.1 Gaussian process regression on four observations with an RBF kernel. Click the plot to add an observation, click a point to remove it, and move the lengthscale to see how far each observation's influence reaches. The strip below shows the posterior standard deviation: zero-width at the data when noise is small, back to the prior value of 1 about two lengthscales away. The points are illustrative.

A few experiments make the equations concrete.

Add a point far from the others. The band pinches to nearly nothing at the new input and opens again on either side. How quickly it opens is set by the lengthscale ℓ\ell of the kernel: the RBF kernel k(x,x′)=exp⁡ ⁣(−(x−x′)2/2ℓ2)k(x, x') = \exp\!\left(-(x - x')^2 / 2\ell^2\right) has fallen to about 0.140.14 two lengthscales away, so an observation says little about inputs more than two lengthscales from it.

Watch the mean between and beyond the data. Between nearby observations the mean interpolates smoothly. Far from all observations it returns to zero, the prior mean, and the band returns to the prior width. The model does not extrapolate trends; it reverts to what it believed before seeing data.

Shrink the lengthscale. The mean starts to wiggle back to zero between points, and the band balloons in every gap. Lengthen it and the mean becomes a stiff curve that may miss the points entirely if they disagree. Choosing the lengthscale is the subject of Chapter 9.

The case of a single observation shows the structure without any matrices.

Example 8.1 One observation

Observe y1=f(x1)y_1 = f(x_1) under an RBF prior with unit amplitude, so k(x1,x1)=1k(x_1, x_1) = 1. Then K=[1]\mK = [1], k(x)=k(x,x1)\vk(x) = k(x, x_1), and Equation (8.3) becomes

μ(x)=k(x,x1) y1,σ2(x)=1−k(x,x1)2.\mu(x) = k(x, x_1)\, y_1, \qquad \sigma^2(x) = 1 - k(x, x_1)^2.

The mean is a copy of the kernel, centered at x1x_1 and scaled to pass through y1y_1. The variance is zero at x1x_1 and rises to 1 as k(x,x1)k(x, x_1) falls to zero. Every feature of the posterior in Figure 8.1 is a superposition of this picture, corrected for how the observations overlap.

8.2.1 The mean is a sum of bumps #

The single-observation case generalizes. Define the weights α=K−1y\bm{\alpha} = \mK^{-1}\vy. Then the mean in Equation (8.3) is

μ(x)=∑i=1nαi k(x,xi),\mu(\vx) = \sum_{i=1}^n \alpha_i\, k(\vx, \vx_i),
(8.4)

a weighted sum of nn kernels, one centered on each observation. Turning on the kernel bumps in the figure draws each term. When two observations are close, their kernels overlap and the weights must compensate for each other, which is why a weight can be much larger than the value it helps to fit, or of the opposite sign.

posterior mean95% credible bandweighted kernels αi k(x, xi)observations−2−1012f(x)0.00.51.00.00.20.40.60.81.0input xposterior sd
posterior mean95% credible bandweighted kernels αi k(x, xi)observations−2−1012f(x)0.00.51.00.00.20.40.60.81.0input xposterior sd
Figure 8.2 The posterior mean (blue) as a sum of weighted kernels (dashed), one per observation, as in Equation (8.4). The two close observations at the left receive weights of opposite sign that nearly cancel outside the gap between them.

Equation (8.4) is also the prediction of kernel ridge regression, a method with no probabilistic reading, when its regularization strength equals the noise variance introduced in the next section. The Gaussian process adds the variance, which ridge regression does not have, and which Bayesian optimization needs (Kanagawa et al., 2018).

Sources cited in Section 8.2 1
  1. Kanagawa et al. (2018) Gaussian Processes and Kernel Methods: A Review on Connections and Equivalences

8.3 Noisy observations #

Real evaluations are rarely exact. A training run with a different random seed gives a different accuracy; a person walking in an exoskeleton has good and bad strides. The standard model adds independent Gaussian noise to each observation:

yi=f(xi)+εi,εi∼N(0,σn2).y_i = f(\vx_i) + \varepsilon_i, \qquad \varepsilon_i \sim \N(0, \sigma_n^2).
(8.5)

Because the noise is independent of ff and across observations, it adds σn2\sigma_n^2 to the variance of each observation and nothing to any covariance. The joint distribution Equation (8.1) keeps its shape with K\mK replaced by K+σn2I\mK + \sigma_n^2 \mI, and so does the derivation:

μ(x)=k(x)⊤(K+σn2I)−1y,σ2(x)=k(x,x)−k(x)⊤(K+σn2I)−1k(x).\mu(\vx) = \vk(\vx)^\T (\mK + \sigma_n^2 \mI)^{-1} \vy, \qquad \sigma^2(\vx) = k(\vx, \vx) - \vk(\vx)^\T (\mK + \sigma_n^2 \mI)^{-1} \vk(\vx).
(8.6)

Two things change in the picture. Move the noise slider in Figure 8.1 and the mean stops passing through the points: it now trades fit against smoothness, the way ridge regression does. The band also stops pinching to zero, because a noisy observation cannot pin down ff exactly.

Pitfall Latent variance and predictive variance

Equation (8.6) gives the posterior variance of the latent value f(x)f(\vx). A new noisy observation yy at x\vx would vary more, by the noise: Var⁡[y∣data]=σ2(x)+σn2\Var[y \mid \text{data}] = \sigma^2(\vx) + \sigma_n^2. Which one a method needs depends on the question. Expected improvement in Section 12.3 asks about ff, so it uses σ2(x)\sigma^2(\vx); a prediction interval for the next measurement uses the sum. Libraries differ in which one they return by default.

The noise variance is usually not known. It is a hyperparameter, fitted along with the lengthscale in Chapter 9. Too little noise makes the model chase every fluctuation; too much makes it ignore real structure. The two can also trade off against each other: a short lengthscale with little noise and a long lengthscale with much noise can explain the same wiggly data, which is one reason fitted hyperparameters deserve a skeptical look.

8.4 Computing it #

The formulas contain a matrix inverse, but a careful implementation never forms one. The matrix K+σn2I\mK + \sigma_n^2 \mI is symmetric and positive definite, so it has a Cholesky factorization LL⊤\mL\mL^\T with L\mL lower triangular (Section 3.5). Solving a triangular system costs O(n2)O(n^2) and is numerically stable; inverting a nearly singular matrix is neither.

Algorithm 8.1 Gaussian process regression

Input: inputs XX, observations y\vy, kernel kk, noise variance σn2\sigma_n^2, test input x\vx.

  1. L←cholesky⁡(K+σn2I)\mL \leftarrow \operatorname{cholesky}(\mK + \sigma_n^2 \mI), so that LL⊤=K+σn2I\mL \mL^\T = \mK + \sigma_n^2 \mI.
  2. α←L⊤\(L\y)\bm{\alpha} \leftarrow \mL^\T \backslash (\mL \backslash \vy), two triangular solves.
  3. μ(x)←k(x)⊤α\mu(\vx) \leftarrow \vk(\vx)^\T \bm{\alpha}.
  4. v←L\k(x)\mathbf{v} \leftarrow \mL \backslash \vk(\vx).
  5. σ2(x)←k(x,x)−v⊤v\sigma^2(\vx) \leftarrow k(\vx, \vx) - \mathbf{v}^\T \mathbf{v}.

Here A\b\mA \backslash \mathbf{b} denotes the solution z\mathbf{z} of Az=b\mA\mathbf{z} = \mathbf{b}. This is Algorithm 2.1 of Rasmussen and Williams (2006), which also returns the log marginal likelihood used in Section 9.3.

Step 4 is the variance formula in disguise: v⊤v=k⊤L−⊤L−1k=k⊤(K+σn2I)−1k\mathbf{v}^\T\mathbf{v} = \vk^\T \mL^{-\T}\mL^{-1}\vk = \vk^\T(\mK + \sigma_n^2\mI)^{-1}\vk.

The cost splits into a part paid once per data set and a part paid per prediction. The factorization in step 1 takes O(n3)O(n^3) time and O(n2)O(n^2) memory. After that, each mean costs O(n)O(n) and each variance O(n2)O(n^2). A laptop factorizes a matrix with a few thousand rows in well under a second, and a Bayesian optimization run rarely has more than a few hundred observations, so the cubic cost is seldom the bottleneck in this book. Larger data sets need approximations that summarize the data with a smaller set of inducing points (Quiñonero-Candela and Rasmussen, 2005; Titsias, 2009).

In code NumPy
import numpy as np

def rbf(a, b, ell=0.12):
    return np.exp(-0.5 * (a[:, None] - b[None, :]) ** 2 / ell**2)

def gp_posterior(x, y, xs, noise=1e-4, ell=0.12):
    L = np.linalg.cholesky(rbf(x, x, ell) + noise * np.eye(len(x)))
    alpha = np.linalg.solve(L.T, np.linalg.solve(L, y))
    Ks = rbf(x, xs, ell)                 # n x m
    mean = Ks.T @ alpha
    v = np.linalg.solve(L, Ks)           # n x m
    var = 1.0 - np.sum(v**2, axis=0)     # k(x, x) = 1 for this kernel
    return mean, var

A production implementation would use a triangular solver (scipy.linalg.solve_triangular) for the solves, which is faster and states the structure. Appendix C builds on this function.

Even a well-posed kernel matrix can fail to factorize in floating point when two inputs are nearly identical, because two rows become nearly equal and the smallest eigenvalue rounds to zero or below. Implementations add a small "jitter", a constant such as 10−6σf210^{-6}\sigma_f^2, to the diagonal and retry with a larger one if the factorization still fails. With observation noise the problem rarely arises, since σn2\sigma_n^2 already plays that role.

Sources cited in Section 8.4 3
  1. Rasmussen and Williams (2006) Gaussian Processes for Machine Learning
  2. Quiñonero-Candela and Rasmussen (2005) A Unifying View of Sparse Approximate Gaussian Process Regression
  3. Titsias (2009) Variational Learning of Inducing Variables in Sparse Gaussian Processes

8.5 Posterior samples #

The mean and the band summarize the posterior one input at a time. They do not show what a single plausible function looks like, because neighboring values are strongly correlated. To see whole functions, draw samples from the joint posterior Equation (8.2) on a grid of inputs. With Σ∗\mSigma_* the posterior covariance and L∗\mL_* its Cholesky factor, each sample is

f∗=μ∗+L∗z,z∼N(0,I),\vf_* = \vmu_* + \mL_* \vz, \qquad \vz \sim \N(\mathbf{0}, \mI),

the sampling recipe of Section 4.3. Turn on the samples in Figure 8.1. Each violet curve passes through (or near) every observation, stays inside the band most of the time, and is as smooth as the kernel allows. Each is a function the model considers possible.

Samples are not only a visualization. Thompson sampling, one of the acquisition rules in Section 12.5, draws one posterior sample and evaluates the objective where that sample is largest. On a grid of mm points, sampling costs O(m3)O(m^3) for the factorization, which limits grids to a few thousand points; for larger or continuous domains, samples can be drawn as functions using random features or pathwise updates (Rahimi and Recht, 2007; Wilson et al., 2020).

Sources cited in Section 8.5 2
  1. Rahimi and Recht (2007) Random Features for Large-Scale Kernel Machines
  2. Wilson et al. (2020) Efficiently Sampling Functions from Gaussian Process Posteriors

8.6 Pitfalls #

Three habits prevent most surprises in practice.

Standardize the outputs. The zero prior mean and unit amplitude assume the function's values are centered near zero with spread near one. A function whose values sit around 1000 would be pulled toward zero away from the data. Subtract the mean of the observations and divide by their standard deviation before fitting, and undo the transformation on the predictions. Libraries such as BoTorch do this with an outcome transform (Balandat et al., 2020).

Scale the inputs. A single lengthscale assumes all input directions vary on comparable scales. Map each input to [0,1][0, 1] first, and give each dimension its own lengthscale when they matter differently (Section 9.2).

Distrust extrapolation. Beyond the data, the posterior returns to the prior by construction. If the objective has a trend that continues past the observed range, a stationary kernel will not predict it. That is usually acceptable in optimization over a bounded domain, but it is a reason to make the domain no larger than it needs to be.

Sources cited in Section 8.6 1
  1. Balandat et al. (2020) BoTorch: A Framework for Efficient Monte-Carlo Bayesian Optimization

8.7 Exercises #

Exercise 8.1

Two observations y1=f(0)y_1 = f(0) and y2=f(δ)y_2 = f(\delta) are made under a noise-free RBF prior with unit amplitude and lengthscale ℓ\ell. Let ρ=exp⁡(−δ2/2ℓ2)\rho = \exp(-\delta^2 / 2\ell^2). Compute the posterior variance at the midpoint x=δ/2x = \delta/2 in terms of ρ\rho, and check that it tends to the single-observation value as δ→0\delta \to 0.

Solution

Here K=[1ρρ1]\mK = \begin{bmatrix} 1 & \rho \\ \rho & 1 \end{bmatrix} and, with r=exp⁡(−δ2/8ℓ2)r = \exp(-\delta^2 / 8\ell^2) the kernel value between the midpoint and each observation, k=(r,r)⊤\vk = (r, r)^\T. The inverse is K−1=11−ρ2[1−ρ−ρ1]\mK^{-1} = \frac{1}{1 - \rho^2}\begin{bmatrix} 1 & -\rho \\ -\rho & 1 \end{bmatrix}, so k⊤K−1k=2r2(1−ρ)1−ρ2=2r21+ρ\vk^\T \mK^{-1}\vk = \frac{2r^2(1 - \rho)}{1 - \rho^2} = \frac{2r^2}{1 + \rho} and

σ2(δ/2)=1−2r21+ρ.\sigma^2(\delta/2) = 1 - \frac{2r^2}{1 + \rho}.

Since r2=ρ1/2r^2 = \rho^{1/2}, as δ→0\delta \to 0 both ρ\rho and rr tend to 1 and the variance tends to 1−2/2=01 - 2/2 = 0, the same as observing the midpoint itself. For small δ\delta the second observation adds almost nothing: two nearly equal inputs carry almost the same information as one.

Exercise 8.2

With noise variance σn2\sigma_n^2 and nn observations all at the same input x0x_0, show that the posterior variance at x0x_0 is σn2/(n+σn2)\sigma_n^2 / (n + \sigma_n^2) for a unit-amplitude kernel. What does this say about repeating an evaluation instead of trying a new input?

Solution

All entries of K\mK are 1, so K=11⊤\mK = \mathbf{1}\mathbf{1}^\T and k(x0)=1\vk(x_0) = \mathbf{1}. Since 1⊤1=n\mathbf{1}^\T\mathbf{1} = n, (11⊤+σn2I)1=(n+σn2)1(\mathbf{1}\mathbf{1}^\T + \sigma_n^2\mI)\mathbf{1} = (n + \sigma_n^2)\mathbf{1}, and so (11⊤+σn2I)−11=1/(n+σn2)(\mathbf{1}\mathbf{1}^\T + \sigma_n^2\mI)^{-1}\mathbf{1} = \mathbf{1}/(n + \sigma_n^2) (Exercise B.1 reaches the same result with the Sherman-Morrison formula). So k⊤(K+σn2I)−1k=n/(n+σn2)\vk^\T(\mK + \sigma_n^2\mI)^{-1}\vk = n/(n + \sigma_n^2) and the variance is 1−n/(n+σn2)=σn2/(n+σn2)1 - n/(n + \sigma_n^2) = \sigma_n^2/(n + \sigma_n^2). Repeating an evaluation shrinks uncertainty at that input like 1/n1/n, the rate of averaging nn noisy measurements, and teaches little about anywhere else. Bayesian optimization repeats an input only when the noise is large relative to the differences it is trying to resolve.

Further reading #

  • Rasmussen and Williams (2006), chapter 2, is the standard derivation, in both the weight-space and function-space views, with the algorithm used here.
  • Garnett (2023), chapters 2 to 4, develops Gaussian processes with Bayesian optimization in mind, including the inference choices this chapter treats as fixed.
  • Görtler et al. (2019) is an interactive visual introduction that complements the figures in this chapter.
  • Williams and Rasmussen (1996) introduced Gaussian process regression to machine learning. The same predictor had long been used in geostatistics as kriging (Krige, 1951; Matheron, 1963).
  • Kanagawa et al. (2018) sets out the exact correspondences between Gaussian process regression and kernel methods such as kernel ridge regression.

References

  1. Balandat, M., Karrer, B., Jiang, D. R., Daulton, S., Letham, B., Wilson, A. G., and Bakshy, E. (2020). BoTorch: A Framework for Efficient Monte-Carlo Bayesian Optimization. Advances in Neural Information Processing Systems 33 (NeurIPS 2020). Cited in §8.6
  2. Garnett, R. (2023). Bayesian Optimization. Cambridge University Press.
  3. Görtler, J., Kehlbeck, R., and Deussen, O. (2019). A Visual Exploration of Gaussian Processes. Distill. doi:10.23915/distill.00017.
  4. Kanagawa, M., Hennig, P., Sejdinovic, D., and Sriperumbudur, B. K. (2018). Gaussian Processes and Kernel Methods: A Review on Connections and Equivalences. arXiv preprint. preprint Cited in §8.2
  5. Krige, D. G. (1951). A Statistical Approach to Some Basic Mine Valuation Problems on the Witwatersrand. Journal of the Southern African Institute of Mining and Metallurgy.
  6. Matheron, G. (1963). Principles of Geostatistics. Economic Geology.
  7. Quiñonero-Candela, J., and Rasmussen, C. E. (2005). A Unifying View of Sparse Approximate Gaussian Process Regression. Journal of Machine Learning Research. Cited in §8.4
  8. Rahimi, A., and Recht, B. (2007). Random Features for Large-Scale Kernel Machines. Advances in Neural Information Processing Systems 20 (NeurIPS 2007). Cited in §8.5
  9. Rasmussen, C. E., and Williams, C. K. I. (2006). Gaussian Processes for Machine Learning. MIT Press. Cited in §8.4
  10. Titsias, M. (2009). Variational Learning of Inducing Variables in Sparse Gaussian Processes. Proceedings of the 12th International Conference on Artificial Intelligence and Statistics (AISTATS 2009). Cited in §8.4
  11. Williams, C. K. I., and Rasmussen, C. E. (1996). Gaussian Processes for Regression. Advances in Neural Information Processing Systems 8 (NeurIPS 1995).
  12. Wilson, J. T., Borovitskiy, V., Terenin, A., Mostowski, P., and Deisenroth, M. P. (2020). Efficiently Sampling Functions from Gaussian Process Posteriors. Proceedings of the 37th International Conference on Machine Learning (ICML 2020). Cited in §8.5