| 
77 | 77 |     "Note that we generate the data with a fixed observation noise $\\sigma = 0.1$.\n",  | 
78 | 78 |     "\n",  | 
79 | 79 |     "## Regression\n",  | 
80 |  | -    "Now let's define our regression model in the form of a neural network. We'll use PyTorch's `nn.Module` for this.  Our input $X$ is a matrix of size $N \\times p$ and our output $y$ is a vector of size $p \\times 1$.  The function `nn.Linear(p, 1)` defines a linear transformation of the form $Xw + b$ where $w$ is the weight matrix and $b$ is the additive bias."  | 
 | 80 | +    "Now let's define our regression model. We'll use PyTorch's `nn.Module` for this.  Our input $X$ is a matrix of size $N \\times p$ and our output $y$ is a vector of size $p \\times 1$.  The function `nn.Linear(p, 1)` defines a linear transformation of the form $Xw + b$ where $w$ is the weight matrix and $b$ is the additive bias."  | 
81 | 81 |    ]  | 
82 | 82 |   },  | 
83 | 83 |   {  | 
 | 
167 | 167 |    "cell_type": "markdown",  | 
168 | 168 |    "metadata": {},  | 
169 | 169 |    "source": [  | 
170 |  | -    "Not too bad - you can see that the neural net learned parameters that were pretty close to the ground truth of $w = 3, b = 1$.  But how confident should we be in these point estimates?\n",  | 
 | 170 | +    "Not too bad - you can see that the regressor learned parameters that were pretty close to the ground truth of $w = 3, b = 1$.  But how confident should we be in these point estimates?\n",  | 
171 | 171 |     "\n",  | 
172 | 172 |     "Bayesian modeling (see [here](http://mlg.eng.cam.ac.uk/zoubin/papers/NatureReprint15.pdf) for an overview) offers a systematic framework for reasoning about model uncertainty. Instead of just learning point estimates, we're going to learn a _distribution_ over values of the parameters $w$ and $b$ that are consistent with the observed data."  | 
173 | 173 |    ]  | 
 | 
182 | 182 |     "\n",  | 
183 | 183 |     "### `random_module()`\n",  | 
184 | 184 |     "\n",  | 
185 |  | -    "In order to do this, we'll 'lift' the parameters $w$ and $b$ to random variables. We can do this in Pyro via `random_module()`, which effectively takes a `nn.Module` and turns it into a distribution over neural networks. Specifically, each parameter in the original neural net is sampled from the provided prior. This allows us to repurpose vanilla neural nets for use in the Bayesian setting. For example:"  | 
 | 185 | +    "In order to do this, we'll 'lift' the parameters $w$ and $b$ to random variables. We can do this in Pyro via `random_module()`, which effectively takes a `nn.Module` and turns it into a distribution over regressors. Specifically, each parameter in the original regression model is sampled from the provided prior. This allows us to repurpose vanilla regression models for use in the Bayesian setting. For example:"  | 
186 | 186 |    ]  | 
187 | 187 |   },  | 
188 | 188 |   {  | 
 | 
195 | 195 |     "sigma = Variable(torch.ones(1, 1))\n",  | 
196 | 196 |     "# define a unit normal prior\n",  | 
197 | 197 |     "prior = Normal(mu, sigma)\n",  | 
198 |  | -    "# overload the parameters in the regression nn with samples from the prior\n",  | 
 | 198 | +    "# overload the parameters in the regression module with samples from the prior\n",  | 
199 | 199 |     "lifted_module = pyro.random_module(\"regression_module\", regression_model, prior)\n",  | 
200 |  | -    "# sample a nn from the prior\n",  | 
201 |  | -    "sampled_nn = lifted_module()"  | 
 | 200 | +    "# sample a regressor from the prior\n",  | 
 | 201 | +    "sampled_reg_model = lifted_module()"  | 
202 | 202 |    ]  | 
203 | 203 |   },  | 
204 | 204 |   {  | 
 | 
207 | 207 |    "source": [  | 
208 | 208 |     "### Model\n",  | 
209 | 209 |     "\n",  | 
210 |  | -    "We now have all the ingredients needed to specify our model. First we define priors over $w$ and $b$.  Because we're uncertain about the parameters a priori, we'll use relatively wide priors $\\mathcal{N}(\\mu = 0, \\sigma = 10)$.  Then we wrap `regression_model` with `random_module` and sample an instance of the neural net, `lifted_nn`. We then run the neural net forward on the inputs `x_data`. Finally we use the `pyro.observe` statement to condition on the observed data `y_data`. Note that we use the same fixed observation "  | 
 | 210 | +    "We now have all the ingredients needed to specify our model. First we define priors over $w$ and $b$.  Because we're uncertain about the parameters a priori, we'll use relatively wide priors $\\mathcal{N}(\\mu = 0, \\sigma = 10)$.  Then we wrap `regression_model` with `random_module` and sample an instance of the regressor, `lifted_rm`. We then run the regressor forward on the inputs `x_data`. Finally we use the `pyro.observe` statement to condition on the observed data `y_data`. Note that we use the same fixed observation "  | 
211 | 211 |    ]  | 
212 | 212 |   },  | 
213 | 213 |   {  | 
 | 
224 | 224 |     "    bias_mu, bias_sigma = Variable(torch.zeros(1)), Variable(10 * torch.ones(1))\n",  | 
225 | 225 |     "    w_prior, b_prior = Normal(mu, sigma), Normal(bias_mu, bias_sigma)\n",  | 
226 | 226 |     "    priors = {'linear.weight': w_prior, 'linear.bias': b_prior}\n",  | 
227 |  | -    "    # lift module parameters to random variables\n",  | 
 | 227 | +    "    # lift module parameters to random variables sampled from the priors\n",  | 
228 | 228 |     "    lifted_module = pyro.random_module(\"module\", regression_model, priors)\n",  | 
229 |  | -    "    # sample a nn (which also samples w and b)\n",  | 
230 |  | -    "    lifted_nn = lifted_module()\n",  | 
231 |  | -    "    # run the nn forward\n",  | 
232 |  | -    "    latent = lifted_nn(x_data).squeeze()\n",  | 
 | 229 | +    "    # sample a regressor (which also samples w and b)\n",  | 
 | 230 | +    "    lifted_reg_model = lifted_module()\n",  | 
 | 231 | +    "    # run the regressor forward conditioned on data\n",  | 
 | 232 | +    "    prediction_mean = lifted_reg_model(x_data).squeeze()\n",  | 
233 | 233 |     "    # condition on the observed data\n",  | 
234 |  | -    "    pyro.observe(\"obs\", Normal(latent, Variable(0.1 * torch.ones(data.size(0)))),\n",  | 
 | 234 | +    "    pyro.observe(\"obs\", Normal(prediction_mean, Variable(0.1 * torch.ones(data.size(0)))),\n",  | 
235 | 235 |     "                 y_data.squeeze())"  | 
236 | 236 |    ]  | 
237 | 237 |   },  | 
 | 
272 | 272 |     "    # overload the parameters in the module with random samples \n",  | 
273 | 273 |     "    # from the guide distributions\n",  | 
274 | 274 |     "    lifted_module = pyro.random_module(\"module\", regression_model, dists)\n",  | 
275 |  | -    "    # sample a nn (which also samples w and b)\n",  | 
 | 275 | +    "    # sample a regressor (which also samples w and b)\n",  | 
276 | 276 |     "    return lifted_module()"  | 
277 | 277 |    ]  | 
278 | 278 |   },  | 
279 | 279 |   {  | 
280 | 280 |    "cell_type": "markdown",  | 
281 | 281 |    "metadata": {},  | 
282 | 282 |    "source": [  | 
283 |  | -    "Note that we choose Gaussians for both guide distributions. Also, to ensure positivity, we pass each log sigma through a `softplus()` transformation.\n",  | 
 | 283 | +    "Note that we choose Gaussians for both guide distributions. Also, to ensure positivity, we pass each log sigma through a `softplus()` transformation (an alternative to ensure positivity would be an `exp()`-transformation).\n",  | 
284 | 284 |     "\n",  | 
285 | 285 |     "## Inference\n",  | 
286 | 286 |     "\n",  | 
 | 
369 | 369 |    "cell_type": "markdown",  | 
370 | 370 |    "metadata": {},  | 
371 | 371 |    "source": [  | 
372 |  | -    "Finally, let's evaluate our model by checking its predictive accuracy on new test data. This is known as _point evaluation_.  We'll sample 20 neural nets from our posterior and run them on the new test data, then average across their predictions and calculate the MSE of the predicted values compared to the ground truth."  | 
 | 372 | +    "Finally, let's evaluate our model by checking its predictive accuracy on new test data. This is known as _point evaluation_.  We'll sample 20 regressors from our posterior and run them on the new test data, then average across their predictions and calculate the MSE of the predicted values compared to the ground truth."  | 
373 | 373 |    ]  | 
374 | 374 |   },  | 
375 | 375 |   {  | 
 | 
404 | 404 |     "```"  | 
405 | 405 |    ]  | 
406 | 406 |   },  | 
 | 407 | +  {  | 
 | 408 | +   "cell_type": "markdown",  | 
 | 409 | +   "metadata": {},  | 
 | 410 | +   "source": [  | 
 | 411 | +    "Bayesian nonlinear regression can also be implemented analogously by lifting neural network modules."  | 
 | 412 | +   ]  | 
 | 413 | +  },  | 
407 | 414 |   {  | 
408 | 415 |    "cell_type": "markdown",  | 
409 | 416 |    "metadata": {},  | 
 | 
0 commit comments