18.2. Априорные распределения гаусовских процессов¶
Понимание гауссовских процессов (GP) важно для рассуждений о построении моделей и их обобщающей способности, а также для достижения наилучших результатов в различных областях, включая активное обучение и настройку гиперпараметров в глубоком обучении. Гауссовские процессы повсюду, и нам выгодно знать, что они собой представляют и как мы можем их использовать.
В этом разделе мы вводим априорные гауссовские процессы над функциями. В следующем ноутбуке мы покажем, как использовать эти априорные распределения для апостериорного вывода и прогнозирования. Следующий раздел можно рассматривать как «гауссовские процессы в двух словах», где мы кратко изложим всё необходимое для практического применения гауссовских процессов.
import numpy as np
from scipy.spatial import distance_matrix
from d2l import torch as d2l
d2l.set_figsize()
18.2.1. Определение¶
Гауссов процесс определяется как набор случайных величин, любое конечное подмножество которых имеет совместное гауссово распределение. Если функция \(f(x)\) является гауссовым процессом со средней функцией \(m(x)\) и ковариационной функцией или ядром \(k(x,x')\), \(f(x) \sim \mathcal{GP}(m, k)\), то любой набор значений функции, взятых в произвольном наборе входных точек \(x\) (временные метки, пространственные координаты, пиксели изображения и т. д.), имеет совместное многомерное гауссово распределение со средним вектором \(\mu\) и ковариационной матрицей \(K\): \(f(x_1),\dots,f(x_n) \sim \mathcal{N}(\mu, K)\), где \(\mu_i = E[f(x_i)] = m(x_i)\) и \(K_{ij} = \textrm{Cov}(f(x_i),f(x_j)) = k(x_i,x_j)\).
Это определение может показаться абстрактным и сложным, однако гауссовские процессы на самом деле являются очень простыми объектами. Любая функция
with \(w\) drawn from a Gaussian (normal) distribution, and \(\phi\) being any vector of basis functions, for example \(\phi(x) = (1, x, x^2, ..., x^d)^{\top}\), is a Gaussian process. Moreover, any Gaussian process f(x) can be expressed in the form of equation (18.2.1). Let’s consider a few concrete examples, to begin getting acquainted with Gaussian processes, after which we can appreciate how simple and useful they really are.
18.2.2. A Simple Gaussian Process¶
Suppose \(f(x) = w_0 + w_1 x\), and \(w_0, w_1 \sim \mathcal{N}(0,1)\), with \(w_0, w_1, x\) all in one dimension. We can equivalently write this function as the inner product \(f(x) = (w_0, w_1)(1, x)^{\top}\). In (18.2.1) above, \(w = (w_0, w_1)^{\top}\) and \(\phi(x) = (1,x)^{\top}\).
For any \(x\), \(f(x)\) is a sum of two Gaussian random variables. Since Gaussians are closed under addition, \(f(x)\) is also a Gaussian random variable for any \(x\). In fact, we can compute for any particular \(x\) that \(f(x)\) is \(\mathcal{N}(0,1+x^2)\). Similarly, the joint distribution for any collection of function values, \((f(x_1),\dots,f(x_n))\), for any collection of inputs \(x_1,\dots,x_n\), is a multivariate Gaussian distribution. Therefore \(f(x)\) is a Gaussian process.
In short, \(f(x)\) is a random function, or a distribution over functions. We can gain some insights into this distribution by repeatedly sampling values for \(w_0, w_1\), and visualizing the corresponding functions \(f(x)\), which are straight lines with slopes and different intercepts, as follows:
def lin_func(x, n_sample):
preds = np.zeros((n_sample, x.shape[0]))
for ii in range(n_sample):
w = np.random.normal(0, 1, 2)
y = w[0] + w[1] * x
preds[ii, :] = y
return preds
x_points = np.linspace(-5, 5, 50)
outs = lin_func(x_points, 10)
lw_bd = -2 * np.sqrt((1 + x_points ** 2))
up_bd = 2 * np.sqrt((1 + x_points ** 2))
d2l.plt.fill_between(x_points, lw_bd, up_bd, alpha=0.25)
d2l.plt.plot(x_points, np.zeros(len(x_points)), linewidth=4, color='black')
d2l.plt.plot(x_points, outs.T)
d2l.plt.xlabel("x", fontsize=20)
d2l.plt.ylabel("f(x)", fontsize=20)
d2l.plt.show()
If \(w_0\) and \(w_1\) are instead drawn from \(\mathcal{N}(0,\alpha^2)\), how do you imagine varying \(\alpha\) affects the distribution over functions?
18.2.3. From Weight Space to Function Space¶
In the plot above, we saw how a distribution over parameters in a model induces a distribution over functions. While we often have ideas about the functions we want to model — whether they’re smooth, periodic, quickly varying, etc. — it is relatively tedious to reason about the parameters, which are largely uninterpretable. Fortunately, Gaussian processes provide an easy mechanism to reason directly about functions. Since a Gaussian distribution is entirely defined by its first two moments, its mean and covariance matrix, a Gaussian process by extension is defined by its mean function and covariance function.
In the above example, the mean function
Аналогично, функция ковариации
Теперь наше распределение над функциями можно непосредственно задать и из него можно брать примеры, без необходимости брать примеры из распределения над параметрами. Например, чтобы взять пример из \(f(x)\), мы можем просто сформировать многомерное гауссово распределение, связанное с любым набором \(x\), которые мы хотим запросить, и брать из него примеры напрямую. Мы начнем видеть, насколько выгодной будет эта формулировка.
Прежде всего отметим, что практически тот же вывод, который мы использовали для простой модели линейной регрессии, рассмотренной выше, можно применить для нахождения функции математического ожидания и функции ковариации для любой модели вида \(f(x) = w^{\top} \phi(x)\), где \(w \sim \mathcal{N}(u,S)\). В этом случае функция математического ожидания имеет вид \(m(x) = u^{\top}\phi(x)\), а функция ковариации — \(k(x,x') = \phi(x)^{\top}S\phi(x')\). Поскольку \(\phi(x)\) может представлять собой вектор любых нелинейных базисных функций, мы рассматриваем очень общий класс моделей, включая модели с бесконечным числом параметров.
18.2.4. Ядро радиальной базисной функции (RBF)¶
Ядро радиальной базисной функции (RBF) — наиболее популярная функция ковариации для гауссовских процессов и ядерных машин в целом. Это ядро имеет вид \(k_{\textrm{RBF}}(x,x') = a^2\exp\left(-\frac{1}{2\ell^2}||x-x'||^2\right)\), где \(a\) — параметр амплитуды, а \(\ell\) — гиперпараметр длины волны.
Выведем это ядро, начиная с пространства весов. Рассмотрим функцию
\(f(x)\) представляет собой сумму радиальных базисных функций с шириной \(\ell\), центрированных в точках \(c_i\), как показано на следующем рисунке.
Мы можем распознать \(f(x)\) как имеющее форму \(w^{\top} \phi(x)\), где \(w = (w_1,\dots,w_J)^{\top}\) и \(\phi(x)\) — это вектор, содержащий каждую из радиальных базисных функций. Ковариационная функция этого гауссовского процесса тогда равна
Теперь рассмотрим, что происходит, когда мы увеличиваем количество параметров (и базисных функций) до бесконечности. Пусть \(c_J = \log J\), \(c_1 = -\log J\), \(c_{i+1}-c_{i} = \Delta c = 2\frac{\log J}{J}\) и \(J \to \infty\). Функция ковариации принимает вид суммы Римана:
Задавая \(c_0 = -\infty\) и \(c_\infty = \infty\), мы распределяем бесконечное множество базисных функций по всей вещественной прямой, располагая их на расстоянии \(\Delta c \to 0\) друг от друга:
Стоит уделить внимание тому, что мы здесь сделали. Перейдя к функциональному представлению, мы показали, как можно описать модель с бесконечным числом параметров, используя конечный объём вычислений. Гауссовский процесс с RBF-ядром является универсальным аппроксиматором, способным представлять любую непрерывную функцию с произвольной точностью. Интуитивно это понятно из приведённого выше вывода. Мы можем свести каждую радиальную базисную функцию к точечной массе, принимающей значение \(\ell \to 0\), и придать каждой такой массе любую желаемую высоту.
Таким образом, гауссовский процесс с ядром RBF — это модель с бесконечным числом параметров, обладающая гораздо большей гибкостью, чем любая нейронная сеть с конечным числом параметров. Возможно, весь шум вокруг переобученных нейронных сетей преувеличен. Как мы увидим, гауссовские процессы с ядром RBF не переобучаются и, более того, демонстрируют особенно убедительную обобщающую способность на небольших наборах данных. Более того, примеры из (Zhang et al., 2021), такие как способность идеально подгонять изображения со случайными метками, но при этом хорошо обобщать на структурированных задачах, можно полностью воспроизвести с помощью гауссовских процессов (Wilson and Izmailov, 2020). Нейронные сети не так уж сильно отличаются от того, как мы их обычно представляем.
Мы можем глубже понять гауссовские процессы с ядром радиальной базисной функции (RBF) и такие гиперпараметры, как масштаб длины, напрямую выбирая выборки из распределения над функциями. Как и раньше, это включает простую процедуру:
Выберем входные точки \(x\), для которых мы хотим сделать запрос к гауссовскому процессу: \(x_1,\dots,x_n\).
Вычислите \(m(x_i)\), \(i = 1,\dots,n\) и \(k(x_i,x_j)\) для \(i,j = 1,\dots,n\), чтобы соответственно сформировать вектор средних и матрицу ковариации \(\mu\) и \(K\), где \((f(x_1),\dots,f(x_n)) \sim \mathcal{N}(\mu, K)\).
Выберите выборку из этого многомерного гауссовского распределения, чтобы получить значения функции для примеров.
Повторите выборку ещё раз, чтобы визуализировать больше примеров функций, заданных в этих точках.
Этот процесс проиллюстрирован на рисунке ниже.
def rbfkernel(x1, x2, ls=4.): #@save
dist = distance_matrix(np.expand_dims(x1, 1), np.expand_dims(x2, 1))
return np.exp(-(1. / ls / 2) * (dist ** 2))
x_points = np.linspace(0, 5, 50)
meanvec = np.zeros(len(x_points))
covmat = rbfkernel(x_points,x_points, 1)
prior_samples= np.random.multivariate_normal(meanvec, covmat, size=5);
d2l.plt.plot(x_points, prior_samples.T, alpha=0.5)
d2l.plt.show()
18.2.5. Ядро нейронной сети¶
Исследования гауссовских процессов в машинном обучении были инициированы работами по нейронным сетям. Радфорд Нил разрабатывал всё более крупные байесовские нейронные сети и в итоге показал в 1994 году (позже опубликованных в 1996 году, поскольку эта работа стала одной из самых известных отклонённых статей на конференции NeurIPS), что такие сети с бесконечным числом скрытых единиц становятся гауссовскими процессами с определёнными функциями ядра (Neal, 1996). Интерес к этому выводу возродился, и такие идеи, как нейронное касательное ядро, используются для изучения обобщающей способности нейронных сетей (Matthews et al., 2018) (Novak et al., 2018). Мы можем вывести ядро нейронной сети следующим образом.
Рассмотрим функцию нейронной сети \(f(x)\) со скрытым слоем:
\(b\) — это смещение, \(v_i\) — веса от скрытых нейронов к выходному, \(h\) — любая ограниченная функция активации скрытого нейрона, \(u_i\) — веса от входа к скрытым нейронам, а \(J\) — количество скрытых нейронов. Пусть \(b\) и \(v_i\) — независимые случайные величины с нулевым средним и дисперсиями \(\sigma_b^2\) и \(\sigma_v^2/J\) соответственно, а распределения \(u_i\) — независимыми и одинаковыми. Тогда, используя центральную предельную теорему, можно показать, что любое множество значений функции \(f(x_1),\dots,f(x_n)\) имеет совместное многомерное гауссово распределение.
Среднее значение и ковариационная функция соответствующего гауссова процесса равны:
В некоторых случаях мы можем вычислить эту ковариационную функцию в замкнутом виде. Пусть \(h(x; u) = \textrm{erf}(u_0 + \sum_{j=1}^{P} u_j x_j)\), где \(\textrm{erf}(z) = \frac{2}{\sqrt{\pi}} \int_{0}^{z} e^{-t^2} dt\), и \(u \sim \mathcal{N}(0,\Sigma)\). Тогда \(k(x,x') = \frac{2}{\pi} \textrm{sin}(\frac{2 \tilde{x}^{\top} \Sigma \tilde{x}'}{\sqrt{(1 + 2 \tilde{x}^{\top} \Sigma \tilde{x})(1 + 2 \tilde{x}'^{\top} \Sigma \tilde{x}')}})\).
Ядро RBF является стационарным, то есть инвариантным относительно сдвига, поэтому его можно записать как функцию от \(\tau = x-x'\). Интуитивно стационарность означает, что высокоуровневые свойства функции, такие как скорость изменения, не меняются при перемещении в пространстве входных данных. Однако ядро нейронной сети является нестационарным. Ниже мы приведём примеры функций из гауссовского процесса с этим ядром. Мы видим, что функция качественно отличается вблизи начала координат.
18.2.6. Резюме¶
Первый шаг байесовского вывода заключается в задании априорного распределения. Гауссовские процессы позволяют определить априорное распределение над функциями. Исходя из традиционного представления модели в «пространстве весов», мы можем получить априорное распределение над функциями, задав функциональную форму модели и введя распределение по её параметрам. Альтернативно мы можем задать априорное распределение непосредственно в пространстве функций, свойства которого контролируются ядром. Подход, основанный на пространстве функций, имеет множество преимуществ. Мы можем строить модели, которые фактически соответствуют бесконечному числу параметров, но требуют конечного объёма вычислений! Кроме того, хотя эти модели обладают высокой гибкостью, они также накладывают строгие предположения о том, какие типы функций являются априори вероятными, что приводит к относительно хорошей обобщающей способности на небольших наборах данных.
Предположения моделей в функциональном пространстве интуитивно задаются ядрами, которые часто кодируют высокоуровневые свойства функций, такие как гладкость и периодичность. Многие ядра являются стационарными, то есть инвариантными относительно сдвига. Функции, выбранные из гауссовского процесса со стационарным ядром, обладают примерно одинаковыми высокоуровневыми свойствами (например, скоростью изменения) независимо от того, в какой части входного пространства мы их рассматриваем.
Гауссовские процессы — это относительно общий класс моделей, включающий множество примеров моделей, с которыми мы уже знакомы, таких как полиномы, ряды Фурье и так далее, при условии наличия гауссовского априорного распределения над параметрами. Они также включают нейронные сети с бесконечным числом параметров, даже без гауссовских распределений над параметрами. Это открытие, сделанное Радфордом Нилом, побудило исследователей в области машинного обучения отойти от нейронных сетей и перейти к гауссовским процессам.
18.2.7. Упражнения¶
Получите примеры априорных функций из гауссовского процесса с ядром Орнштейна-Уленбека (OU), \(k_{\textrm{OU}}(x,x') = \exp\left(-\frac{1}{2\ell}||x - x'|\right)\). Если вы зафиксируете длину корреляции \(\ell\) на том же уровне, как эти функции будут отличаться от примеров функций гауссовского процесса с ядром RBF?
Как изменение амплитуды \(a^2\) ядра RBF влияет на распределение функций?
Предположим, что мы формируем \(u(x) = f(x) + 2g(x)\), где \(f(x) \sim \mathcal{GP}(m_1,k_1)\) и \(g(x) \sim \mathcal{GP}(m_2,k_2)\). Является ли \(u(x)\) гауссовским процессом, и если да, то каковы его среднее значение и функция ковариации?
Предположим, что мы формируем \(g(x) = a(x)f(x)\), где \(f(x) \sim \mathcal{GP}(0,k)\) и \(a(x) = x^2\). Является ли \(g(x)\) гауссовским процессом, и если да, то каковы его среднее значение и ковариационная функция? Каково влияние \(a(x)\)? Как выглядят функции выборки, порожденные из \(g(x)\)?
Предположим, что мы формируем \(u(x) = f(x)g(x)\), где \(f(x) \sim \mathcal{GP}(m_1,k_1)\) и \(g(x) \sim \mathcal{GP}(m_2,k_2)\). Является ли \(u(x)\) гауссовским процессом, и если да, то каковы его математическое ожидание и функция ковариации?