{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# Center-Gap GPQR (independent centrals)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"import torch\n",
"from torch.distributions import Normal\n",
"from gpytorch.variational import CholeskyVariationalDistribution\n",
"from gpytorch.variational import VariationalStrategy\n",
"from gpytorch.means import ConstantMean, Mean\n",
"from gpytorch.kernels import RBFKernel, ScaleKernel\n",
"from gpytorch.mlls import VariationalELBO\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from gpytorch_qr.means import CenterGapMean\n",
"from gpytorch_qr.models import CenterGapQuantileGP\n",
"from gpytorch_qr.variational import CenterGapLMCVariationalStrategy\n",
"from gpytorch_qr.likelihoods import (\n",
" CenterGapQuantileLikelihood,\n",
" MultiOutputCenterGapQuantileLikelihood,\n",
")\n",
"\n",
"try:\n",
" import sys\n",
"\n",
" sys.path.insert(0, os.path.abspath(\"..\"))\n",
"\n",
" import config_notebook\n",
"except ImportError:\n",
" print(\"Output will not be deterministic SVG.\")\n",
"\n",
"torch.manual_seed(42)\n",
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"n_epochs = int(os.getenv(\"GPYTORCHQR_N_EPOCHS\", 5000))"
]
},
{
"cell_type": "markdown",
"id": "2",
"metadata": {},
"source": [
"## Data preparation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"def mean1(x):\n",
" return torch.cos(x * 2 * 3.14)\n",
"\n",
"\n",
"def mean2(x):\n",
" return torch.sin(x * 2 * 3.14)\n",
"\n",
"\n",
"def std(x):\n",
" return x + 0.1\n",
"\n",
"\n",
"x_range = torch.linspace(0, 1, 100).reshape(-1, 1).to(device)\n",
"x = x_range.repeat(5, 1)\n",
"y1 = mean1(x) + torch.randn(x.shape, device=device).mul(std(x))\n",
"y2 = mean2(x) + torch.randn(x.shape, device=device).mul(std(x))\n",
"y = torch.concatenate([y1, y2], dim=-1)\n",
"\n",
"q1 = torch.tensor([0.1, 0.5, 0.9], device=device)\n",
"true_quantiles1 = mean1(x_range) + Normal(0, std(x_range)).icdf(q1)\n",
"\n",
"q2 = torch.tensor([0.1, 0.25, 0.5, 0.75, 0.9], device=device)\n",
"true_quantiles2 = mean2(x_range) + Normal(0, std(x_range)).icdf(q2)\n",
"\n",
"x_pred = torch.linspace(0, 1.5, 100).reshape(-1, 1).to(device)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(1, 2)\n",
"\n",
"axes[0].scatter(x.cpu(), y1.cpu(), c=\"gray\")\n",
"axes[0].plot(x_range.cpu(), true_quantiles1.cpu())\n",
"\n",
"axes[1].scatter(x.cpu(), y2.cpu(), c=\"gray\")\n",
"axes[1].plot(x_range.cpu(), true_quantiles2.cpu())\n",
"\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"id": "5",
"metadata": {},
"source": [
"## Prior mean"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {},
"outputs": [],
"source": [
"class PriorMean1(Mean):\n",
" def __init__(self, batch_shape=torch.Size()):\n",
" super().__init__()\n",
" self.batch_shape = batch_shape\n",
"\n",
" def forward(self, x):\n",
" return mean1(x).squeeze(-1).expand(*self.batch_shape, x.shape[-2])\n",
"\n",
"\n",
"class PriorMean2(Mean):\n",
" def __init__(self, batch_shape=torch.Size()):\n",
" super().__init__()\n",
" self.batch_shape = batch_shape\n",
"\n",
" def forward(self, x):\n",
" return mean2(x).squeeze(-1).expand(*self.batch_shape, x.shape[-2])\n",
"\n",
"\n",
"prior_mean_1 = PriorMean1().to(device)\n",
"prior_mean_2 = PriorMean2().to(device)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(1, 2)\n",
"\n",
"axes[0].scatter(x.cpu(), y1.cpu(), c=\"gray\")\n",
"axes[0].plot(x_pred.cpu(), prior_mean_1(x_pred).detach().cpu())\n",
"\n",
"axes[1].scatter(x.cpu(), y2.cpu(), c=\"gray\")\n",
"axes[1].plot(x_pred.cpu(), prior_mean_2(x_pred).detach().cpu())\n",
"\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"id": "8",
"metadata": {},
"source": [
"## Define model and likelihood"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {},
"outputs": [],
"source": [
"class MyGP(CenterGapQuantileGP):\n",
" def __init__(\n",
" self,\n",
" inducing_points,\n",
" num_quantiles,\n",
" num_lower_quantiles,\n",
" num_latents,\n",
" ):\n",
" N, D = inducing_points.size()\n",
" variational_distribution = CholeskyVariationalDistribution(\n",
" N,\n",
" batch_shape=torch.Size([num_latents]),\n",
" )\n",
" variational_strategy = CenterGapLMCVariationalStrategy(\n",
" VariationalStrategy(\n",
" self,\n",
" inducing_points,\n",
" variational_distribution,\n",
" learn_inducing_locations=True,\n",
" ),\n",
" sum(num_quantiles),\n",
" num_latents,\n",
" num_quantiles=num_quantiles,\n",
" num_lower_quantiles=num_lower_quantiles,\n",
" )\n",
"\n",
" mean = CenterGapMean(\n",
" torch.nn.ModuleList(\n",
" [\n",
" PriorMean1(batch_shape=torch.Size([1])),\n",
" PriorMean2(batch_shape=torch.Size([1])),\n",
" ]\n",
" ),\n",
" ConstantMean(batch_shape=torch.Size([num_latents - 2])),\n",
" )\n",
" covar = ScaleKernel(\n",
" RBFKernel(ard_num_dims=D, batch_shape=torch.Size([num_latents])),\n",
" batch_shape=torch.Size([num_latents]),\n",
" )\n",
" super().__init__(\n",
" variational_strategy, mean, covar, num_quantiles, num_lower_quantiles\n",
" )\n",
"\n",
"\n",
"inducing_points = torch.linspace(0, 1, 10).reshape(-1, 1).to(device)\n",
"central_q1_index = (q1 - 0.5).abs().argmin().item()\n",
"central_q2_index = (q2 - 0.5).abs().argmin().item()\n",
"num_latents = len(q1) + len(q2)\n",
"gp = MyGP(\n",
" inducing_points,\n",
" [len(q1), len(q2)],\n",
" [central_q1_index, central_q2_index],\n",
" num_latents,\n",
").to(device)\n",
"likelihood = MultiOutputCenterGapQuantileLikelihood(\n",
" CenterGapQuantileLikelihood(q1, central_q1_index),\n",
" CenterGapQuantileLikelihood(q2, central_q2_index),\n",
").to(device)"
]
},
{
"cell_type": "markdown",
"id": "10",
"metadata": {},
"source": [
"## Train"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11",
"metadata": {},
"outputs": [],
"source": [
"gp.train()\n",
"likelihood.train()\n",
"mll = VariationalELBO(likelihood, gp, num_data=len(y))\n",
"optimizer = torch.optim.Adam(\n",
" list(gp.parameters()) + list(likelihood.parameters()),\n",
" lr=0.001,\n",
")\n",
"\n",
"for _ in range(n_epochs):\n",
" output = gp(x)\n",
" loss = -mll(output, y)\n",
" loss.backward()\n",
" optimizer.step()\n",
" optimizer.zero_grad()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {},
"outputs": [],
"source": [
"gp.eval()\n",
"with torch.no_grad():\n",
" mean_q = gp.mean_quantiles_mc(x_pred)\n",
" lower_q, upper_q = gp.quantile_quantiles_mc(\n",
" x_pred, torch.tensor([0.025, 0.975]).to(device)\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(1, 2)\n",
"\n",
"axes[0].scatter(x.cpu(), y1.cpu(), c=\"gray\")\n",
"axes[0].plot(x_range.cpu(), true_quantiles1.cpu(), color=\"k\")\n",
"for i in range(len(q1)):\n",
" axes[0].plot(x_pred.cpu(), mean_q[:, i].cpu(), label=f\"q={q1[i].item():.2f}\")\n",
" axes[0].fill_between(\n",
" x_pred.cpu().squeeze(),\n",
" lower_q[:, i].cpu(),\n",
" upper_q[:, i].cpu(),\n",
" alpha=0.3,\n",
" )\n",
"\n",
"axes[1].scatter(x.cpu(), y2.cpu(), c=\"gray\")\n",
"axes[1].plot(x_range.cpu(), true_quantiles2.cpu(), color=\"k\")\n",
"for i in range(len(q2)):\n",
" axes[1].plot(\n",
" x_pred.cpu(), mean_q[:, len(q1) + i].cpu(), label=f\"q={q2[i].item():.2f}\"\n",
" )\n",
" axes[1].fill_between(\n",
" x_pred.cpu().squeeze(),\n",
" lower_q[:, len(q1) + i].cpu(),\n",
" upper_q[:, len(q1) + i].cpu(),\n",
" alpha=0.3,\n",
" )\n",
"\n",
"fig.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "heavyedge",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}