1.7. Гауссовские процессы
Гауссовские процессы (GP) — это непараметрический метод обучения с учителем, используемый для решения задач регрессии и вероятностной классификации.
Преимущества гауссовских процессов:
- Предсказание интерполирует наблюдения (по крайней мере, для регулярных ядер).
- Предсказание является вероятностным (гауссовским), поэтому можно вычислять эмпирические доверительные интервалы и на их основе решать, следует ли переобучить модель (обучение онлайн, адаптивное обучение) в некоторой интересующей области.
- Универсальность: можно задавать различные ядра. Предусмотрены распространённые ядра, но также можно задавать пользовательские ядра.
К недостаткам гауссовских процессов относятся:
- Наша реализация не является разреженной, то есть для предсказания используется информация обо всех объектах и признаках.
- Они теряют эффективность в пространствах большой размерности — в частности, когда число признаков превышает несколько десятков.
1.7.1. Регрессия на основе гауссовских процессов (GPR)
GaussianProcessRegressor реализует гауссовские процессы (GP) для решения задач регрессии. Для этого необходимо задать априорное распределение GP. GP объединяет это априорное распределение и функцию правдоподобия на основе обучающих выборок. Такой подход позволяет выполнять вероятностное предсказание, возвращая в качестве результата среднее значение и стандартное отклонение.
Предполагается, что априорное среднее постоянно и равно нулю (для normalize_y=False) или среднему значению обучающих данных (для normalize_y=True). Априорная ковариация задаётся передачей объекта ядра. Гиперпараметры ядра оптимизируются при обучении GaussianProcessRegressor путём максимизации логарифма маргинального правдоподобия (LML) на основе переданного optimizer. Поскольку у LML может быть несколько локальных максимумов, оптимизатор можно запускать повторно, задав n_restarts_optimizer. Первый запуск всегда выполняется с начальными значениями гиперпараметров ядра; последующие запуски выполняются со значениями гиперпараметров, случайно выбранными из допустимого диапазона. Если необходимо оставить начальные гиперпараметры фиксированными, в качестве оптимизатора можно передать None.
Уровень шума в целевых значениях можно задать, передав его через параметр alpha — глобально в виде скаляра или отдельно для каждой точки данных. Обратите внимание, что умеренный уровень шума также может помочь справиться с численной нестабильностью при обучении, поскольку фактически он реализован как регуляризация Тихонова, то есть добавляется к диагонали матрицы ядра. Альтернативой явному заданию уровня шума является включение компонента WhiteKernel в ядро. Этот компонент может оценить общий уровень шума по данным (см. пример ниже). На рисунке ниже показано влияние шума в целевых значениях, учтённого с помощью параметра alpha.
Реализация основана на алгоритме 2.1 из [RW2006]. Помимо API стандартных оценивателей scikit-learn, GaussianProcessRegressor:
- позволяет выполнять предсказание без предварительного обучения (на основе априорного распределения GP);
- предоставляет дополнительный метод
sample_y(X), который вычисляет значения выборок, полученных из GPR (априорного или апостериорного распределения), для заданных входных данных; - предоставляет метод
log_marginal_likelihood(theta), который можно использовать извне для других способов выбора гиперпараметров, например с помощью метода Монте-Карло по цепям Маркова.
Примеры
- Регрессия на основе гауссовских процессов: базовый вводный пример
- Способность регрессии на основе гауссовских процессов (GPR) оценивать уровень шума в данных
- Сравнение гребневой регрессии с ядром и регрессии на основе гауссовских процессов
- Прогнозирование уровня CO2 на наборе данных Mona Loa с помощью регрессии на основе гауссовских процессов (GPR)
1.7.2. Классификация на основе гауссовских процессов (GPC)
GaussianProcessClassifier реализует гауссовские процессы (GP) для решения задач классификации, а точнее — вероятностной классификации, при которой предсказания для тестовых данных представляются в виде вероятностей классов. GaussianProcessClassifier задаёт априорное распределение GP для скрытой функции \(f\), которая затем преобразуется с помощью функции связи \(\pi\) для получения вероятностной классификации. Скрытая функция \(f\) — это так называемая функция-помеха, значения которой не наблюдаются и сами по себе не имеют значения. Она нужна для удобного задания модели, а при предсказании \(f\) исключается (интегрируется). GaussianProcessClassifier реализует логистическую функцию связи, интеграл от которой нельзя вычислить аналитически, но для бинарного случая его легко аппроксимировать.
В отличие от случая регрессии, апостериорное распределение скрытой функции \(f\) не является гауссовским даже при гауссовском априорном распределении GP, поскольку гауссовское правдоподобие неприменимо к дискретным меткам классов. Вместо него используется негауссовское правдоподобие, соответствующее логистической функции связи (логиту). GaussianProcessClassifier аппроксимирует негауссовское апостериорное распределение гауссовским с помощью аппроксимации Лапласа. Дополнительные сведения приведены в главе 3 книги [RW2006].
Предполагается, что априорное среднее GP равно нулю. Априорная ковариация задаётся передачей объекта ядра. Гиперпараметры ядра оптимизируются при обучении GaussianProcessRegressor путём максимизации логарифма маргинального правдоподобия (LML) на основе переданного optimizer. Поскольку у LML может быть несколько локальных максимумов, оптимизатор можно запускать повторно, задав n_restarts_optimizer. Первый запуск всегда выполняется с начальными значениями гиперпараметров ядра; последующие запуски выполняются со значениями гиперпараметров, случайно выбранными из допустимого диапазона. Если необходимо оставить начальные гиперпараметры фиксированными, в качестве оптимизатора можно передать None.
В некоторых случаях требуются сведения о скрытой функции \(f\) (то есть о среднем \(\bar{f_*}\) и дисперсии \(\text{Var}[f_*]\), описанных в формулах (3.21) и (3.24) из [RW2006]). GaussianProcessClassifier предоставляет доступ к этим величинам с помощью метода latent_mean_and_variance.
GaussianProcessClassifier поддерживает многоклассовую классификацию, выполняя обучение и предсказание по схеме «один против остальных» или «один против одного». В схеме «один против остальных» для каждого класса обучается отдельный бинарный классификатор на основе гауссовских процессов, который отделяет этот класс от остальных. В схеме «один против одного» для каждой пары классов обучается отдельный бинарный классификатор на основе гауссовских процессов, который разделяет эти два класса. Предсказания бинарных классификаторов объединяются в многоклассовые предсказания. Дополнительные сведения см. в разделе о многоклассовой классификации.
В случае классификации на основе гауссовских процессов схема «один против одного» может быть вычислительно эффективнее, поскольку требует решения большего числа задач на подмножествах всего обучающего набора, а не меньшего числа задач на всём наборе данных. Поскольку вычислительная сложность классификации на основе гауссовских процессов кубически зависит от размера набора данных, это может значительно ускорить работу. Однако обратите внимание, что схема «один против одного» не поддерживает предсказание оценок вероятностей и позволяет получать только обычные предсказания. Кроме того, GaussianProcessClassifier пока не реализует внутри себя полноценную многоклассовую аппроксимацию Лапласа, а, как описано выше, решает несколько бинарных задач классификации и объединяет их результаты по схеме «один против остальных» или «один против одного».
1.7.3. Примеры GPC
1.7.3.1. Вероятностные предсказания с помощью GPC
В этом примере показаны предсказанные вероятности GPC для ядра RBF с различными значениями гиперпараметров. На первом рисунке показаны предсказанные вероятности GPC с произвольно выбранными гиперпараметрами и с гиперпараметрами, соответствующими максимуму логарифма маргинального правдоподобия (LML).
Хотя значения LML для гиперпараметров, выбранных путём оптимизации LML, значительно выше, по логарифмической потере на тестовых данных они показывают немного худший результат. На рисунке видно, что причина в резком изменении вероятностей классов на границах классов (что хорошо), но при этом предсказанные вероятности вдали от границ классов близки к 0,5 (что плохо). Этот нежелательный эффект обусловлен используемой внутри GPC аппроксимацией Лапласа.
На втором рисунке показан логарифм маргинального правдоподобия для различных значений гиперпараметров ядра; два значения гиперпараметров, использованных на первом рисунке, отмечены чёрными точками.
1.7.3.2. Иллюстрация работы GPC на наборе данных XOR
В этом примере показана работа GPC на данных XOR. Сравниваются стационарное изотропное ядро (RBF) и нестационарное ядро (DotProduct). На этом конкретном наборе данных ядро DotProduct даёт значительно лучшие результаты, поскольку границы классов линейны и совпадают с координатными осями. Однако на практике стационарные ядра, такие как RBF, часто дают лучшие результаты.
1.7.3.3. Классификация на основе гауссовских процессов (GPC) на наборе данных iris
В этом примере показаны предсказанные вероятности GPC для изотропного и анизотропного ядер RBF на двумерной версии набора данных iris. Это демонстрирует применимость GPC к небинарной классификации. Анизотропное ядро RBF обеспечивает немного более высокий логарифм маргинального правдоподобия, назначая разные масштабы длины двум измерениям признаков.
1.7.4. Ядра гауссовских процессов
Ядра (также называемые «функциями ковариации» в контексте гауссовских процессов) — важнейший компонент гауссовских процессов, определяющий форму априорного и апостериорного распределений гауссовского процесса. Они кодируют предположения о функции, которую необходимо обучить, задавая «сходство» двух точек данных и предполагая, что похожие точки данных должны иметь похожие целевые значения. Можно выделить две категории ядер: стационарные ядра зависят только от расстояния между двумя точками данных, а не от их абсолютных значений \(k(x_i, x_j)= k(d(x_i, x_j))\), поэтому они инвариантны относительно переносов во входном пространстве; нестационарные ядра также зависят от конкретных значений точек данных. Стационарные ядра, в свою очередь, делятся на изотропные и анизотропные; изотропные ядра также инвариантны относительно поворотов во входном пространстве. Дополнительные сведения см. в главе 4 работы [RW2006]. В этом примере показано, как определить пользовательское ядро для дискретных данных. Рекомендации по оптимальному комбинированию различных ядер см. в [Duv2014].
API ядер гауссовских процессов
Основное назначение Kernel — вычислять ковариацию гауссовского процесса между точками данных. Для этого можно вызвать метод __call__ ядра. Этот метод можно использовать для вычисления либо «автоковариации» всех пар точек данных в двумерном массиве X, либо «перекрёстной ковариации» всех комбинаций точек данных двумерного массива X с точками данных двумерного массива Y. Для всех ядер k (кроме WhiteKernel) выполняется следующее равенство: k(X) == K(X, Y=X)
Если используется только диагональ автоковариации, можно вызвать метод diag() ядра. Он вычислительно эффективнее эквивалентного вызова __call__: np.diag(k(X, X)) == k.diag(X)
Ядра задаются вектором гиперпараметров \(\theta\). Эти гиперпараметры могут, например, управлять масштабами длины или периодичностью ядра (см. ниже). Все ядра поддерживают вычисление аналитических градиентов автоковариации ядра по \(log(\theta)\) при установке eval_gradient=True в методе __call__. То есть возвращается массив (len(X), len(X), len(theta)), в котором элемент [i, j, l] содержит \(\frac{\partial k_\theta(x_i, x_j)}{\partial log(\theta_l)}\). Этот градиент используется гауссовским процессом (как регрессором, так и классификатором) для вычисления градиента логарифма маргинального правдоподобия. В свою очередь, он используется для определения значения \(\theta\), максимизирующего логарифм маргинального правдоподобия, с помощью градиентного подъёма. Для каждого гиперпараметра при создании экземпляра ядра необходимо указать начальное значение и границы. Текущее значение \(\theta\) можно получить и задать с помощью свойства theta объекта ядра. Кроме того, границы гиперпараметров доступны через свойство bounds ядра. Обратите внимание: оба свойства (theta и bounds) возвращают логарифмированные значения, используемые внутри, поскольку они обычно лучше подходят для градиентной оптимизации. Описание каждого гиперпараметра хранится в соответствующем ядре в виде экземпляра Hyperparameter. Обратите внимание: ядро, использующее гиперпараметр с именем “x”, должно иметь атрибуты self.x и self.x_bounds.
Абстрактный базовый класс для всех ядер — Kernel. Kernel реализует интерфейс, аналогичный интерфейсу BaseEstimator, и предоставляет методы get_params(), set_params() и clone(). Благодаря этому значения ядра можно задавать и с помощью метаоценщиков, таких как Pipeline или GridSearchCV. Обратите внимание: из-за вложенной структуры ядер (возникающей при применении операторов над ядрами, см. ниже) имена параметров ядра могут быть довольно сложными. В общем случае для бинарного оператора ядра параметры левого операнда получают префикс k1__, а параметры правого операнда — k2__. Дополнительный удобный метод clone_with_theta(theta) возвращает клонированную версию ядра, в которой гиперпараметры установлены в theta. Пример:
>>> from sklearn.gaussian_process.kernels import ConstantKernel, RBF
>>> kernel = ConstantKernel(constant_value=1.0, constant_value_bounds=(0.0, 10.0)) * RBF(length_scale=0.5, length_scale_bounds=(0.0, 10.0)) + RBF(length_scale=2.0, length_scale_bounds=(0.0, 10.0))
>>> for hyperparameter in kernel.hyperparameters: print(hyperparameter)
Hyperparameter(name='k1__k1__constant_value', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
Hyperparameter(name='k1__k2__length_scale', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
Hyperparameter(name='k2__length_scale', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
>>> params = kernel.get_params()
>>> for key in sorted(params): print("%s : %s" % (key, params[key]))
k1 : 1**2 * RBF(length_scale=0.5)
k1__k1 : 1**2
k1__k1__constant_value : 1.0
k1__k1__constant_value_bounds : (0.0, 10.0)
k1__k2 : RBF(length_scale=0.5)
k1__k2__length_scale : 0.5
k1__k2__length_scale_bounds : (0.0, 10.0)
k2 : RBF(length_scale=2)
k2__length_scale : 2.0
k2__length_scale_bounds : (0.0, 10.0)
>>> print(kernel.theta) # Note: log-transformed
[ 0. -0.69314718 0.69314718]
>>> print(kernel.bounds) # Note: log-transformed
[[ -inf 2.30258509]
[ -inf 2.30258509]
[ -inf 2.30258509]]
Все ядра гауссовских процессов совместимы с sklearn.metrics.pairwise и наоборот: экземпляры подклассов Kernel можно передавать как metric в pairwise_kernels из sklearn.metrics.pairwise. Кроме того, функции ядер из pairwise можно использовать в качестве ядер гауссовских процессов с помощью класса-обёртки PairwiseKernel. Единственное ограничение: градиенты гиперпараметров вычисляются численно, а не аналитически, и все эти ядра поддерживают только изотропные расстояния. Параметр gamma считается гиперпараметром и может оптимизироваться. Остальные параметры ядра задаются непосредственно при инициализации и остаются неизменными.
1.7.4.1. Базовые ядра
Ядро ConstantKernel можно использовать как часть ядра-произведения Product, где оно масштабирует величину другого множителя (ядра), или как часть ядра-суммы Sum, где оно изменяет среднее значение гауссовского процесса. Оно зависит от параметра \(constant\_value\). Определение:
Основное применение ядра WhiteKernel — использование в составе ядра-суммы, где оно описывает шумовую составляющую сигнала. Настройка параметра \(noise\_level\) соответствует оценке уровня шума. Определение:
1.7.4.2. Операторы над ядрами
Операторы над ядрами принимают одно или два базовых ядра и объединяют их в новое ядро. Ядро Sum принимает два ядра \(k_1\) и \(k_2\) и объединяет их по формуле \(k_{sum}(X, Y) = k_1(X, Y) + k_2(X, Y)\). Ядро Product принимает два ядра \(k_1\) и \(k_2\) и объединяет их по формуле \(k_{product}(X, Y) = k_1(X, Y) * k_2(X, Y)\). Ядро Exponentiation принимает одно базовое ядро и скалярный параметр \(p\) и объединяет их по формуле \(k_{exp}(X, Y) = k(X, Y)^p\). Обратите внимание: для объектов Kernel переопределены специальные методы __add__, __mul___ и __pow__, поэтому можно, например, использовать RBF() + RBF() как сокращённую запись для Sum(RBF(), RBF()).
1.7.4.3. Ядро радиальной базисной функции (RBF)
Ядро RBF является стационарным. Оно также известно как ядро «квадратичной экспоненты». Оно задаётся параметром масштаба длины \(l>0\), который может быть скаляром (изотропный вариант ядра) или вектором с таким же числом измерений, как и входные данные \(x\) (анизотропный вариант ядра). Ядро определяется формулой:
где \(d(\cdot, \cdot)\) — евклидово расстояние. Это ядро бесконечно дифференцируемо, а значит, гауссовские процессы с этим ядром в качестве функции ковариации имеют среднеквадратичные производные всех порядков и поэтому являются очень гладкими. Априорное и апостериорное распределения гауссовского процесса, полученного с помощью ядра RBF, показаны на следующем рисунке:
1.7.4.4. Ядро Матерна
Ядро Matern является стационарным и представляет собой обобщение ядра RBF. В него добавлен параметр \(\nu\), управляющий гладкостью получаемой функции. Ядро задаётся параметром масштаба длины \(l>0\), который может быть скаляром (изотропный вариант ядра) или вектором с таким же числом измерений, как и входные данные \(x\) (анизотропный вариант ядра).
Математическое определение ядра Матерна
Ядро определяется формулой:
где \(d(\cdot,\cdot)\) — евклидово расстояние, \(K_\nu(\cdot)\) — модифицированная функция Бесселя, а \(\Gamma(\cdot)\) — гамма-функция. При \(\nu\rightarrow\infty\) ядро Матерна сходится к ядру RBF. При \(\nu = 1/2\) ядро Матерна становится тождественным ядру абсолютной экспоненты, то есть
В частности, при \(\nu = 3/2\):
а при \(\nu = 5/2\):
— популярные варианты для обучения функций, которые не являются бесконечно дифференцируемыми (как предполагает ядро RBF), но имеют как минимум одну (\(\nu = 3/2\)) или две производные (\(\nu = 5/2\)).
Возможность управлять гладкостью обучаемой функции с помощью \(\nu\) позволяет адаптировать модель к свойствам истинной функциональной зависимости.
Априорное и апостериорное распределения гауссовского процесса, полученного с помощью ядра Матерна, показаны на следующем рисунке:
Дополнительные сведения о различных вариантах ядра Матерна см. в [RW2006], с. 84.
1.7.4.5. Рационально-квадратичное ядро
Ядро RationalQuadratic можно рассматривать как масштабную смесь (бесконечную сумму) ядер RBF с различными характерными масштабами длины. Оно задаётся параметром масштаба длины \(l>0\) и параметром масштабной смеси \(\alpha>0\). На данный момент поддерживается только изотропный вариант, в котором \(l\) является скаляром. Ядро определяется формулой:
Априорное и апостериорное распределения гауссовского процесса, полученного с помощью ядра RationalQuadratic, показаны на следующем рисунке:
1.7.4.6. Ядро экспоненциального квадрата синуса
Ядро ExpSineSquared позволяет моделировать периодические функции. Оно задаётся параметром масштаба длины \(l>0\) и параметром периодичности \(p>0\). На данный момент поддерживается только изотропный вариант, в котором \(l\) является скаляром. Ядро определяется формулой:
Априорное и апостериорное распределения гауссовского процесса, полученного с помощью ядра ExpSineSquared, показаны на следующем рисунке:
1.7.4.7. Скалярное произведение
Ядро DotProduct является нестационарным и может быть получено из линейной регрессии, если задать коэффициентам \(x_d (d = 1, . . . , D)\) априорное распределение \(N(0, 1)\), а смещению — априорное распределение \(N(0, \sigma_0^2)\). Ядро DotProduct инвариантно относительно поворота координат вокруг начала координат, но не относительно переносов. Оно задаётся параметром \(\sigma_0^2\). При \(\sigma_0^2 = 0\) ядро называется однородным линейным ядром, в противном случае — неоднородным. Ядро определяется формулой
Ядро DotProduct часто комбинируют с возведением в степень. Пример со степенью 2 показан на следующем рисунке:
1.7.4.8. Литература
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/modules/gaussian_process.html