Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Hierarchical Bayesian Neural Networks

Code is based on This blog post by Thomas Wiecki (see Original PyMC3 Notebook). Converted to Blackjax by Aleyna Kara (@karalleyna) and Kevin Murphy (@murphyk). (For a Numpyro version, see here.)

We create T=18 different versions of the “two moons” dataset, each rotated by a different amount. These correspond to T different nonlinear binary classification “tasks” that we have to solve. We only get a few labeled samples from each each task, so solving them separately (with T independent MLPs, or multi layer perceptrons) will result in poor performance. If we pool all the data, and fit a single MLP, we also get poor performance, because we are mixing together different decision boundaries. But if we use a hierarchical Bayesian model, with one MLP per task, and one learned prior MLP, we will get better results, as we will see.

Below is a high level illustration of the multi-task setup. Φ\Phi is the learned prior, and Θt\Theta_t are the parameters for task tt. We assume Nt=50N^t=50 training samples per task, and Mt=50M^t=50 test samples. (We could of course consider more imbalanced scenarios.)

hbayes-multi-task.png

Setup

Notebook Cell

Data

We create T=18 different versions of the “two moons” dataset, each rotated by a different amount. These correspond to T different binary classification “tasks” that we have to solve.

Source
<Figure size 640x480 with 1 Axes>
Source
<Figure size 1500x1200 with 16 Axes>

Utility Functions for Training and Testing

Hyperparameters

We use an MLP with 2 hidden layers, each with 5 hidden units.

Fit Separate MLPs, One Per Task

Let wijltw^t_{ijl} be the weight for node ii to node jj in layer ll in task tt. We assume

wijlt∼N(0,1)w^t_{ijl} \sim N(0,1)

and compute the posterior for all the weights.

Results

Accuracy is reasonable, but the decision boundaries have not captured the underlying Z pattern in the data, due to having too little data per task. (Bayes model averaging results in a simple linear decision boundary, and prevents overfitting.)

Source
Train accuracy = 87.00%
Source
Test accuracy = 82.33%
Source

Below we show that the decision boundaries do not look reasonable, since there is not enough data to fit each model separately.

Source
<Figure size 1500x1200 with 16 Axes>
Source
<Figure size 1500x1200 with 4 Axes>

Hierarchical Model

Now we use a hierarchical Bayesian model, which has a common Gaussian prior for all the weights, but allows each task to have its own task-specific parameters. More precisely, let wijltw^t_{ijl} be the weight for node ii to node jj in layer ll in task tt. We assume

wijlt∼N(μijl,σl)w^t_{ijl} \sim N(\mu_{ijl}, \sigma_l)
μijl∼N(0,1)\mu_{ijl} \sim N(0,1)
σl∼N+(0,1)\sigma_l \sim N_+(0,1)

or, in non-centered form,

wijlt=μijl+ϵijltσlw^t_{ijl} = \mu_{ijl} + \epsilon^t_{ijl} \sigma_l

In the figure below, we illustrate this prior, using an MLP with D inputs, 2 hidden layers (of size L1L_1 and L2L_2), and a scalar output (representing the logit).

bnn_hierarchical.png
CPU times: user 1min 34s, sys: 614 ms, total: 1min 35s
Wall time: 1min 28s

Results

We see that the train and test accuracy are higher, and the decision boundaries all have the shared “Z” shape, as desired.

Source
Train accuracy = 90.44%
Source
Test accuracy = 87.22%
Source
<Figure size 1500x1200 with 16 Axes>
Source
<Figure size 1500x1200 with 4 Axes>