diff --git a/examples/08_Advanced_Usage/SVGP_Model_Updating.ipynb b/examples/08_Advanced_Usage/SVGP_Model_Updating.ipynb new file mode 100644 index 000000000..40e85535d --- /dev/null +++ b/examples/08_Advanced_Usage/SVGP_Model_Updating.ipynb @@ -0,0 +1,476 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "3403d231", + "metadata": {}, + "outputs": [], + "source": [ + "import tqdm\n", + "import math\n", + "import torch\n", + "import gpytorch\n", + "from matplotlib import pyplot as plt\n", + "\n", + "# Make plots inline\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "dd5cad91", + "metadata": {}, + "source": [ + "## SVGP Model Updating\n", + "\n", + "In this notebook, we will be describing a \"fantasy model\" strategy for stochastic variational GPs (SVGPs) analogous to fantasy modelling for exact GPs. \n", + "\n", + "To understand what a \"fantasy model\" is, we first think about exact GPs. Imagine, we have trained a GP on some data $\\mathcal{D} := \\{x_i, y_i\\}_{i=1}^N$, which is the same as saying that $\\mathbf{y} \\sim \\mathcal{GP}(\\mu(\\mathbf{x}), K(\\mathbf{x}, \\mathbf{x}'))$. \n", + "\n", + "If we observe some new data $\\mathcal{D}^*:= \\{x_j, y_j\\}_{j=1}^{N^*}$, then that data is easily incorporated into our GP model as $(\\mathbf{y}, \\mathbf{y}^*) \\sim \\mathcal{GP}(\\mu([\\mathbf{x}, \\mathbf{x}^*]), K([\\mathbf{x}, \\mathbf{x}^*], [\\mathbf{x}, \\mathbf{x}^*]')$.\n", + "To compute predictions with this new model (conditional on the same hyper-parameters), we could use the following piece of code for an exact GP:\n", + "\n", + "```python\n", + "updated_model = deepcopy(model)\n", + "updated_model.set_train_data(torch.cat((train_x, new_x)), torch.cat((train_y, new_y)), strict=False)\n", + "```\n", + "\n", + "or we could take advantage of linear algebraic identies to efficiently produce the same model, which is the `get_fantasy_model` function for exact GPs in GPyTorch:\n", + "```python\n", + "updated_model = model.get_fantasy_model(new_x, new_y)\n", + "```\n", + "\n", + "The second approach is significantly more computationally efficient, costing $\\mathcal{O}((N^*)^2 N)$ time versus $\\mathcal{O}((N + N^*)^3)$ time.\n", + "\n", + "In this tutorial notebook, we describe the **online variational conditioning** (OVC) approach of [Maddox et al, '21](https://arxiv.org/abs/2110.15172) which provides a closed form method for updating SVGPs in the same manner as exact GPs are updated with respect ot new data, via the usage of the `get_fantasy_model` method." + ] + }, + { + "cell_type": "markdown", + "id": "6bc1b924", + "metadata": {}, + "source": [ + "### Training Data\n", + "\n", + "First, we construct some training data, here $250$ data points from a noisy sine wave." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "81daa65c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'y')" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "train_x = torch.linspace(0, 3, 250).view(-1, 1).contiguous()\n", + "train_y = torch.sin(6. * train_x) + 0.3 * torch.randn_like(train_x)\n", + "\n", + "plt.scatter(train_x, train_y, marker = \"*\", color = \"black\")\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")" + ] + }, + { + "cell_type": "markdown", + "id": "a1d8b8f0", + "metadata": {}, + "source": [ + "### Model definition\n", + "\n", + "Next, we define our model class definition. The only difference from a standard approximate GP is that we require the likelihood object to be a) Gaussian (for now) and b) to be stored inside of the `ApproximateGP` object." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "50f30949", + "metadata": {}, + "outputs": [], + "source": [ + "from gpytorch.models import ApproximateGP\n", + "from gpytorch.variational import CholeskyVariationalDistribution\n", + "from gpytorch.variational import VariationalStrategy\n", + "\n", + "class GPModel(ApproximateGP):\n", + " def __init__(self, inducing_points, likelihood):\n", + " variational_distribution = CholeskyVariationalDistribution(inducing_points.size(0))\n", + " variational_strategy = VariationalStrategy(self, inducing_points, variational_distribution, learn_inducing_locations=True)\n", + " super(GPModel, self).__init__(variational_strategy)\n", + " self.mean_module = gpytorch.means.ConstantMean()\n", + " self.covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.RBFKernel())\n", + " self.likelihood = likelihood\n", + " \n", + " def forward(self, x):\n", + " mean_x = self.mean_module(x)\n", + " covar_x = self.covar_module(x)\n", + " return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)" + ] + }, + { + "cell_type": "markdown", + "id": "9c19020b", + "metadata": {}, + "source": [ + "We initialize the SVGP with $25$ inducing points." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9cfef053", + "metadata": {}, + "outputs": [], + "source": [ + "likelihood = gpytorch.likelihoods.GaussianLikelihood()\n", + "model = GPModel(torch.randn(25, 1) + 2., likelihood)\n" + ] + }, + { + "cell_type": "markdown", + "id": "11113b9d", + "metadata": {}, + "source": [ + "### Model Training\n", + "\n", + "As we don't have a lot of data, we train the model with full-batch (although this isn't a restriction) and for $500$ iterations (b/c our choice of inducing points may not have been very good)." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "990fae51", + "metadata": {}, + "outputs": [], + "source": [ + "model.train()\n", + "likelihood.train()\n", + "\n", + "optimizer = torch.optim.Adam([\n", + " {'params': model.parameters()},\n", + " # {'params': likelihood.parameters()},\n", + "], lr=0.1)\n", + "\n", + "# Our loss object. We're using the VariationalELBO\n", + "mll = gpytorch.mlls.VariationalELBO(likelihood, model, num_data=train_y.size(0))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "25e5394a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration: 0 \t Loss: 1.6754810810089111\n", + "Iteration: 50 \t Loss: 0.5079809427261353\n", + "Iteration: 100 \t Loss: 0.39197731018066406\n", + "Iteration: 150 \t Loss: 0.36815035343170166\n", + "Iteration: 200 \t Loss: 0.3656342625617981\n", + "Iteration: 250 \t Loss: 0.3653048574924469\n", + "Iteration: 300 \t Loss: 0.3654007315635681\n", + "Iteration: 350 \t Loss: 0.3680660128593445\n", + "Iteration: 400 \t Loss: 0.3646673262119293\n", + "Iteration: 450 \t Loss: 0.36463457345962524\n", + "Iteration: 500 \t Loss: 0.36551928520202637\n" + ] + } + ], + "source": [ + "iters = 500 + 1\n", + "\n", + "for i in range(iters):\n", + " optimizer.zero_grad()\n", + " output = model(train_x)\n", + " loss = -mll(output, train_y.squeeze())\n", + " loss.backward()\n", + " optimizer.step()\n", + " if i % 50 == 0:\n", + " print(\"Iteration: \", i, \"\\t Loss:\", loss.item())" + ] + }, + { + "cell_type": "markdown", + "id": "20163340", + "metadata": {}, + "source": [ + "### Model Evaluation\n", + "\n", + "Now, that we've trained our SVGP, we choose some data to evaluate it on -- here $250$ data points from $[0, 8]$ to illustrate the performance both for interpolation (on $[0,3]$) and extrapolation (on $[3, 8]$)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "874a34f0", + "metadata": {}, + "outputs": [], + "source": [ + "model.eval()\n", + "likelihood.eval()\n", + "\n", + "test_x = torch.linspace(0, 8, 250).view(-1,1)\n", + "with torch.no_grad():\n", + " posterior = likelihood(model(test_x))" + ] + }, + { + "cell_type": "markdown", + "id": "9e2093f8", + "metadata": {}, + "source": [ + "As expected, the posterior model fits the training data well but reverts to a zero mean and high prediction outside of the region of the training data." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d56cc9f1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'y')" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEGCAYAAAB7DNKzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAACCW0lEQVR4nO2dd3zb1bn/38eybMmWPOQR2/JOnMRxEjsLMh3AEAIkZZcWOmhpoUDpr+3t7ea25fbe0g1py20odNCWZSgjECCE0SwgJCTOTux4xSPeW5Yl2ef3x7HkEduxHdsKcN6vl16ypK++eqzE5/meZ3weIaVEo9FoNJrhCPC3ARqNRqM5v9GOQqPRaDQjoh2FRqPRaEZEOwqNRqPRjIh2FBqNRqMZkUB/GzAZREdHy9TUVH+bodFoNB8a9u7dWy+ljBnqNb85CiFEEvAYEAf0AA9LKR8cdIwAHgSuBBzArVLKD8527tTUVPbs2TPxRms0Gs1HFCFE2XCv+XNH4QH+Q0r5gRDCCuwVQrwupTzS75grgIze24XA//XeazQajWaK8FuOQkpZ7d0dSCnbgKOAfdBhVwOPScW7QIQQIn6KTdVoNJqPNedFMlsIkQosAN4b9JIdONXvcQVnOhPvOW4XQuwRQuypq6ubFDs1Go3m44jfk9lCCAvwLPB1KWXr4JeHeMuQmiNSyoeBhwEWL16sdUk0mnPA7XZTUVGB0+n0tymaCcZkMpGYmIjRaBz1e/zqKIQQRpST+KeU8l9DHFIBJPV7nAhUTYVtGs3HmYqKCqxWK6mpqaiaEs1HASklDQ0NVFRUkJaWNur3+S301FvR9ChwVEr5m2EOexH4nFAsBVqklNVTZqRG8zHF6XQSFRWlncRHDCEEUVFRY94p+nNHsQL4LHBQCLG/97nvA8kAUso/AptRpbFFqPLYL0y9mRrNxxPtJD6ajOff1W+OQkq5g6FzEP2PkcDdU2ORRqPRaIbivKh60mjOV5xOOHwYtm5Vtw8+gMpKcLv9bdlHH4PBQE5ODnPnzuXGG2/E4XCM6f2lpaU8/vjjw74mhODee+/1PVdfX4/RaOSrX/3qOdn9UUQ7Co1mGKqq4J//hO3b1c9VVbBnD2zaBH/5i3IcZWXKmWgmHrPZzP79+zl06BBBQUH88Y9/HNP7R3IUAOnp6bz00ku+x/n5+WRlZY3b3o8y2lFoNENQUwMvvAAWC9jtEBmpbvHx6nFsrNpZvPIK/PWv8NxzUFCgnmtrg54ef/8GHy1WrVpFUVERjY2NXHPNNcyfP5+lS5dy4MABAP7973+Tk5NDTk4OCxYsoK2tje9+97ts376dnJwcfvvb355xTrPZTGZmpk/u56mnnuKTn/yk7/W6ujquv/56lixZwpIlS9i5cycAu3fvZvny5SxYsIDly5dz/PhxAP76179y3XXXsXbtWjIyMvj2t7892V/LlOH3PgqN5nzD7YY33oCwMAgJGfoYgwFsNvVzTw90dMB77w10EKGhytGEhIDJBEYjBAaqm8EAAQHqBuDNL54v+WO3Gzo71c//+Z/Qux5PGPPnwy9/efbjOjvB4/Hw0kuvcNlla/nBD37E3LkLeOKJ53n77Tf5zGc+x3vv7efnP/8Vv/nNH1i2bAXt7e2AiZ/85H4eeOBX/OtfL/nO5cXpBCnh2ms/xT/+8STh4XEIYSA6OoHy8io6O+GrX/1/3HXXN1i+fCWnTpXziU9czr59R0lJmc1rr20jMDCQN9/cyne+832eeOJZXC7Yt28/77yzj+DgYLKzZ/HlL99DYmLS0L/cJCAEBAdP/P8j7Sg0mkEcOgQtLZCYOLrjAwLAalU3L1KqxbarSzmR7m51k7LPmYy06/D3KPuFC9XOCMDlUrZPJC5X3/mHo7OzkyVLcgC48MJVXH/9bVxxxYU8+uiztLXBokWX0NDQQGVlCwsXruBb3/om119/C1dddR0JCYk4HODxDP057e3qd1q2bC0//vG9hIdP46qrbsLpVP9ubW3wxhtbOXy4T3qupaWV6uo2Wlpa+MEPPk9xcSFCCDweN21tyvmsWJFHQEA4bjdkZMzh2LEywsOnzlEAREWpC5GJRDsKjaYfLpdKWE+bdm7nEQKCgtTtw4jB0Gf7L37hHxvMZjM7duwf9Kw843sNChJ861vf5YorruL11zdz1VVLee65rRiNyokP9W8QFKT+jSyWIBYsWMQf//hr3nnnMK++usn3Hil7eP31dzCbzQPe+8Mf3sPq1Rfz+OPPUV5eyrp1FxEUpHaKZnOw7/MCAw0I4ZnS/wOTVWShcxQaTT9KStQf2xjUDTRTyPLlueTn/xOAHTveJioqmrCwMEpKTpKVNY+vf/075OQsprDwGBaLlfb2s2xbgLvv/g9+/OOfY7NFDXj+4ovX8Kc//d73+ODB/QC0trYQH68k5x5//K8T84ud52hHodH0IiXs2wcREf62RDMc3/3uj9m3bw8rVsznJz/5Lg899DcA/u//HmDZsrmsXJmNyWTm0kuvICtrPoGBgaxcmc1DD52ZzPaSmZnFpz/9+TOe//nPN7B/v/qspUvn8Oc/q6qrr33t29x33/e4/PIVdE90TO48RUh/B0MngcWLF0s9uEgzVpqa4MknR5+b+CiTkHCU6dMz/W2GZoy43arI4mw5iqNHj5KZOfDfVwixV0q5eKjj9Y5CM+U4nSrE09Xlb0sGUlHRV4Wk0Wj60MlszZTidMLTT0NzM2RmwqWXnj8loUePQni4v63QaM4/9PWTZko5dkzVs6emwvHjUFzsb4sU7e3Q2Kh6HzQazUC0oxgnTqeSb/gIpngmDZdLSWBER6tdREQEHDly1rdNCfX1/rZAozl/0aGnceBwwMsvK+0fb/hEx7bPzunTKtnmrSsPC1N5AYdj+A7oqaKi4sPb86DRTDZ6eRsHBw5AQwOkpUFRkdIF0pyd8nIlL+BFCHC7nfzv/z7o95GbpaXKcWk0mjPRO4ox0trq5IEHNnLNNXcghImQECX5EB/vb8vOb6RUTnVwsritrZBt23ZSWHgJ8+bN84ttbW0qR6ET2cOzaRPU1U3c+WJiYP36kY+JijIwZ848PB4Ps2Zl8tBDfyNkDFvP8vJS3ntvFzfeePOQrxcVneB73/s6J0+ewGg0MmfOPH7+898RGzv2tvznn8/nZz/7L2Jj49i06a0BNlx4YSYzZszC7XaRk7OY3/3u0THNq/ayb98ennzyMX7+8w1jfu+5oh3FGNm+vZDCwp3U1V1CaOg8IiPVArh8uU6EjkRTk0piR/U2v+7Ykc/hw9twOp04HJIHH9yA2WwiNzeXG2+8ccpt04xMXd3EXgxVj2KgsdlsZvv2/QB8+cu38Je//JG77/7mqD+jvLyUZ555fEhH4XQ6uemmq/jpT3/DFVcoj7V9+1vU19eNy1H84x+P8qtfPcSqVRef8Vpq6nS2b99Pd3c31157Gc899zSf/OQtY/6MBQsWs2DBkG0Ok45fQ09CiD8LIWqFEIeGef0iIUSLEGJ/7+2/ptpGL/n5+dxzzz08+OAGDAbJpk0b2LjxHnbtykeIib3a+ihSXz+wDDY7O4+IiDjKygqIiZlFR4eLpKQk8vLypty22tqJF1HTTCzLlq2iuLiIpqZGbrnlGlasmM9lly3l0CEla7tz579ZtSqHVatyyM1VMuM/+cl3eeed7axalXNGZ/YzzzzOkiXLfE4CYNWqi5kzZy5Op5O77/4Cy5fPIzd3Adu3qx3C44//lc9+9jpuuGEtixZl8F//pWTEf/GL+3j33R1885tf4d57/3PY38FgMLBw4QVUV1cCsH//Xq66ajUXXbSI66+/nNOnlff84IP3WbFiPmvWLOPee/+TZcvmAkqy5Kab1gEM+z384hc/5ktf+iIXXXQR6enpbNgwMbsPf+co/gqsPcsx26WUOb23+6bApiHJy8sjPj6R1lYX6elZeDwuIiPjqK4uRAgnFRX+suzDQWWlktr2YrXaSE7OoqmpisrKA7S0dLBu3TpsXu3uKbbNYpnyj9WMEo/Hw9atrzBnzjx+9rMfMX/+AnbuPMC99/4vd975OQB+97tf8ctf/oHt2/ezefN2zGYzP/rR/Sxbtort2/dz113fGHDOo0cPkZOzaMjPe+SRPwCwa9dBHnnkCe688/O+HNrBg/t59NGn2LnzIM899xQVFaf49rf/i5ycxTz88D/57/8eXjvd6XSyd+975OWtxe128+1v38Pf/vYMb7+9l1tu+SI//ekPALj77i/wm9/8kS1b3sEwzBXMcN8DwLFjx3jttdfYvXs3P/nJT3BPgFKgXx2FlHIb0OhPG0aLzWZjxYr1uFzt1NaW4HR2kJSURXHxftrbCykr87eFfdTVwRNPwKuvOvn1r/2fKAZVIeZdjHfsyGfjxnvYtGkDQUEhCAFFRSd5+OGHp9yunh61oxgkEKo5D+js7GTVqhwuvngxiYnJfPazt/Huuzu46abPApCbewmNjQ20tLRw4YUr+OEPv8nGjRtoaWkmMHD8UfX+nzFz5mySklIoKjoBwOrVeYSHh2MymZg1aw6nTp39D7+09CSrVuUwfXoUiYnJzJ07n8LC4xw7dohrr72MVaty+NWvfkpVVQUtLc20t7dx4YXLAbjhhqHzK8N9DwBXXnkVwcHBREdHExsbS80EVNt8GHIUy4QQBUAV8C0p5eGhDhJC3A7cDpCcnDwphuzcWUBUVAqxsTbeeecZXnppA1ZrFK+9tgGXy0RPTy6f/ezUxtcH09amEo9Go8qnvPfeTtas8V+iGFTPSVtbX1VRdnYeNTXFNDWdZtaspdTWVjJnzhK+/OXrpty21lY1l0CHns4/+ucovAylTSeE4Bvf+C5r1iiZ8TVrlMz4SMyencXOnf8e8rWR9O+CgvrK9gwGA93dnhE/B/pyFKdPV7N+/UVs3vwiKSlpzJ6dxZYt7ww4trl5dAmz4b4HgODggTZ6PGe38Wz4O/R0Nj4AUqSU2cDvgOeHO1BK+bCUcrGUcnFMTMykGGOz5fKZz9zHVVfdxbJl12O1RpGcrMJQNlsS2dlTH18fzKFD8N57+Tz11D3s3r2BxkbJL3+5gXvuuYf8/Hy/2NR7oePDarWxZMl6pOyhsbESj6eDWbOuJzNz6ucVNzdP+UdqzoGJkhm/4Yab2b17F6+99rLvua1bX+Xw4YMDPqOo6AQVFeVkZMw6Z9vj4uL50Y/u54EHfkZGxizq6+vYvVs5CrfbzdGjh4mIiMRisfL+++8C8K9/PTmm72GyOK8dhZSyVUrZ3vvzZsAohIj2hy0uF4CdyEgLVquN5cuvR8oeampUGCo7ex0ez9TH1/vjdMLBg2rKVnR0It3dLuz2LBob/ZcoBiWNMZjS0gJiY1NYu/YOYmOTOXXqAB0dU29bXZ0aOKMZmZgYVak0UbfxXstNlMy42WzmySdf4k9/+h2LFmWwdOkcHn/8r8TExHLbbXfR3d3N8uXz+OIXb+Khh/464Cr9XLjqqmtwOBzs2fMef/vbM/z4x99h5cpscnNz2L17FwC/+92jfP3rt7NmzTKklISFnVm3Pdz3MFn4XWZcCJEKvCSlnDvEa3FAjZRSCiEuAJ5B7TBGNHoyZMZra+G55yAhQT3etu0JCgvfZ/nyG9i16xkSEy/gqqs+xRVXTOjHjoljx+Dtt8Fuh/LyI/zzn/diNFro7OzgL3+5j6ysOX6x67XXnDz22Eauu+4OgoJURruhoZKQkHDMZgudne2UlLTyuc8lTHk/yqZNKvykm+0GomXG/Ud7ezuW3oTeb397PzU11dx//4Ojeu9kyYz79VpKCPEEcBEQLYSoAH4EGAGklH8EbgDuFEJ4gE7gU2dzEpNFU9NAXaesrFyWLFmP2WwhNXU+ra2t1Nb6w7I+jh/vW/C8V+zLl9/Aa689wzvvHPCbozhwoJDi4p1UVV1CaqrKlURF2X2vm80WwsMttLZOfeNiXR1ERk7tZ2o0I7Fly8v89rc/w+PxkJSUwkMP/dXfJvnXUUgpP32W138P/H6kY6aKqqqBlTGDFzqz2UJFhQr/9C8DnSqcTrWl9+54+juyoKD5pKe3TrlN+fn5vP32NgoKnAQEyN4qJxNZWbmsXDkw6R8crHotZp17KHjUdHaqkKIOPWnOJ6677iauu+4mf5sxgPM6R3E+UVFx9lr7gABV3eMPvLsZb1NbVJQds1kZHBNjobMzYcptysvLIzY2EY/H5Uv6x8QMnfQ3m6deM6t16n2nRvOhRDuKUdDZqbSAzqYuKqX/Fp+SkoGCe/0JDVU7op6eqbXJZrOxapXqPfEm/RcvXofVembS32RSO4qpDCz6y6lrNB82tKMYBa2to5vCFhSEX/IUUo6sfmowKCfhDye2Z08BNltfdVNp6YEhj/Pa6HBMnW21tVpaXKMZDTo6OwoG9wEMh/eqeKrp6FC7npHUL3p6VEI+ImLKzAIgNTWXG29cT0KCSvo7HCN7K4dj6sQVdUe2RjM69I5iFNTUDJ2gdrmcvPjig7hcSiLDZBq6Z2CyGeozB9sWHKzCT1OP6j0BlfSPiho5VzKVvRSNjf4pPNCcncbGBp/I36xZccyZY/c9dqmmpmHZt28P3/nO1876GWvWLJ8QW3fseJvk5HBycxewZMksrrwyl1dffWlU73vvvV0TYsNko3cUo+D06aGvPKuqCjl6dCfz56uyT6NRXdm73UpCY6qorj7z8wbb5s1TTCU9Parzedowqs0ul5NXX93I2rWqv0KI0e/ezhWnU1c8nc/YbFE++Y777/8xoaEW7rnnW77XPR7PsHpOo5Xj3rJl4hbpZctW8dRTyjkcPLifW265BrPZzOrVwze57tjxNqGhFp+u0/mM/jM5C93dapqdt77f5XLy0ENfISjITHe3BykHln2mp99IR8fUhnjKylRF1ki2ZWbmMmPGjfT0TN3Y1s5ORvy8wc5sKndk7e1T8zkfJ5xOJ3/5y0a+8IU7ME3CVu2uu24lMtLGgQP7yM5eyLXX3sT3vvd1nM5OTCYzf/jDX8jImMWOHW/zu9/9iqeeeon77/8xFRXllJYWU1FRzp13fp077lC7jcRECxUV7ezY8Tb33/9joqKiOXr0ENnZi3j44X8ghGDLls388IffxGaLJjt7IaWlxT6HMBzz5uXw7W//F3/60+9ZvTqPV17ZxK9//VNcLhc2WxQPP/xPnM5O/vKXP2IwGHj66X/w85//jpaW5jOOG89sjMlAO4qz4K2M8S52VVWFtLY20NnZRnS0neTkLKqqimhpqSEzcwVdXUypo3C71eKakABlZYW0tzcTFxdJW1sjyclZ1NSUYLdnsGBBnm+S21R1IQ+3GHuHFrlczgHObMaMXCyWqRFV9IdcyEedkycL2b17J7m5l5CVNTkilEVFJ3j++a0YDAZaW1vZvHkbgYGBvP32Vv77v7/PY489e8Z7Tpw4xqZNb9He3saSJbP44hfvPGPC3IED+3jnncPExyewdu0K3n13JwsWLOYb37iDzZu3kZKSxm23jdj2NYDs7IX87ndKcnzZspW8/vq7CCF47LFH2LDhF/z0p7/mC1/4yoCdUnNz05DHnQ9oR3EWvJVC/Rc3t7uL6uoiTp8+SX19BQZDEAaDgba2BozGhCm9Wm1pgb1783npJWVbYKCRurpTlJTso7a2lLCwGF9JalvbQBXXyWa4xdirHltefmSAM1u0KG/KRPqam6duZ/VR5/nn89m1S00r7OmRbNy4AZPJxPLluVxzzcQ6/muuudE3o6G1tYW77vo8J08WIoTA4xl67sKaNUp2Ozg4mJiYWGpra7DbEwccs2jRBb7n5s7Noby8FIvFQmpqOikpaQBcf/2n+dvfRieF319AorKygi9+8SZOn67G7Xb5zjeY0R7nD/SfylloalKlsdnZebS1NXLkyHba2upxu510drZRW1tKUdEe2toa2bRpA/n5U6vS2tICs2crEUBvY1tLSy02WwI33PC9M0pSpyoHAGoxHkpzxqse63QO7K+IiLDhcqn8wWRTX68T2RPF6tV5JCQk4na7yMzMwu12YbcnjRifHy8hIX0lcf/7v/eyatXFvPPOIZ58ctOwc1f6C/oFBAwtDT6UfPi5qAUdOLCPmTOVltJ3vnMPX/rSV9m16yC//e3GYe0c7XH+QDuKs1BToxLZVquNq666G4MhkI6OFiyWSDIylhATk4zJFEpi4mw8HhexsUlMnz51Kq2nT0Nk5MCF12Syctttv2HRorXcfPN9ZGXlAmphnMru55EW46Ki92lrayAv79YBziwgYGp6KRoatKOYKCIjbaxdu56OjnZKS0twODq4/PJ1REZOrppya2sL8fFKSufxx/864efPyJhNaWkx5eWlADz33FOjet+hQwf45S//my996W6fnQkJys4nnuhTeR0sgz7c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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(test_x, posterior.mean, color = \"blue\", label = \"Post Mean\")\n", + "plt.fill_between(test_x.squeeze(), *posterior.confidence_region(), color = \"blue\", alpha = 0.3, label = \"Post Conf Region\")\n", + "plt.scatter(train_x, train_y, color = \"black\", marker = \"*\", alpha = 0.5, label = \"Training Data\")\n", + "plt.legend()\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")" + ] + }, + { + "cell_type": "markdown", + "id": "d3f79b90", + "metadata": {}, + "source": [ + "### Model Updating\n", + "\n", + "Now, we choose $25$ points to condition the model on -- imagining that these data points have just been acquired, perhaps from an active learning or Bayesian optimization loop." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0896fe69", + "metadata": {}, + "outputs": [], + "source": [ + "val_x = torch.linspace(3, 5, 25).view(-1,1)\n", + "val_y = torch.sin(6. * val_x) + 0.3 * torch.randn_like(val_x)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2bbfaf5f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/wesleymaddox/Documents/GitHub/wjm_gpytorch/gpytorch/utils/cholesky.py:40: NumericalWarning: A not p.d., added jitter of 1.0e-06 to the diagonal\n", + " warnings.warn(\n", + "/Users/wesleymaddox/Documents/GitHub/wjm_gpytorch/gpytorch/utils/cholesky.py:40: NumericalWarning: A not p.d., added jitter of 1.0e-05 to the diagonal\n", + " warnings.warn(\n", + "/Users/wesleymaddox/Documents/GitHub/wjm_gpytorch/gpytorch/utils/cholesky.py:40: NumericalWarning: A not p.d., added jitter of 1.0e-04 to the diagonal\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "cond_model = model.variational_strategy.get_fantasy_model(inputs=val_x, targets=val_y.squeeze())" + ] + }, + { + "cell_type": "markdown", + "id": "fb931dc8", + "metadata": {}, + "source": [ + "Note that the updated model returned is an ExactGP class rather than a SVGP." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ac5e171c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "_BaseExactGP(\n", + " (likelihood): GaussianLikelihood(\n", + " (noise_covar): HomoskedasticNoise(\n", + " (raw_noise_constraint): GreaterThan(1.000E-04)\n", + " )\n", + " )\n", + " (mean_module): ConstantMean()\n", + " (covar_module): ScaleKernel(\n", + " (base_kernel): RBFKernel(\n", + " (raw_lengthscale_constraint): Positive()\n", + " (distance_module): None\n", + " )\n", + " (raw_outputscale_constraint): Positive()\n", + " )\n", + ")" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cond_model" + ] + }, + { + "cell_type": "markdown", + "id": "4f929bf8", + "metadata": {}, + "source": [ + "We compute its posterior distribution on the same testing dataset as before." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "f67ed240", + "metadata": {}, + "outputs": [], + "source": [ + "with torch.no_grad():\n", + " updated_posterior = cond_model.likelihood(cond_model(test_x))" + ] + }, + { + "cell_type": "markdown", + "id": "52238773", + "metadata": {}, + "source": [ + "Finally, we plot the updated model, showing that the model has been updated to the newly observed data (grey) without forgetting the previous training data (black)." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "a914fd04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'y')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(test_x, posterior.mean, color = \"blue\", label = \"Post Mean\")\n", + "plt.fill_between(test_x.squeeze(), *posterior.confidence_region(), color = \"blue\", alpha = 0.3, label = \"Post Conf Region\")\n", + "plt.scatter(train_x, train_y, color = \"black\", marker = \"*\", alpha = 0.5, label = \"Training Data\")\n", + "\n", + "plt.plot(test_x, updated_posterior.mean, color = \"orange\", label = \"Fant Mean\")\n", + "plt.fill_between(test_x.squeeze(), *updated_posterior.confidence_region(), color = \"orange\", alpha = 0.3, label = \"Fant Conf Region\")\n", + "\n", + "plt.scatter(val_x, val_y, color = \"grey\", marker = \"*\", alpha = 0.5, label = \"New Data\")\n", + "plt.legend()\n", + "plt.xlabel(\"x\")\n", + "plt.ylabel(\"y\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a7b20f6", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/08_Advanced_Usage/index.rst b/examples/08_Advanced_Usage/index.rst index b6026d702..d97466760 100644 --- a/examples/08_Advanced_Usage/index.rst +++ b/examples/08_Advanced_Usage/index.rst @@ -59,6 +59,14 @@ See the `1D derivatives GP example`_ or the `2D derivatives GP example`_ for exa Simple_Batch_Mode_GP_Regression.ipynb: +Variational Fantasization +---------------------------------- +We also include an example of how to perform fantasy modelling (e.g. efficient, closed form updates) for variational +Gaussian process models, enabling their usage for lookahead optimization. + +.. _Variational fantasization: + SVGP_Model_Updating.ipynb + Converting Models to TorchScript ---------------------------------- @@ -73,3 +81,4 @@ how to convert both an exact GP and a variational GP to a ScriptModule that can TorchScript_Exact_Models.ipynb TorchScript_Variational_Models.ipynb + SVGP_Model_Updating.ipynb diff --git a/gpytorch/models/approximate_gp.py b/gpytorch/models/approximate_gp.py index 88c0022f0..85e2674f4 100644 --- a/gpytorch/models/approximate_gp.py +++ b/gpytorch/models/approximate_gp.py @@ -75,6 +75,33 @@ def pyro_model(self, input, beta=1.0, name_prefix=""): """ return super().pyro_model(input, beta=beta, name_prefix=name_prefix) + def get_fantasy_model(self, inputs, targets, **kwargs): + r""" + Returns a new GP model that incorporates the specified inputs and targets as new training data using + online variational conditioning (OVC). + + This function first casts the inducing points and variational parameters into pseudo-points before + returning an equivalent ExactGP model with a specialized likelihood. + + .. note:: + If `targets` is a batch (e.g. `b x m`), then the GP returned from this method will be a batch mode GP. + If `inputs` is of the same (or lesser) dimension as `targets`, then it is assumed that the fantasy points + are the same for each target batch. + + :param torch.Tensor inputs: (`b1 x ... x bk x m x d` or `f x b1 x ... x bk x m x d`) Locations of fantasy + observations. + :param torch.Tensor targets: (`b1 x ... x bk x m` or `f x b1 x ... x bk x m`) Labels of fantasy observations. + :return: An `ExactGP` model with `n + m` training examples, where the `m` fantasy examples have been added + and all test-time caches have been updated. + :rtype: ~gpytorch.models.ExactGP + + Reference: "Conditioning Sparse Variational Gaussian Processes for Online Decision-Making," + Maddox, Stanton, Wilson, NeurIPS, '21 + https://papers.nips.cc/paper/2021/hash/325eaeac5bef34937cfdc1bd73034d17-Abstract.html + + """ + return self.variational_strategy.get_fantasy_model(inputs=inputs, targets=targets, **kwargs) + def __call__(self, inputs, prior=False, **kwargs): if inputs.dim() == 1: inputs = inputs.unsqueeze(-1) diff --git a/gpytorch/test/variational_test_case.py b/gpytorch/test/variational_test_case.py index 57943a323..077bf88a7 100644 --- a/gpytorch/test/variational_test_case.py +++ b/gpytorch/test/variational_test_case.py @@ -95,6 +95,28 @@ def _eval_iter(self, model, batch_shape=torch.Size([]), cuda=False): return output + def _fantasy_iter( + self, + model, + likelihood, + batch_shape=torch.Size([]), + cuda=False, + num_fant=10, + covar_module=None, + mean_module=None, + ): + model.likelihood = likelihood + val_x = torch.randn(*batch_shape, num_fant, 2).clamp(-2.5, 2.5) + val_y = torch.linspace(-1, 1, num_fant) + val_y = val_y.view(num_fant, *([1] * (len(self.event_shape) - 1))) + val_y = val_y.expand(*batch_shape, num_fant, *self.event_shape[1:]) + if cuda: + model = model.cuda() + val_x = val_x.cuda() + val_y = val_y.cuda() + updated_model = model.get_fantasy_model(val_x, val_y, covar_module=covar_module, mean_module=mean_module) + return updated_model + @abstractproperty def batch_shape(self): raise NotImplementedError @@ -272,3 +294,102 @@ def test_training_all_batch_zero_mean(self): expected_batch_shape=(torch.Size([3, 4]) + self.batch_shape), constant_mean=False, ) + + def test_fantasy_call( + self, + data_batch_shape=None, + inducing_batch_shape=None, + model_batch_shape=None, + expected_batch_shape=None, + constant_mean=True, + ): + # Batch shapes + model_batch_shape = model_batch_shape if model_batch_shape is not None else self.batch_shape + data_batch_shape = data_batch_shape if data_batch_shape is not None else self.batch_shape + inducing_batch_shape = inducing_batch_shape if inducing_batch_shape is not None else self.batch_shape + expected_batch_shape = expected_batch_shape if expected_batch_shape is not None else self.batch_shape + + num_inducing = 16 + num_fant = 10 + # Make model and likelihood + model, likelihood = self._make_model_and_likelihood( + batch_shape=model_batch_shape, + inducing_batch_shape=inducing_batch_shape, + distribution_cls=self.distribution_cls, + strategy_cls=self.strategy_cls, + constant_mean=constant_mean, + num_inducing=num_inducing, + ) + + # we iterate through the covar and mean module possible settings + covar_mean_options = [ + {"covar_module": None, "mean_module": None}, + {"covar_module": gpytorch.kernels.MaternKernel(), "mean_module": gpytorch.means.ZeroMean()}, + ] + for cm_dict in covar_mean_options: + fant_model = self._fantasy_iter( + model, likelihood, data_batch_shape, self.cuda, num_fant=num_fant, **cm_dict + ) + self.assertTrue(isinstance(fant_model, gpytorch.models.ExactGP)) + + # we check to ensure setting the covar_module and mean_modules are okay + if cm_dict["covar_module"] is None: + self.assertEqual(type(fant_model.covar_module), type(model.covar_module)) + else: + self.assertNotEqual(type(fant_model.covar_module), type(model.covar_module)) + if cm_dict["mean_module"] is None: + self.assertEqual(type(fant_model.mean_module), type(model.mean_module)) + else: + self.assertNotEqual(type(fant_model.mean_module), type(model.mean_module)) + + # now we check to ensure the shapes of the fantasy strategy are correct + self.assertTrue(fant_model.prediction_strategy is not None) + for key in fant_model.prediction_strategy._memoize_cache.keys(): + if key[0] == "mean_cache": + break + mean_cache = fant_model.prediction_strategy._memoize_cache[key] + self.assertEqual(mean_cache.shape, torch.Size([*expected_batch_shape, num_inducing + num_fant])) + + # we remove the mean_module and covar_module and check for errors + del model.mean_module + with self.assertRaises(ModuleNotFoundError): + self._fantasy_iter(model, likelihood, data_batch_shape, self.cuda, num_fant=num_fant) + + model.mean_module = gpytorch.means.ZeroMean() + del model.covar_module + with self.assertRaises(ModuleNotFoundError): + self._fantasy_iter(model, likelihood, data_batch_shape, self.cuda, num_fant=num_fant) + + # finally we check to ensure failure for a non-gaussian likelihood + with self.assertRaises(NotImplementedError): + self._fantasy_iter( + model, + gpytorch.likelihoods.BernoulliLikelihood(), + data_batch_shape, + self.cuda, + num_fant=num_fant, + ) + + def test_fantasy_call_batch_inducing(self): + return self.test_fantasy_call( + model_batch_shape=(torch.Size([3]) + self.batch_shape), + data_batch_shape=self.batch_shape, + inducing_batch_shape=(torch.Size([3]) + self.batch_shape), + expected_batch_shape=(torch.Size([3]) + self.batch_shape), + ) + + def test_fantasy_call_batch_data(self): + return self.test_fantasy_call( + model_batch_shape=self.batch_shape, + inducing_batch_shape=self.batch_shape, + data_batch_shape=(torch.Size([3]) + self.batch_shape), + expected_batch_shape=(torch.Size([3]) + self.batch_shape), + ) + + def test_fantasy_call_batch_model(self): + return self.test_fantasy_call( + model_batch_shape=(torch.Size([3]) + self.batch_shape), + inducing_batch_shape=self.batch_shape, + data_batch_shape=self.batch_shape, + expected_batch_shape=(torch.Size([3]) + self.batch_shape), + ) diff --git a/gpytorch/variational/_variational_strategy.py b/gpytorch/variational/_variational_strategy.py index faff22133..779d1fc04 100644 --- a/gpytorch/variational/_variational_strategy.py +++ b/gpytorch/variational/_variational_strategy.py @@ -1,14 +1,38 @@ #!/usr/bin/env python3 +import functools from abc import ABC, abstractproperty +from copy import deepcopy import torch from .. import settings from ..distributions import Delta, MultivariateNormal +from ..likelihoods import GaussianLikelihood +from ..models import ExactGP from ..module import Module from ..utils.broadcasting import _mul_broadcast_shape -from ..utils.memoize import cached, clear_cache_hook +from ..utils.memoize import add_to_cache, cached, clear_cache_hook + + +class _BaseExactGP(ExactGP): + def __init__(self, train_inputs, train_targets, likelihood, mean_module, covar_module): + super().__init__(train_inputs, train_targets, likelihood) + self.mean_module = mean_module + self.covar_module = covar_module + + def forward(self, x): + mean = self.mean_module(x) + covar = self.covar_module(x) + return MultivariateNormal(mean, covar) + + +def _add_cache_hook(tsr, pred_strat): + if tsr.grad_fn is not None: + wrapper = functools.partial(clear_cache_hook, pred_strat) + functools.update_wrapper(wrapper, clear_cache_hook) + tsr.grad_fn.register_hook(wrapper) + return tsr class _VariationalStrategy(Module, ABC): @@ -16,6 +40,8 @@ class _VariationalStrategy(Module, ABC): Abstract base class for all Variational Strategies. """ + has_fantasy_strategy = False + def __init__(self, model, inducing_points, variational_distribution, learn_inducing_locations=True): super().__init__() @@ -97,6 +123,158 @@ def kl_divergence(self): kl_divergence = torch.distributions.kl.kl_divergence(self.variational_distribution, self.prior_distribution) return kl_divergence + @cached(name="amortized_exact_gp") + def amortized_exact_gp(self, mean_module=None, covar_module=None): + mean_module = self.model.mean_module if mean_module is None else mean_module + covar_module = self.model.covar_module if covar_module is None else covar_module + + with torch.no_grad(): + # from here on down, we refer to the inducing points as pseudo_inputs + pseudo_target_covar, pseudo_target_mean = self.pseudo_points + pseudo_inputs = self.inducing_points.detach() + if pseudo_inputs.ndim < pseudo_target_mean.ndim: + pseudo_inputs = pseudo_inputs.expand(*pseudo_target_mean.shape[:-2], *pseudo_inputs.shape) + # TODO: add flag for conditioning into SGPR after building fantasy strategy for SGPR + new_covar_module = deepcopy(covar_module) + + # update inducing mean if necessary + pseudo_target_mean = pseudo_target_mean.squeeze() + mean_module(pseudo_inputs) + + inducing_exact_model = _BaseExactGP( + pseudo_inputs, + pseudo_target_mean, + mean_module=deepcopy(mean_module), + covar_module=new_covar_module, + likelihood=deepcopy(self.model.likelihood), + ) + + # now fantasize around this model + # as this model is new, we need to compute a posterior to construct the prediction strategy + # which uses the likelihood pseudo caches + faked_points = torch.randn( + *pseudo_target_mean.shape[:-2], + 1, + pseudo_inputs.shape[-1], + device=pseudo_inputs.device, + dtype=pseudo_inputs.dtype, + ) + inducing_exact_model.eval() + _ = inducing_exact_model(faked_points) + + # then we overwrite the likelihood to take into account the multivariate normal term + pred_strat = inducing_exact_model.prediction_strategy + pred_strat._memoize_cache = {} + with torch.no_grad(): + updated_lik_train_train_covar = pred_strat.train_prior_dist.lazy_covariance_matrix + pseudo_target_covar + pred_strat.lik_train_train_covar = updated_lik_train_train_covar + + # do the mean cache because the mean cache doesn't solve against lik_train_train_covar + train_mean = inducing_exact_model.mean_module(*inducing_exact_model.train_inputs) + train_labels_offset = (inducing_exact_model.prediction_strategy.train_labels - train_mean).unsqueeze(-1) + mean_cache = updated_lik_train_train_covar.inv_matmul(train_labels_offset).squeeze(-1) + mean_cache = _add_cache_hook(mean_cache, inducing_exact_model.prediction_strategy) + add_to_cache(pred_strat, "mean_cache", mean_cache) + # TODO: check to see if we need to do the covar_cache? + + inducing_exact_model.prediction_strategy = pred_strat + return inducing_exact_model + + def pseudo_points(self): + raise NotImplementedError("Each variational strategy must implement its own pseudo points method") + + def get_fantasy_model( + self, + inputs, + targets, + mean_module=None, + covar_module=None, + **kwargs, + ): + r""" + Performs the online variational conditioning (OVC) strategy of Maddox et al, '21 to return + an exact GP model that incorporates the inputs and targets alongside the variational model's inducing + points and targets. + + Currently, instead of directly updating the variational parameters (and inducing points), we instead + return an ExactGP model rather than an updated variational GP model. This is done primarily for + numerical stability. + + Unlike the ExactGP's call for get_fantasy_model, we enable options for mean_module and covar_module + that allow specification of the mean / covariance. We expect that either the mean and covariance + modules are attributes of the model itself called mean_module and covar_module respectively OR that you + pass them into this method explicitly. + + :param torch.Tensor inputs: (`b1 x ... x bk x m x d` or `f x b1 x ... x bk x m x d`) Locations of fantasy + observations. + :param torch.Tensor targets: (`b1 x ... x bk x m` or `f x b1 x ... x bk x m`) Labels of fantasy observations. + :param torch.nn.Module mean_module: torch module describing the mean function of the GP model. Optional if + `mean_module` is already an attribute of the variational GP. + :param torch.nn.Module covar_module: torch module describing the covariance function of the GP model. Optional + if `covar_module` is already an attribute of the variational GP. + :return: An `ExactGP` model with `k + m` training examples, where the `m` fantasy examples have been added + and all test-time caches have been updated. We assume that there are `k` inducing points in this variational + GP. Note that we return an `ExactGP` rather than a variational GP. + :rtype: ~gpytorch.models.ExactGP + + Reference: "Conditioning Sparse Variational Gaussian Processes for Online Decision-Making," + Maddox, Stanton, Wilson, NeurIPS, '21 + https://papers.nips.cc/paper/2021/hash/325eaeac5bef34937cfdc1bd73034d17-Abstract.html + """ + + # currently, we only support fantasization for CholeskyVariationalDistribution and + # whitened / unwhitened variational strategies + if not self.has_fantasy_strategy: + raise NotImplementedError( + "No fantasy model support for ", + self.__name__, + ". Only VariationalStrategy and UnwhitenedVariationalStrategy are currently supported.", + ) + if not isinstance(self.model.likelihood, GaussianLikelihood): + raise NotImplementedError( + "No fantasy model support for ", + self.model.likelihood, + ". Only GaussianLikelihoods are currently supported.", + ) + # we assume that either the user has given the model a mean_module and a covar_module + # or that it will be passed into the get_fantasy_model function. we check for these. + if mean_module is None: + mean_module = getattr(self.model, "mean_module", None) + if mean_module is None: + raise ModuleNotFoundError( + "Either you must provide a mean_module as input to get_fantasy_model", + "or it must be an attribute of the model called mean_module.", + ) + if covar_module is None: + covar_module = getattr(self.model, "covar_module", None) + if covar_module is None: + # raise an error + raise ModuleNotFoundError( + "Either you must provide a covar_module as input to get_fantasy_model", + "or it must be an attribute of the model called covar_module.", + ) + + # first we construct an exact model over the inducing points with the inducing covariance + # matrix + inducing_exact_model = self.amortized_exact_gp(mean_module=mean_module, covar_module=covar_module) + + # then we update this model by adding in the inputs and pseudo targets + # finally we fantasize wrt targets + fantasy_model = inducing_exact_model.get_fantasy_model(inputs, targets, **kwargs) + fant_pred_strat = fantasy_model.prediction_strategy + + # first we update the lik_train_train_covar + # do the mean cache again because the mean cache resets the likelihood forward + train_mean = fantasy_model.mean_module(*fantasy_model.train_inputs) + train_labels_offset = (fant_pred_strat.train_labels - train_mean).unsqueeze(-1) + fantasy_lik_train_root_inv = fant_pred_strat.lik_train_train_covar.root_inv_decomposition() + mean_cache = fantasy_lik_train_root_inv.matmul(train_labels_offset).squeeze(-1) + mean_cache = _add_cache_hook(mean_cache, fant_pred_strat) + add_to_cache(fant_pred_strat, "mean_cache", mean_cache) + # TODO: should we update the covar_cache? + + fantasy_model.prediction_strategy = fant_pred_strat + return fantasy_model + def __call__(self, x, prior=False, **kwargs): # If we're in prior mode, then we're done! if prior: diff --git a/gpytorch/variational/unwhitened_variational_strategy.py b/gpytorch/variational/unwhitened_variational_strategy.py index f3985d473..bfe1c5d64 100644 --- a/gpytorch/variational/unwhitened_variational_strategy.py +++ b/gpytorch/variational/unwhitened_variational_strategy.py @@ -4,6 +4,8 @@ import torch +from gpytorch.variational.cholesky_variational_distribution import CholeskyVariationalDistribution + from .. import settings from ..distributions import MultivariateNormal from ..lazy import ( @@ -17,6 +19,7 @@ ) from ..utils.broadcasting import _mul_broadcast_shape from ..utils.cholesky import psd_safe_cholesky +from ..utils.errors import NotPSDError from ..utils.memoize import add_to_cache, cached from ._variational_strategy import _VariationalStrategy @@ -44,6 +47,7 @@ class UnwhitenedVariationalStrategy(_VariationalStrategy): the inducing point locations :math:`\mathbf Z` should be learned (i.e. are they parameters of the model). """ + has_fantasy_strategy = True @cached(name="cholesky_factor", ignore_args=True) def _cholesky_factor(self, induc_induc_covar): @@ -58,6 +62,58 @@ def prior_distribution(self): res = MultivariateNormal(out.mean, out.lazy_covariance_matrix.add_jitter()) return res + @property + @cached(name="pseudo_points_memo") + def pseudo_points(self): + # TODO: implement for other distributions + # retrieve the variational mean, m and covariance matrix, S. + if not isinstance(self._variational_distribution, CholeskyVariationalDistribution): + raise NotImplementedError( + "Only CholeskyVariationalDistribution has pseudo-point support currently, ", + "but your _variational_distribution is a ", + self._variational_distribution.__name__, + ) + + # retrieve the variational mean, m and covariance matrix, S. + var_cov_root = TriangularLazyTensor(self._variational_distribution.chol_variational_covar) + var_cov = CholLazyTensor(var_cov_root) + var_mean = self.variational_distribution.mean # .unsqueeze(-1) + if var_mean.shape[-1] != 1: + var_mean = var_mean.unsqueeze(-1) + + # R = K - S + Kmm = self.model.covar_module(self.inducing_points) + res = Kmm - var_cov + + cov_diff = res + + # D_a = (S^{-1} - K^{-1})^{-1} = S + S R^{-1} S + # note that in the whitened case R = I - S, unwhitened R = K - S + # we compute (R R^{T})^{-1} R^T S for stability reasons as R is probably not PSD. + eval_lhs = var_cov.evaluate() + eval_rhs = cov_diff.transpose(-1, -2).matmul(eval_lhs) + inner_term = cov_diff.matmul(cov_diff.transpose(-1, -2)) + # TODO: flag the jitter here + inner_solve = inner_term.add_jitter(1e-3).inv_matmul(eval_rhs, eval_lhs.transpose(-1, -2)) + inducing_covar = var_cov + inner_solve + + # mean term: D_a S^{-1} m + # unwhitened: (S - S R^{-1} S) S^{-1} m = (I - S R^{-1}) m + rhs = cov_diff.transpose(-1, -2).matmul(var_mean) + inner_rhs_mean_solve = inner_term.add_jitter(1e-3).inv_matmul(rhs) + pseudo_target_mean = var_mean + var_cov.matmul(inner_rhs_mean_solve) + + # ensure inducing covar is psd + try: + pseudo_target_covar = CholLazyTensor(inducing_covar.add_jitter(1e-3).cholesky()).evaluate() + except NotPSDError: + from gpytorch.lazy import DiagLazyTensor + + evals, evecs = inducing_covar.symeig(eigenvectors=True) + pseudo_target_covar = evecs.matmul(DiagLazyTensor(evals + 1e-4)).matmul(evecs.transpose(-1, -2)).evaluate() + + return pseudo_target_covar, pseudo_target_mean + def forward(self, x, inducing_points, inducing_values, variational_inducing_covar=None): # If our points equal the inducing points, we're done if torch.equal(x, inducing_points): diff --git a/gpytorch/variational/variational_strategy.py b/gpytorch/variational/variational_strategy.py index 5addd5b38..c40301bf1 100644 --- a/gpytorch/variational/variational_strategy.py +++ b/gpytorch/variational/variational_strategy.py @@ -4,14 +4,26 @@ import torch +from gpytorch.variational._variational_strategy import _VariationalStrategy +from gpytorch.variational.cholesky_variational_distribution import CholeskyVariationalDistribution + from ..distributions import MultivariateNormal -from ..lazy import DiagLazyTensor, MatmulLazyTensor, RootLazyTensor, SumLazyTensor, TriangularLazyTensor, delazify +from ..lazy import ( + CholLazyTensor, + DiagLazyTensor, + MatmulLazyTensor, + RootLazyTensor, + SumLazyTensor, + TriangularLazyTensor, + delazify, +) from ..settings import _linalg_dtype_cholesky, trace_mode from ..utils.cholesky import psd_safe_cholesky -from ..utils.errors import CachingError +from ..utils.errors import CachingError, NotPSDError from ..utils.memoize import cached, clear_cache_hook, pop_from_cache_ignore_args from ..utils.warnings import OldVersionWarning -from ._variational_strategy import _VariationalStrategy + +# from ._variational_strategy import _VariationalStrategy def _ensure_updated_strategy_flag_set( @@ -67,6 +79,8 @@ def __init__(self, model, inducing_points, variational_distribution, learn_induc self.register_buffer("updated_strategy", torch.tensor(True)) self._register_load_state_dict_pre_hook(_ensure_updated_strategy_flag_set) + self.has_fantasy_strategy = True + @cached(name="cholesky_factor", ignore_args=True) def _cholesky_factor(self, induc_induc_covar): L = psd_safe_cholesky(delazify(induc_induc_covar).type(_linalg_dtype_cholesky.value())) @@ -84,6 +98,65 @@ def prior_distribution(self): res = MultivariateNormal(zeros, DiagLazyTensor(ones)) return res + @property + @cached(name="pseudo_points_memo") + def pseudo_points(self): + # TODO: have var_mean, var_cov come from a method of _variational_distribution + # while having Kmm_root be a root decomposition to enable CIQVariationalDistribution support. + + # retrieve the variational mean, m and covariance matrix, S. + if not isinstance(self._variational_distribution, CholeskyVariationalDistribution): + raise NotImplementedError( + "Only CholeskyVariationalDistribution has pseudo-point support currently, ", + "but your _variational_distribution is a ", + self._variational_distribution.__name__, + ) + + var_cov_root = TriangularLazyTensor(self._variational_distribution.chol_variational_covar) + var_cov = CholLazyTensor(var_cov_root) + var_mean = self.variational_distribution.mean + if var_mean.shape[-1] != 1: + var_mean = var_mean.unsqueeze(-1) + + # compute R = I - S + cov_diff = var_cov.add_jitter(-1.0) + cov_diff = -1.0 * cov_diff + + # K^{1/2} + Kmm = self.model.covar_module(self.inducing_points) + Kmm_root = Kmm.cholesky() + + # D_a = (S^{-1} - K^{-1})^{-1} = S + S R^{-1} S + # note that in the whitened case R = I - S, unwhitened R = K - S + # we compute (R R^{T})^{-1} R^T S for stability reasons as R is probably not PSD. + eval_var_cov = var_cov.evaluate() + eval_rhs = cov_diff.transpose(-1, -2).matmul(eval_var_cov) + inner_term = cov_diff.matmul(cov_diff.transpose(-1, -2)) + # TODO: flag the jitter here + inner_solve = inner_term.add_jitter(1e-3).inv_matmul(eval_rhs, eval_var_cov.transpose(-1, -2)) + inducing_covar = var_cov + inner_solve + + inducing_covar = Kmm_root.matmul(inducing_covar).matmul(Kmm_root.transpose(-1, -2)) + + # mean term: D_a S^{-1} m + # unwhitened: (S - S R^{-1} S) S^{-1} m = (I - S R^{-1}) m + rhs = cov_diff.transpose(-1, -2).matmul(var_mean) + # TODO: this jitter too + inner_rhs_mean_solve = inner_term.add_jitter(1e-3).inv_matmul(rhs) + pseudo_target_mean = Kmm_root.matmul(inner_rhs_mean_solve) + + # ensure inducing covar is psd + # TODO: make this be an explicit root decomposition + try: + pseudo_target_covar = CholLazyTensor(inducing_covar.add_jitter(1e-3).cholesky()).evaluate() + except NotPSDError: + from gpytorch.lazy import DiagLazyTensor + + evals, evecs = inducing_covar.symeig(eigenvectors=True) + pseudo_target_covar = evecs.matmul(DiagLazyTensor(evals + 1e-4)).matmul(evecs.transpose(-1, -2)).evaluate() + + return pseudo_target_covar, pseudo_target_mean + def forward(self, x, inducing_points, inducing_values, variational_inducing_covar=None, **kwargs): # Compute full prior distribution full_inputs = torch.cat([inducing_points, x], dim=-2) diff --git a/test/examples/test_svgp_gp_regression.py b/test/examples/test_svgp_gp_regression.py index 5624de89c..94e39df5e 100644 --- a/test/examples/test_svgp_gp_regression.py +++ b/test/examples/test_svgp_gp_regression.py @@ -114,6 +114,16 @@ def test_regression_error( # Make sure CG was called (or not), and no warnings were thrown self.assertFalse(cg_mock.called) + if distribution_cls is gpytorch.variational.CholeskyVariationalDistribution: + # finally test fantasization + # we only will check that tossing the entire training set into the model will reduce the mae + model.likelihood = likelihood + fant_model = model.get_fantasy_model(train_x, train_y) + fant_preds = fant_model.likelihood(fant_model(train_x)).mean.squeeze() + updated_abs_error = torch.mean(torch.abs(train_y - fant_preds) / 2) + # TODO: figure out why this error is worse than before + self.assertLess(updated_abs_error.item(), 0.15) + def test_predictive_ll_regression_error(self): return self.test_regression_error( mll_cls=gpytorch.mlls.PredictiveLogLikelihood, diff --git a/test/examples/test_unwhitened_svgp_regression.py b/test/examples/test_unwhitened_svgp_regression.py index 8120dadb4..c1bc686bd 100644 --- a/test/examples/test_unwhitened_svgp_regression.py +++ b/test/examples/test_unwhitened_svgp_regression.py @@ -81,6 +81,16 @@ def test_regression_error( mean_abs_error = torch.mean(torch.abs(train_y - test_preds) / 2) self.assertLess(mean_abs_error.item(), 0.014) + if distribution_cls is gpytorch.variational.CholeskyVariationalDistribution: + # finally test fantasization + # we only will check that tossing the entire training set into the model will reduce the mae + model.likelihood = likelihood + fant_model = model.get_fantasy_model(train_x, train_y) + fant_preds = fant_model.likelihood(fant_model(train_x)).mean.squeeze() + updated_abs_error = torch.mean(torch.abs(train_y - fant_preds) / 2) + # TODO: figure out why this error is worse than before + self.assertLess(updated_abs_error.item(), 0.15) + if __name__ == "__main__": unittest.main() diff --git a/test/variational/test_batch_decoupled_variational_strategy.py b/test/variational/test_batch_decoupled_variational_strategy.py index a592c8060..99acf289b 100644 --- a/test/variational/test_batch_decoupled_variational_strategy.py +++ b/test/variational/test_batch_decoupled_variational_strategy.py @@ -57,6 +57,11 @@ def test_eval_iteration(self, *args, **kwargs): self.assertEqual(cholesky_mock.call_count, 1) # One to compute cache, that's it! self.assertFalse(ciq_mock.called) + def test_fantasy_call(self, *args, **kwargs): + # with self.assertRaises(AttributeError): + # super().test_fantasy_call(*args, **kwargs) + pass + class TestBatchDecoupledPredictiveGP(TestBatchDecoupledVariationalGP): @property diff --git a/test/variational/test_ciq_variational_strategy.py b/test/variational/test_ciq_variational_strategy.py index 3bfc7cb3b..c72b17c77 100644 --- a/test/variational/test_ciq_variational_strategy.py +++ b/test/variational/test_ciq_variational_strategy.py @@ -37,6 +37,10 @@ def test_eval_iteration(self, *args, **kwargs): self.assertFalse(cholesky_mock.called) self.assertEqual(ciq_mock.call_count, 2) # One for each evaluation call + def test_fantasy_call(self, *args, **kwargs): + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestMeanFieldCiqVariationalGP(TestCiqVariationalGP): @property diff --git a/test/variational/test_grid_interpolation_variational_strategy.py b/test/variational/test_grid_interpolation_variational_strategy.py index 385b3ab8d..5747a7ca0 100644 --- a/test/variational/test_grid_interpolation_variational_strategy.py +++ b/test/variational/test_grid_interpolation_variational_strategy.py @@ -75,6 +75,10 @@ def test_eval_iteration(self, *args, **kwargs): self.assertFalse(cholesky_mock.called) self.assertFalse(ciq_mock.called) + def test_fantasy_call(self, *args, **kwargs): + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestGridPredictiveGP(TestGridVariationalGP): @property diff --git a/test/variational/test_independent_multitask_variational_strategy.py b/test/variational/test_independent_multitask_variational_strategy.py index ab88f52ed..e5f9aa09d 100644 --- a/test/variational/test_independent_multitask_variational_strategy.py +++ b/test/variational/test_independent_multitask_variational_strategy.py @@ -60,6 +60,10 @@ def test_eval_iteration(self, *args, expected_batch_shape=None, **kwargs): expected_batch_shape = expected_batch_shape[:-1] super().test_eval_iteration(*args, expected_batch_shape=expected_batch_shape, **kwargs) + def test_fantasy_call(self, *args, **kwargs): + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestMultitaskPredictiveGP(TestMultitaskVariationalGP): @property diff --git a/test/variational/test_lmc_variational_strategy.py b/test/variational/test_lmc_variational_strategy.py index 2e5255200..76eea8175 100644 --- a/test/variational/test_lmc_variational_strategy.py +++ b/test/variational/test_lmc_variational_strategy.py @@ -68,6 +68,10 @@ def test_eval_iteration(self, *args, expected_batch_shape=None, **kwargs): self.assertFalse(cg_mock.called) self.assertFalse(ciq_mock.called) + def test_fantasy_call(self, *args, **kwargs): + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestLMCPredictiveGP(TestLMCVariationalGP): @property diff --git a/test/variational/test_orthogonally_decoupled_variational_strategy.py b/test/variational/test_orthogonally_decoupled_variational_strategy.py index 873204eb1..c1b2847f7 100644 --- a/test/variational/test_orthogonally_decoupled_variational_strategy.py +++ b/test/variational/test_orthogonally_decoupled_variational_strategy.py @@ -57,6 +57,10 @@ def test_eval_iteration(self, *args, **kwargs): self.assertFalse(ciq_mock.called) self.assertEqual(cholesky_mock.call_count, 1) # One to compute cache, that's it! + def test_fantasy_call(self, *args, **kwargs): + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestOrthogonallyDecoupledPredictiveGP(TestOrthogonallyDecoupledVariationalGP): @property diff --git a/test/variational/test_unwhitened_variational_strategy.py b/test/variational/test_unwhitened_variational_strategy.py index 362d8f662..f7047c4cf 100644 --- a/test/variational/test_unwhitened_variational_strategy.py +++ b/test/variational/test_unwhitened_variational_strategy.py @@ -40,6 +40,14 @@ def test_eval_iteration(self, *args, **kwargs): self.assertFalse(ciq_mock.called) self.assertEqual(cholesky_mock.call_count, 1) # One to compute cache, that's it! + def test_fantasy_call(self, *args, **kwargs): + # we only want to check CholeskyVariationalDistribution + if self.distribution_cls is gpytorch.variational.CholeskyVariationalDistribution: + return super().test_fantasy_call(*args, **kwargs) + + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestUnwhitenedPredictiveGP(TestUnwhitenedVariationalGP): @property diff --git a/test/variational/test_variational_strategy.py b/test/variational/test_variational_strategy.py index 4b879af4f..569d92ed3 100644 --- a/test/variational/test_variational_strategy.py +++ b/test/variational/test_variational_strategy.py @@ -37,6 +37,14 @@ def test_eval_iteration(self, *args, **kwargs): self.assertEqual(cholesky_mock.call_count, 1) # One to compute cache, that's it! self.assertFalse(ciq_mock.called) + def test_fantasy_call(self, *args, **kwargs): + # we only want to check CholeskyVariationalDistribution + if self.distribution_cls is gpytorch.variational.CholeskyVariationalDistribution: + return super().test_fantasy_call(*args, **kwargs) + + with self.assertRaises(AttributeError): + super().test_fantasy_call(*args, **kwargs) + class TestPredictiveGP(TestVariationalGP): @property