├── .gitignore ├── README.md ├── binary_laplace_gpc.py ├── demo_binary_gpc.ipynb ├── demo_gpr.ipynb ├── gp.py └── test_gp.py /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pytorch-minimal-gaussian-process 2 | 3 | In search of truth, simplicity is needed. There exist heavy-weighted libraries, but as you know, we need to go bare bone sometimes. 4 | Here is a minimal implementation of Gaussian process regression in PyTorch. 5 | 6 | The implementation generally follows Algorithm 2.1 in [Gaussian Process for Machine Learning (Rassmussen and Williams, 2006)](http://www.gaussianprocess.org/gpml/). 7 | 8 | 9 | * Author: [Sangwoong Yoon](https://swyoon.github.io/), [Hyeokjun Kwon](https://www.linkedin.com/in/hyeokjun-kwon-24b992210) 10 | 11 | ## Features 12 | 13 | * Gaussian process regression with squared exponential kernel. 14 | * Hyperparameter optimization via marginal likelihood maximization using Pytorch built-in autograd functionality. (See `demo.ipynb`) 15 | * Unittesting using Pytest. 16 | 17 | ## Updates 18 | 19 | * 2022-01-01: Bugfix in predictive variance computation 20 | * 2023-01-03: Implement binary Laplace Gaussian process regression 21 | 22 | ## Dependency 23 | 24 | * Numpy 25 | * PyTorch 26 | * PyTest 27 | * Matplotlib (for demo) 28 | 29 | ## How to Use 30 | ### Gaussian process regression 31 | ```python 32 | from gp import GP 33 | 34 | # generate data 35 | X = torch.randn(100,1) 36 | y = torch.sin(X * 2 * np.pi /4). + torch.randn(100, 1) * 0.1 37 | grid = torch.linspace(-5, 5, 200)[:,None] 38 | 39 | # run GP 40 | gp = GP() # you may specify initial hyperparameters using keyword arguments 41 | gp.fit(X, y) 42 | mu, var = gp.forward(grid) 43 | ``` 44 | 45 | ### Gaussian process classification 46 | ```python 47 | from gp import GP 48 | 49 | # generate data 50 | X = torch.randn(100,1) 51 | f = torch.sin(X * 3 * np.pi / 4) 52 | y = (f > 0.).int() * 2 - 1 53 | grid = torch.linspace(-5, 5, 200)[:,None] 54 | 55 | # run GP 56 | gp = BinaryLaplaceGPC() # you may specify initial hyperparameters using keyword arguments 57 | gp.fit(X, y) 58 | mu, var, pi = gp.forward(grid) 59 | ``` 60 | ## Unittesting 61 | 62 | ``` 63 | $ pytest 64 | ``` 65 | 66 | ## See also 67 | 68 | * [GPyTorch](https://gpytorch.ai/): A full-featured Gaussian process package based on PyTorch. 69 | -------------------------------------------------------------------------------- /binary_laplace_gpc.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from abc import ABCMeta, abstractmethod 4 | import math 5 | from typing import Dict, Union 6 | 7 | import numpy as np 8 | import torch 9 | import torch.nn as nn 10 | 11 | 12 | class Likelihood(metaclass=ABCMeta): 13 | registry: Dict[str, Likelihood] = {} 14 | 15 | def __init__(self): 16 | pass 17 | 18 | def __init_subclass__(cls): 19 | assert cls.__name__ not in cls.registry, f"Likelihood name {cls.__name__} already exists." 20 | cls.registry[cls.__name__] = cls 21 | 22 | @abstractmethod 23 | def get_log_likelihood(self, y: torch.Tensor, f: torch.Tensor) -> torch.Tensor: 24 | """Get log-likelihood for given target 'y' and latent function 'f'. 25 | 26 | Args: 27 | y (torch.Tensor, (N,1)): classification targets on the points. 28 | f (torch.Tensor, (N,1)): the value of sampled latent function on the points. 29 | 30 | Returns: 31 | torch.Tensor: likelihood (scalar value) 32 | """ 33 | pass 34 | 35 | @abstractmethod 36 | def get_jacobian_of_log_likelihood(self, y: torch.Tensor, f: torch.Tensor) -> torch.Tensor: 37 | """Get Jacobian of log-likelihood for given target 'y' and latent function 'f'. 38 | 39 | Args: 40 | y (torch.Tensor, (N,1)): classification targets on the points. 41 | f (torch.Tensor, (N,1)): the value of sampled latent function on the points. 42 | 43 | Returns: 44 | torch.Tensor, (N,1): Jacobian 45 | """ 46 | pass 47 | 48 | @abstractmethod 49 | def get_hessian_of_log_likelihood(self, y: torch.Tensor, f: torch.Tensor) -> torch.Tensor: 50 | """Get Hessian of log-likelihood for given target 'y' and latent function 'f'. 51 | 52 | Args: 53 | y (torch.Tensor, (N,1)): classification targets on the points. 54 | f (torch.Tensor, (N,1)): the value of sampled latent function on the points. 55 | 56 | Returns: 57 | torch.Tensor, (N,N): Hessian 58 | """ 59 | pass 60 | 61 | 62 | class Logistic(Likelihood): 63 | def get_log_likelihood(self, y: torch.Tensor, f: torch.Tensor) -> torch.Tensor: 64 | return (-torch.log(1 + torch.exp(-y * f))).sum() 65 | 66 | def get_jacobian_of_log_likelihood(self, y, f): 67 | t = (y + 1) / 2 68 | pi = 1 / (1 + torch.exp(-f)) 69 | return t - pi 70 | 71 | def get_hessian_of_log_likelihood(self, y, f): 72 | pi = 1 / (1 + torch.exp(-f)) 73 | return torch.diag((-pi * (1 - pi)).squeeze(-1)) 74 | 75 | 76 | class CumulativeGaussian(Likelihood): 77 | def get_log_likelihood(self, y: torch.Tensor, f: torch.Tensor) -> torch.Tensor: 78 | return torch.log(self.get_cdf(y * f)) 79 | 80 | def get_jacobian_of_log_likelihood(self, y, f): 81 | return y * self.get_prob(f) / self.get_cdf(y * f) 82 | 83 | def get_hessian_of_log_likelihood(self, y, f): 84 | prob = self.get_prob(f) 85 | cdf = self.get_cdf(y * f) 86 | return torch.diag((-(prob**2) / (cdf**2) - (y * f * prob) / cdf).squeeze(-1)) 87 | 88 | @staticmethod 89 | def get_prob(z): 90 | return torch.exp(-((z**2) / 2 - math.log(math.sqrt(2 * math.pi)))) 91 | 92 | @staticmethod 93 | def get_cdf(z): 94 | return 0.5 * ( 95 | 1 + torch.erf(z / math.sqrt(2)) 96 | ) # See https://github.com/pytorch/pytorch/blob/master/torch/distributions/normal.py (cdf) 97 | 98 | 99 | class BinaryLaplaceGPC(nn.Module): 100 | def __init__( 101 | self, 102 | length_scale: float = 1.0, 103 | amplitude_scale: float = 1.0, 104 | likelihood_func: str = "Logistic", 105 | eps: float = 0.001, 106 | n_samples: int = 10, 107 | ): 108 | super().__init__() 109 | self.length_scale_ = nn.Parameter(torch.tensor(np.log(length_scale))) 110 | self.amplitude_scale_ = nn.Parameter(torch.tensor(np.log(amplitude_scale))) 111 | 112 | self.likelihood_func = Likelihood.registry[likelihood_func]() 113 | self.eps = eps 114 | self.n_samples = n_samples 115 | 116 | @property 117 | def length_scale(self): 118 | return torch.exp(self.length_scale_) 119 | 120 | @property 121 | def amplitude_scale(self): 122 | return torch.exp(self.amplitude_scale_) 123 | 124 | def forward(self, x): 125 | """compute prediction. fit() must have been called. 126 | x: test input data point. N x D tensor for the data dimensionality D.""" 127 | L = self.L 128 | sqrt_W = self.sqrt_W 129 | k = self.kernel_mat(self.X, x) 130 | v = torch.linalg.solve(L, sqrt_W.mm(k)) 131 | mu = k.T.mm(self.likelihood_func.get_jacobian_of_log_likelihood(self.y, self.f)) # (N',1) 132 | var = self.amplitude_scale - torch.diag(v.T.mm(v)) # (N') 133 | 134 | z = mu.repeat(1, self.n_samples) + torch.sqrt(var).unsqueeze(-1) * torch.randn_like( 135 | mu.repeat(1, self.n_samples) 136 | ) # (N',{self.n_samples}) 137 | 138 | pi = torch.sigmoid(z).mean(-1) 139 | return mu, var, pi 140 | 141 | def fit(self, X, y): 142 | """should be called before forward() call. 143 | X: training input data point. N x D tensor for the data dimensionality D. 144 | y: training target data point. N x 1 tensor.""" 145 | f = torch.zeros_like(y).float() 146 | N = X.shape[0] 147 | K = self.kernel_mat(X, X) 148 | while True: 149 | f = f.detach() 150 | W = -self.likelihood_func.get_hessian_of_log_likelihood(y, f) 151 | sqrt_W = W.sqrt() 152 | L = torch.linalg.cholesky(torch.eye(N, device=y.device) + sqrt_W.mm(K.mm(sqrt_W))) 153 | b = W.mm(f) + self.likelihood_func.get_jacobian_of_log_likelihood(y, f) 154 | a = b - sqrt_W.mm(torch.linalg.solve(L.T, torch.linalg.solve(L, sqrt_W.mm(K.mm(b))))) 155 | diff = (torch.abs(K.mm(a) - f)).max() 156 | f = K.mm(a) 157 | if diff < self.eps: 158 | break 159 | 160 | approx_marginal_likelihood = ( 161 | -0.5 * a.T.mm(f) 162 | - torch.log(torch.diag(L)).sum() 163 | + self.likelihood_func.get_log_likelihood(y, f) 164 | ) 165 | self.X = X 166 | self.y = y 167 | self.sqrt_W = sqrt_W 168 | self.L = L 169 | self.K = K 170 | self.f = f 171 | return approx_marginal_likelihood 172 | 173 | def kernel_mat(self, X, Z): 174 | Xsq = (X**2).sum(dim=1, keepdim=True) 175 | Zsq = (Z**2).sum(dim=1, keepdim=True) 176 | sqdist = Xsq + Zsq.T - 2 * X.mm(Z.T) 177 | return self.amplitude_scale * torch.exp(-0.5 * sqdist / self.length_scale) 178 | 179 | def train_step(self, X, y, opt): 180 | """gradient-based optimization of hyperparameters 181 | opt: torch.optim.Optimizer object.""" 182 | opt.zero_grad() 183 | nll = -self.fit(X, y).sum() 184 | nll.backward() 185 | opt.step() 186 | return { 187 | "loss": nll.item(), 188 | "length": self.length_scale.detach().cpu(), 189 | "amplitude": self.amplitude_scale.detach().cpu(), 190 | } 191 | -------------------------------------------------------------------------------- /demo_gpr.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "91982316-822a-4894-883a-fc90f3272d7b", 6 | "metadata": {}, 7 | "source": [ 8 | "# Gaussian Process Demo with Hyperparameter Optimization" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "e89f94a2-ea56-49f7-91d1-bd22d2d23280", 15 | "metadata": { 16 | "execution": { 17 | "iopub.execute_input": "2022-01-01T05:52:31.658215Z", 18 | "iopub.status.busy": "2022-01-01T05:52:31.657722Z", 19 | "iopub.status.idle": "2022-01-01T05:52:32.815778Z", 20 | "shell.execute_reply": "2022-01-01T05:52:32.815043Z", 21 | "shell.execute_reply.started": "2022-01-01T05:52:31.658077Z" 22 | }, 23 | "tags": [] 24 | }, 25 | "outputs": [], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import matplotlib.pyplot as plt\n", 29 | "import torch\n", 30 | "import torch.nn as nn\n", 31 | "from torch.optim import SGD\n", 32 | "from tqdm.auto import tqdm\n", 33 | "from gp import GP" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 2, 39 | "id": "3fa2c96c-3e1a-4df9-9c64-e20e61121c81", 40 | "metadata": { 41 | "execution": { 42 | "iopub.execute_input": "2022-01-01T05:52:32.817213Z", 43 | "iopub.status.busy": "2022-01-01T05:52:32.816988Z", 44 | "iopub.status.idle": "2022-01-01T05:52:32.977612Z", 45 | "shell.execute_reply": "2022-01-01T05:52:32.976965Z", 46 | "shell.execute_reply.started": "2022-01-01T05:52:32.817181Z" 47 | }, 48 | "tags": [] 49 | }, 50 | "outputs": [ 51 | { 52 | "data": { 53 | "text/plain": [ 54 | "[]" 55 | ] 56 | }, 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "output_type": "execute_result" 60 | }, 61 | { 62 | "data": { 63 | "image/png": "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\n", 64 | "text/plain": [ 65 | "
" 66 | ] 67 | }, 68 | "metadata": { 69 | "needs_background": "light" 70 | }, 71 | "output_type": "display_data" 72 | } 73 | ], 74 | "source": [ 75 | "X = torch.randn(100,1)\n", 76 | "f = torch.sin(X * 2 * np.pi /4).flatten()\n", 77 | "y = f + torch.randn_like(f) * 0.1\n", 78 | "y = y[:,None]\n", 79 | "grid = torch.linspace(-5, 5, 200)[:,None]\n", 80 | "plt.plot(X.flatten(), y.flatten(), '.')" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 3, 86 | "id": "57373fe8-e229-4956-94a2-da31a11234b1", 87 | "metadata": { 88 | "execution": { 89 | "iopub.execute_input": "2022-01-01T05:52:32.978822Z", 90 | "iopub.status.busy": "2022-01-01T05:52:32.978603Z", 91 | "iopub.status.idle": "2022-01-01T05:52:33.224514Z", 92 | "shell.execute_reply": "2022-01-01T05:52:33.223895Z", 93 | "shell.execute_reply.started": "2022-01-01T05:52:32.978791Z" 94 | }, 95 | "tags": [] 96 | }, 97 | "outputs": [ 98 | { 99 | "data": { 100 | "image/png": "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\n", 101 | "text/plain": [ 102 | "
" 103 | ] 104 | }, 105 | "metadata": { 106 | "needs_background": "light" 107 | }, 108 | "output_type": "display_data" 109 | } 110 | ], 111 | "source": [ 112 | "gp = GP(length_scale=4, amplitude_scale=0.1)\n", 113 | "gp.fit(X, y)\n", 114 | "mu, var = gp.forward(grid)\n", 115 | "mu = mu.detach().numpy().flatten()\n", 116 | "std = torch.sqrt(var).detach().numpy().flatten()\n", 117 | "plt.plot(X.flatten(), y, '.')\n", 118 | "plt.plot(grid.flatten(), mu)\n", 119 | "plt.fill_between(grid.flatten(), y1=mu+std, y2=mu-std, alpha=0.3)\n", 120 | "plt.title('Before hyperparameter optimization');" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 4, 126 | "id": "0feec28e-d592-40d0-a335-fbabf4609ccc", 127 | "metadata": { 128 | "execution": { 129 | "iopub.execute_input": "2022-01-01T05:52:33.225713Z", 130 | "iopub.status.busy": "2022-01-01T05:52:33.225491Z", 131 | "iopub.status.idle": "2022-01-01T05:52:34.092101Z", 132 | "shell.execute_reply": "2022-01-01T05:52:34.091482Z", 133 | "shell.execute_reply.started": "2022-01-01T05:52:33.225681Z" 134 | }, 135 | "tags": [] 136 | }, 137 | "outputs": [ 138 | { 139 | "data": { 140 | "application/vnd.jupyter.widget-view+json": { 141 | "model_id": "e326aa217cef4ca1b84e267c92241464", 142 | "version_major": 2, 143 | "version_minor": 0 144 | }, 145 | "text/plain": [ 146 | "HBox(children=(FloatProgress(value=0.0, max=50.0), HTML(value='')))" 147 | ] 148 | }, 149 | "metadata": {}, 150 | "output_type": "display_data" 151 | }, 152 | { 153 | "name": "stdout", 154 | "output_type": "stream", 155 | "text": [ 156 | "\n" 157 | ] 158 | }, 159 | { 160 | "data": { 161 | "image/png": "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\n", 162 | "text/plain": [ 163 | "
" 164 | ] 165 | }, 166 | "metadata": { 167 | "needs_background": "light" 168 | }, 169 | "output_type": "display_data" 170 | } 171 | ], 172 | "source": [ 173 | "opt = SGD(gp.parameters(), lr=0.01)\n", 174 | "l_loss = []; l_length = []; l_noise = []; l_amp = []\n", 175 | "for i in tqdm(range(50)):\n", 176 | " d_train = gp.train_step(X, y, opt)\n", 177 | " l_loss.append(d_train['loss'])\n", 178 | " l_length.append(d_train['length'])\n", 179 | " l_noise.append(d_train['noise'])\n", 180 | " l_amp.append(d_train['amplitude'])\n", 181 | "fig, axs = plt.subplots(ncols=4, figsize=(16,4))\n", 182 | "axs[0].plot(l_loss); axs[0].set_title('Negative Log-Likelihood'); axs[0].set_xlabel('iteration')\n", 183 | "axs[1].plot(torch.stack(l_length)); axs[1].set_title('Length scale'); axs[1].set_xlabel('iteration')\n", 184 | "axs[2].plot(torch.stack(l_noise)); axs[2].set_title('Noise scale'); axs[2].set_xlabel('iteration')\n", 185 | "axs[3].plot(torch.stack(l_amp)); axs[3].set_title('Amplitude scale'); axs[3].set_xlabel('iteration');" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 6, 191 | "id": "cdb8d726-64e7-4302-b628-1286ed8e4be0", 192 | "metadata": { 193 | "execution": { 194 | "iopub.execute_input": "2022-01-01T05:52:41.080109Z", 195 | "iopub.status.busy": "2022-01-01T05:52:41.079550Z", 196 | "iopub.status.idle": "2022-01-01T05:52:41.320703Z", 197 | "shell.execute_reply": "2022-01-01T05:52:41.319740Z", 198 | "shell.execute_reply.started": "2022-01-01T05:52:41.080034Z" 199 | }, 200 | "tags": [] 201 | }, 202 | "outputs": [ 203 | { 204 | "data": { 205 | "image/png": "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\n", 206 | "text/plain": [ 207 | "
" 208 | ] 209 | }, 210 | "metadata": { 211 | "needs_background": "light" 212 | }, 213 | "output_type": "display_data" 214 | } 215 | ], 216 | "source": [ 217 | "mu, var = gp.forward(grid)\n", 218 | "mu = mu.detach().numpy().flatten()\n", 219 | "std = torch.sqrt(var).detach().numpy().flatten()\n", 220 | "plt.plot(X.flatten(), y, '.')\n", 221 | "plt.plot(grid.flatten(), mu)\n", 222 | "plt.fill_between(grid.flatten(), y1=mu+std, y2=mu-std, alpha=0.3)\n", 223 | "plt.title('After hyperparameter optimization');" 224 | ] 225 | } 226 | ], 227 | "metadata": { 228 | "kernelspec": { 229 | "display_name": "Python 3 (ipykernel)", 230 | "language": "python", 231 | "name": "python3" 232 | }, 233 | "language_info": { 234 | "codemirror_mode": { 235 | "name": "ipython", 236 | "version": 3 237 | }, 238 | "file_extension": ".py", 239 | "mimetype": "text/x-python", 240 | "name": "python", 241 | "nbconvert_exporter": "python", 242 | "pygments_lexer": "ipython3", 243 | "version": "3.8.12" 244 | } 245 | }, 246 | "nbformat": 4, 247 | "nbformat_minor": 5 248 | } 249 | -------------------------------------------------------------------------------- /gp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | 5 | 6 | class GP(nn.Module): 7 | def __init__(self, length_scale=1.0, noise_scale=1.0, amplitude_scale=1.0): 8 | super().__init__() 9 | self.length_scale_ = nn.Parameter(torch.tensor(np.log(length_scale))) 10 | self.noise_scale_ = nn.Parameter(torch.tensor(np.log(noise_scale))) 11 | self.amplitude_scale_ = nn.Parameter(torch.tensor(np.log(amplitude_scale))) 12 | 13 | @property 14 | def length_scale(self): 15 | return torch.exp(self.length_scale_) 16 | 17 | @property 18 | def noise_scale(self): 19 | return torch.exp(self.noise_scale_) 20 | 21 | @property 22 | def amplitude_scale(self): 23 | return torch.exp(self.amplitude_scale_) 24 | 25 | def forward(self, x): 26 | """compute prediction. fit() must have been called. 27 | x: test input data point. N x D tensor for the data dimensionality D.""" 28 | y = self.y 29 | L = self.L 30 | alpha = self.alpha 31 | k = self.kernel_mat(self.X, x) 32 | v = torch.linalg.solve(L, k) 33 | mu = k.T.mm(alpha) 34 | var = self.amplitude_scale + self.noise_scale - torch.diag(v.T.mm(v)) 35 | return mu, var 36 | 37 | def fit(self, X, y): 38 | """should be called before forward() call. 39 | X: training input data point. N x D tensor for the data dimensionality D. 40 | y: training target data point. N x 1 tensor.""" 41 | D = X.shape[1] 42 | K = self.kernel_mat_self(X) 43 | L = torch.linalg.cholesky(K) 44 | alpha = torch.linalg.solve(L.T, torch.linalg.solve(L, y)) 45 | marginal_likelihood = ( 46 | -0.5 * y.T.mm(alpha) - torch.log(torch.diag(L)).sum() - D * 0.5 * np.log(2 * np.pi) 47 | ) 48 | self.X = X 49 | self.y = y 50 | self.L = L 51 | self.alpha = alpha 52 | self.K = K 53 | return marginal_likelihood 54 | 55 | def kernel_mat_self(self, X): 56 | sq = (X**2).sum(dim=1, keepdim=True) 57 | sqdist = sq + sq.T - 2 * X.mm(X.T) 58 | return self.amplitude_scale * torch.exp( 59 | -0.5 * sqdist / self.length_scale 60 | ) + self.noise_scale * torch.eye(len(X)) 61 | 62 | def kernel_mat(self, X, Z): 63 | Xsq = (X**2).sum(dim=1, keepdim=True) 64 | Zsq = (Z**2).sum(dim=1, keepdim=True) 65 | sqdist = Xsq + Zsq.T - 2 * X.mm(Z.T) 66 | return self.amplitude_scale * torch.exp(-0.5 * sqdist / self.length_scale) 67 | 68 | def train_step(self, X, y, opt): 69 | """gradient-based optimization of hyperparameters 70 | opt: torch.optim.Optimizer object.""" 71 | opt.zero_grad() 72 | nll = -self.fit(X, y).sum() 73 | nll.backward() 74 | opt.step() 75 | return { 76 | "loss": nll.item(), 77 | "length": self.length_scale.detach().cpu(), 78 | "noise": self.noise_scale.detach().cpu(), 79 | "amplitude": self.amplitude_scale.detach().cpu(), 80 | } 81 | -------------------------------------------------------------------------------- /test_gp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch.optim import SGD 4 | from gp import GP 5 | from binary_laplace_gpc import BinaryLaplaceGPC 6 | 7 | 8 | def test_gp(): 9 | X = torch.randn(10, 1) 10 | f = torch.sin(X * 2 * np.pi / 4).flatten() 11 | y = f + torch.randn_like(f) * 0.1 12 | y = y[:, None] 13 | grid = torch.linspace(-5, 5, 20)[:, None] 14 | 15 | gp = GP() 16 | gp.fit(X, y) 17 | mu, var = gp.forward(grid) 18 | mu = mu.detach().numpy().flatten() 19 | std = torch.sqrt(var).detach().numpy().flatten() 20 | 21 | 22 | def test_gp_opt(): 23 | X = torch.randn(10, 1) 24 | f = torch.sin(X * 2 * np.pi / 4).flatten() 25 | y = f + torch.randn_like(f) * 0.1 26 | y = y[:, None] 27 | grid = torch.linspace(-5, 5, 20)[:, None] 28 | 29 | gp = GP() 30 | opt = SGD(gp.parameters(), lr=0.01) 31 | for i in range(2): 32 | d_train = gp.train_step(X, y, opt) 33 | 34 | 35 | def test_gpc(): 36 | X = torch.randn(10, 1) 37 | f = torch.sin(X * 3 * np.pi / 4) 38 | y = (f > 0.).int() * 2 - 1 39 | grid = torch.linspace(-5, 5, 20)[:, None] 40 | 41 | gp = BinaryLaplaceGPC() 42 | gp.fit(X, y) 43 | mu, var, pi = gp.forward(grid) 44 | mu = mu.detach().numpy().flatten() 45 | std = torch.sqrt(var).detach().numpy().flatten() 46 | pi = pi.detach().numpy().flatten() 47 | 48 | 49 | def test_gpc_opt(): 50 | X = torch.randn(10, 1) 51 | f = torch.sin(X * 3 * np.pi / 4) 52 | y = (f > 0.).int() * 2 - 1 53 | grid = torch.linspace(-5, 5, 20)[:, None] 54 | 55 | gp = BinaryLaplaceGPC() 56 | opt = SGD(gp.parameters(), lr=0.0001) 57 | for i in range(2): 58 | d_train = gp.train_step(X, y, opt) 59 | --------------------------------------------------------------------------------