From c067e8edfb3812bdf03c9c71527b03e465c4a514 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 12 Nov 2019 15:30:12 +0100 Subject: [PATCH 01/29] Add comparison with standard SVI --- bimodal_posterior.py | 51 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/bimodal_posterior.py b/bimodal_posterior.py index de92785..c1f8c7d 100644 --- a/bimodal_posterior.py +++ b/bimodal_posterior.py @@ -4,7 +4,7 @@ import torch.distributions.constraints as constraints import pyro from pyro.optim import Adam, SGD -from pyro.infer import SVI, Trace_ELBO, config_enumerate +from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO import pyro.distributions as dist from pyro.infer.autoguide import AutoDelta from pyro import poutine @@ -35,7 +35,7 @@ def guide(data, index): variance_q = pyro.param('variance_{}'.format(index), torch.tensor([1.0]), constraints.positive) - mu_q = pyro.param('mu_{}'.format(index), torch.tensor([1.0])) + mu_q = pyro.param('mu_{}'.format(index), torch.tensor([0.5])) pyro.sample("mu", dist.Normal(mu_q, variance_q)) @config_enumerate @@ -182,5 +182,50 @@ def boosting_bbvi(): pyplot.ylabel('probability density'); pyplot.show() +def run_standard_svi(): + + adam_params = {"lr": 0.002, "betas": (0.90, 0.999)} + optimizer = Adam(adam_params) + gradient_norms = defaultdict(list) + losses = [] + wrapped_guide = partial(guide, index=0) + wrapped_guide(data) + for name, value in pyro.get_param_store().named_parameters(): + if not name in gradient_norms: + value.register_hook(lambda g, name=name: gradient_norms[name].append(g.norm().item())) + + + svi = SVI(model, wrapped_guide, optimizer, loss=Trace_ELBO()) + for step in range(n_steps): + loss = svi.step(data) + losses.append(loss) + + + pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') + for name, grad_norms in gradient_norms.items(): + pyplot.plot(grad_norms, label=name) + pyplot.xlabel('iters') + pyplot.ylabel('gradient norm') + # pyplot.yscale('log') + pyplot.legend(loc='best') + pyplot.title('Gradient norms during SVI'); + pyplot.show() + + scale = pyro.param("variance_{}".format(0)).item() + loc = pyro.param("mu_{}".format(0)).item() + X = np.arange(-10, 10, 0.1) + Y1 = scipy.stats.norm.pdf((X - loc) / scale) + + print('Resulting Mu: ', loc) + print('Resulting Variance: ', scale) + + pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') + pyplot.plot(X, Y1, 'r-') + pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*') + pyplot.title('Standard SVI result') + pyplot.ylabel('probability density'); + pyplot.show() + + if __name__ == '__main__': - boosting_bbvi() \ No newline at end of file + run_standard_svi() \ No newline at end of file From d4f71e915dbcacc0d641a7bce16a041c24715aac Mon Sep 17 00:00:00 2001 From: Lorenz Date: Sun, 17 Nov 2019 10:22:35 +0100 Subject: [PATCH 02/29] Add RELBO components plot --- bimodal_posterior.py | 46 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/bimodal_posterior.py b/bimodal_posterior.py index c1f8c7d..70de3cd 100644 --- a/bimodal_posterior.py +++ b/bimodal_posterior.py @@ -17,7 +17,7 @@ import matplotlib from matplotlib import pyplot -PRINT_INTERMEDIATE_LATENT_VALUES = True +PRINT_INTERMEDIATE_LATENT_VALUES = False PRINT_TRACES = False # this is for running the notebook in our testing framework @@ -33,9 +33,13 @@ data = torch.tensor([4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3]) +model_log_prob = [] +guide_log_prob = [] +approximation_log_prob = [] + def guide(data, index): variance_q = pyro.param('variance_{}'.format(index), torch.tensor([1.0]), constraints.positive) - mu_q = pyro.param('mu_{}'.format(index), torch.tensor([0.5])) + mu_q = pyro.param('mu_{}'.format(index), torch.tensor([1.0])) pyro.sample("mu", dist.Normal(mu_q, variance_q)) @config_enumerate @@ -75,6 +79,10 @@ def relbo(model, guide, *args, **kwargs): approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs) # We will accumulate the various terms of the ELBO in `elbo`. + guide_log_prob.append(guide_trace.log_prob_sum()) + model_log_prob.append(model_trace.log_prob_sum()) + approximation_log_prob.append(approximation_trace.log_prob_sum()) + # This is how we computed the ELBO before using TraceEnum_ELBO: # elbo = model_trace.log_prob_sum() - guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() @@ -92,7 +100,7 @@ def relbo(model, guide, *args, **kwargs): def boosting_bbvi(): - n_iterations = 2 + n_iterations = 6 initial_approximation = dummy_approximation components = [initial_approximation] @@ -118,6 +126,14 @@ def boosting_bbvi(): for name, value in pyro.get_param_store().named_parameters(): if not name in gradient_norms: value.register_hook(lambda g, name=name: gradient_norms[name].append(g.norm().item())) + + global model_log_prob + model_log_prob = [] + global guide_log_prob + guide_log_prob = [] + global approximation_log_prob + approximation_log_prob = [] + svi = SVI(model, wrapped_guide, optimizer, loss=relbo) for step in range(n_steps): @@ -140,6 +156,16 @@ def boosting_bbvi(): pyplot.title('-ELBO against time for component {}'.format(t)); pyplot.show() + pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') + pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') + pyplot.xlabel('Update Steps') + pyplot.ylabel('Log Prob') + pyplot.title('RELBO components throughout SVI'.format(t)); + pyplot.legend() + pyplot.show() + components.append(wrapped_guide) new_weight = 2 / (t + 1) @@ -170,13 +196,13 @@ def boosting_bbvi(): print(scales) X = np.arange(-10, 10, 0.1) - Y1 = weights[1].item() * scipy.stats.norm.pdf((X - locs[1]) / scales[1]) - Y2 = weights[2].item() * scipy.stats.norm.pdf((X - locs[2]) / scales[2]) - pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') - pyplot.plot(X, Y1, 'r-') - pyplot.plot(X, Y2, 'b-') - pyplot.plot(X, Y1 + Y2, 'k--') + total_approximation = np.zeros(X.shape) + for i in range(1, n_iterations + 1): + Y = weights[i].item() * scipy.stats.norm.pdf((X - locs[i]) / scales[i]) + pyplot.plot(X, Y) + total_approximation += Y + pyplot.plot(X, total_approximation) pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*') pyplot.title('Approximation of posterior over mu') pyplot.ylabel('probability density'); @@ -228,4 +254,4 @@ def run_standard_svi(): if __name__ == '__main__': - run_standard_svi() \ No newline at end of file + boosting_bbvi() \ No newline at end of file From 757daf55eaf26ec2f707703ab373aee5db1c10d5 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 18 Nov 2019 15:04:14 +0100 Subject: [PATCH 03/29] Add first draft of BLR --- bayesian_logistic_regression.py | 233 ++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 bayesian_logistic_regression.py diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py new file mode 100644 index 0000000..ee921e2 --- /dev/null +++ b/bayesian_logistic_regression.py @@ -0,0 +1,233 @@ +import math +import os +import torch +import torch.distributions.constraints as constraints +import pyro +from pyro.optim import Adam, SGD +from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO +import pyro.distributions as dist +from pyro.infer.autoguide import AutoDelta +from pyro import poutine +from pyro.poutine import trace, replay, block +from functools import partial +import numpy as np +import scipy.stats +from pyro.infer.autoguide import AutoDelta +from collections import defaultdict +import matplotlib +from matplotlib import pyplot + + +PRINT_INTERMEDIATE_LATENT_VALUES = False +PRINT_TRACES = False + +# this is for running the notebook in our testing framework +smoke_test = ('CI' in os.environ) +n_steps = 2 if smoke_test else 1000 +pyro.set_rng_seed(2) + +# enable validation (e.g. validate parameters of distributions) +pyro.enable_validation(True) + +# clear the param store in case we're in a REPL +pyro.clear_param_store() + +model_log_prob = [] +guide_log_prob = [] +approximation_log_prob = [] + +def guide(observations, input_data, index): + variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) + mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) + pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) + +def logistic_regression_model(observations, input_data): + w = pyro.sample('w', dist.MultivariateNormal(20*torch.ones(input_data.shape[1]), torch.eye(input_data.shape[1]))) + with pyro.plate("data", input_data.shape[0]): + sigmoid = torch.sigmoid(torch.matmul(torch.tensor(input_data).double(),torch.tensor(w).double())) + obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) + +@config_enumerate +def approximation(observations, input_data, components, weights): + assignment = pyro.sample('assignment', dist.Categorical(weights)) + distribution = components[assignment](observations, input_data) + +def dummy_approximation(observations, input_data): + variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1])) + mu_q = pyro.param('mu_0', 20*torch.ones(input_data.shape[1])) + pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) + +def relbo(model, guide, *args, **kwargs): + + approximation = kwargs.pop('approximation', None) + relbo_lambda = kwargs.pop('relbo_lambda', None) + # Run the guide with the arguments passed to SVI.step() and trace the execution, + # i.e. record all the calls to Pyro primitives like sample() and param(). + #print("enter relbo") + guide_trace = trace(guide).get_trace(*args, **kwargs) + #print(guide_trace.nodes['obs_1']) + model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) + #print(model_trace.nodes['obs_1']) + + + approximation_trace = trace(replay(block(approximation, expose=['w']), guide_trace)).get_trace(*args, **kwargs) + # We will accumulate the various terms of the ELBO in `elbo`. + + guide_log_prob.append(guide_trace.log_prob_sum()) + model_log_prob.append(model_trace.log_prob_sum()) + approximation_log_prob.append(approximation_trace.log_prob_sum()) + + # This is how we computed the ELBO before using TraceEnum_ELBO: + elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() + + # loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, + # guide, + # *args, **kwargs) + + # print(loss_fn) + # print(approximation_trace.log_prob_sum()) + #elbo = -loss_fn - approximation_trace.log_prob_sum() + # Return (-elbo) since by convention we do gradient descent on a loss and + # the ELBO is a lower bound that needs to be maximized. + + return -elbo + + +def boosting_bbvi(): + + npz_train_file = np.load('ds1.100_train.npz') + npz_test_file = np.load('ds1.100_test.npz') + + X_train = torch.tensor(npz_train_file['X']) + y_train = torch.tensor(npz_train_file['y']) + y_train[y_train == -1] = 0 + X_test = torch.tensor(npz_test_file['X']) + y_test = torch.tensor(npz_test_file['y']) + y_test[y_test == -1] = 0 + n_iterations = 2 + + relbo_lambda = 1 + initial_approximation = dummy_approximation + components = [initial_approximation] + weights = torch.tensor([1.]) + wrapped_approximation = partial(approximation, components=components, + weights=weights) + + locs = [0] + scales = [0] + + gradient_norms = defaultdict(list) + duality_gap = [] + for t in range(1, n_iterations + 1): + # setup the inference algorithm + wrapped_guide = partial(guide, index=t) + # do gradient steps + losses = [] + # Register hooks to monitor gradient norms. + wrapped_guide(y_train, X_train) + print(pyro.get_param_store().named_parameters()) + + adam_params = {"lr": 0.0005, "betas": (0.90, 0.999)} + optimizer = Adam(adam_params) + for name, value in pyro.get_param_store().named_parameters(): + if not name in gradient_norms: + value.register_hook(lambda g, name=name: gradient_norms[name].append(g.norm().item())) + + global model_log_prob + model_log_prob = [] + global guide_log_prob + guide_log_prob = [] + global approximation_log_prob + approximation_log_prob = [] + + + svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=relbo) + for step in range(n_steps): + loss = svi.step(y_train, X_train, approximation=wrapped_approximation, relbo_lambda=relbo_lambda) + losses.append(loss) + + if PRINT_INTERMEDIATE_LATENT_VALUES: + print('Loss: {}'.format(loss)) + variance = pyro.param("variance_{}".format(t)).item() + mu = pyro.param("mu_{}".format(t)).item() + print('mu = {}'.format(mu)) + print('variance = {}'.format(variance)) + + if step % 100 == 0: + print('.', end=' ') + + pyplot.plot(range(len(losses)), losses) + pyplot.xlabel('Update Steps') + pyplot.ylabel('-ELBO') + pyplot.title('-ELBO against time for component {}'.format(t)); + pyplot.show() + + pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') + pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') + pyplot.xlabel('Update Steps') + pyplot.ylabel('Log Prob') + pyplot.title('RELBO components throughout SVI'.format(t)); + pyplot.legend() + pyplot.show() + + components.append(wrapped_guide) + new_weight = 2 / (t + 1) + + weights = weights * (1-new_weight) + weights = torch.cat((weights, torch.tensor([new_weight]))) + + wrapped_approximation = partial(approximation, components=components, weights=weights) + + e_log_p = 0 + for i in range(50): + qt_trace = trace(wrapped_approximation).get_trace(y_train, X_train) + replayed_model_trace = trace(replay(logistic_regression_model, qt_trace)).get_trace(y_train, X_train) + e_log_p = e_log_p + replayed_model_trace.log_prob_sum() + + duality_gap.append(replayed_model_trace.log_prob_sum()/10) + + # scale = pyro.param("variance_{}".format(t)).item() + # scales.append(scale) + # loc = pyro.param("mu_{}".format(t)).item() + # locs.append(loc) + # print('mu = {}'.format(loc)) + # print('variance = {}'.format(scale)) + + pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') + for name, grad_norms in gradient_norms.items(): + pyplot.plot(grad_norms, label=name) + pyplot.xlabel('iters') + pyplot.ylabel('gradient norm') + # pyplot.yscale('log') + pyplot.legend(loc='best') + pyplot.title('Gradient norms during SVI'); + pyplot.show() + + + pyplot.plot(range(1, len(duality_gap) + 1), duality_gap) + pyplot.title('E[log p] w.r.t. q_t'); + pyplot.xlabel('Approximation components') + pyplot.ylabel('Log probability') + pyplot.show() + # print(weights) + # print(locs) + # print(scales) + + # X = np.arange(-10, 10, 0.1) + # pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') + # total_approximation = np.zeros(X.shape) + # for i in range(1, n_iterations + 1): + # Y = weights[i].item() * scipy.stats.norm.pdf((X - locs[i]) / scales[i]) + # pyplot.plot(X, Y) + # total_approximation += Y + # pyplot.plot(X, total_approximation) + # pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*') + # pyplot.title('Approximation of posterior over mu with lambda={}'.format(relbo_lambda)) + # pyplot.ylabel('probability density'); + # pyplot.show() + + +if __name__ == '__main__': + boosting_bbvi() \ No newline at end of file From 7627927c28bbf54ac40cce5c674444b2890da898 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 19 Nov 2019 10:07:37 +0100 Subject: [PATCH 04/29] Fix bug in guide --- bayesian_logistic_regression.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index ee921e2..948f18d 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -23,7 +23,7 @@ # this is for running the notebook in our testing framework smoke_test = ('CI' in os.environ) -n_steps = 2 if smoke_test else 1000 +n_steps = 2 if smoke_test else 5000 pyro.set_rng_seed(2) # enable validation (e.g. validate parameters of distributions) @@ -38,11 +38,12 @@ def guide(observations, input_data, index): variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) - mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) + #variance_q = torch.eye(input_data.shape[1]) + mu_q = pyro.param('mu_{}'.format(index), 20*torch.ones(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) def logistic_regression_model(observations, input_data): - w = pyro.sample('w', dist.MultivariateNormal(20*torch.ones(input_data.shape[1]), torch.eye(input_data.shape[1]))) + w = pyro.sample('w', dist.MultivariateNormal(torch.ones(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(torch.tensor(input_data).double(),torch.tensor(w).double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) From f53b55862d4d10895c0729906d6eda7e49ffca56 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 19 Nov 2019 10:32:25 +0100 Subject: [PATCH 05/29] Use MCMC to infer weights --- bayesian_logistic_regression.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 948f18d..65bfc83 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -16,6 +16,8 @@ from collections import defaultdict import matplotlib from matplotlib import pyplot +from pyro.infer import MCMC, NUTS +import pandas as pd PRINT_INTERMEDIATE_LATENT_VALUES = False @@ -94,8 +96,16 @@ def relbo(model, guide, *args, **kwargs): return -elbo -def boosting_bbvi(): +# Utility function to print latent sites' quantile information. +def summary(samples): + site_stats = {} + for site_name, values in samples.items(): + marginal_site = pd.DataFrame(values) + describe = marginal_site.describe(percentiles=[.05, 0.25, 0.5, 0.75, 0.95]).transpose() + site_stats[site_name] = describe[["mean", "std", "5%", "25%", "50%", "75%", "95%"]] + return site_stats +def load_data(): npz_train_file = np.load('ds1.100_train.npz') npz_test_file = np.load('ds1.100_test.npz') @@ -107,6 +117,11 @@ def boosting_bbvi(): y_test[y_test == -1] = 0 n_iterations = 2 + return X_train, y_train, X_test, y_test + +def boosting_bbvi(): + + X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = dummy_approximation components = [initial_approximation] @@ -229,6 +244,19 @@ def boosting_bbvi(): # pyplot.ylabel('probability density'); # pyplot.show() +def run_mcmc(): + + X_train, y_train, X_test, y_test = load_data() + nuts_kernel = NUTS(logistic_regression_model) + + mcmc = MCMC(nuts_kernel, num_samples=200, warmup_steps=100) + mcmc.run(y_train, X_train) + + hmc_samples = {k: v.detach().cpu().numpy() for k, v in mcmc.get_samples().items()} + + for site, values in summary(hmc_samples).items(): + print("Site: {}".format(site)) + print(values, "\n") if __name__ == '__main__': - boosting_bbvi() \ No newline at end of file + run_mcmc() \ No newline at end of file From 1833dbecab22a7ba783625b3c62d9a7186198719 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 19 Nov 2019 12:06:33 +0100 Subject: [PATCH 06/29] Add debugging output --- bayesian_logistic_regression.py | 57 ++++++++++++++++----------------- environment.yml | 1 + 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 65bfc83..04edcc2 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -18,6 +18,7 @@ from matplotlib import pyplot from pyro.infer import MCMC, NUTS import pandas as pd +import pickle PRINT_INTERMEDIATE_LATENT_VALUES = False @@ -41,9 +42,10 @@ def guide(observations, input_data, index): variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) #variance_q = torch.eye(input_data.shape[1]) - mu_q = pyro.param('mu_{}'.format(index), 20*torch.ones(input_data.shape[1])) + mu_q = pyro.param('mu_{}'.format(index), torch.rand(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) +@config_enumerate def logistic_regression_model(observations, input_data): w = pyro.sample('w', dist.MultivariateNormal(torch.ones(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): @@ -70,7 +72,9 @@ def relbo(model, guide, *args, **kwargs): guide_trace = trace(guide).get_trace(*args, **kwargs) #print(guide_trace.nodes['obs_1']) model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) - #print(model_trace.nodes['obs_1']) + + #print(model_trace.nodes['obs']) + approximation_trace = trace(replay(block(approximation, expose=['w']), guide_trace)).get_trace(*args, **kwargs) @@ -83,13 +87,13 @@ def relbo(model, guide, *args, **kwargs): # This is how we computed the ELBO before using TraceEnum_ELBO: elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() - # loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, - # guide, - # *args, **kwargs) + loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, + guide, + *args, **kwargs) # print(loss_fn) # print(approximation_trace.log_prob_sum()) - #elbo = -loss_fn - approximation_trace.log_prob_sum() + elbo = -loss_fn - approximation_trace.log_prob_sum() # Return (-elbo) since by convention we do gradient descent on a loss and # the ELBO is a lower bound that needs to be maximized. @@ -115,12 +119,12 @@ def load_data(): X_test = torch.tensor(npz_test_file['X']) y_test = torch.tensor(npz_test_file['y']) y_test[y_test == -1] = 0 - n_iterations = 2 return X_train, y_train, X_test, y_test def boosting_bbvi(): + n_iterations = 1 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = dummy_approximation @@ -172,11 +176,11 @@ def boosting_bbvi(): if step % 100 == 0: print('.', end=' ') - pyplot.plot(range(len(losses)), losses) - pyplot.xlabel('Update Steps') - pyplot.ylabel('-ELBO') - pyplot.title('-ELBO against time for component {}'.format(t)); - pyplot.show() + # pyplot.plot(range(len(losses)), losses) + # pyplot.xlabel('Update Steps') + # pyplot.ylabel('-ELBO') + # pyplot.title('-ELBO against time for component {}'.format(t)); + # pyplot.show() pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') @@ -227,22 +231,14 @@ def boosting_bbvi(): pyplot.xlabel('Approximation components') pyplot.ylabel('Log probability') pyplot.show() - # print(weights) - # print(locs) - # print(scales) - - # X = np.arange(-10, 10, 0.1) - # pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white') - # total_approximation = np.zeros(X.shape) - # for i in range(1, n_iterations + 1): - # Y = weights[i].item() * scipy.stats.norm.pdf((X - locs[i]) / scales[i]) - # pyplot.plot(X, Y) - # total_approximation += Y - # pyplot.plot(X, total_approximation) - # pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*') - # pyplot.title('Approximation of posterior over mu with lambda={}'.format(relbo_lambda)) - # pyplot.ylabel('probability density'); - # pyplot.show() + + for i in range(1, n_iterations + 1): + mu = pyro.param('mu_{}'.format(i)) + sigma = pyro.param('variance_{}'.format(i)) + print('Mu: ') + print(mu) + print('Sigma: ') + print(sigma) def run_mcmc(): @@ -254,9 +250,12 @@ def run_mcmc(): hmc_samples = {k: v.detach().cpu().numpy() for k, v in mcmc.get_samples().items()} + with open('hmc_samples.pkl', 'wb') as outfile: + pickle.dump(hmc_samples, outfile) + for site, values in summary(hmc_samples).items(): print("Site: {}".format(site)) print(values, "\n") if __name__ == '__main__': - run_mcmc() \ No newline at end of file + boosting_bbvi() \ No newline at end of file diff --git a/environment.yml b/environment.yml index 360dce0..d378886 100644 --- a/environment.yml +++ b/environment.yml @@ -8,6 +8,7 @@ dependencies: - scipy - torchvision - pytorch + - pandas - pip - pip: - pyro-ppl==0.5.1 From e7d6587a6da5c667c90eea6e56d9416d2e321744 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 20 Nov 2019 10:58:12 +0100 Subject: [PATCH 07/29] Change prior; use TraceEnum_ELBO --- bayesian_logistic_regression.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 04edcc2..90e4695 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -47,7 +47,7 @@ def guide(observations, input_data, index): @config_enumerate def logistic_regression_model(observations, input_data): - w = pyro.sample('w', dist.MultivariateNormal(torch.ones(input_data.shape[1]), torch.eye(input_data.shape[1]))) + w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(torch.tensor(input_data).double(),torch.tensor(w).double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) From 9ea4eb7bceff6a90fe45fa9bce205b01501fe636 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 25 Nov 2019 10:37:50 +0100 Subject: [PATCH 08/29] Add standard SVI as a comparison --- bayesian_logistic_regression.py | 38 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 90e4695..583740d 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -26,7 +26,7 @@ # this is for running the notebook in our testing framework smoke_test = ('CI' in os.environ) -n_steps = 2 if smoke_test else 5000 +n_steps = 2 if smoke_test else 3000 pyro.set_rng_seed(2) # enable validation (e.g. validate parameters of distributions) @@ -147,7 +147,7 @@ def boosting_bbvi(): wrapped_guide(y_train, X_train) print(pyro.get_param_store().named_parameters()) - adam_params = {"lr": 0.0005, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.001, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) for name, value in pyro.get_param_store().named_parameters(): if not name in gradient_norms: @@ -235,9 +235,9 @@ def boosting_bbvi(): for i in range(1, n_iterations + 1): mu = pyro.param('mu_{}'.format(i)) sigma = pyro.param('variance_{}'.format(i)) - print('Mu: ') + print('Mu_{}: '.format(i)) print(mu) - print('Sigma: ') + print('Sigma{}: '.format(i)) print(sigma) def run_mcmc(): @@ -257,5 +257,33 @@ def run_mcmc(): print("Site: {}".format(site)) print(values, "\n") + +def run_svi(): + # setup the optimizer + X_train, y_train, X_test, y_test = load_data() + n_steps = 5000 + n_iterations = 1 + adam_params = {"lr": 0.0005, "betas": (0.90, 0.999)} + optimizer = Adam(adam_params) + + # setup the inference algorithm + wrapped_guide = partial(guide, index=0) + svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=Trace_ELBO()) + + # do gradient steps + for step in range(n_steps): + svi.step(y_train, X_train) + if step % 100 == 0: + print('.', end='') + + for i in range(0, n_iterations): + mu = pyro.param('mu_{}'.format(i)) + sigma = pyro.param('variance_{}'.format(i)) + print('Mu_{}: '.format(i)) + print(mu) + print('Sigma{}: '.format(i)) + print(sigma) + + if __name__ == '__main__': - boosting_bbvi() \ No newline at end of file + run_svi() \ No newline at end of file From 0994a6424d32120b1aa10013fbccfb3bd1eecda6 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 25 Nov 2019 12:15:15 +0100 Subject: [PATCH 09/29] Fix tensor copying bug --- bayesian_logistic_regression.py | 54 +++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 583740d..4307217 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -19,6 +19,8 @@ from pyro.infer import MCMC, NUTS import pandas as pd import pickle +from pyro.infer.autoguide import AutoDiagonalNormal + PRINT_INTERMEDIATE_LATENT_VALUES = False @@ -26,7 +28,7 @@ # this is for running the notebook in our testing framework smoke_test = ('CI' in os.environ) -n_steps = 2 if smoke_test else 3000 +n_steps = 2 if smoke_test else 5000 pyro.set_rng_seed(2) # enable validation (e.g. validate parameters of distributions) @@ -42,14 +44,14 @@ def guide(observations, input_data, index): variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) #variance_q = torch.eye(input_data.shape[1]) - mu_q = pyro.param('mu_{}'.format(index), torch.rand(input_data.shape[1])) + mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) @config_enumerate def logistic_regression_model(observations, input_data): w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): - sigmoid = torch.sigmoid(torch.matmul(torch.tensor(input_data).double(),torch.tensor(w).double())) + sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) @config_enumerate @@ -58,7 +60,7 @@ def approximation(observations, input_data, components, weights): distribution = components[assignment](observations, input_data) def dummy_approximation(observations, input_data): - variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1])) + variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive) mu_q = pyro.param('mu_0', 20*torch.ones(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) @@ -113,18 +115,18 @@ def load_data(): npz_train_file = np.load('ds1.100_train.npz') npz_test_file = np.load('ds1.100_test.npz') - X_train = torch.tensor(npz_train_file['X']) - y_train = torch.tensor(npz_train_file['y']) + X_train = torch.tensor(npz_train_file['X']).double() + y_train = torch.tensor(npz_train_file['y']).double() y_train[y_train == -1] = 0 - X_test = torch.tensor(npz_test_file['X']) - y_test = torch.tensor(npz_test_file['y']) + X_test = torch.tensor(npz_test_file['X']).double() + y_test = torch.tensor(npz_test_file['y']).double() y_test[y_test == -1] = 0 return X_train, y_train, X_test, y_test def boosting_bbvi(): - n_iterations = 1 + n_iterations = 2 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = dummy_approximation @@ -147,7 +149,7 @@ def boosting_bbvi(): wrapped_guide(y_train, X_train) print(pyro.get_param_store().named_parameters()) - adam_params = {"lr": 0.001, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) for name, value in pyro.get_param_store().named_parameters(): if not name in gradient_norms: @@ -267,23 +269,31 @@ def run_svi(): optimizer = Adam(adam_params) # setup the inference algorithm - wrapped_guide = partial(guide, index=0) + #wrapped_guide = partial(guide, index=0) + wrapped_guide = AutoDiagonalNormal(logistic_regression_model) svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=Trace_ELBO()) - + losses = [] + # do gradient steps for step in range(n_steps): - svi.step(y_train, X_train) + loss = svi.step(y_train, X_train) + losses.append(loss) if step % 100 == 0: print('.', end='') - for i in range(0, n_iterations): - mu = pyro.param('mu_{}'.format(i)) - sigma = pyro.param('variance_{}'.format(i)) - print('Mu_{}: '.format(i)) - print(mu) - print('Sigma{}: '.format(i)) - print(sigma) - + # for i in range(0, n_iterations): + # mu = pyro.param('mu_{}'.format(i)) + # sigma = pyro.param('variance_{}'.format(i)) + # print('Mu_{}: '.format(i)) + # print(mu) + # print('Sigma{}: '.format(i)) + # print(sigma) + + pyplot.plot(range(len(losses)), losses) + pyplot.xlabel('Update Steps') + pyplot.ylabel('-ELBO') + pyplot.title('-ELBO against time for component {}'.format(1)); + pyplot.show() if __name__ == '__main__': - run_svi() \ No newline at end of file + boosting_bbvi() \ No newline at end of file From d93a3dfff3c8943b5514ee7af6c0081f2627f995 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 26 Nov 2019 09:58:15 +0100 Subject: [PATCH 10/29] Evaluate model using log prob on test data --- bayesian_logistic_regression.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 4307217..a4af6fb 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -4,7 +4,7 @@ import torch.distributions.constraints as constraints import pyro from pyro.optim import Adam, SGD -from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO +from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO, Predictive import pyro.distributions as dist from pyro.infer.autoguide import AutoDelta from pyro import poutine @@ -20,6 +20,7 @@ import pandas as pd import pickle from pyro.infer.autoguide import AutoDiagonalNormal +import inspect @@ -45,7 +46,8 @@ def guide(observations, input_data, index): variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) #variance_q = torch.eye(input_data.shape[1]) mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) - pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) + w = pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) + return w @config_enumerate def logistic_regression_model(observations, input_data): @@ -57,13 +59,21 @@ def logistic_regression_model(observations, input_data): @config_enumerate def approximation(observations, input_data, components, weights): assignment = pyro.sample('assignment', dist.Categorical(weights)) - distribution = components[assignment](observations, input_data) + w = components[assignment](observations, input_data) + return w def dummy_approximation(observations, input_data): variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive) mu_q = pyro.param('mu_0', 20*torch.ones(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) +def predictive_model(wrapped_approximation, observations, input_data): + w = wrapped_approximation(observations, input_data) + # w = w_dict['w'] + with pyro.plate("data", input_data.shape[0]): + sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) + obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) + def relbo(model, guide, *args, **kwargs): approximation = kwargs.pop('approximation', None) @@ -126,7 +136,7 @@ def load_data(): def boosting_bbvi(): - n_iterations = 2 + n_iterations = 1 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = dummy_approximation @@ -242,6 +252,11 @@ def boosting_bbvi(): print('Sigma{}: '.format(i)) print(sigma) + wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_approximation, observations=y_test, input_data=X_test) + predictive_trace = trace(wrapped_predictive_model).get_trace() + print('Log prob on test data') + print(predictive_trace.log_prob_sum()) + def run_mcmc(): X_train, y_train, X_test, y_test = load_data() @@ -265,7 +280,7 @@ def run_svi(): X_train, y_train, X_test, y_test = load_data() n_steps = 5000 n_iterations = 1 - adam_params = {"lr": 0.0005, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) # setup the inference algorithm @@ -295,5 +310,10 @@ def run_svi(): pyplot.title('-ELBO against time for component {}'.format(1)); pyplot.show() + wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_guide, observations=y_test, input_data=X_test) + predictive_trace = trace(wrapped_predictive_model).get_trace() + print('Log prob on test data') + print(predictive_trace.log_prob_sum()) + if __name__ == '__main__': boosting_bbvi() \ No newline at end of file From 2d69c2c460dd239f3fd74fdd8c175f468567c638 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 26 Nov 2019 10:49:00 +0100 Subject: [PATCH 11/29] Update plot of ELBO[q_t, p] --- bimodal_posterior.py | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/bimodal_posterior.py b/bimodal_posterior.py index 70de3cd..636a92f 100644 --- a/bimodal_posterior.py +++ b/bimodal_posterior.py @@ -67,6 +67,7 @@ def dummy_approximation(data): def relbo(model, guide, *args, **kwargs): approximation = kwargs.pop('approximation', None) + relbo_lambda = kwargs.pop('relbo_lambda', None) # Run the guide with the arguments passed to SVI.step() and trace the execution, # i.e. record all the calls to Pyro primitives like sample() and param(). #print("enter relbo") @@ -84,15 +85,15 @@ def relbo(model, guide, *args, **kwargs): approximation_log_prob.append(approximation_trace.log_prob_sum()) # This is how we computed the ELBO before using TraceEnum_ELBO: - # elbo = model_trace.log_prob_sum() - guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() + elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() - loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, - guide, - *args, **kwargs) + # loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, + # guide, + # *args, **kwargs) # print(loss_fn) # print(approximation_trace.log_prob_sum()) - elbo = -loss_fn - approximation_trace.log_prob_sum() + #elbo = -loss_fn - approximation_trace.log_prob_sum() # Return (-elbo) since by convention we do gradient descent on a loss and # the ELBO is a lower bound that needs to be maximized. @@ -102,6 +103,7 @@ def relbo(model, guide, *args, **kwargs): def boosting_bbvi(): n_iterations = 6 + relbo_lambda = 1 initial_approximation = dummy_approximation components = [initial_approximation] weights = torch.tensor([1.]) @@ -112,6 +114,9 @@ def boosting_bbvi(): scales = [0] gradient_norms = defaultdict(list) + duality_gap = [] + entropies = [] + model_log_likelihoods = [] for t in range(1, n_iterations + 1): # setup the inference algorithm wrapped_guide = partial(guide, index=t) @@ -137,7 +142,7 @@ def boosting_bbvi(): svi = SVI(model, wrapped_guide, optimizer, loss=relbo) for step in range(n_steps): - loss = svi.step(data, approximation=wrapped_approximation) + loss = svi.step(data, approximation=wrapped_approximation, relbo_lambda=relbo_lambda) losses.append(loss) if PRINT_INTERMEDIATE_LATENT_VALUES: @@ -174,6 +179,22 @@ def boosting_bbvi(): wrapped_approximation = partial(approximation, components=components, weights=weights) + e_log_p = 0 + n_samples = 50 + entropy = 0 + model_log_likelihood = 0 + elbo = 0 + for i in range(n_samples): + qt_trace = trace(wrapped_approximation).get_trace(data) + replayed_model_trace = trace(replay(model, qt_trace)).get_trace(data) + model_log_likelihood += replayed_model_trace.log_prob_sum() + entropy -= qt_trace.log_prob_sum() + elbo = elbo + replayed_model_trace.log_prob_sum() - qt_trace.log_prob_sum() + + duality_gap.append(elbo/n_samples) + model_log_likelihoods.append(model_log_likelihood/n_samples) + entropies.append(entropy/n_samples) + scale = pyro.param("variance_{}".format(t)).item() scales.append(scale) loc = pyro.param("mu_{}".format(t)).item() @@ -191,6 +212,15 @@ def boosting_bbvi(): pyplot.title('Gradient norms during SVI'); pyplot.show() + + pyplot.plot(range(1, len(duality_gap) + 1), duality_gap, label='ELBO') + pyplot.plot(range(1, len(entropies) + 1), entropies, label='Entropy of q_t') + pyplot.plot(range(1, len(model_log_likelihoods) + 1),model_log_likelihoods, label='E[logp] w.r.t. q_t') + pyplot.title('ELBO(p, q_t)'); + pyplot.legend(); + pyplot.xlabel('Approximation components') + pyplot.ylabel('Log probability') + pyplot.show() print(weights) print(locs) print(scales) @@ -204,7 +234,7 @@ def boosting_bbvi(): total_approximation += Y pyplot.plot(X, total_approximation) pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*') - pyplot.title('Approximation of posterior over mu') + pyplot.title('Approximation of posterior over mu with lambda={}'.format(relbo_lambda)) pyplot.ylabel('probability density'); pyplot.show() From 9d90421b378bc836cb63bf485ea46031f1bdd064 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 2 Dec 2019 15:06:36 +0100 Subject: [PATCH 12/29] Back up before refactoring guide --- bayesian_logistic_regression.py | 58 +++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index a4af6fb..f22337f 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -22,8 +22,6 @@ from pyro.infer.autoguide import AutoDiagonalNormal import inspect - - PRINT_INTERMEDIATE_LATENT_VALUES = False PRINT_TRACES = False @@ -42,6 +40,7 @@ guide_log_prob = [] approximation_log_prob = [] +@config_enumerate def guide(observations, input_data, index): variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) #variance_q = torch.eye(input_data.shape[1]) @@ -69,7 +68,8 @@ def dummy_approximation(observations, input_data): def predictive_model(wrapped_approximation, observations, input_data): w = wrapped_approximation(observations, input_data) - # w = w_dict['w'] + if type(w) is dict: + w = w['w'] with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) @@ -87,8 +87,6 @@ def relbo(model, guide, *args, **kwargs): #print(model_trace.nodes['obs']) - - approximation_trace = trace(replay(block(approximation, expose=['w']), guide_trace)).get_trace(*args, **kwargs) # We will accumulate the various terms of the ELBO in `elbo`. @@ -136,7 +134,7 @@ def load_data(): def boosting_bbvi(): - n_iterations = 1 + n_iterations = 2 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = dummy_approximation @@ -150,6 +148,8 @@ def boosting_bbvi(): gradient_norms = defaultdict(list) duality_gap = [] + model_log_likelihoods = [] + entropies = [] for t in range(1, n_iterations + 1): # setup the inference algorithm wrapped_guide = partial(guide, index=t) @@ -172,6 +172,10 @@ def boosting_bbvi(): global approximation_log_prob approximation_log_prob = [] + if t == 1: + n_steps = 5000 + else: + n_steps = 1000 svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=relbo) for step in range(n_steps): @@ -207,18 +211,28 @@ def boosting_bbvi(): components.append(wrapped_guide) new_weight = 2 / (t + 1) + if t == 2: + new_weight = 0.05 weights = weights * (1-new_weight) weights = torch.cat((weights, torch.tensor([new_weight]))) wrapped_approximation = partial(approximation, components=components, weights=weights) e_log_p = 0 - for i in range(50): + n_samples = 50 + entropy = 0 + model_log_likelihood = 0 + elbo = 0 + for i in range(n_samples): qt_trace = trace(wrapped_approximation).get_trace(y_train, X_train) replayed_model_trace = trace(replay(logistic_regression_model, qt_trace)).get_trace(y_train, X_train) - e_log_p = e_log_p + replayed_model_trace.log_prob_sum() + model_log_likelihood += replayed_model_trace.log_prob_sum() + entropy -= qt_trace.log_prob_sum() + elbo = elbo + replayed_model_trace.log_prob_sum() - qt_trace.log_prob_sum() - duality_gap.append(replayed_model_trace.log_prob_sum()/10) + duality_gap.append(elbo/n_samples) + model_log_likelihoods.append(model_log_likelihood/n_samples) + entropies.append(entropy/n_samples) # scale = pyro.param("variance_{}".format(t)).item() # scales.append(scale) @@ -238,8 +252,11 @@ def boosting_bbvi(): pyplot.show() - pyplot.plot(range(1, len(duality_gap) + 1), duality_gap) - pyplot.title('E[log p] w.r.t. q_t'); + pyplot.plot(range(1, len(duality_gap) + 1), duality_gap, label='ELBO') + pyplot.plot(range(1, len(entropies) + 1), entropies, label='Entropy of q_t') + pyplot.plot(range(1, len(model_log_likelihoods) + 1),model_log_likelihoods, label='E[logp] w.r.t. q_t') + pyplot.title('ELBO(p, q_t)'); + pyplot.legend(); pyplot.xlabel('Approximation components') pyplot.ylabel('Log probability') pyplot.show() @@ -253,9 +270,13 @@ def boosting_bbvi(): print(sigma) wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_approximation, observations=y_test, input_data=X_test) - predictive_trace = trace(wrapped_predictive_model).get_trace() + n_samples = 50 + log_likelihood = 0 + for i in range(n_samples): + predictive_trace = trace(wrapped_predictive_model).get_trace() + log_likelihood += predictive_trace.log_prob_sum() print('Log prob on test data') - print(predictive_trace.log_prob_sum()) + print(log_likelihood/n_samples) def run_mcmc(): @@ -278,8 +299,7 @@ def run_mcmc(): def run_svi(): # setup the optimizer X_train, y_train, X_test, y_test = load_data() - n_steps = 5000 - n_iterations = 1 + n_steps = 10000 adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) @@ -311,9 +331,13 @@ def run_svi(): pyplot.show() wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_guide, observations=y_test, input_data=X_test) - predictive_trace = trace(wrapped_predictive_model).get_trace() + n_samples = 50 + log_likelihood = 0 + for i in range(n_samples): + predictive_trace = trace(wrapped_predictive_model).get_trace() + log_likelihood += predictive_trace.log_prob_sum() print('Log prob on test data') - print(predictive_trace.log_prob_sum()) + print(log_likelihood/n_samples) if __name__ == '__main__': boosting_bbvi() \ No newline at end of file From c7df037bd8dc07f74790606d51aac96c8ccc563d Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 3 Dec 2019 15:37:27 +0100 Subject: [PATCH 13/29] Refactor --- __init__.py | 0 bayesian_logistic_regression.py | 112 ++++++++++++++------------------ bbbvi.py | 75 +++++++++++++++++++++ bimodal_posterior.py | 71 +++++--------------- 4 files changed, 137 insertions(+), 121 deletions(-) create mode 100644 __init__.py create mode 100644 bbbvi.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index f22337f..cddd9ec 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -21,6 +21,7 @@ import pickle from pyro.infer.autoguide import AutoDiagonalNormal import inspect +from bbbvi import relbo, Approximation PRINT_INTERMEDIATE_LATENT_VALUES = False PRINT_TRACES = False @@ -40,26 +41,48 @@ guide_log_prob = [] approximation_log_prob = [] -@config_enumerate -def guide(observations, input_data, index): - variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) - #variance_q = torch.eye(input_data.shape[1]) - mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) - w = pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) - return w - -@config_enumerate +# @config_enumerate +# def guide(observations, input_data, index): +# variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) +# #variance_q = torch.eye(input_data.shape[1]) +# mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) +# w = pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) +# return w + +class Guide: + def __init__(self, index, n_variables, initial_loc=None, initial_scale=None): + self.index = index + self.n_variables = n_variables + if not initial_loc: + self.initial_loc = torch.zeros(n_variables) + self.initial_scale = torch.eye(n_variables) + else: + self.initial_scale = initial_scale + self.initial_loc = initial_loc + + def get_distribution(self): + scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive) + #scale_q = torch.eye(self.n_variables) + locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc) + return dist.MultivariateNormal(locs_q, scale_q) + + def __call__(self, observations, input_data): + distribution = self.get_distribution() + w = pyro.sample("w", distribution) + return w + def logistic_regression_model(observations, input_data): w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) -@config_enumerate -def approximation(observations, input_data, components, weights): - assignment = pyro.sample('assignment', dist.Categorical(weights)) - w = components[assignment](observations, input_data) - return w +# @config_enumerate +# def approximation(observations, input_data, components, weights): +# assignment = pyro.sample('assignment', dist.Categorical(weights)) +# distribution = components[assignment].get_distribution() +# w = pyro.sample("w", distribution) +# return w def dummy_approximation(observations, input_data): variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive) @@ -74,41 +97,6 @@ def predictive_model(wrapped_approximation, observations, input_data): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) -def relbo(model, guide, *args, **kwargs): - - approximation = kwargs.pop('approximation', None) - relbo_lambda = kwargs.pop('relbo_lambda', None) - # Run the guide with the arguments passed to SVI.step() and trace the execution, - # i.e. record all the calls to Pyro primitives like sample() and param(). - #print("enter relbo") - guide_trace = trace(guide).get_trace(*args, **kwargs) - #print(guide_trace.nodes['obs_1']) - model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) - - #print(model_trace.nodes['obs']) - - approximation_trace = trace(replay(block(approximation, expose=['w']), guide_trace)).get_trace(*args, **kwargs) - # We will accumulate the various terms of the ELBO in `elbo`. - - guide_log_prob.append(guide_trace.log_prob_sum()) - model_log_prob.append(model_trace.log_prob_sum()) - approximation_log_prob.append(approximation_trace.log_prob_sum()) - - # This is how we computed the ELBO before using TraceEnum_ELBO: - elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() - - loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, - guide, - *args, **kwargs) - - # print(loss_fn) - # print(approximation_trace.log_prob_sum()) - elbo = -loss_fn - approximation_trace.log_prob_sum() - # Return (-elbo) since by convention we do gradient descent on a loss and - # the ELBO is a lower bound that needs to be maximized. - - return -elbo - # Utility function to print latent sites' quantile information. def summary(samples): @@ -134,14 +122,14 @@ def load_data(): def boosting_bbvi(): - n_iterations = 2 + n_iterations = 1 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 - initial_approximation = dummy_approximation + initial_approximation = Guide(index=0, n_variables=X_train.shape[1]) components = [initial_approximation] + weights = torch.tensor([1.]) - wrapped_approximation = partial(approximation, components=components, - weights=weights) + wrapped_approximation = Approximation(components, weights) locs = [0] scales = [0] @@ -152,12 +140,11 @@ def boosting_bbvi(): entropies = [] for t in range(1, n_iterations + 1): # setup the inference algorithm - wrapped_guide = partial(guide, index=t) + wrapped_guide = Guide(index=t, n_variables=X_train.shape[1]) # do gradient steps losses = [] # Register hooks to monitor gradient norms. wrapped_guide(y_train, X_train) - print(pyro.get_param_store().named_parameters()) adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) @@ -172,11 +159,6 @@ def boosting_bbvi(): global approximation_log_prob approximation_log_prob = [] - if t == 1: - n_steps = 5000 - else: - n_steps = 1000 - svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=relbo) for step in range(n_steps): loss = svi.step(y_train, X_train, approximation=wrapped_approximation, relbo_lambda=relbo_lambda) @@ -185,7 +167,7 @@ def boosting_bbvi(): if PRINT_INTERMEDIATE_LATENT_VALUES: print('Loss: {}'.format(loss)) variance = pyro.param("variance_{}".format(t)).item() - mu = pyro.param("mu_{}".format(t)).item() + mu = pyro.param("locs_{}".format(t)).item() print('mu = {}'.format(mu)) print('variance = {}'.format(variance)) @@ -208,7 +190,7 @@ def boosting_bbvi(): pyplot.legend() pyplot.show() - components.append(wrapped_guide) + wrapped_approximation.components.append(wrapped_guide) new_weight = 2 / (t + 1) if t == 2: @@ -216,7 +198,7 @@ def boosting_bbvi(): weights = weights * (1-new_weight) weights = torch.cat((weights, torch.tensor([new_weight]))) - wrapped_approximation = partial(approximation, components=components, weights=weights) + wrapped_approximation.weights = weights e_log_p = 0 n_samples = 50 @@ -262,8 +244,8 @@ def boosting_bbvi(): pyplot.show() for i in range(1, n_iterations + 1): - mu = pyro.param('mu_{}'.format(i)) - sigma = pyro.param('variance_{}'.format(i)) + mu = pyro.param('locs_{}'.format(i)) + sigma = pyro.param('scale_{}'.format(i)) print('Mu_{}: '.format(i)) print(mu) print('Sigma{}: '.format(i)) diff --git a/bbbvi.py b/bbbvi.py new file mode 100644 index 0000000..8dc0f9f --- /dev/null +++ b/bbbvi.py @@ -0,0 +1,75 @@ +import math +import os +import torch +import torch.distributions.constraints as constraints +import pyro +from pyro.optim import Adam, SGD +from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO +import pyro.distributions as dist +from pyro.infer.autoguide import AutoDelta +from pyro import poutine +from pyro.poutine import trace, replay, block +from functools import partial +import numpy as np +import scipy.stats +from pyro.infer.autoguide import AutoDelta +from collections import defaultdict +import matplotlib +from matplotlib import pyplot + +def relbo(model, guide, *args, **kwargs): + + approximation = kwargs.pop('approximation', None) + relbo_lambda = kwargs.pop('relbo_lambda', None) + # Run the guide with the arguments passed to SVI.step() and trace the execution, + # i.e. record all the calls to Pyro primitives like sample() and param(). + #print("enter relbo") + guide_trace = trace(guide).get_trace(*args, **kwargs) + #print(guide_trace.nodes['obs_1']) + model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) + #print(model_trace.nodes['obs_1']) + + + approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs) + # We will accumulate the various terms of the ELBO in `elbo`. + + # guide_log_prob.append(guide_trace.log_prob_sum()) + # model_log_prob.append(model_trace.log_prob_sum()) + # approximation_log_prob.append(approximation_trace.log_prob_sum()) + + # This is how we computed the ELBO before using TraceEnum_ELBO: + elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() + + loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, + guide, + *args, **kwargs) + + # print(loss_fn) + # print(approximation_trace.log_prob_sum()) + elbo = -loss_fn - approximation_trace.log_prob_sum() + #elbo = -loss_fn + 0.1 * pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(approximation, + # guide, + # *args, **kwargs) + # Return (-elbo) since by convention we do gradient descent on a loss and + # the ELBO is a lower bound that needs to be maximized. + + return -elbo + +class Approximation: + + def __init__(self, components= None, weights=None): + if not components: + self.components = [] + else: + self.components = components + + if not weights: + self.weights = [] + else: + self.weights = weights + + def __call__(self, *args, **kwargs): + assignment = pyro.sample('assignment', dist.Categorical(self.weights)) + result = self.components[assignment](*args, **kwargs) + return result + diff --git a/bimodal_posterior.py b/bimodal_posterior.py index 636a92f..5400129 100644 --- a/bimodal_posterior.py +++ b/bimodal_posterior.py @@ -16,6 +16,7 @@ from collections import defaultdict import matplotlib from matplotlib import pyplot +from bbbvi import relbo, Approximation PRINT_INTERMEDIATE_LATENT_VALUES = False PRINT_TRACES = False @@ -54,61 +55,19 @@ def model(data): # Local variables. pyro.sample('obs_{}'.format(i), dist.Normal(mu*mu, variance), obs=data[i]) -@config_enumerate -def approximation(data, components, weights): - assignment = pyro.sample('assignment', dist.Categorical(weights)) - distribution = components[assignment](data) def dummy_approximation(data): variance_q = pyro.param('variance_0', torch.tensor([1.0]), constraints.positive) mu_q = pyro.param('mu_0', torch.tensor([20.0])) pyro.sample("mu", dist.Normal(mu_q, variance_q)) -def relbo(model, guide, *args, **kwargs): - - approximation = kwargs.pop('approximation', None) - relbo_lambda = kwargs.pop('relbo_lambda', None) - # Run the guide with the arguments passed to SVI.step() and trace the execution, - # i.e. record all the calls to Pyro primitives like sample() and param(). - #print("enter relbo") - guide_trace = trace(guide).get_trace(*args, **kwargs) - #print(guide_trace.nodes['obs_1']) - model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) - #print(model_trace.nodes['obs_1']) - - - approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs) - # We will accumulate the various terms of the ELBO in `elbo`. - - guide_log_prob.append(guide_trace.log_prob_sum()) - model_log_prob.append(model_trace.log_prob_sum()) - approximation_log_prob.append(approximation_trace.log_prob_sum()) - - # This is how we computed the ELBO before using TraceEnum_ELBO: - elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() - - # loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, - # guide, - # *args, **kwargs) - - # print(loss_fn) - # print(approximation_trace.log_prob_sum()) - #elbo = -loss_fn - approximation_trace.log_prob_sum() - # Return (-elbo) since by convention we do gradient descent on a loss and - # the ELBO is a lower bound that needs to be maximized. - - return -elbo - - def boosting_bbvi(): - n_iterations = 6 - + n_iterations = 2 relbo_lambda = 1 initial_approximation = dummy_approximation components = [initial_approximation] weights = torch.tensor([1.]) - wrapped_approximation = partial(approximation, components=components, - weights=weights) + wrapped_approximation = Approximation(components, weights) locs = [0] scales = [0] @@ -161,23 +120,23 @@ def boosting_bbvi(): pyplot.title('-ELBO against time for component {}'.format(t)); pyplot.show() - pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') - pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') - pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') - pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') - pyplot.xlabel('Update Steps') - pyplot.ylabel('Log Prob') - pyplot.title('RELBO components throughout SVI'.format(t)); - pyplot.legend() - pyplot.show() - - components.append(wrapped_guide) + # pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') + # pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') + # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') + # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') + # pyplot.xlabel('Update Steps') + # pyplot.ylabel('Log Prob') + # pyplot.title('RELBO components throughout SVI'.format(t)); + # pyplot.legend() + # pyplot.show() + + wrapped_approximation.components.append(wrapped_guide) new_weight = 2 / (t + 1) weights = weights * (1-new_weight) weights = torch.cat((weights, torch.tensor([new_weight]))) - wrapped_approximation = partial(approximation, components=components, weights=weights) + wrapped_approximation.weights = weights e_log_p = 0 n_samples = 50 From 8bc117176e96fc31ce043b3f70e62ba3b5dc816e Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 3 Dec 2019 15:51:40 +0100 Subject: [PATCH 14/29] Add BLR config that actually improves test log prob --- bayesian_logistic_regression.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index cddd9ec..fa78cd8 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -122,7 +122,7 @@ def load_data(): def boosting_bbvi(): - n_iterations = 1 + n_iterations = 2 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 initial_approximation = Guide(index=0, n_variables=X_train.shape[1]) @@ -180,15 +180,15 @@ def boosting_bbvi(): # pyplot.title('-ELBO against time for component {}'.format(t)); # pyplot.show() - pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') - pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') - pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') - pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') - pyplot.xlabel('Update Steps') - pyplot.ylabel('Log Prob') - pyplot.title('RELBO components throughout SVI'.format(t)); - pyplot.legend() - pyplot.show() + # pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') + # pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') + # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') + # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') + # pyplot.xlabel('Update Steps') + # pyplot.ylabel('Log Prob') + # pyplot.title('RELBO components throughout SVI'.format(t)); + # pyplot.legend() + # pyplot.show() wrapped_approximation.components.append(wrapped_guide) new_weight = 2 / (t + 1) From 41ada32dee019587ca1a8eb645d2e1363b78de75 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 4 Dec 2019 10:17:39 +0100 Subject: [PATCH 15/29] Backup best BBBVI BLR results --- bayesian_logistic_regression.py | 76 +++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index fa78cd8..5869fbe 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -28,7 +28,7 @@ # this is for running the notebook in our testing framework smoke_test = ('CI' in os.environ) -n_steps = 2 if smoke_test else 5000 +n_steps = 2 if smoke_test else 10000 pyro.set_rng_seed(2) # enable validation (e.g. validate parameters of distributions) @@ -55,7 +55,7 @@ def __init__(self, index, n_variables, initial_loc=None, initial_scale=None): self.n_variables = n_variables if not initial_loc: self.initial_loc = torch.zeros(n_variables) - self.initial_scale = torch.eye(n_variables) + self.initial_scale = torch.ones(n_variables) else: self.initial_scale = initial_scale self.initial_loc = initial_loc @@ -64,7 +64,7 @@ def get_distribution(self): scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive) #scale_q = torch.eye(self.n_variables) locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc) - return dist.MultivariateNormal(locs_q, scale_q) + return dist.Laplace(locs_q, scale_q).to_event(1) def __call__(self, observations, input_data): distribution = self.get_distribution() @@ -72,7 +72,7 @@ def __call__(self, observations, input_data): return w def logistic_regression_model(observations, input_data): - w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.eye(input_data.shape[1]))) + w = pyro.sample('w', dist.Laplace(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1)) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) @@ -86,7 +86,7 @@ def logistic_regression_model(observations, input_data): def dummy_approximation(observations, input_data): variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive) - mu_q = pyro.param('mu_0', 20*torch.ones(input_data.shape[1])) + mu_q = pyro.param('mu_0', 100*torch.ones(input_data.shape[1])) pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) def predictive_model(wrapped_approximation, observations, input_data): @@ -120,12 +120,52 @@ def load_data(): return X_train, y_train, X_test, y_test + +def relbo(model, guide, *args, **kwargs): + + approximation = kwargs.pop('approximation', None) + relbo_lambda = kwargs.pop('relbo_lambda', None) + # Run the guide with the arguments passed to SVI.step() and trace the execution, + # i.e. record all the calls to Pyro primitives like sample() and param(). + #print("enter relbo") + guide_trace = trace(guide).get_trace(*args, **kwargs) + #print(guide_trace.nodes['obs_1']) + model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs) + #print(model_trace.nodes['obs_1']) + + + approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs) + # We will accumulate the various terms of the ELBO in `elbo`. + + guide_log_prob.append(guide_trace.log_prob_sum()) + model_log_prob.append(model_trace.log_prob_sum()) + approximation_log_prob.append(approximation_trace.log_prob_sum()) + + # This is how we computed the ELBO before using TraceEnum_ELBO: + elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum() + + loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model, + guide, + *args, **kwargs) + + # print(loss_fn) + # print(approximation_trace.log_prob_sum()) + elbo = -loss_fn - approximation_trace.log_prob_sum() + #elbo = -loss_fn + 0.1 * pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(approximation, + # guide, + # *args, **kwargs) + # Return (-elbo) since by convention we do gradient descent on a loss and + # the ELBO is a lower bound that needs to be maximized. + + return -elbo + def boosting_bbvi(): n_iterations = 2 X_train, y_train, X_test, y_test = load_data() relbo_lambda = 1 - initial_approximation = Guide(index=0, n_variables=X_train.shape[1]) + #initial_approximation = Guide(index=0, n_variables=X_train.shape[1]) + initial_approximation = dummy_approximation components = [initial_approximation] weights = torch.tensor([1.]) @@ -146,7 +186,7 @@ def boosting_bbvi(): # Register hooks to monitor gradient norms. wrapped_guide(y_train, X_train) - adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.008, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) for name, value in pyro.get_param_store().named_parameters(): if not name in gradient_norms: @@ -180,21 +220,21 @@ def boosting_bbvi(): # pyplot.title('-ELBO against time for component {}'.format(t)); # pyplot.show() - # pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') - # pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') - # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') - # pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') - # pyplot.xlabel('Update Steps') - # pyplot.ylabel('Log Prob') - # pyplot.title('RELBO components throughout SVI'.format(t)); - # pyplot.legend() - # pyplot.show() + pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob') + pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob') + pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO') + pyplot.xlabel('Update Steps') + pyplot.ylabel('Log Prob') + pyplot.title('RELBO components throughout SVI'.format(t)); + pyplot.legend() + pyplot.show() wrapped_approximation.components.append(wrapped_guide) new_weight = 2 / (t + 1) - if t == 2: - new_weight = 0.05 + # if t == 2: + # new_weight = 0.05 weights = weights * (1-new_weight) weights = torch.cat((weights, torch.tensor([new_weight]))) From 059eb6fbda4d647353145bf5e216f4901e639c74 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 4 Dec 2019 11:38:47 +0100 Subject: [PATCH 16/29] Add new best BLR configuration --- bayesian_logistic_regression.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 5869fbe..8c0cbab 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -186,7 +186,7 @@ def boosting_bbvi(): # Register hooks to monitor gradient norms. wrapped_guide(y_train, X_train) - adam_params = {"lr": 0.008, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.01, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) for name, value in pyro.get_param_store().named_parameters(): if not name in gradient_norms: @@ -322,7 +322,7 @@ def run_svi(): # setup the optimizer X_train, y_train, X_test, y_test = load_data() n_steps = 10000 - adam_params = {"lr": 0.005, "betas": (0.90, 0.999)} + adam_params = {"lr": 0.01, "betas": (0.90, 0.999)} optimizer = Adam(adam_params) # setup the inference algorithm @@ -362,4 +362,4 @@ def run_svi(): print(log_likelihood/n_samples) if __name__ == '__main__': - boosting_bbvi() \ No newline at end of file + run_svi() \ No newline at end of file From 8a8e33148f3c9eb264528727d5b63eda0cd1f539 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 10 Dec 2019 09:30:32 +0100 Subject: [PATCH 17/29] Extend BBBVI tutorial --- bayesian_logistic_regression.py | 6 +- boosting_bbvi_tutorial.ipynb | 781 ++++++++++++++++++++++++++++++++ 2 files changed, 784 insertions(+), 3 deletions(-) create mode 100644 boosting_bbvi_tutorial.ipynb diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index 8c0cbab..bd88c62 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -64,7 +64,7 @@ def get_distribution(self): scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive) #scale_q = torch.eye(self.n_variables) locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc) - return dist.Laplace(locs_q, scale_q).to_event(1) + return dist.MultivariateNormal(locs_q, scale_q).to_event(1) def __call__(self, observations, input_data): distribution = self.get_distribution() @@ -72,7 +72,7 @@ def __call__(self, observations, input_data): return w def logistic_regression_model(observations, input_data): - w = pyro.sample('w', dist.Laplace(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1)) + w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1)) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) @@ -362,4 +362,4 @@ def run_svi(): print(log_likelihood/n_samples) if __name__ == '__main__': - run_svi() \ No newline at end of file + boosting_bbvi() \ No newline at end of file diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb new file mode 100644 index 0000000..000497a --- /dev/null +++ b/boosting_bbvi_tutorial.ipynb @@ -0,0 +1,781 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Boosting Black Box Variational Inference\n", + "## Introduction\n", + "This tutorial demonstrates how to implement boosting black box variational inference in Pyro. In comparison to standard variational inference, boosting VI approximates the target density with a mixture of density functions rather than a single density. It thus offers an easy way of getting more complex approximation of distributions in siutations where a single density doesn't approximate the target well enough.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Theoretical Background\n", + "\n", + "### Variational Inference\n", + "For an introduction to standard Variational Inference, we recommend first checking out [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html).\n", + "Recall that in standard Variational Inference, we maximize the Evidence Lower BOund (ELBO):\n", + "$$ E_s[\\text{log} p(x, z)] - E_s[\\text{log} s(z)]$$\n", + "\n", + "where $s(z)$ is the approximating distribution, the guide, and $p(x,z)$ the target distribution.\n", + "\n", + "### Boosting Black Box Variational Inference\n", + "\n", + "In the boosting BBVI, we greedily components to our approximation by maximising the Residual ELBO (RELBO):\n", + "\n", + "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s] - E_s[\\text{log} q^t]$$\n", + "\n", + "Roughly, the algorithm is thus the following:\n", + "\n", + "```~python\n", + "initalize q_0\n", + "for t=1:T\n", + " Find s_t that maximizes RELBO\n", + " gamma = 2/(t+1)\n", + " q_t = (1 - gamma)*q_t + gamma*s_t\n", + " \n", + "```\n", + "\n", + "where `q_t` is the approximation at time step `t`.\n", + "\n", + " \n", + "Conveniently, we do not need to make any additional assumptions about the variational family that's being used." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## BBBVI in Pyro" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To implement boosting black box variational inference in Pyro, we need to consider the following three components:\n", + "- How to set up the guide and the approximation\n", + "- How to implement the RELBO\n", + "- How to run SVI and update the approximation\n", + "\n", + "We will illustrate these points by looking at two examples. First, we will use BBBVI to approximate a bimodal posterior and then we'll use BBBVI for Bayesian Logistic Regression on the ChemReact data set.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Model\n", + "\n", + "Boosting BBVI is particularly useful in situations where we're trying to approximate mulitmodal posteriors. In this tutorial, we'll thus consider the following model:\n", + " \n", + " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", + " $$y \\sim \\mathcal{N}(\\mu^2, 1)$$\n", + " \n", + " Observing some data points around 4, we expect $p(mu|y)$ to be a bimodal distributions with means around -2 and + 2." + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": {}, + "outputs": [], + "source": [ + "def model(data):\n", + " # Global variables.\n", + " prior_loc = torch.tensor([0.])\n", + " prior_scale = torch.tensor([5.])\n", + " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", + " scale = torch.tensor([1.])\n", + "\n", + " with pyro.plate('data', len(data)):\n", + " # Local variables.\n", + " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Guide" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "metadata": {}, + "outputs": [], + "source": [ + "def guide(data, index):\n", + " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", + " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([1.0]))\n", + " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The RELBO" + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "metadata": {}, + "outputs": [], + "source": [ + "def relbo(model, guide, *args, **kwargs):\n", + "\n", + " approximation = kwargs.pop('approximation', None)\n", + " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", + " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", + " # i.e. record all the calls to Pyro primitives like sample() and param().\n", + " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", + "\n", + " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", + "\n", + "\n", + "\n", + " approximation_trace = trace(replay(block(approximation, expose=['loc']), guide_trace)).get_trace(*args, **kwargs)\n", + " # We will acculoclate the various terms of the ELBO in `elbo`.\n", + "\n", + " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", + " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum()\n", + "\n", + " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", + " guide,\n", + " *args, **kwargs)\n", + "\n", + " elbo = -loss_fn - 0.1 * approximation_trace.log_prob_sum()\n", + "\n", + " return -elbo " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Approximation" + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "metadata": {}, + "outputs": [], + "source": [ + "def approximation(data, components, weights):\n", + " assignment = pyro.sample('assignment', dist.Categorical(weights))\n", + " result = components[assignment](data)\n", + " return result " + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": {}, + "outputs": [], + "source": [ + "def dummy_approximation(data):\n", + " scale_q = pyro.param('scale_0', torch.tensor([1.0]), constraints.positive)\n", + " loc_q = pyro.param('loc_0', torch.tensor([20.0]))\n", + " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Greedy Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = 1.9530718326568604\n", + "scale = 0.09594951570034027\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = -2.3136916160583496\n", + "scale = 0.17421917617321014\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA18AAAFuCAYAAAB+/6JIAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXxTVfo/8M/Nnq60lK6WUhARBKS0yCZTGKDK6oIgILuggIKIqPDlp4Ay7GodGVAUUWQRFVwYFCxKEYZFZBsBFxzRIm3ZhLbQLE1yfn8kuZAmaZNSGmw+79crrzYnJ/c+SW7TPDnPPUcSQggQERERERHRdaUIdABERERERETBgMkXERERERFRDWDyRUREREREVAOYfBEREREREdUAJl9EREREREQ1gMkXERERERFRDWDyRUREREREVAOYfBEREREREdUAJl9EREREREQ1gMkXURD75z//CUmS0Lx580CHct00aNAAI0aMCMi+16xZg+zsbI+3SZKEmTNn1mxAfvrqq6+QkZGB0NBQSJKETz75JNAhuajo+a0OgTx2blQzZ86EJEmBDsMnI0aMQIMGDVza5syZ4/E4fueddyBJEr777rsq7SuQz8u1xg4AnTt3RufOnasvKB+sXLkSAwcORJMmTaBQKNxeK6LaShXoAIgocN5++20AwNGjR7F37160bds2wBFVv48//hgREREB2feaNWtw5MgRTJo0ye223bt346abbgpAVL4RQmDAgAG45ZZb8NlnnyE0NBRNmjQJdFguKnp+q0Mgjx26ds899xyeeOIJl7Y5c+bggQcewL333hugqMjpvffeQ2FhIe644w7YbDaUlZUFOiSiGsHkiyhIfffddzh8+DB69eqFTZs2Yfny5QFNvgwGA/R6fbVvNy0trdq3WR3atWsX6BAqlJ+fjz///BP33XcfunbtGuhwapTzWKzOY8dqtcJisUCr1VbbNq+X0tJShISEBDqMa9aoUaNAh0AV2LJlCxQKewFW7969ceTIkQBHRFQzWHZIFKSWL18OAJg3bx46dOiA999/H6WlpS59fvvtN0iShAULFuAf//gH6tevD51Oh4yMDHz11VcufZ1lNwcPHsT999+PiIgIREZGYsiQITh79qxL3wYNGqB3797YsGED0tLSoNPpMGvWLACA0WjEtGnTkJqa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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\"\"\"\n", + "\n", + "\"\"\"\n", + "import math\n", + "import os\n", + "from collections import defaultdict\n", + "from functools import partial\n", + "\n", + "import matplotlib\n", + "import numpy as np\n", + "import pyro\n", + "import pyro.distributions as dist\n", + "import scipy.stats\n", + "import torch\n", + "import torch.distributions.constraints as constraints\n", + "from matplotlib import pyplot\n", + "from pyro import poutine\n", + "from pyro.infer import SVI, Trace_ELBO, TraceEnum_ELBO, config_enumerate\n", + "from pyro.infer.autoguide import AutoDelta\n", + "from pyro.optim import SGD, Adam\n", + "from pyro.poutine import block, replay, trace\n", + "\n", + "# this is for running the notebook in our testing framework\n", + "smoke_test = ('CI' in os.environ)\n", + "n_steps = 2 if smoke_test else 10000\n", + "pyro.set_rng_seed(2)\n", + "\n", + "# enable validation (e.g. validate parameters of distributions)\n", + "pyro.enable_validation(True)\n", + "\n", + "# clear the param store in case we're in a REPL\n", + "pyro.clear_param_store()\n", + "\n", + "data = torch.tensor([4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3])\n", + "\n", + "def guide(data, index):\n", + " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", + " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([1.0]))\n", + " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", + "\n", + "def model(data):\n", + " # Global variables.\n", + " prior_loc = torch.tensor([0.])\n", + " prior_scale = torch.tensor([5.])\n", + " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", + " scale = torch.tensor([1.])\n", + "\n", + " with pyro.plate('data', len(data)):\n", + " # Local variables.\n", + " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)\n", + "\n", + "def relbo(model, guide, *args, **kwargs):\n", + "\n", + " approximation = kwargs.pop('approximation', None)\n", + " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", + " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", + " # i.e. record all the calls to Pyro primitives like sample() and param().\n", + " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", + "\n", + " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", + "\n", + "\n", + " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", + " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", + " # We will acculoclate the various terms of the ELBO in `elbo`.\n", + "\n", + " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", + " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum()\\\n", + " - approximation_trace.log_prob_sum()\n", + "\n", + " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", + " guide,\n", + " *args,\n", + " **kwargs)\n", + "\n", + " elbo = -loss_fn - 0.1 * approximation_trace.log_prob_sum()\n", + "\n", + " return -elbo\n", + "\n", + "def approximation(data, components, weights):\n", + " assignment = pyro.sample('assignment', dist.Categorical(weights))\n", + " result = components[assignment](data)\n", + " return result\n", + "\n", + "def dummy_approximation(data):\n", + " scale_q = pyro.param('scale_0', torch.tensor([1.0]), constraints.positive)\n", + " loc_q = pyro.param('loc_0', torch.tensor([20.0]))\n", + " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", + "\n", + "def boosting_bbvi():\n", + " n_iterations = 2\n", + " relbo_lambda = 1\n", + " initial_approximation = dummy_approximation\n", + " components = [initial_approximation]\n", + " weights = torch.tensor([1.])\n", + " wrapped_approximation = partial(approximation, components=components, weights=weights)\n", + "\n", + " locs = [0]\n", + " scales = [0]\n", + "\n", + " gradient_norms = defaultdict(list)\n", + " duality_gap = []\n", + " entropies = []\n", + " model_log_likelihoods = []\n", + " for t in range(1, n_iterations + 1):\n", + " # setup the inference algorithm\n", + " wrapped_guide = partial(guide, index=t)\n", + " # do gradient steps\n", + " losses = []\n", + " # Register hooks to monitor gradient norms.\n", + "\n", + " adam_params = {\"lr\": 0.002, \"betas\": (0.90, 0.999)}\n", + " optimizer = Adam(adam_params)\n", + "\n", + " svi = SVI(model, wrapped_guide, optimizer, loss=relbo)\n", + " for step in range(n_steps):\n", + " loss = svi.step(data, approximation=wrapped_approximation, relbo_lambda=relbo_lambda)\n", + " losses.append(loss)\n", + "\n", + " if step % 100 == 0:\n", + " print('.', end=' ')\n", + "\n", + " components.append(wrapped_guide)\n", + " new_weight = 2 / (t + 1)\n", + "\n", + " if t == 2:\n", + " new_weight = 0.5\n", + " weights = weights * (1-new_weight)\n", + " weights = torch.cat((weights, torch.tensor([new_weight])))\n", + "\n", + " wrapped_approximation = partial(approximation, components=components, weights=weights)\n", + "\n", + " scale = pyro.param(\"scale_{}\".format(t)).item()\n", + " scales.append(scale)\n", + " loc = pyro.param(\"loc_{}\".format(t)).item()\n", + " locs.append(loc)\n", + " print('loc = {}'.format(loc))\n", + " print('scale = {}'.format(scale))\n", + "\n", + "\n", + " X = np.arange(-10, 10, 0.1)\n", + " pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white')\n", + " total_approximation = np.zeros(X.shape)\n", + " for i in range(1, n_iterations + 1):\n", + " Y = weights[i].item() * scipy.stats.norm.pdf((X - locs[i]) / scales[i])\n", + " pyplot.plot(X, Y)\n", + " total_approximation += Y\n", + " pyplot.plot(X, total_approximation)\n", + " pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*')\n", + " pyplot.title('Approximation of posterior over loc with lambda={}'.format(relbo_lambda))\n", + " pyplot.ylabel('probability density')\n", + " pyplot.show()\n", + "\n", + "if __name__ == '__main__':\n", + " boosting_bbvi()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bayesian Logistic Regression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## import math\n", + "import os\n", + "import torch\n", + "import torch.distributions.constraints as constraints\n", + "import pyro\n", + "from pyro.optim import Adam, SGD\n", + "from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO, Predictive\n", + "import pyro.distributions as dist\n", + "from pyro.infer.autoguide import AutoDelta\n", + "from pyro import poutine \n", + "from pyro.poutine import trace, replay, block\n", + "from functools import partial\n", + "import numpy as np\n", + "import scipy.stats\n", + "from pyro.infer.autoguide import AutoDelta\n", + "from collections import defaultdict\n", + "import matplotlib\n", + "from matplotlib import pyplot\n", + "from pyro.infer import MCMC, NUTS\n", + "import pandas as pd\n", + "import pickle\n", + "from pyro.infer.autoguide import AutoDiagonalNormal\n", + "import inspect\n", + "from bbbvi import relbo, Approximation\n", + "\n", + "PRINT_INTERMEDIATE_LATENT_VALUES = False\n", + "PRINT_TRACES = False\n", + "\n", + "# this is for running the notebook in our testing framework\n", + "smoke_test = ('CI' in os.environ)\n", + "n_steps = 2 if smoke_test else 10000\n", + "pyro.set_rng_seed(2)\n", + "\n", + "# enable validation (e.g. validate parameters of distributions)\n", + "pyro.enable_validation(True)\n", + "\n", + "# clear the param store in case we're in a REPL\n", + "pyro.clear_param_store()\n", + "\n", + "model_log_prob = []\n", + "guide_log_prob = []\n", + "approximation_log_prob = []\n", + "\n", + "class Guide:\n", + " def __init__(self, index, n_variables, initial_loc=None, initial_scale=None):\n", + " self.index = index\n", + " self.n_variables = n_variables\n", + " if not initial_loc:\n", + " self.initial_loc = torch.zeros(n_variables)\n", + " self.initial_scale = torch.ones(n_variables)\n", + " else:\n", + " self.initial_scale = initial_scale\n", + " self.initial_loc = initial_loc \n", + "\n", + " def get_distribution(self):\n", + " scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive)\n", + " #scale_q = torch.eye(self.n_variables)\n", + " locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc)\n", + " return dist.Laplace(locs_q, scale_q).to_event(1)\n", + "\n", + " def __call__(self, observations, input_data):\n", + " distribution = self.get_distribution()\n", + " w = pyro.sample(\"w\", distribution)\n", + " return w\n", + " \n", + "def logistic_regression_model(observations, input_data):\n", + " w = pyro.sample('w', dist.Laplace(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1))\n", + " with pyro.plate(\"data\", input_data.shape[0]):\n", + " sigmoid = torch.sigmoid(torch.matmul(input_data, w.double()))\n", + " obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations)\n", + "\n", + "# @config_enumerate\n", + "# def approximation(observations, input_data, components, weights):\n", + "# assignment = pyro.sample('assignment', dist.Categorical(weights))\n", + "# distribution = components[assignment].get_distribution()\n", + "# w = pyro.sample(\"w\", distribution)\n", + "# return w\n", + "\n", + "def dummy_approximation(observations, input_data):\n", + " variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive)\n", + " mu_q = pyro.param('mu_0', 100*torch.ones(input_data.shape[1]))\n", + " pyro.sample(\"w\", dist.MultivariateNormal(mu_q, variance_q))\n", + "\n", + "def predictive_model(wrapped_approximation, observations, input_data):\n", + " w = wrapped_approximation(observations, input_data)\n", + " if type(w) is dict:\n", + " w = w['w']\n", + " with pyro.plate(\"data\", input_data.shape[0]):\n", + " sigmoid = torch.sigmoid(torch.matmul(input_data, w.double()))\n", + " obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations)\n", + "\n", + "\n", + "# Utility function to print latent sites' quantile information.\n", + "def summary(samples):\n", + " site_stats = {}\n", + " for site_name, values in samples.items():\n", + " marginal_site = pd.DataFrame(values)\n", + " describe = marginal_site.describe(percentiles=[.05, 0.25, 0.5, 0.75, 0.95]).transpose()\n", + " site_stats[site_name] = describe[[\"mean\", \"std\", \"5%\", \"25%\", \"50%\", \"75%\", \"95%\"]]\n", + " return site_stats\n", + "\n", + "def load_data():\n", + " npz_train_file = np.load('ds1.100_train.npz')\n", + " npz_test_file = np.load('ds1.100_test.npz')\n", + "\n", + " X_train = torch.tensor(npz_train_file['X']).double()\n", + " y_train = torch.tensor(npz_train_file['y']).double()\n", + " y_train[y_train == -1] = 0\n", + " X_test = torch.tensor(npz_test_file['X']).double()\n", + " y_test = torch.tensor(npz_test_file['y']).double()\n", + " y_test[y_test == -1] = 0\n", + "\n", + " return X_train, y_train, X_test, y_test\n", + "\n", + "\n", + "def relbo(model, guide, *args, **kwargs):\n", + "\n", + " approximation = kwargs.pop('approximation', None)\n", + " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", + " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", + " # i.e. record all the calls to Pyro primitives like sample() and param().\n", + " #print(\"enter relbo\")\n", + " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", + " #print(guide_trace.nodes['obs_1'])\n", + " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", + " #print(model_trace.nodes['obs_1'])\n", + "\n", + "\n", + " approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs)\n", + " # We will accumulate the various terms of the ELBO in `elbo`.\n", + "\n", + " guide_log_prob.append(guide_trace.log_prob_sum())\n", + " model_log_prob.append(model_trace.log_prob_sum())\n", + " approximation_log_prob.append(approximation_trace.log_prob_sum())\n", + "\n", + " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", + " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum()\n", + "\n", + " loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", + " guide,\n", + " *args, **kwargs)\n", + "\n", + " # print(loss_fn)\n", + " # print(approximation_trace.log_prob_sum())\n", + " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", + " #elbo = -loss_fn + 0.1 * pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(approximation,\n", + " # guide,\n", + " # *args, **kwargs)\n", + " # Return (-elbo) since by convention we do gradient descent on a loss and\n", + " # the ELBO is a lower bound that needs to be maximized.\n", + "\n", + " return -elbo\n", + "\n", + "def boosting_bbvi():\n", + "\n", + " n_iterations = 2\n", + " X_train, y_train, X_test, y_test = load_data()\n", + " relbo_lambda = 1\n", + " #initial_approximation = Guide(index=0, n_variables=X_train.shape[1])\n", + " initial_approximation = dummy_approximation\n", + " components = [initial_approximation]\n", + "\n", + " weights = torch.tensor([1.])\n", + " wrapped_approximation = Approximation(components, weights)\n", + "\n", + " locs = [0]\n", + " scales = [0]\n", + "\n", + " gradient_norms = defaultdict(list)\n", + " duality_gap = []\n", + " model_log_likelihoods = []\n", + " entropies = []\n", + " for t in range(1, n_iterations + 1):\n", + " # setup the inference algorithm\n", + " wrapped_guide = Guide(index=t, n_variables=X_train.shape[1])\n", + " # do gradient steps\n", + " losses = []\n", + " # Register hooks to monitor gradient norms.\n", + " wrapped_guide(y_train, X_train)\n", + "\n", + " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", + " optimizer = Adam(adam_params)\n", + " for name, value in pyro.get_param_store().named_parameters():\n", + " if not name in gradient_norms:\n", + " value.register_hook(lambda g, name=name: gradient_norms[name].append(g.norm().item()))\n", + " \n", + " global model_log_prob\n", + " model_log_prob = []\n", + " global guide_log_prob\n", + " guide_log_prob = []\n", + " global approximation_log_prob\n", + " approximation_log_prob = []\n", + "\n", + " svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=relbo)\n", + " for step in range(n_steps):\n", + " loss = svi.step(y_train, X_train, approximation=wrapped_approximation, relbo_lambda=relbo_lambda)\n", + " losses.append(loss)\n", + "\n", + " if PRINT_INTERMEDIATE_LATENT_VALUES:\n", + " print('Loss: {}'.format(loss))\n", + " variance = pyro.param(\"variance_{}\".format(t)).item()\n", + " mu = pyro.param(\"locs_{}\".format(t)).item()\n", + " print('mu = {}'.format(mu))\n", + " print('variance = {}'.format(variance))\n", + "\n", + " if step % 100 == 0:\n", + " print('.', end=' ')\n", + "\n", + " # pyplot.plot(range(len(losses)), losses)\n", + " # pyplot.xlabel('Update Steps')\n", + " # pyplot.ylabel('-ELBO')\n", + " # pyplot.title('-ELBO against time for component {}'.format(t));\n", + " # pyplot.show()\n", + "\n", + " pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob')\n", + " pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob')\n", + " pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob')\n", + " pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO')\n", + " pyplot.xlabel('Update Steps')\n", + " pyplot.ylabel('Log Prob')\n", + " pyplot.title('RELBO components throughout SVI'.format(t));\n", + " pyplot.legend()\n", + " pyplot.show()\n", + "\n", + " wrapped_approximation.components.append(wrapped_guide)\n", + " new_weight = 2 / (t + 1)\n", + "\n", + " # if t == 2:\n", + " # new_weight = 0.05\n", + " weights = weights * (1-new_weight)\n", + " weights = torch.cat((weights, torch.tensor([new_weight])))\n", + "\n", + " wrapped_approximation.weights = weights\n", + "\n", + " e_log_p = 0\n", + " n_samples = 50\n", + " entropy = 0\n", + " model_log_likelihood = 0\n", + " elbo = 0\n", + " for i in range(n_samples):\n", + " qt_trace = trace(wrapped_approximation).get_trace(y_train, X_train)\n", + " replayed_model_trace = trace(replay(logistic_regression_model, qt_trace)).get_trace(y_train, X_train)\n", + " model_log_likelihood += replayed_model_trace.log_prob_sum()\n", + " entropy -= qt_trace.log_prob_sum()\n", + " elbo = elbo + replayed_model_trace.log_prob_sum() - qt_trace.log_prob_sum()\n", + "\n", + " duality_gap.append(elbo/n_samples)\n", + " model_log_likelihoods.append(model_log_likelihood/n_samples)\n", + " entropies.append(entropy/n_samples)\n", + "\n", + " # scale = pyro.param(\"variance_{}\".format(t)).item()\n", + " # scales.append(scale)\n", + " # loc = pyro.param(\"mu_{}\".format(t)).item()\n", + " # locs.append(loc)\n", + " # print('mu = {}'.format(loc))\n", + " # print('variance = {}'.format(scale))\n", + "\n", + " pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white')\n", + " for name, grad_norms in gradient_norms.items():\n", + " pyplot.plot(grad_norms, label=name)\n", + " pyplot.xlabel('iters')\n", + " pyplot.ylabel('gradient norm')\n", + " # pyplot.yscale('log')\n", + " pyplot.legend(loc='best')\n", + " pyplot.title('Gradient norms during SVI');\n", + " pyplot.show() \n", + "\n", + "\n", + " pyplot.plot(range(1, len(duality_gap) + 1), duality_gap, label='ELBO')\n", + " pyplot.plot(range(1, len(entropies) + 1), entropies, label='Entropy of q_t')\n", + " pyplot.plot(range(1, len(model_log_likelihoods) + 1),model_log_likelihoods, label='E[logp] w.r.t. q_t')\n", + " pyplot.title('ELBO(p, q_t)');\n", + " pyplot.legend();\n", + " pyplot.xlabel('Approximation components')\n", + " pyplot.ylabel('Log probability')\n", + " pyplot.show()\n", + "\n", + " for i in range(1, n_iterations + 1):\n", + " mu = pyro.param('locs_{}'.format(i))\n", + " sigma = pyro.param('scale_{}'.format(i))\n", + " print('Mu_{}: '.format(i))\n", + " print(mu)\n", + " print('Sigma{}: '.format(i))\n", + " print(sigma)\n", + "\n", + " wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_approximation, observations=y_test, input_data=X_test)\n", + " n_samples = 50\n", + " log_likelihood = 0\n", + " for i in range(n_samples):\n", + " predictive_trace = trace(wrapped_predictive_model).get_trace()\n", + " log_likelihood += predictive_trace.log_prob_sum()\n", + " print('Log prob on test data')\n", + " print(log_likelihood/n_samples)\n", + "\n", + "def run_mcmc():\n", + "\n", + " X_train, y_train, X_test, y_test = load_data()\n", + " nuts_kernel = NUTS(logistic_regression_model)\n", + "\n", + " mcmc = MCMC(nuts_kernel, num_samples=200, warmup_steps=100)\n", + " mcmc.run(y_train, X_train)\n", + "\n", + " hmc_samples = {k: v.detach().cpu().numpy() for k, v in mcmc.get_samples().items()}\n", + "\n", + " with open('hmc_samples.pkl', 'wb') as outfile:\n", + " pickle.dump(hmc_samples, outfile)\n", + "\n", + " for site, values in summary(hmc_samples).items():\n", + " print(\"Site: {}\".format(site))\n", + " print(values, \"\\n\")\n", + "\n", + "\n", + "def run_svi():\n", + " # setup the optimizer\n", + " X_train, y_train, X_test, y_test = load_data()\n", + " n_steps = 10000\n", + " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", + " optimizer = Adam(adam_params)\n", + "\n", + " # setup the inference algorithm\n", + " #wrapped_guide = partial(guide, index=0)\n", + " wrapped_guide = AutoDiagonalNormal(logistic_regression_model)\n", + " svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=Trace_ELBO())\n", + " losses = []\n", + " \n", + " # do gradient steps\n", + " for step in range(n_steps):\n", + " loss = svi.step(y_train, X_train)\n", + " losses.append(loss)\n", + " if step % 100 == 0:\n", + " print('.', end='')\n", + "\n", + " \n", + "\n", + " pyplot.plot(range(len(losses)), losses)\n", + " pyplot.xlabel('Update Steps')\n", + " pyplot.ylabel('-ELBO')\n", + " pyplot.title('-ELBO against time for component {}'.format(1));\n", + " pyplot.show()\n", + "\n", + " wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_guide, observations=y_test, input_data=X_test)\n", + " n_samples = 50\n", + " log_likelihood = 0\n", + " for i in range(n_samples):\n", + " predictive_trace = trace(wrapped_predictive_model).get_trace()\n", + " log_likelihood += predictive_trace.log_prob_sum()\n", + " print('Log prob on test data')\n", + " print(log_likelihood/n_samples)\n", + "\n", + "if __name__ == '__main__':\n", + " boosting_bbvi()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "file_extension": ".py", + "kernelspec": { + "display_name": "Python 3", + "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.7.5" + }, + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3 + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 01092e6c505b599a78d773740df8cbede8947809 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 11 Dec 2019 12:02:26 +0100 Subject: [PATCH 18/29] Rewrit explanations in bbbvi tutorial --- boosting_bbvi_tutorial.ipynb | 540 ++++++----------------------------- 1 file changed, 90 insertions(+), 450 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 000497a..e49e4ba 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -6,50 +6,55 @@ "source": [ "# Boosting Black Box Variational Inference\n", "## Introduction\n", - "This tutorial demonstrates how to implement boosting black box variational inference in Pyro. In comparison to standard variational inference, boosting VI approximates the target density with a mixture of density functions rather than a single density. It thus offers an easy way of getting more complex approximation of distributions in siutations where a single density doesn't approximate the target well enough.\n" + "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Infernce, we approximate a target distribution with a iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. \n", + "\n", + "## Contents\n", + "* [Theoretical Background](#theoretical-background)\n", + " - Variational Inference\n", + " - Boosting Black Box Variational Inference\n", + "* [BBBVI in Pyro](#bbbvi-pyro)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Theoretical Background\n", + "## Theoretical Background \n", "\n", "### Variational Inference\n", - "For an introduction to standard Variational Inference, we recommend first checking out [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html).\n", - "Recall that in standard Variational Inference, we maximize the Evidence Lower BOund (ELBO):\n", - "$$ E_s[\\text{log} p(x, z)] - E_s[\\text{log} s(z)]$$\n", + "For an introduction to regular Variational Inference, we recommend first having a look at [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html).\n", + "\n", + "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. First, one chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution.\n", + "This approximating density is found by maximizing the Evidence Lower BOund (ELBO):\n", + "$$ \\mathbb{E}_s[\\text{log} p(x, z)] - \\mathbb{E}_s[\\text{log} s(z)]$$\n", "\n", - "where $s(z)$ is the approximating distribution, the guide, and $p(x,z)$ the target distribution.\n", + "where $s(z)$ is the approximating density and $p(x,z)$ is the target distribution.\n", "\n", "### Boosting Black Box Variational Inference\n", "\n", - "In the boosting BBVI, we greedily components to our approximation by maximising the Residual ELBO (RELBO):\n", + "In boosting BBVI, the approximation takes the form:\n", + "$$\\sum_{i=1}^T \\gamma_t s_t(z)$$\n", "\n", - "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s] - E_s[\\text{log} q^t]$$\n", + "$$\\text{where} \\sum_{i=1}^T \\gamma_t =1$$\n", "\n", - "Roughly, the algorithm is thus the following:\n", + "and $s_t(z)$ are elements of the variational family.\n", "\n", - "```~python\n", - "initalize q_0\n", - "for t=1:T\n", - " Find s_t that maximizes RELBO\n", - " gamma = 2/(t+1)\n", - " q_t = (1 - gamma)*q_t + gamma*s_t\n", - " \n", - "```\n", + "The components of the approximation $s_t(z)$ are selected greedily components by maximising the Residual ELBO (RELBO):\n", "\n", - "where `q_t` is the approximation at time step `t`.\n", + "$$\\mathbb{E}_s[\\text{log} p(x,z)] - \\lambda \\mathbb{E}_s[\\text{log}s(z)] - \\mathbb{E}_s[\\text{log} q^t(z)]$$\n", "\n", - " \n", - "Conveniently, we do not need to make any additional assumptions about the variational family that's being used." + "It's called *black box* variational inference inference because this optimisation does not have to be tailored to the variational family which is being used. Setting $\\lambda$ to 1, regular SVI methods can be used to compute $$\\mathbb{E}_s[\\text{log} p(x,z)] - \\lambda \\mathbb{E}_s[\\text{log}s(z)]$$. See the explanation of the section on the implementation of the RELBO below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(z)]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", + "\n", + "In [1] a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBo.\n", + "\n", + " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## BBBVI in Pyro" + "## BBBVI in Pyro " ] }, { @@ -57,11 +62,11 @@ "metadata": {}, "source": [ "To implement boosting black box variational inference in Pyro, we need to consider the following three components:\n", - "- How to set up the guide and the approximation\n", - "- How to implement the RELBO\n", - "- How to run SVI and update the approximation\n", + "1. The approximation components (guides) and the approximation itself.\n", + "2. The RELBO.\n", + "3. Running SVI to find new components and update the approximation.\n", "\n", - "We will illustrate these points by looking at two examples. First, we will use BBBVI to approximate a bimodal posterior and then we'll use BBBVI for Bayesian Logistic Regression on the ChemReact data set.\n" + "We will illustrate these points by looking at simple example: approximating a bimodal posterior.\n" ] }, { @@ -73,14 +78,16 @@ "Boosting BBVI is particularly useful in situations where we're trying to approximate mulitmodal posteriors. In this tutorial, we'll thus consider the following model:\n", " \n", " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", - " $$y \\sim \\mathcal{N}(\\mu^2, 1)$$\n", + " $$y \\sim \\mathcal{N}(\\mu^2, 0.1)$$\n", " \n", - " Observing some data points around 4, we expect $p(mu|y)$ to be a bimodal distributions with means around -2 and + 2." + "Additionally, we have some observations of $y$ around +4. We thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around -2 and +2.\n", + " \n", + "In Pyro, this model takes the following shape:" ] }, { "cell_type": "code", - "execution_count": 178, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -89,7 +96,7 @@ " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", - " scale = torch.tensor([1.])\n", + " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", " # Local variables.\n", @@ -100,12 +107,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The Guide" + "### The Guide\n", + "\n", + "Next, we specify the guide which in our case will make up the compoents of our mixture. Recall that in Pyro the guide needs to take the same arguments as the model which is why our guide function also takes the data as an input. \n", + "\n", + "We also need to make sure that every `pyro.sample()` statement from the model has a matching `pyro.sample()` statement in the guide. In our case, we include `loc` in both the model and the guide.\n", + "\n", + "In contrast to regular SVI, our guide takes an additional argument: `index`. Having this argument allows us to easily create new guides in each iteration of the greedy algorithm. In particular, we use make use of `partial()` from the [functools library](https://docs.python.org/3.7/library/functools.html) to create guides which only take `data` as an argument. The statement `partial(guide, index=t)` creates a guide that will take only `data` as an input and which has trainable parameters `scale_t` and `loc_t`.\n", + "\n", + "Putting all of this together, we get the following guide:" ] }, { "cell_type": "code", - "execution_count": 180, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -119,12 +134,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The RELBO" + "### The RELBO\n", + "\n", + "We implement a modified ELBO function which we then pass to Pyro's SVI class to do the heavy lifting for us.\n", + "\n", + "Conveniently, the RELBO is very similar to the normal ELBO which allows us to reuse the Pyro's existing ELBO to compute part of it. Specifically, we compute \n", + "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s]$$\n", + "using `Trace_ELBO` and then compute \n", + "$$ - E_s[\\text{log} q^t]$$\n", + "using Poutine. For some background on how this works, we recommend going through the tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." ] }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -136,23 +159,19 @@ " # i.e. record all the calls to Pyro primitives like sample() and param().\n", " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", - " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", - "\n", - "\n", - "\n", - " approximation_trace = trace(replay(block(approximation, expose=['loc']), guide_trace)).get_trace(*args, **kwargs)\n", + " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", + " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", " # We will acculoclate the various terms of the ELBO in `elbo`.\n", "\n", - " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", - " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum()\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", - " guide,\n", - " *args, **kwargs)\n", + " guide,\n", + " *args,\n", + " **kwargs)\n", "\n", - " elbo = -loss_fn - 0.1 * approximation_trace.log_prob_sum()\n", + " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", "\n", - " return -elbo " + " return -elbo" ] }, { @@ -163,27 +182,24 @@ ] }, { - "cell_type": "code", - "execution_count": 169, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "def approximation(data, components, weights):\n", - " assignment = pyro.sample('assignment', dist.Categorical(weights))\n", - " result = components[assignment](data)\n", - " return result " + "Our approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample an index of a component according to the mixture weights. In a second step, we get a sample from the corresponding component.\n", + "\n", + "Similarly as with the guide, we use `partial(approximation, components=components, weights=weights)` to get an approximation function which has the same signature as the model." ] }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 169, "metadata": {}, "outputs": [], "source": [ - "def dummy_approximation(data):\n", - " scale_q = pyro.param('scale_0', torch.tensor([1.0]), constraints.positive)\n", - " loc_q = pyro.param('loc_0', torch.tensor([20.0]))\n", - " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))" + "def approximation(data, components, weights):\n", + " assignment = pyro.sample('assignment', dist.Categorical(weights))\n", + " result = components[assignment](data)\n", + " return result " ] }, { @@ -195,22 +211,22 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = 1.9530718326568604\n", - "scale = 0.09594951570034027\n", - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = -2.3136916160583496\n", - "scale = 0.17421917617321014\n" + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = -2.01552677154541\n", + "scale = 0.03500283882021904\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = 2.0315308570861816\n", + "scale = 0.04819779098033905\n" ] }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA18AAAFuCAYAAAB+/6JIAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdeXxTVfo/8M/Nnq60lK6WUhARBKS0yCZTGKDK6oIgILuggIKIqPDlp4Ay7GodGVAUUWQRFVwYFCxKEYZFZBsBFxzRIm3ZhLbQLE1yfn8kuZAmaZNSGmw+79crrzYnJ/c+SW7TPDnPPUcSQggQERERERHRdaUIdABERERERETBgMkXERERERFRDWDyRUREREREVAOYfBEREREREdUAJl9EREREREQ1gMkXERERERFRDWDyRUREREREVAOYfBEREREREdUAJl9EREREREQ1gMkXURD75z//CUmS0Lx580CHct00aNAAI0aMCMi+16xZg+zsbI+3SZKEmTNn1mxAfvrqq6+QkZGB0NBQSJKETz75JNAhuajo+a0OgTx2blQzZ86EJEmBDsMnI0aMQIMGDVza5syZ4/E4fueddyBJEr777rsq7SuQz8u1xg4AnTt3RufOnasvKB+sXLkSAwcORJMmTaBQKNxeK6LaShXoAIgocN5++20AwNGjR7F37160bds2wBFVv48//hgREREB2feaNWtw5MgRTJo0ye223bt346abbgpAVL4RQmDAgAG45ZZb8NlnnyE0NBRNmjQJdFguKnp+q0Mgjx26ds899xyeeOIJl7Y5c+bggQcewL333hugqMjpvffeQ2FhIe644w7YbDaUlZUFOiSiGsHkiyhIfffddzh8+DB69eqFTZs2Yfny5QFNvgwGA/R6fbVvNy0trdq3WR3atWsX6BAqlJ+fjz///BP33XcfunbtGuhwapTzWKzOY8dqtcJisUCr1VbbNq+X0tJShISEBDqMa9aoUaNAh0AV2LJlCxQKewFW7969ceTIkQBHRFQzWHZIFKSWL18OAJg3bx46dOiA999/H6WlpS59fvvtN0iShAULFuAf//gH6tevD51Oh4yMDHz11VcufZ1lNwcPHsT999+PiIgIREZGYsiQITh79qxL3wYNGqB3797YsGED0tLSoNPpMGvWLACA0WjEtGnTkJqa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\n", + "image/png": "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nj175OmCla1Tp07Q6XQYMGAAXn75ZRQWFmLx4sXydDlbTZo0wcaNG7F48WIkJCRApVIhMTHR6X6nT5+O//znP2jfvj1ef/11hIaGYs2aNdi8eTPmzZuH4ODgSok/LS0NnTp1Qvv27TF58mTodDosWrQIx44dw7p1626pCnL+/Hk8+eSTGDVqFK5evYrp06fD19cXU6dOBWBpLT1v3jw888wz6N69O/7+97+jqKgI8+fPx5UrV+TW2levXkX79u0xcOBAPPjggwgKCsLBgwexZcsWPPXUU/LxSnt9+/fvjzVr1qBr16548cUX8cgjj0Cr1eLPP//Ezp078cQTT+DJJ590+/lNnDgRq1atQrdu3TBr1ixER0dj8+bNWLRoEcaMGVPhxNXV895qwIABSE1NxYABA1BUVOSw3qpNmzZ47rnnMHz4cHz//fd47LHHEBAQgNzcXOzZswdNmjTBmDFjKhSrvQceeADPPfcc3n33XahUKnTp0gV//PEHXnvtNURFRWHixIkALOv63nzzTYwcORIdO3bEqFGjULt2bfz66684evQo3nvvvTKP06FDB5hMJmzfvl3Rar1jx46YPn06JElyad1akyZNkJWVhU2bNiEiIgJBQUG35eLhSUlJCAkJwejRozF9+nRotVqsWbMGR48erfRjWX3//fcYOXIknn76aZw5cwbTpk1DZGQkxo4dC8BS+Z48eTJmz56tGDdjxgyHaYfWyy+MHTsWffr0wZkzZ/CPf/wDERERDuuCK/r6nThxAidOnABgSewKCgrk2RiNGzdG48aNK7RfoirPM30+iMgTevXqJXQ6nTh//nypY/r37y80Go3Iy8uTu7bNnTtXzJw5U9StW1fodDoRHx8vtm7dqvg+a7evQ4cOiR49eojAwEARFBQkBgwYIM6dO6cYGx0dLbp16+b0+Ddv3hSvvPKKiI6OFlqtVkRERIgxY8Yo2iVPmzZNqFQqhw5te/fuFRqNRrz44ouKYznrdvjJJ58ovtfaMezgwYNOn5dty+xNmzaJhx9+WPj6+orIyEjx0ksvia+//loAEDt37pTHXbp0SfTp00dUr15dSJKk6IYGu26HQgjx008/iR49eojg4GCh0+nEww8/LJYvX64YU1r81p+V/Xhndu/eLf72t7+JgIAA4efnJ1q1aiU2bdrkdH/udDv86KOPxPjx40XNmjWFj4+PaNu2raIlttXnn38uWrZsKXx9fUVAQIDo0KGDomV4YWGhGD16tGjatKmoVq2a8PPzEw888ICYPn26uHHjhjyurNfXYDCIBQsWyD+nwMBA8eCDD4q///3v4pdffpHHlXUu2p87Qghx+vRpMXDgQFGjRg2h1WrFAw88IObPn6/o3ujOa2flynlva+DAgQKAaNOmTan7XLZsmWjZsqX8c27QoIEYMmSI4meSnJwsHnroIZfjdNbVz2Qyiblz54r7779faLVaERYWJgYNGiTOnDnj8P1fffWVSE5OFgEBAcLf3180btxYcSmF0pjNZhEWFiYAiLNnz8rbrZ36mjdv7vA9zrod/vDDD6JNmzbC399f0eGvtN9/67lt+3vtjLPXZe/evaJ169bC399f1KxZU4wcOVIcPnzY4fd06NChIiAgwGGfpf1s7M9Za+zffPONGDx4sKhevbrcUt/2XBfC8jqmpaWJqKgoodPpRNOmTcWmTZtEcnKyQ7fDOXPmiJiYGOHj4yMaNWokPvjgg3K7OrrDui9nN/u/jUT3EkmICtT/icgr/PHHH4iNjcX8+fMdLmhsb8aMGZg5cyb++uuvSlmfRHePrKwstG/fHp988oncuIWIiIgccc0XERERERHRHcDki4iIiIiI6A7gtEMiIiIiIqI7gJUvIiIiIiKiO4DJFxERERER0R3A5IuIiIiIiOgO4EWWK8hsNiMnJwdBQUG3dFFSIiIiIiK6uwkhcO3aNdSpUwcqVen1LSZfFZSTk4OoqChPh0FERERERFXEmTNnULdu3VIfZ/JVQUFBQQAsL3C1atU8HA0REREREXlKfn4+oqKi5ByhNEy+Ksg61bBatWpMvoiIiIiIqNzlSGy4QUREREREdAcw+SIiIiIiIroDmHwRERERERHdAUy+iIiIiIiI7gAmX0RERERERHcAky8iIiIiIqI7gMkXERERERHRHcDki4iIiIiI6A5g8kVERERERHQHMPkiIiKXmc1mT4dARER012LyRURELpnw9b/w8IrW2HTyoKdDISIiuisx+SIiIpccPn8AUBdg5x/feToUIiKiuxKTLyIicokQlimHRk49JCIiqhAmX0RE5BIzTAAAkzB5OBIiIqK7E5MvIiJyibXyZRasfBEREVWEx5OvRYsWITY2Fr6+vkhISMDu3btLHXv8+HH07t0bMTExkCQJ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\n", "text/plain": [ "
" ] @@ -220,26 +236,19 @@ } ], "source": [ - "\"\"\"\n", - "\n", - "\"\"\"\n", - "import math\n", "import os\n", "from collections import defaultdict\n", "from functools import partial\n", "\n", - "import matplotlib\n", "import numpy as np\n", "import pyro\n", "import pyro.distributions as dist\n", "import scipy.stats\n", - "import torch\n", + "import torch \n", "import torch.distributions.constraints as constraints\n", "from matplotlib import pyplot\n", - "from pyro import poutine\n", - "from pyro.infer import SVI, Trace_ELBO, TraceEnum_ELBO, config_enumerate\n", - "from pyro.infer.autoguide import AutoDelta\n", - "from pyro.optim import SGD, Adam\n", + "from pyro.infer import SVI, Trace_ELBO\n", + "from pyro.optim import Adam\n", "from pyro.poutine import block, replay, trace\n", "\n", "# this is for running the notebook in our testing framework\n", @@ -253,11 +262,11 @@ "# clear the param store in case we're in a REPL\n", "pyro.clear_param_store()\n", "\n", - "data = torch.tensor([4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3])\n", + "data = torch.tensor([4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3]*10)\n", "\n", "def guide(data, index):\n", " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", - " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([1.0]))\n", + " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([0.0]))\n", " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", "\n", "def model(data):\n", @@ -265,7 +274,7 @@ " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", - " scale = torch.tensor([1.])\n", + " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", " # Local variables.\n", @@ -279,23 +288,17 @@ " # i.e. record all the calls to Pyro primitives like sample() and param().\n", " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", - " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", - "\n", - "\n", " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", " # We will acculoclate the various terms of the ELBO in `elbo`.\n", "\n", - " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", - " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum()\\\n", - " - approximation_trace.log_prob_sum()\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", " guide,\n", " *args,\n", " **kwargs)\n", "\n", - " elbo = -loss_fn - 0.1 * approximation_trace.log_prob_sum()\n", + " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", "\n", " return -elbo\n", "\n", @@ -312,7 +315,7 @@ "def boosting_bbvi():\n", " n_iterations = 2\n", " relbo_lambda = 1\n", - " initial_approximation = dummy_approximation\n", + " initial_approximation = partial(guide, index=0)\n", " components = [initial_approximation]\n", " weights = torch.tensor([1.])\n", " wrapped_approximation = partial(approximation, components=components, weights=weights)\n", @@ -320,7 +323,6 @@ " locs = [0]\n", " scales = [0]\n", "\n", - " gradient_norms = defaultdict(list)\n", " duality_gap = []\n", " entropies = []\n", " model_log_likelihoods = []\n", @@ -331,7 +333,7 @@ " losses = []\n", " # Register hooks to monitor gradient norms.\n", "\n", - " adam_params = {\"lr\": 0.002, \"betas\": (0.90, 0.999)}\n", + " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", " optimizer = Adam(adam_params)\n", "\n", " svi = SVI(model, wrapped_guide, optimizer, loss=relbo)\n", @@ -381,374 +383,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Bayesian Logistic Regression" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "## import math\n", - "import os\n", - "import torch\n", - "import torch.distributions.constraints as constraints\n", - "import pyro\n", - "from pyro.optim import Adam, SGD\n", - "from pyro.infer import SVI, Trace_ELBO, config_enumerate, TraceEnum_ELBO, Predictive\n", - "import pyro.distributions as dist\n", - "from pyro.infer.autoguide import AutoDelta\n", - "from pyro import poutine \n", - "from pyro.poutine import trace, replay, block\n", - "from functools import partial\n", - "import numpy as np\n", - "import scipy.stats\n", - "from pyro.infer.autoguide import AutoDelta\n", - "from collections import defaultdict\n", - "import matplotlib\n", - "from matplotlib import pyplot\n", - "from pyro.infer import MCMC, NUTS\n", - "import pandas as pd\n", - "import pickle\n", - "from pyro.infer.autoguide import AutoDiagonalNormal\n", - "import inspect\n", - "from bbbvi import relbo, Approximation\n", - "\n", - "PRINT_INTERMEDIATE_LATENT_VALUES = False\n", - "PRINT_TRACES = False\n", - "\n", - "# this is for running the notebook in our testing framework\n", - "smoke_test = ('CI' in os.environ)\n", - "n_steps = 2 if smoke_test else 10000\n", - "pyro.set_rng_seed(2)\n", - "\n", - "# enable validation (e.g. validate parameters of distributions)\n", - "pyro.enable_validation(True)\n", + "### References\n", "\n", - "# clear the param store in case we're in a REPL\n", - "pyro.clear_param_store()\n", - "\n", - "model_log_prob = []\n", - "guide_log_prob = []\n", - "approximation_log_prob = []\n", - "\n", - "class Guide:\n", - " def __init__(self, index, n_variables, initial_loc=None, initial_scale=None):\n", - " self.index = index\n", - " self.n_variables = n_variables\n", - " if not initial_loc:\n", - " self.initial_loc = torch.zeros(n_variables)\n", - " self.initial_scale = torch.ones(n_variables)\n", - " else:\n", - " self.initial_scale = initial_scale\n", - " self.initial_loc = initial_loc \n", - "\n", - " def get_distribution(self):\n", - " scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive)\n", - " #scale_q = torch.eye(self.n_variables)\n", - " locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc)\n", - " return dist.Laplace(locs_q, scale_q).to_event(1)\n", - "\n", - " def __call__(self, observations, input_data):\n", - " distribution = self.get_distribution()\n", - " w = pyro.sample(\"w\", distribution)\n", - " return w\n", - " \n", - "def logistic_regression_model(observations, input_data):\n", - " w = pyro.sample('w', dist.Laplace(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1))\n", - " with pyro.plate(\"data\", input_data.shape[0]):\n", - " sigmoid = torch.sigmoid(torch.matmul(input_data, w.double()))\n", - " obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations)\n", - "\n", - "# @config_enumerate\n", - "# def approximation(observations, input_data, components, weights):\n", - "# assignment = pyro.sample('assignment', dist.Categorical(weights))\n", - "# distribution = components[assignment].get_distribution()\n", - "# w = pyro.sample(\"w\", distribution)\n", - "# return w\n", - "\n", - "def dummy_approximation(observations, input_data):\n", - " variance_q = pyro.param('variance_0', torch.eye(input_data.shape[1]), constraints.positive)\n", - " mu_q = pyro.param('mu_0', 100*torch.ones(input_data.shape[1]))\n", - " pyro.sample(\"w\", dist.MultivariateNormal(mu_q, variance_q))\n", - "\n", - "def predictive_model(wrapped_approximation, observations, input_data):\n", - " w = wrapped_approximation(observations, input_data)\n", - " if type(w) is dict:\n", - " w = w['w']\n", - " with pyro.plate(\"data\", input_data.shape[0]):\n", - " sigmoid = torch.sigmoid(torch.matmul(input_data, w.double()))\n", - " obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations)\n", - "\n", - "\n", - "# Utility function to print latent sites' quantile information.\n", - "def summary(samples):\n", - " site_stats = {}\n", - " for site_name, values in samples.items():\n", - " marginal_site = pd.DataFrame(values)\n", - " describe = marginal_site.describe(percentiles=[.05, 0.25, 0.5, 0.75, 0.95]).transpose()\n", - " site_stats[site_name] = describe[[\"mean\", \"std\", \"5%\", \"25%\", \"50%\", \"75%\", \"95%\"]]\n", - " return site_stats\n", - "\n", - "def load_data():\n", - " npz_train_file = np.load('ds1.100_train.npz')\n", - " npz_test_file = np.load('ds1.100_test.npz')\n", - "\n", - " X_train = torch.tensor(npz_train_file['X']).double()\n", - " y_train = torch.tensor(npz_train_file['y']).double()\n", - " y_train[y_train == -1] = 0\n", - " X_test = torch.tensor(npz_test_file['X']).double()\n", - " y_test = torch.tensor(npz_test_file['y']).double()\n", - " y_test[y_test == -1] = 0\n", - "\n", - " return X_train, y_train, X_test, y_test\n", - "\n", - "\n", - "def relbo(model, guide, *args, **kwargs):\n", - "\n", - " approximation = kwargs.pop('approximation', None)\n", - " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", - " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", - " # i.e. record all the calls to Pyro primitives like sample() and param().\n", - " #print(\"enter relbo\")\n", - " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", - " #print(guide_trace.nodes['obs_1'])\n", - " model_trace = trace(replay(model, guide_trace)).get_trace(*args, **kwargs)\n", - " #print(model_trace.nodes['obs_1'])\n", - "\n", - "\n", - " approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs)\n", - " # We will accumulate the various terms of the ELBO in `elbo`.\n", + "[1] Locatello, Francesco, et al. \"Boosting black box variational inference.\" Advances in Neural Information Processing Systems. 2018.\n", "\n", - " guide_log_prob.append(guide_trace.log_prob_sum())\n", - " model_log_prob.append(model_trace.log_prob_sum())\n", - " approximation_log_prob.append(approximation_trace.log_prob_sum())\n", - "\n", - " # This is how we computed the ELBO before using TraceEnum_ELBO:\n", - " elbo = model_trace.log_prob_sum() - relbo_lambda * guide_trace.log_prob_sum() - approximation_trace.log_prob_sum()\n", - "\n", - " loss_fn = pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", - " guide,\n", - " *args, **kwargs)\n", - "\n", - " # print(loss_fn)\n", - " # print(approximation_trace.log_prob_sum())\n", - " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", - " #elbo = -loss_fn + 0.1 * pyro.infer.TraceEnum_ELBO(max_plate_nesting=1).differentiable_loss(approximation,\n", - " # guide,\n", - " # *args, **kwargs)\n", - " # Return (-elbo) since by convention we do gradient descent on a loss and\n", - " # the ELBO is a lower bound that needs to be maximized.\n", - "\n", - " return -elbo\n", - "\n", - "def boosting_bbvi():\n", - "\n", - " n_iterations = 2\n", - " X_train, y_train, X_test, y_test = load_data()\n", - " relbo_lambda = 1\n", - " #initial_approximation = Guide(index=0, n_variables=X_train.shape[1])\n", - " initial_approximation = dummy_approximation\n", - " components = [initial_approximation]\n", - "\n", - " weights = torch.tensor([1.])\n", - " wrapped_approximation = Approximation(components, weights)\n", - "\n", - " locs = [0]\n", - " scales = [0]\n", - "\n", - " gradient_norms = defaultdict(list)\n", - " duality_gap = []\n", - " model_log_likelihoods = []\n", - " entropies = []\n", - " for t in range(1, n_iterations + 1):\n", - " # setup the inference algorithm\n", - " wrapped_guide = Guide(index=t, n_variables=X_train.shape[1])\n", - " # do gradient steps\n", - " losses = []\n", - " # Register hooks to monitor gradient norms.\n", - " wrapped_guide(y_train, X_train)\n", - "\n", - " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", - " optimizer = Adam(adam_params)\n", - " for name, value in pyro.get_param_store().named_parameters():\n", - " if not name in gradient_norms:\n", - " value.register_hook(lambda g, name=name: gradient_norms[name].append(g.norm().item()))\n", - " \n", - " global model_log_prob\n", - " model_log_prob = []\n", - " global guide_log_prob\n", - " guide_log_prob = []\n", - " global approximation_log_prob\n", - " approximation_log_prob = []\n", - "\n", - " svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=relbo)\n", - " for step in range(n_steps):\n", - " loss = svi.step(y_train, X_train, approximation=wrapped_approximation, relbo_lambda=relbo_lambda)\n", - " losses.append(loss)\n", - "\n", - " if PRINT_INTERMEDIATE_LATENT_VALUES:\n", - " print('Loss: {}'.format(loss))\n", - " variance = pyro.param(\"variance_{}\".format(t)).item()\n", - " mu = pyro.param(\"locs_{}\".format(t)).item()\n", - " print('mu = {}'.format(mu))\n", - " print('variance = {}'.format(variance))\n", - "\n", - " if step % 100 == 0:\n", - " print('.', end=' ')\n", - "\n", - " # pyplot.plot(range(len(losses)), losses)\n", - " # pyplot.xlabel('Update Steps')\n", - " # pyplot.ylabel('-ELBO')\n", - " # pyplot.title('-ELBO against time for component {}'.format(t));\n", - " # pyplot.show()\n", - "\n", - " pyplot.plot(range(len(guide_log_prob)), -1 * np.array(guide_log_prob), 'b-', label='- Guide log prob')\n", - " pyplot.plot(range(len(approximation_log_prob)), -1 * np.array(approximation_log_prob), 'r-', label='- Approximation log prob')\n", - " pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob), 'g-', label='Model log prob')\n", - " pyplot.plot(range(len(model_log_prob)), np.array(model_log_prob) -1 * np.array(approximation_log_prob) -1 * np.array(guide_log_prob), label='RELBO')\n", - " pyplot.xlabel('Update Steps')\n", - " pyplot.ylabel('Log Prob')\n", - " pyplot.title('RELBO components throughout SVI'.format(t));\n", - " pyplot.legend()\n", - " pyplot.show()\n", - "\n", - " wrapped_approximation.components.append(wrapped_guide)\n", - " new_weight = 2 / (t + 1)\n", - "\n", - " # if t == 2:\n", - " # new_weight = 0.05\n", - " weights = weights * (1-new_weight)\n", - " weights = torch.cat((weights, torch.tensor([new_weight])))\n", - "\n", - " wrapped_approximation.weights = weights\n", - "\n", - " e_log_p = 0\n", - " n_samples = 50\n", - " entropy = 0\n", - " model_log_likelihood = 0\n", - " elbo = 0\n", - " for i in range(n_samples):\n", - " qt_trace = trace(wrapped_approximation).get_trace(y_train, X_train)\n", - " replayed_model_trace = trace(replay(logistic_regression_model, qt_trace)).get_trace(y_train, X_train)\n", - " model_log_likelihood += replayed_model_trace.log_prob_sum()\n", - " entropy -= qt_trace.log_prob_sum()\n", - " elbo = elbo + replayed_model_trace.log_prob_sum() - qt_trace.log_prob_sum()\n", - "\n", - " duality_gap.append(elbo/n_samples)\n", - " model_log_likelihoods.append(model_log_likelihood/n_samples)\n", - " entropies.append(entropy/n_samples)\n", - "\n", - " # scale = pyro.param(\"variance_{}\".format(t)).item()\n", - " # scales.append(scale)\n", - " # loc = pyro.param(\"mu_{}\".format(t)).item()\n", - " # locs.append(loc)\n", - " # print('mu = {}'.format(loc))\n", - " # print('variance = {}'.format(scale))\n", - "\n", - " pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white')\n", - " for name, grad_norms in gradient_norms.items():\n", - " pyplot.plot(grad_norms, label=name)\n", - " pyplot.xlabel('iters')\n", - " pyplot.ylabel('gradient norm')\n", - " # pyplot.yscale('log')\n", - " pyplot.legend(loc='best')\n", - " pyplot.title('Gradient norms during SVI');\n", - " pyplot.show() \n", - "\n", - "\n", - " pyplot.plot(range(1, len(duality_gap) + 1), duality_gap, label='ELBO')\n", - " pyplot.plot(range(1, len(entropies) + 1), entropies, label='Entropy of q_t')\n", - " pyplot.plot(range(1, len(model_log_likelihoods) + 1),model_log_likelihoods, label='E[logp] w.r.t. q_t')\n", - " pyplot.title('ELBO(p, q_t)');\n", - " pyplot.legend();\n", - " pyplot.xlabel('Approximation components')\n", - " pyplot.ylabel('Log probability')\n", - " pyplot.show()\n", - "\n", - " for i in range(1, n_iterations + 1):\n", - " mu = pyro.param('locs_{}'.format(i))\n", - " sigma = pyro.param('scale_{}'.format(i))\n", - " print('Mu_{}: '.format(i))\n", - " print(mu)\n", - " print('Sigma{}: '.format(i))\n", - " print(sigma)\n", - "\n", - " wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_approximation, observations=y_test, input_data=X_test)\n", - " n_samples = 50\n", - " log_likelihood = 0\n", - " for i in range(n_samples):\n", - " predictive_trace = trace(wrapped_predictive_model).get_trace()\n", - " log_likelihood += predictive_trace.log_prob_sum()\n", - " print('Log prob on test data')\n", - " print(log_likelihood/n_samples)\n", - "\n", - "def run_mcmc():\n", - "\n", - " X_train, y_train, X_test, y_test = load_data()\n", - " nuts_kernel = NUTS(logistic_regression_model)\n", - "\n", - " mcmc = MCMC(nuts_kernel, num_samples=200, warmup_steps=100)\n", - " mcmc.run(y_train, X_train)\n", - "\n", - " hmc_samples = {k: v.detach().cpu().numpy() for k, v in mcmc.get_samples().items()}\n", - "\n", - " with open('hmc_samples.pkl', 'wb') as outfile:\n", - " pickle.dump(hmc_samples, outfile)\n", - "\n", - " for site, values in summary(hmc_samples).items():\n", - " print(\"Site: {}\".format(site))\n", - " print(values, \"\\n\")\n", - "\n", - "\n", - "def run_svi():\n", - " # setup the optimizer\n", - " X_train, y_train, X_test, y_test = load_data()\n", - " n_steps = 10000\n", - " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", - " optimizer = Adam(adam_params)\n", - "\n", - " # setup the inference algorithm\n", - " #wrapped_guide = partial(guide, index=0)\n", - " wrapped_guide = AutoDiagonalNormal(logistic_regression_model)\n", - " svi = SVI(logistic_regression_model, wrapped_guide, optimizer, loss=Trace_ELBO())\n", - " losses = []\n", - " \n", - " # do gradient steps\n", - " for step in range(n_steps):\n", - " loss = svi.step(y_train, X_train)\n", - " losses.append(loss)\n", - " if step % 100 == 0:\n", - " print('.', end='')\n", - "\n", - " \n", - "\n", - " pyplot.plot(range(len(losses)), losses)\n", - " pyplot.xlabel('Update Steps')\n", - " pyplot.ylabel('-ELBO')\n", - " pyplot.title('-ELBO against time for component {}'.format(1));\n", - " pyplot.show()\n", - "\n", - " wrapped_predictive_model = partial(predictive_model, wrapped_approximation=wrapped_guide, observations=y_test, input_data=X_test)\n", - " n_samples = 50\n", - " log_likelihood = 0\n", - " for i in range(n_samples):\n", - " predictive_trace = trace(wrapped_predictive_model).get_trace()\n", - " log_likelihood += predictive_trace.log_prob_sum()\n", - " print('Log prob on test data')\n", - " print(log_likelihood/n_samples)\n", - "\n", - "if __name__ == '__main__':\n", - " boosting_bbvi()" + "[2] Ranganath, Rajesh, Sean Gerrish, and David Blei. \"Black box variational inference.\" Artificial Intelligence and Statistics. 2014." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 708780a9864537acbdaa11be717c2b8641b2a916 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 11 Dec 2019 13:33:59 +0100 Subject: [PATCH 19/29] Add list of contents and comments --- boosting_bbvi_tutorial.ipynb | 115 +++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index e49e4ba..05ed9cc 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -6,13 +6,18 @@ "source": [ "# Boosting Black Box Variational Inference\n", "## Introduction\n", - "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Infernce, we approximate a target distribution with a iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. \n", + "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Inference [2], we approximate a target distribution with a iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. We show how this can be implement as a relatively simple extension of Pyro's SVI.\n", "\n", "## Contents\n", "* [Theoretical Background](#theoretical-background)\n", - " - Variational Inference\n", - " - Boosting Black Box Variational Inference\n", - "* [BBBVI in Pyro](#bbbvi-pyro)" + " - [Variational Inference](#variational-inference)\n", + " - [Boosting Black Box Variational Inference](#bbbvi)\n", + "* [BBBVI in Pyro](#bbbvi-pyro)\n", + " - [The Model](#the-model)\n", + " - [The Guide](#the-guide)\n", + " - [The Relbo](#the-relbo)\n", + " - [The Approximation](#the-approximation)\n", + " - [The Greedy Algorithm](#the-greedy-algorithm)" ] }, { @@ -21,7 +26,7 @@ "source": [ "## Theoretical Background \n", "\n", - "### Variational Inference\n", + "### Variational Inference \n", "For an introduction to regular Variational Inference, we recommend first having a look at [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html).\n", "\n", "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. First, one chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution.\n", @@ -30,7 +35,7 @@ "\n", "where $s(z)$ is the approximating density and $p(x,z)$ is the target distribution.\n", "\n", - "### Boosting Black Box Variational Inference\n", + "### Boosting Black Box Variational Inference \n", "\n", "In boosting BBVI, the approximation takes the form:\n", "$$\\sum_{i=1}^T \\gamma_t s_t(z)$$\n", @@ -45,9 +50,7 @@ "\n", "It's called *black box* variational inference inference because this optimisation does not have to be tailored to the variational family which is being used. Setting $\\lambda$ to 1, regular SVI methods can be used to compute $$\\mathbb{E}_s[\\text{log} p(x,z)] - \\lambda \\mathbb{E}_s[\\text{log}s(z)]$$. See the explanation of the section on the implementation of the RELBO below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(z)]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", "\n", - "In [1] a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBo.\n", - "\n", - " \n" + "In [1] a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBo." ] }, { @@ -64,7 +67,7 @@ "To implement boosting black box variational inference in Pyro, we need to consider the following three components:\n", "1. The approximation components (guides) and the approximation itself.\n", "2. The RELBO.\n", - "3. Running SVI to find new components and update the approximation.\n", + "3. Using SVI to find new components and update the approximation.\n", "\n", "We will illustrate these points by looking at simple example: approximating a bimodal posterior.\n" ] @@ -73,7 +76,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The Model\n", + "### The Model \n", "\n", "Boosting BBVI is particularly useful in situations where we're trying to approximate mulitmodal posteriors. In this tutorial, we'll thus consider the following model:\n", " \n", @@ -87,19 +90,17 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "def model(data):\n", - " # Global variables.\n", " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", - " # Local variables.\n", " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)" ] }, @@ -107,7 +108,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The Guide\n", + "### The Guide \n", "\n", "Next, we specify the guide which in our case will make up the compoents of our mixture. Recall that in Pyro the guide needs to take the same arguments as the model which is why our guide function also takes the data as an input. \n", "\n", @@ -115,7 +116,7 @@ "\n", "In contrast to regular SVI, our guide takes an additional argument: `index`. Having this argument allows us to easily create new guides in each iteration of the greedy algorithm. In particular, we use make use of `partial()` from the [functools library](https://docs.python.org/3.7/library/functools.html) to create guides which only take `data` as an argument. The statement `partial(guide, index=t)` creates a guide that will take only `data` as an input and which has trainable parameters `scale_t` and `loc_t`.\n", "\n", - "Putting all of this together, we get the following guide:" + "Choosing our variational distribution to be a Normal distribution parameterized by $loc_t$ and $scale_t$ we get the following guide:" ] }, { @@ -126,7 +127,7 @@ "source": [ "def guide(data, index):\n", " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", - " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([1.0]))\n", + " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([0.0]))\n", " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))" ] }, @@ -134,35 +135,34 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The RELBO\n", + "### The RELBO \n", "\n", - "We implement a modified ELBO function which we then pass to Pyro's SVI class to do the heavy lifting for us.\n", + "We implement a modified ELBO function, the RELBO, which we then pass to Pyro's SVI class to find the approximation components $s_t(z)$\n", "\n", "Conveniently, the RELBO is very similar to the normal ELBO which allows us to reuse the Pyro's existing ELBO to compute part of it. Specifically, we compute \n", "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s]$$\n", "using `Trace_ELBO` and then compute \n", "$$ - E_s[\\text{log} q^t]$$\n", - "using Poutine. For some background on how this works, we recommend going through the tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." + "using Poutine. For more information on how this works, we recommend going through the tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "def relbo(model, guide, *args, **kwargs):\n", "\n", " approximation = kwargs.pop('approximation', None)\n", - " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", " # i.e. record all the calls to Pyro primitives like sample() and param().\n", " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", + " # We do not want to update parameters of previously fitted components and thus block all\n", + " # parameters in the approximation apart from loc.\n", " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", - " # We will acculoclate the various terms of the ELBO in `elbo`.\n", - "\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", " guide,\n", @@ -178,14 +178,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The Approximation" + "### The Approximation " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Our approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample an index of a component according to the mixture weights. In a second step, we get a sample from the corresponding component.\n", + "Our implementation of the approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample an index of a component according to the mixture weights. In a second step, we get a sample from the corresponding component.\n", "\n", "Similarly as with the guide, we use `partial(approximation, components=components, weights=weights)` to get an approximation function which has the same signature as the model." ] @@ -206,27 +206,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### The Greedy Algorithm" + "### The Greedy Algorithm " ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = -2.01552677154541\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 1:\n", + "loc = -2.01552677154541\n", "scale = 0.03500283882021904\n", - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . loc = 2.0315308570861816\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 2:\n", + "loc = 2.0315308570861816\n", "scale = 0.04819779098033905\n" ] }, { "data": { - "image/png": "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nj175OmCla1Tp07Q6XQYMGAAXn75ZRQWFmLx4sXydDlbTZo0wcaNG7F48WIkJCRApVIhMTHR6X6nT5+O//znP2jfvj1ef/11hIaGYs2aNdi8eTPmzZuH4ODgSok/LS0NnTp1Qvv27TF58mTodDosWrQIx44dw7p1626pCnL+/Hk8+eSTGDVqFK5evYrp06fD19cXU6dOBWBpLT1v3jw888wz6N69O/7+97+jqKgI8+fPx5UrV+TW2levXkX79u0xcOBAPPjggwgKCsLBgwexZcsWPPXUU/LxSnt9+/fvjzVr1qBr16548cUX8cgjj0Cr1eLPP//Ezp078cQTT+DJJ590+/lNnDgRq1atQrdu3TBr1ixER0dj8+bNWLRoEcaMGVPhxNXV895qwIABSE1NxYABA1BUVOSw3qpNmzZ47rnnMHz4cHz//fd47LHHEBAQgNzcXOzZswdNmjTBmDFjKhSrvQceeADPPfcc3n33XahUKnTp0gV//PEHXnvtNURFRWHixIkALOv63nzzTYwcORIdO3bEqFGjULt2bfz66684evQo3nvvvTKP06FDB5hMJmzfvl3Rar1jx46YPn06JElyad1akyZNkJWVhU2bNiEiIgJBQUG35eLhSUlJCAkJwejRozF9+nRotVqsWbMGR48erfRjWX3//fcYOXIknn76aZw5cwbTpk1DZGQkxo4dC8BS+Z48eTJmz56tGDdjxgyHaYfWyy+MHTsWffr0wZkzZ/CPf/wDERERDuuCK/r6nThxAidOnABgSewKCgrk2RiNGzdG48aNK7RfoirPM30+iMgTevXqJXQ6nTh//nypY/r37y80Go3Iy8uTu7bNnTtXzJw5U9StW1fodDoRHx8vtm7dqvg+a7evQ4cOiR49eojAwEARFBQkBgwYIM6dO6cYGx0dLbp16+b0+Ddv3hSvvPKKiI6OFlqtVkRERIgxY8Yo2iVPmzZNqFQqhw5te/fuFRqNRrz44ouKYznrdvjJJ58ovtfaMezgwYNOn5dty+xNmzaJhx9+WPj6+orIyEjx0ksvia+//loAEDt37pTHXbp0SfTp00dUr15dSJKk6IYGu26HQgjx008/iR49eojg4GCh0+nEww8/LJYvX64YU1r81p+V/Xhndu/eLf72t7+JgIAA4efnJ1q1aiU2bdrkdH/udDv86KOPxPjx40XNmjWFj4+PaNu2raIlttXnn38uWrZsKXx9fUVAQIDo0KGDomV4YWGhGD16tGjatKmoVq2a8PPzEw888ICYPn26uHHjhjyurNfXYDCIBQsWyD+nwMBA8eCDD4q///3v4pdffpHHlXUu2p87Qghx+vRpMXDgQFGjRg2h1WrFAw88IObPn6/o3ujOa2flynlva+DAgQKAaNOmTan7XLZsmWjZsqX8c27QoIEYMmSI4meSnJwsHnroIZfjdNbVz2Qyiblz54r7779faLVaERYWJgYNGiTOnDnj8P1fffWVSE5OFgEBAcLf3180btxYcSmF0pjNZhEWFiYAiLNnz8rbrZ36mjdv7vA9zrod/vDDD6JNmzbC399f0eGvtN9/67lt+3vtjLPXZe/evaJ169bC399f1KxZU4wcOVIcPnzY4fd06NChIiAgwGGfpf1s7M9Za+zffPONGDx4sKhevbrcUt/2XBfC8jqmpaWJqKgoodPpRNOmTcWmTZtEcnKyQ7fDOXPmiJiYGOHj4yMaNWokPvjgg3K7OrrDui9nN/u/jUT3EkmICtT/icgr/PHHH4iNjcX8+fMdLmhsb8aMGZg5cyb++uuvSlmfRHePrKwstG/fHp988oncuIWIiIgccc0XERERERHRHcDki4iIiIiI6A7gtEMiIiIiIqI7gJUvIiIiIiKiO4DJFxERERER0R3A5IuIiIiIiOgO4EWWK8hsNiMnJwdBQUG3dFFSIiIiIiK6uwkhcO3aNdSpUwcqVen1LSZfFZSTk4OoqChPh0FERERERFXEmTNnULdu3VIfZ/JVQUFBQQAsL3C1atU8HA0REREREXlKfn4+oqKi5ByhNEy+Ksg61bBatWpMvoiIiIiIqNzlSGy4QUREREREdAcw+SIiIiIiIroDmHwRERERERHdAUy+iIiIiIiI7gAmX0RERERERHcAky8iIiIiIqI7gMkXERERERHRHcDki4iIiIiI6A5g8kVERERERHQHMPkiIiKXmc1mT4dARER012LyRURELpnw9b/w8IrW2HTyoKdDISIiuisx+SIiIpccPn8AUBdg5x/feToUIiKiuxKTLyIicokQlimHRk49JCIiqhAmX0RE5BIzTAAAkzB5OBIiIqK7E5MvIiJyibXyZRasfBEREVWEx5OvRYsWITY2Fr6+vkhISMDu3btLHXv8+HH07t0bMTExkCQJ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\n", + "image/png": "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NG3aFM8//3ylYi3tnnvuwYgRI/Dee+9Bp9OhS5cu+OOPP/D6668jOjoaY8eOBWBf1/fWW29h2LBheOihhzB8+HBERkbi119/xb59+/D+++9XSTxEVI35ps8HEZHvPPbYY8JkMolTp06VOaZv377CYDCI/Px8tWvb9OnTxZQpU0TDhg2FyWQSCQkJ4uuvv9b8nNIFbffu3aJHjx4iNDRUhIWFiX79+omTJ09qxsbExIhu3bq5Pf7Vq1fFK6+8ImJiYoTRaBT16tUTzz//vDh//rw6ZuLEiUKn07l0aNu2bZswGAzixRdf1BzLXbfDTz75RPOzCxcuFADErl273L4u55bZa9asEc2bNxeBgYGiQYMG4qWXXhJfffWVACA2btyojjt37px48sknxW233SYkSdJ0iUOpbodCCPHzzz+LHj16iPDwcGEymUTz5s3FwoULNWPKil/5XZUe786WLVvEX/7yFxESEiKCgoJEmzZtxJo1a9zuz5tuh//+97/FmDFjRJ06dURAQIBo3769+OGHH1zGr169WrRu3VoEBgaKkJAQ0alTJ/F///d/6vNFRUXiueeeE82aNRM1atQQQUFB4p577hGTJk0SV65cUceV9/5aLBYxa9Ys9fcUGhoq7r33XvHXv/5VHD58WB1X3rlY+twRQoijR4+K/v37i9q1awuj0SjuueceMXPmTE33Rm/eO4Un572z/v37CwCiXbt2Ze5zwYIFonXr1urv+Y477hCDBg3S/E5SUlLEfffd53Gc7lrNy7Ispk+fLu6++25hNBpFRESEGDBggDh27JjLz3/55ZciJSVFhISEiODgYNGkSRPNpRSI6NYlCcG6NxFRef744w/ExcVh5syZLhc0Lm3y5MmYMmUKTp8+XSXrk+jmsWnTJnTs2BGffPKJ2riFiIjIGdd8ERERERER3QBMvoiIiIiIiG4ATjskIiIiIiK6AVj5IiIiIiIiugGYfBEREREREd0ATL6IiIiIiIhuAF5kuZJsNhtOnDiBsLCwa7oYJxERERER3dyEELh06RLq168Pna7s+haTr0o6ceIEoqOjfR0GERERERFVE8eOHUPDhg3LfJ7JVyWFhYUBsL/BNWrU8HE0RERERETkKwUFBYiOjlZzhLIw+aokZaphjRo1mHwREREREVGFy5HYcIOIiIiIiOgGYPJFRERERER0AzD5IiIi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8HARHh4upkyZIq5fv97oPldWVgoAorKysukvmIiIiILSF198IW7duiWEEOLWrVviiy++aFTbTz75RHzyySfScatWrWrWPl/PR0Qtp7GxQYuv8xWsuM4XEREREREBjY8NWJ+ciIiIiIgoABh8ERERERERBQCDLyIiIiIiogBg8EVERERERBQADL6IiIiIiIgCgMEXERERERFRALT4IsvBylWhv6qqqoV7QkRERERELckVEzS0iheDr2aqrq4GAPTo0aOFe0JERERERK1BdXU1jEaj4n4ustxMDocDly5dQnh4OFQqVYv2paqqCj169MD58+e54LOf8Br7F6+v//Ea+xevr//xGvsXr6//8Rr7V0tfXyEEqqurERsbC7Va+c4uZr6aSa1Wo3v37i3dDTcRERH8P7Of8Rr7F6+v//Ea+xevr//xGvsXr6//8Rr7V0teX18ZLxcW3CAiIiIiIgoABl9EREREREQBoFm6dOnSlu4E/XwajQbDhg2DVsuZpP7Ca+xfvL7+x2vsX7y+/sdr7F+8vv7Ha+xfwXB9WXCDiIiIiIgoADjtkIiIiIiIKAAYfBEREREREQUAgy8iIiIIkTlrAAAMs0lEQVQiIqIAYPBFREREREQUAAy+gsCKFSuQmpqK9u3b46677pJtU1ZWhscffxwdOnRAZGQkXnzxRVitVp/nvX79OsxmM4xGI4xGI8xmM27cuOGPlxBU8vLyoFKpZB+HDh1SPG7YsGFe7SdNmhTAngeXnj17el2vhQsX+jxGCIGlS5ciNjYW7dq1w7Bhw3DixIkA9Th4fP/995g+fTri4+PRrl079OrVC0uWLGnwPYFj2Ld169YhPj4eYWFhSE5Oxr59+3y237ZtG/r16weDwYB+/fphx44dAepp8MnMzMSDDz6I8PBwREVF4YknnsC3337r85j33ntP9n26pqYmQL0OHkuXLvW6TiaTyecx+fn5SE5ORlhYGH7xi19gw4YNAeptcJL7TFOpVHj++edl23P8+vbll1/i8ccfR2xsLFQqFT766CO3/c39PtDU93F/YPAVBKxWKyZMmIDnnntOdr/dbsfo0aNx69Yt7N+/H1u3bsW2bdvw0ksv+Tzv5MmTceTIEezatQu7du3CkSNHYDab/fESgkpqaiouX77s9pgxYwZ69uyJAQMG+Dx25syZbse98847Aep1cFq+fLnb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832gOe/jfhPQ8h7ULOfOnRMlJSVi2bJlomPHjqKkpESUlJSI6upqIYQQNptNJCYmikceeUQcPnxY5Obmiu7du4s5c+ZI5zhw4IBISEgQFy5ckLaNHDlS3HvvvaKwsFAUFhaK/v37izFjxgT89bVWubm5AoA4efKk174LFy6IhIQEceDAASGEEKdPnxbLli0Thw4dEqWlpeLTTz8Vffv2FQ888ICw2WyB7nqrV1BQIFavXi1KSkrE2bNnRXZ2toiNjRVjx451a5eQkCC2b98u/b1y5UphNBrF9u3bxbFjx8TTTz8tYmJiRFVVVaBfQqt28eJF8ctf/lI8/PDD4sKFC+Ly5cvSw4VjuGm2bt0qdDqd2LRpkzh58qSYN2+e6NChg/j++++FEEKYzWa3iln//ve/hUajEStXrhRff/21WLlypdBqtW4VZqnec889J4xGo8jLy3Mbrz/++KPUxvMaL126VOzatUucOXNGlJSUiD/84Q9Cq9VKY5rqvfTSSyIvL0+cPXtWFBUViTFjxojw8HBp/C5cuFCYzWap/dmzZ0X79u3F/PnzxcmTJ8WmTZuETqcTH374YUu9hKBgt9vF3XffLV599VWvfRy/TVNdXS193wUgfWc4d+6cEKJx3wcefvhhsXbtWunvht7HA4XBVxCYNm2aAOD12Lt3r9Tm3LlzYvTo0aJdu3aic+fOYs6cOaKmpkbav3fvXgFAlJaWStsqKirElClTRHh4uAgPDxdTpkwR169fD+Ara92efvppkZqaKruvtLTU7X+DsrIyMWTIENG5c2eh1+tFr169xIsvvigqKioC2OPgUVxcLAYOHCiMRqMICwsTCQkJYsmSJeLWrVtu7QCIzZs3S387HA6xZMkSYTKZhMFgEEOGDBHHjh0LcO9bv82bN8u+Z9z+exvHcNO9/fbbIi4uTuj1epGUlORWBn3o0KFi2rRpbu0/+OADkZCQIHQ6nejbt6/Ytm1bgHscPJTG6+3///e8xvPmzRN333230Ov1omvXriItLU0UFBQEvvNBID09XcTExAidTidiY2PF7373O3HixAlp/7Rp08TQoUPdjsnLyxMPPPCA0Ov1omfPnmL9+vUB7nXw2b17twAgvv32W699HL9N4/re6vlwXcPGfB+Ii4sTS5Yscdvm6308UFRCOO+gJCIiIiIiIr9htUMiIiIiIqIAYPBFREREREQUAAy+iIiIiIiIAoDBFxERERERUQAw+CIiIiIiIgoABl9EREREREQBwOCLiIiIiIgoABh8ERERERERBQCDLyIiIiIiogBg8EVERERERBQADL6IiIiIiIgCgMEXERERERFRAPx/AMO5VSjQcssAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] @@ -244,7 +246,7 @@ "import pyro\n", "import pyro.distributions as dist\n", "import scipy.stats\n", - "import torch \n", + "import torch\n", "import torch.distributions.constraints as constraints\n", "from matplotlib import pyplot\n", "from pyro.infer import SVI, Trace_ELBO\n", @@ -269,52 +271,49 @@ " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([0.0]))\n", " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", "\n", + "\n", "def model(data):\n", - " # Global variables.\n", " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", - " # Local variables.\n", + "\n", " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)\n", "\n", + "\n", "def relbo(model, guide, *args, **kwargs):\n", "\n", " approximation = kwargs.pop('approximation', None)\n", - " relbo_lambda = kwargs.pop('relbo_lambda', None)\n", " # Run the guide with the arguments passed to SVI.step() and trace the execution,\n", " # i.e. record all the calls to Pyro primitives like sample() and param().\n", " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", + " # We do not want to update parameters of previously fitted components and thus block all\n", + " # parameters in the approximation apart from loc.\n", " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", - " # We will acculoclate the various terms of the ELBO in `elbo`.\n", - "\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", " guide,\n", " *args,\n", " **kwargs)\n", "\n", - " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", + " relbo = -loss_fn - approximation_trace.log_prob_sum()\n", + " \n", + " # By convention, the negative (R)ELBO is returned.\n", + " return - relbo\n", "\n", - " return -elbo\n", "\n", "def approximation(data, components, weights):\n", " assignment = pyro.sample('assignment', dist.Categorical(weights))\n", " result = components[assignment](data)\n", " return result\n", "\n", - "def dummy_approximation(data):\n", - " scale_q = pyro.param('scale_0', torch.tensor([1.0]), constraints.positive)\n", - " loc_q = pyro.param('loc_0', torch.tensor([20.0]))\n", - " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", "\n", "def boosting_bbvi():\n", " n_iterations = 2\n", - " relbo_lambda = 1\n", " initial_approximation = partial(guide, index=0)\n", " components = [initial_approximation]\n", " weights = torch.tensor([1.])\n", @@ -323,37 +322,41 @@ " locs = [0]\n", " scales = [0]\n", "\n", - " duality_gap = []\n", - " entropies = []\n", - " model_log_likelihoods = []\n", " for t in range(1, n_iterations + 1):\n", - " # setup the inference algorithm\n", + " \n", + " # Create guide that only takes data as argument\n", " wrapped_guide = partial(guide, index=t)\n", - " # do gradient steps\n", " losses = []\n", - " # Register hooks to monitor gradient norms.\n", "\n", " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", " optimizer = Adam(adam_params)\n", "\n", + " # Pass our custom RELBO to SVI as the loss function.\n", " svi = SVI(model, wrapped_guide, optimizer, loss=relbo)\n", " for step in range(n_steps):\n", - " loss = svi.step(data, approximation=wrapped_approximation, relbo_lambda=relbo_lambda)\n", + " # Pass the existing approximation to SVI.\n", + " loss = svi.step(data, approximation=wrapped_approximation)\n", " losses.append(loss)\n", "\n", " if step % 100 == 0:\n", " print('.', end=' ')\n", "\n", + " # Update the list of approximation components.\n", " components.append(wrapped_guide)\n", + " \n", + " # Set new mixture weight.\n", " new_weight = 2 / (t + 1)\n", "\n", + " # In this specific case, we set the mixture weight of the second component to 0.5.\n", " if t == 2:\n", " new_weight = 0.5\n", " weights = weights * (1-new_weight)\n", " weights = torch.cat((weights, torch.tensor([new_weight])))\n", "\n", + " # Update the approximation\n", " wrapped_approximation = partial(approximation, components=components, weights=weights)\n", "\n", + " print('Parameters of component {}:'.format(t))\n", " scale = pyro.param(\"scale_{}\".format(t)).item()\n", " scales.append(scale)\n", " loc = pyro.param(\"loc_{}\".format(t)).item()\n", @@ -362,6 +365,7 @@ " print('scale = {}'.format(scale))\n", "\n", "\n", + " # Plot the resulting approximation\n", " X = np.arange(-10, 10, 0.1)\n", " pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white')\n", " total_approximation = np.zeros(X.shape)\n", @@ -371,7 +375,7 @@ " total_approximation += Y\n", " pyplot.plot(X, total_approximation)\n", " pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*')\n", - " pyplot.title('Approximation of posterior over loc with lambda={}'.format(relbo_lambda))\n", + " pyplot.title('Approximation of posterior over loc')\n", " pyplot.ylabel('probability density')\n", " pyplot.show()\n", "\n", @@ -379,6 +383,13 @@ " boosting_bbvi()\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that boosting BBVI successfully approximates the bimodal posterior distributions with modes around -2 and +2." + ] + }, { "cell_type": "markdown", "metadata": {}, From 10334f32f56555924d07daa65cdd79d4866fa451 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Wed, 11 Dec 2019 16:13:07 +0100 Subject: [PATCH 20/29] Fix errors in writing --- boosting_bbvi_tutorial.ipynb | 56 ++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 05ed9cc..2e8c49e 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -6,7 +6,7 @@ "source": [ "# Boosting Black Box Variational Inference\n", "## Introduction\n", - "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Inference [2], we approximate a target distribution with a iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. We show how this can be implement as a relatively simple extension of Pyro's SVI.\n", + "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Inference [2], we approximate a target distribution with an iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. We show how this can be implement as a relatively straightforward extension of Pyro's SVI.\n", "\n", "## Contents\n", "* [Theoretical Background](#theoretical-background)\n", @@ -27,28 +27,30 @@ "## Theoretical Background \n", "\n", "### Variational Inference \n", - "For an introduction to regular Variational Inference, we recommend first having a look at [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html).\n", + "For an introduction to regular Variational Inference, we recommend having a look at [the tutorial on SVI in Pyro](https://pyro.ai/examples/svi_part_i.html) and this excellent review [3].\n", "\n", - "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. First, one chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution.\n", + "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. For instance, one might have observed variables $\\textbf{x}$, latent variables $\\textbf{z}$ and a joint distribution $p(\\textbf{x}, \\textbf{z})$. One can then use Variational Inference to approximate $p(\\textbf{z}|\\textbf{x})$. To do so, one first chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution $p(\\textbf{z}|\\textbf{x})$.\n", "This approximating density is found by maximizing the Evidence Lower BOund (ELBO):\n", - "$$ \\mathbb{E}_s[\\text{log} p(x, z)] - \\mathbb{E}_s[\\text{log} s(z)]$$\n", + "$$ \\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\mathbb{E}_s[\\text{log} s(\\mathbf{z})]$$\n", "\n", - "where $s(z)$ is the approximating density and $p(x,z)$ is the target distribution.\n", + "where $s(\\mathbf{z})$ is the approximating density.\n", "\n", "### Boosting Black Box Variational Inference \n", "\n", - "In boosting BBVI, the approximation takes the form:\n", - "$$\\sum_{i=1}^T \\gamma_t s_t(z)$$\n", + "In boosting black box Variational inference (BBBVI), we approximate the target density with a mixture of densities from the variational family:\n", + "$$\\sum_{i=1}^T \\gamma_t s_t(\\mathbf{z})$$\n", "\n", "$$\\text{where} \\sum_{i=1}^T \\gamma_t =1$$\n", "\n", - "and $s_t(z)$ are elements of the variational family.\n", + "and $s_t(\\mathbf{z})$ are elements of the variational family.\n", "\n", - "The components of the approximation $s_t(z)$ are selected greedily components by maximising the Residual ELBO (RELBO):\n", + "The components of the approximation $s_{t+1}(\\mathbf{z})$ are selected greedily by maximising the Residual ELBO (RELBO):\n", "\n", - "$$\\mathbb{E}_s[\\text{log} p(x,z)] - \\lambda \\mathbb{E}_s[\\text{log}s(z)] - \\mathbb{E}_s[\\text{log} q^t(z)]$$\n", + "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", "\n", - "It's called *black box* variational inference inference because this optimisation does not have to be tailored to the variational family which is being used. Setting $\\lambda$ to 1, regular SVI methods can be used to compute $$\\mathbb{E}_s[\\text{log} p(x,z)] - \\lambda \\mathbb{E}_s[\\text{log}s(z)]$$. See the explanation of the section on the implementation of the RELBO below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(z)]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", + "Where the first two terms are the same as in the ELBO and the last term is the cross entropy of the next component $s_{t+1}(\\mathbf{z})$ and the existing approximation $q^t(\\mathbf{z})$.\n", + "\n", + "It's called *black box* Variational Inference because this optimization does not have to be tailored to the variational family which is being used. By setting $\\lambda$ (the regularization factor of the entropy term) to 1, standard SVI methods can be used to compute $\\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})]$. See the explanation of [the section on the implementation of the RELBO](#the-relbo) below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", "\n", "In [1] a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBo." ] @@ -67,7 +69,7 @@ "To implement boosting black box variational inference in Pyro, we need to consider the following three components:\n", "1. The approximation components (guides) and the approximation itself.\n", "2. The RELBO.\n", - "3. Using SVI to find new components and update the approximation.\n", + "3. Using Pyro's SVI to find new components of the approximation.\n", "\n", "We will illustrate these points by looking at simple example: approximating a bimodal posterior.\n" ] @@ -78,12 +80,12 @@ "source": [ "### The Model \n", "\n", - "Boosting BBVI is particularly useful in situations where we're trying to approximate mulitmodal posteriors. In this tutorial, we'll thus consider the following model:\n", + "Boosting BBVI is particularly useful when we want to approximate mulitmodal distributions. In this tutorial, we'll thus consider the following model:\n", " \n", " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", " $$y \\sim \\mathcal{N}(\\mu^2, 0.1)$$\n", " \n", - "Additionally, we have some observations of $y$ around +4. We thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around -2 and +2.\n", + "In our example, we also have some observations of $y$ around $4$. We thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", " \n", "In Pyro, this model takes the following shape:" ] @@ -114,7 +116,7 @@ "\n", "We also need to make sure that every `pyro.sample()` statement from the model has a matching `pyro.sample()` statement in the guide. In our case, we include `loc` in both the model and the guide.\n", "\n", - "In contrast to regular SVI, our guide takes an additional argument: `index`. Having this argument allows us to easily create new guides in each iteration of the greedy algorithm. In particular, we use make use of `partial()` from the [functools library](https://docs.python.org/3.7/library/functools.html) to create guides which only take `data` as an argument. The statement `partial(guide, index=t)` creates a guide that will take only `data` as an input and which has trainable parameters `scale_t` and `loc_t`.\n", + "In contrast to regular SVI, our guide takes an additional argument: `index`. Having this argument allows us to easily create new guides in each iteration of the greedy algorithm. Specifically, we make use of `partial()` from the [functools library](https://docs.python.org/3.7/library/functools.html) to create guides which only take `data` as an argument. The statement `partial(guide, index=t)` creates a guide that will take only `data` as an input and which has trainable parameters `scale_t` and `loc_t`.\n", "\n", "Choosing our variational distribution to be a Normal distribution parameterized by $loc_t$ and $scale_t$ we get the following guide:" ] @@ -137,13 +139,14 @@ "source": [ "### The RELBO \n", "\n", - "We implement a modified ELBO function, the RELBO, which we then pass to Pyro's SVI class to find the approximation components $s_t(z)$\n", + "We implement the RELBO as a function which can be passed to Pyro's SVI class to find the approximation components $s_t(z)$. Recall that the RELBO has the following form:\n", + "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", "\n", - "Conveniently, the RELBO is very similar to the normal ELBO which allows us to reuse the Pyro's existing ELBO to compute part of it. Specifically, we compute \n", + "Conveniently, the this is very similar to the regular ELBO which allows us to reuse Pyro's existing ELBO. Specifically, we compute \n", "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s]$$\n", - "using `Trace_ELBO` and then compute \n", + "using Pyro's `Trace_ELBO` and then compute \n", "$$ - E_s[\\text{log} q^t]$$\n", - "using Poutine. For more information on how this works, we recommend going through the tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." + "using Poutine. For more information on how this works, we recommend going through the Pyro tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." ] }, { @@ -185,7 +188,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Our implementation of the approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample an index of a component according to the mixture weights. In a second step, we get a sample from the corresponding component.\n", + "Our implementation of the approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample a component according to the mixture weights. In a second step, we draw a sample from the corresponding component.\n", "\n", "Similarly as with the guide, we use `partial(approximation, components=components, weights=weights)` to get an approximation function which has the same signature as the model." ] @@ -209,9 +212,16 @@ "### The Greedy Algorithm " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using all of the above components and using Pyro's SVI we get the complete implementation of BBBVI:" + ] + }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -398,7 +408,9 @@ "\n", "[1] Locatello, Francesco, et al. \"Boosting black box variational inference.\" Advances in Neural Information Processing Systems. 2018.\n", "\n", - "[2] Ranganath, Rajesh, Sean Gerrish, and David Blei. \"Black box variational inference.\" Artificial Intelligence and Statistics. 2014." + "[2] Ranganath, Rajesh, Sean Gerrish, and David Blei. \"Black box variational inference.\" Artificial Intelligence and Statistics. 2014.\n", + "\n", + "[3] Blei, David M., Alp Kucukelbir, and Jon D. McAuliffe. \"Variational inference: A review for statisticians.\" Journal of the American statistical Association 112.518 (2017): 859-877." ] } ], From fdcc93131abbcaffea65ab24bc5b49552933f192 Mon Sep 17 00:00:00 2001 From: "[TNU]Yu Yao" <49576883+TNU-yaoy@users.noreply.github.com> Date: Thu, 12 Dec 2019 17:15:31 +0100 Subject: [PATCH 21/29] suggested changes to bbbvi tutorial --- boosting_bbvi_tutorial.ipynb | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 2e8c49e..18d360d 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -38,21 +38,23 @@ "### Boosting Black Box Variational Inference \n", "\n", "In boosting black box Variational inference (BBBVI), we approximate the target density with a mixture of densities from the variational family:\n", - "$$\\sum_{i=1}^T \\gamma_t s_t(\\mathbf{z})$$\n", + "$$q^T(\\mathbb{z}) = \\sum_{t=1}^T \\gamma_t s_t(\\mathbf{z})$$\n", "\n", - "$$\\text{where} \\sum_{i=1}^T \\gamma_t =1$$\n", + "$$\\text{where} \\sum_{t=1}^T \\gamma_t =1$$\n", "\n", "and $s_t(\\mathbf{z})$ are elements of the variational family.\n", "\n", - "The components of the approximation $s_{t+1}(\\mathbf{z})$ are selected greedily by maximising the Residual ELBO (RELBO):\n", + "The components of the approximation are selected greedily by maximising the so-called Residual ELBO (RELBO) with respect to the next component $s_{t+1}(\\mathbf{z})$:\n", "\n", "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", "\n", - "Where the first two terms are the same as in the ELBO and the last term is the cross entropy of the next component $s_{t+1}(\\mathbf{z})$ and the existing approximation $q^t(\\mathbf{z})$.\n", + "Where the first two terms are the same as in the ELBO and the last term is the cross entropy between the next component $s_{t+1}(\\mathbf{z})$ and the current approximation $q^t(\\mathbf{z})$.\n", "\n", "It's called *black box* Variational Inference because this optimization does not have to be tailored to the variational family which is being used. By setting $\\lambda$ (the regularization factor of the entropy term) to 1, standard SVI methods can be used to compute $\\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})]$. See the explanation of [the section on the implementation of the RELBO](#the-relbo) below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", "\n", - "In [1] a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBo." + "In [1], a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBO. Here, we used the fixed step size method.", + "\n", + "For more details on the theory behind boosting black box variational inference, please refer to [1].", ] }, { @@ -66,10 +68,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To implement boosting black box variational inference in Pyro, we need to consider the following three components:\n", - "1. The approximation components (guides) and the approximation itself.\n", - "2. The RELBO.\n", - "3. Using Pyro's SVI to find new components of the approximation.\n", + "To implement boosting black box variational inference in Pyro, we need to consider the following points:\n", + "1. The approximation components $s_{t}(\\mathbf{z})$ (guides).\n", + "2. The RELBO.\n", + "3. The approximation itself $q^t(\\mathbf{z})$.\n", + "4. Using Pyro's SVI to find new components of the approximation.\n", "\n", "We will illustrate these points by looking at simple example: approximating a bimodal posterior.\n" ] @@ -85,7 +88,7 @@ " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", " $$y \\sim \\mathcal{N}(\\mu^2, 0.1)$$\n", " \n", - "In our example, we also have some observations of $y$ around $4$. We thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", + "Here, $\mu$ is the latent and $y$ the observed variable. Given the set of iid. observations $\\mathbb{y} = \[4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3\]$, we thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", " \n", "In Pyro, this model takes the following shape:" ] @@ -112,7 +115,7 @@ "source": [ "### The Guide \n", "\n", - "Next, we specify the guide which in our case will make up the compoents of our mixture. Recall that in Pyro the guide needs to take the same arguments as the model which is why our guide function also takes the data as an input. \n", + "Next, we specify the guide which in our case will make up the components of our mixture. Recall that in Pyro the guide needs to take the same arguments as the model which is why our guide function also takes the data as an input. \n", "\n", "We also need to make sure that every `pyro.sample()` statement from the model has a matching `pyro.sample()` statement in the guide. In our case, we include `loc` in both the model and the guide.\n", "\n", @@ -139,10 +142,10 @@ "source": [ "### The RELBO \n", "\n", - "We implement the RELBO as a function which can be passed to Pyro's SVI class to find the approximation components $s_t(z)$. Recall that the RELBO has the following form:\n", + "We implement the RELBO as a function which can be passed to Pyro's SVI class in place of ELBO to find the approximation components $s_t(z)$. Recall that the RELBO has the following form:\n", "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", "\n", - "Conveniently, the this is very similar to the regular ELBO which allows us to reuse Pyro's existing ELBO. Specifically, we compute \n", + "Conveniently, this is very similar to the regular ELBO which allows us to reuse Pyro's existing ELBO. Specifically, we compute \n", "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s]$$\n", "using Pyro's `Trace_ELBO` and then compute \n", "$$ - E_s[\\text{log} q^t]$$\n", @@ -188,7 +191,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Our implementation of the approximation $\\sum_{i=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample a component according to the mixture weights. In a second step, we draw a sample from the corresponding component.\n", + "Our implementation of the approximation $q^T(z) = \\sum_{t=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample a component according to the mixture weights. In a second step, we draw a sample from the corresponding component.\n", "\n", "Similarly as with the guide, we use `partial(approximation, components=components, weights=weights)` to get an approximation function which has the same signature as the model." ] @@ -216,7 +219,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Using all of the above components and using Pyro's SVI we get the complete implementation of BBBVI:" + "Using all of the above components and using Pyro's SVI, we get the complete implementation of BBBVI:" ] }, { @@ -323,6 +326,7 @@ "\n", "\n", "def boosting_bbvi():\n", + " # T=2\n", " n_iterations = 2\n", " initial_approximation = partial(guide, index=0)\n", " components = [initial_approximation]\n", From 108946db4b7c9b7365014efc608d69f6fe186151 Mon Sep 17 00:00:00 2001 From: "[TNU]Yu Yao" <49576883+TNU-yaoy@users.noreply.github.com> Date: Thu, 12 Dec 2019 17:20:00 +0100 Subject: [PATCH 22/29] fixed syntax error --- boosting_bbvi_tutorial.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 18d360d..1b5e372 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -88,7 +88,7 @@ " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", " $$y \\sim \\mathcal{N}(\\mu^2, 0.1)$$\n", " \n", - "Here, $\mu$ is the latent and $y$ the observed variable. Given the set of iid. observations $\\mathbb{y} = \[4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3\]$, we thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", + "Here, $\\mu$ is the latent and $y$ the observed variable. Given the set of iid. observations $\\mathbb{y} = (4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3)$, we thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", " \n", "In Pyro, this model takes the following shape:" ] From e7e6d972880781e34f717cab819deff8c62136fe Mon Sep 17 00:00:00 2001 From: yaoy Date: Thu, 12 Dec 2019 17:37:43 +0100 Subject: [PATCH 23/29] fixed syntax error --- boosting_bbvi_tutorial.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 1b5e372..80bbab9 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -54,7 +54,7 @@ "\n", "In [1], a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBO. Here, we used the fixed step size method.", "\n", - "For more details on the theory behind boosting black box variational inference, please refer to [1].", + "For more details on the theory behind boosting black box variational inference, please refer to [1]." ] }, { From 18e87c2c2a615e2ec937b181df573ca4485571d0 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Sun, 15 Dec 2019 18:02:00 +0100 Subject: [PATCH 24/29] Back up before merging --- bayesian_logistic_regression.py | 20 ++++++++++---------- bimodal_posterior.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bayesian_logistic_regression.py b/bayesian_logistic_regression.py index bd88c62..e978bf1 100644 --- a/bayesian_logistic_regression.py +++ b/bayesian_logistic_regression.py @@ -42,12 +42,12 @@ approximation_log_prob = [] # @config_enumerate -# def guide(observations, input_data, index): -# variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) -# #variance_q = torch.eye(input_data.shape[1]) -# mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) -# w = pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) -# return w +def guide(observations, input_data, index): + variance_q = pyro.param('variance_{}'.format(index), torch.eye(input_data.shape[1]), constraints.positive) + #variance_q = torch.eye(input_data.shape[1]) + mu_q = pyro.param('mu_{}'.format(index), torch.zeros(input_data.shape[1])) + w = pyro.sample("w", dist.MultivariateNormal(mu_q, variance_q)) + return w class Guide: def __init__(self, index, n_variables, initial_loc=None, initial_scale=None): @@ -55,7 +55,7 @@ def __init__(self, index, n_variables, initial_loc=None, initial_scale=None): self.n_variables = n_variables if not initial_loc: self.initial_loc = torch.zeros(n_variables) - self.initial_scale = torch.ones(n_variables) + self.initial_scale = torch.eye(n_variables) else: self.initial_scale = initial_scale self.initial_loc = initial_loc @@ -64,7 +64,7 @@ def get_distribution(self): scale_q = pyro.param('scale_{}'.format(self.index), self.initial_scale, constraints.positive) #scale_q = torch.eye(self.n_variables) locs_q = pyro.param('locs_{}'.format(self.index), self.initial_loc) - return dist.MultivariateNormal(locs_q, scale_q).to_event(1) + return dist.MultivariateNormal(locs_q, scale_q) def __call__(self, observations, input_data): distribution = self.get_distribution() @@ -72,7 +72,7 @@ def __call__(self, observations, input_data): return w def logistic_regression_model(observations, input_data): - w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.ones(input_data.shape[1])).to_event(1)) + w = pyro.sample('w', dist.MultivariateNormal(torch.zeros(input_data.shape[1]), torch.eye(input_data.shape[1]))) with pyro.plate("data", input_data.shape[0]): sigmoid = torch.sigmoid(torch.matmul(input_data, w.double())) obs = pyro.sample('obs', dist.Bernoulli(sigmoid), obs=observations) @@ -134,7 +134,7 @@ def relbo(model, guide, *args, **kwargs): #print(model_trace.nodes['obs_1']) - approximation_trace = trace(replay(block(approximation, expose=['mu']), guide_trace)).get_trace(*args, **kwargs) + approximation_trace = trace(replay(block(approximation, expose=['w']), guide_trace)).get_trace(*args, **kwargs) # We will accumulate the various terms of the ELBO in `elbo`. guide_log_prob.append(guide_trace.log_prob_sum()) diff --git a/bimodal_posterior.py b/bimodal_posterior.py index 5400129..469dd42 100644 --- a/bimodal_posterior.py +++ b/bimodal_posterior.py @@ -38,6 +38,7 @@ guide_log_prob = [] approximation_log_prob = [] + def guide(data, index): variance_q = pyro.param('variance_{}'.format(index), torch.tensor([1.0]), constraints.positive) mu_q = pyro.param('mu_{}'.format(index), torch.tensor([1.0])) @@ -98,7 +99,6 @@ def boosting_bbvi(): global approximation_log_prob approximation_log_prob = [] - svi = SVI(model, wrapped_guide, optimizer, loss=relbo) for step in range(n_steps): loss = svi.step(data, approximation=wrapped_approximation, relbo_lambda=relbo_lambda) From b2cad4a862722cb1ab5b1ed752de7d44ab7237bd Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 16 Dec 2019 10:25:59 +0100 Subject: [PATCH 25/29] Change variable naming, change data used --- boosting_bbvi_tutorial.ipynb | 74 ++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 80bbab9..de0f3ab 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -6,7 +6,7 @@ "source": [ "# Boosting Black Box Variational Inference\n", "## Introduction\n", - "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Inference [2], we approximate a target distribution with an iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. We show how this can be implement as a relatively straightforward extension of Pyro's SVI.\n", + "This tutorial demonstrates how to implement boosting black box Variational Inference [1] in Pyro. In boosting Variational Inference [2], we approximate a target distribution with an iteratively selected mixture of densities. In cases where a single denisity provided by regular Variational Inference doesn't adequately approximate a target density, boosting VI thus offers a simple way of getting more complex approximations. We show how this can be implemented as a relatively straightforward extension of Pyro's SVI.\n", "\n", "## Contents\n", "* [Theoretical Background](#theoretical-background)\n", @@ -31,7 +31,7 @@ "\n", "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. For instance, one might have observed variables $\\textbf{x}$, latent variables $\\textbf{z}$ and a joint distribution $p(\\textbf{x}, \\textbf{z})$. One can then use Variational Inference to approximate $p(\\textbf{z}|\\textbf{x})$. To do so, one first chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution $p(\\textbf{z}|\\textbf{x})$.\n", "This approximating density is found by maximizing the Evidence Lower BOund (ELBO):\n", - "$$ \\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\mathbb{E}_s[\\text{log} s(\\mathbf{z})]$$\n", + "$$ \\mathbb{E}_q[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\mathbb{E}_q[\\text{log} q(\\mathbf{z})]$$\n", "\n", "where $s(\\mathbf{z})$ is the approximating density.\n", "\n", @@ -52,8 +52,7 @@ "\n", "It's called *black box* Variational Inference because this optimization does not have to be tailored to the variational family which is being used. By setting $\\lambda$ (the regularization factor of the entropy term) to 1, standard SVI methods can be used to compute $\\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})]$. See the explanation of [the section on the implementation of the RELBO](#the-relbo) below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", "\n", - "In [1], a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBO. Here, we used the fixed step size method.", - "\n", + "In [1], a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBO. Here, we used the fixed step size method.\n", "For more details on the theory behind boosting black box variational inference, please refer to [1]." ] }, @@ -70,7 +69,7 @@ "source": [ "To implement boosting black box variational inference in Pyro, we need to consider the following points:\n", "1. The approximation components $s_{t}(\\mathbf{z})$ (guides).\n", - "2. The RELBO.\n", + "2. The RELBO.\n", "3. The approximation itself $q^t(\\mathbf{z})$.\n", "4. Using Pyro's SVI to find new components of the approximation.\n", "\n", @@ -85,28 +84,28 @@ "\n", "Boosting BBVI is particularly useful when we want to approximate mulitmodal distributions. In this tutorial, we'll thus consider the following model:\n", " \n", - " $$\\mu \\sim \\mathcal{N}(0,5)$$\n", - " $$y \\sim \\mathcal{N}(\\mu^2, 0.1)$$\n", + " $$\\mathbf{z} \\sim \\mathcal{N}(0,5)$$\n", + " $$\\mathbf{x} \\sim \\mathcal{N}(\\mathbf{z}^2, 0.1)$$\n", " \n", - "Here, $\\mu$ is the latent and $y$ the observed variable. Given the set of iid. observations $\\mathbb{y} = (4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3)$, we thus expect $p(\\mu|y)$ to be a bimodal distributions with modes around $-2$ and $2$.\n", + "Given the set of iid. observations $\\text{data} ~ \\mathcal{N}(4, 0.1)$, we thus expect $p(\\mathbf{z}|\\mathbf{x})$ to be a bimodal distributions with modes around $-2$ and $2$.\n", " \n", "In Pyro, this model takes the following shape:" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "def model(data):\n", " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", - " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", + " z = pyro.sample('z', dist.Normal(prior_loc, prior_scale))\n", " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", - " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)" + " pyro.sample('x', dist.Normal(z*z, scale), obs=data)" ] }, { @@ -133,7 +132,7 @@ "def guide(data, index):\n", " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([0.0]))\n", - " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))" + " pyro.sample(\"z\", dist.Normal(loc_q, scale_q))" ] }, { @@ -154,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -166,8 +165,8 @@ " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", " # We do not want to update parameters of previously fitted components and thus block all\n", - " # parameters in the approximation apart from loc.\n", - " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", + " # parameters in the approximation apart from z.\n", + " replayed_approximation = trace(replay(block(approximation, expose=['z']), guide_trace))\n", " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", @@ -175,9 +174,10 @@ " *args,\n", " **kwargs)\n", "\n", - " elbo = -loss_fn - approximation_trace.log_prob_sum()\n", - "\n", - " return -elbo" + " relbo = -loss_fn - approximation_trace.log_prob_sum()\n", + " \n", + " # By convention, the negative (R)ELBO is returned.\n", + " return -relbo" ] }, { @@ -224,24 +224,24 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 1:\n", - "loc = -2.01552677154541\n", - "scale = 0.03500283882021904\n", - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 2:\n", - "loc = 2.0315308570861816\n", - "scale = 0.04819779098033905\n" + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 1:\n", + "loc = -1.9950288534164429\n", + "scale = 0.038874927908182144\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 2:\n", + "loc = 2.009120225906372\n", + "scale = 0.01808810420334339\n" ] }, { "data": { - "image/png": "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NG3aFM8//3ylYi3tnnvuwYgRI/Dee+9Bp9OhS5cu+OOPP/D6668jOjoaY8eOBWBf1/fWW29h2LBheOihhzB8+HBERkbi119/xb59+/D+++9XSTxEVI35ps8HEZHvPPbYY8JkMolTp06VOaZv377CYDCI/Px8tWvb9OnTxZQpU0TDhg2FyWQSCQkJ4uuvv9b8nNIFbffu3aJHjx4iNDRUhIWFiX79+omTJ09qxsbExIhu3bq5Pf7Vq1fFK6+8ImJiYoTRaBT16tUTzz//vDh//rw6ZuLEiUKn07l0aNu2bZswGAzixRdf1BzLXbfDTz75RPOzCxcuFADErl273L4u55bZa9asEc2bNxeBgYGiQYMG4qWXXhJfffWVACA2btyojjt37px48sknxW233SYkSdJ0iUOpbodCCPHzzz+LHj16iPDwcGEymUTz5s3FwoULNWPKil/5XZUe786WLVvEX/7yFxESEiKCgoJEmzZtxJo1a9zuz5tuh//+97/FmDFjRJ06dURAQIBo3769+OGHH1zGr169WrRu3VoEBgaKkJAQ0alTJ/F///d/6vNFRUXiueeeE82aNRM1atQQQUFB4p577hGTJk0SV65cUceV9/5aLBYxa9Ys9fcUGhoq7r33XvHXv/5VHD58WB1X3rlY+twRQoijR4+K/v37i9q1awuj0SjuueceMXPmTE33Rm/eO4Un572z/v37CwCiXbt2Ze5zwYIFonXr1urv+Y477hCDBg3S/E5SUlLEfffd53Gc7lrNy7Ispk+fLu6++25hNBpFRESEGDBggDh27JjLz3/55ZciJSVFhISEiODgYNGkSRPNpRSI6NYlCcG6NxFRef744w/ExcVh5syZLhc0Lm3y5MmYMmUKTp8+XSXrk+jmsWnTJnTs2BGffPKJ2riFiIjIGdd8ERERERER3QBMvoiIiIiIiG4ATjskIiIiIiK6AVj5IiIiIiIiugGYfBEREREREd0ATL6IiIiIiIhuAF5kuZJsNhtOnDiBsLCwa7oYJxERERER3dyEELh06RLq168Pna7s+haTr0o6ceIEoqOjfR0GERERERFVE8eOHUPDhg3LfJ7JVyWFhYUBsL/BNWrU8HE0RERERETkKwUFBYiOjlZzhLIw+aokZaphjRo1mHwREREREVGFy5HYcIOIiIiIiOgGYPJFRERERER0AzD5IiIi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8HARHh4upkyZIq5fv97oPldWVgoAorKysukvmIiIiILSF198IW7duiWEEOLWrVviiy++aFTbTz75RHzyySfScatWrWrWPl/PR0Qtp7GxQYuv8xWsuM4XEREREREBjY8NWJ+ciIiIiIgoABh8ERERERERBQCDLyIiIiIiogBg8EVERERERBQADL6IiIiIiIgCgMEXERERERFRALT4IsvBylWhv6qqqoV7QkRERERELckVEzS0iheDr2aqrq4GAPTo0aOFe0JERERERK1BdXU1jEaj4n4ustxMDocDly5dQnh4OFQqVYv2paqqCj169MD58+e54LOf8Br7F6+v//Ea+xevr//xGvsXr6//8Rr7V0tfXyEEqqurERsbC7Va+c4uZr6aSa1Wo3v37i3dDTcRERH8P7Of8Rr7F6+v//Ea+xevr//xGvsXr6//8Rr7V0teX18ZLxcW3CAiIiIiIgoABl9EREREREQBoFm6dOnSlu4E/XwajQbDhg2DVsuZpP7Ca+xfvL7+x2vsX7y+/sdr7F+8vv7Ha+xfwXB9WXCDiIiIiIgoADjtkIiIiIiIKAAYfBEREREREQUAgy8iIiIIkTlrAAAMs0lEQVQiIqIAYPBFREREREQUAAy+gsCKFSuQmpqK9u3b46677pJtU1ZWhscffxwdOnRAZGQkXnzxRVitVp/nvX79OsxmM4xGI4xGI8xmM27cuOGPlxBU8vLyoFKpZB+HDh1SPG7YsGFe7SdNmhTAngeXnj17el2vhQsX+jxGCIGlS5ciNjYW7dq1w7Bhw3DixIkA9Th4fP/995g+fTri4+PRrl079OrVC0uWLGnwPYFj2Ld169YhPj4eYWFhSE5Oxr59+3y237ZtG/r16weDwYB+/fphx44dAepp8MnMzMSDDz6I8PBwREVF4YknnsC3337r85j33ntP9n26pqYmQL0OHkuXLvW6TiaTyecx+fn5SE5ORlhYGH7xi19gw4YNAeptcJL7TFOpVHj++edl23P8+vbll1/i8ccfR2xsLFQqFT766CO3/c39PtDU93F/YPAVBKxWKyZMmIDnnntOdr/dbsfo0aNx69Yt7N+/H1u3bsW2bdvw0ksv+Tzv5MmTceTIEezatQu7du3CkSNHYDab/fESgkpqaiouX77s9pgxYwZ69uyJAQMG+Dx25syZbse98847Aep1cFq+fLnb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832gOe/jfhPQ8h7ULOfOnRMlJSVi2bJlomPHjqKkpESUlJSI6upqIYQQNptNJCYmikceeUQcPnxY5Obmiu7du4s5c+ZI5zhw4IBISEgQFy5ckLaNHDlS3HvvvaKwsFAUFhaK/v37izFjxgT89bVWubm5AoA4efKk174LFy6IhIQEceDAASGEEKdPnxbLli0Thw4dEqWlpeLTTz8Vffv2FQ888ICw2WyB7nqrV1BQIFavXi1KSkrE2bNnRXZ2toiNjRVjx451a5eQkCC2b98u/b1y5UphNBrF9u3bxbFjx8TTTz8tYmJiRFVVVaBfQqt28eJF8ctf/lI8/PDD4sKFC+Ly5cvSw4VjuGm2bt0qdDqd2LRpkzh58qSYN2+e6NChg/j++++FEEKYzWa3iln//ve/hUajEStXrhRff/21WLlypdBqtW4VZqnec889J4xGo8jLy3Mbrz/++KPUxvMaL126VOzatUucOXNGlJSUiD/84Q9Cq9VKY5rqvfTSSyIvL0+cPXtWFBUViTFjxojw8HBp/C5cuFCYzWap/dmzZ0X79u3F/PnzxcmTJ8WmTZuETqcTH374YUu9hKBgt9vF3XffLV599VWvfRy/TVNdXS193wUgfWc4d+6cEKJx3wcefvhhsXbtWunvht7HA4XBVxCYNm2aAOD12Lt3r9Tm3LlzYvTo0aJdu3aic+fOYs6cOaKmpkbav3fvXgFAlJaWStsqKirElClTRHh4uAgPDxdTpkwR169fD+Ara92efvppkZqaKruvtLTU7X+DsrIyMWTIENG5c2eh1+tFr169xIsvvigqKioC2OPgUVxcLAYOHCiMRqMICwsTCQkJYsmSJeLWrVtu7QCIzZs3S387HA6xZMkSYTKZhMFgEEOGDBHHjh0LcO9bv82bN8u+Z9z+exvHcNO9/fbbIi4uTuj1epGUlORWBn3o0KFi2rRpbu0/+OADkZCQIHQ6nejbt6/Ytm1bgHscPJTG6+3///e8xvPmzRN333230Ov1omvXriItLU0UFBQEvvNBID09XcTExAidTidiY2PF7373O3HixAlp/7Rp08TQoUPdjsnLyxMPPPCA0Ov1omfPnmL9+vUB7nXw2b17twAgvv32W699HL9N4/re6vlwXcPGfB+Ii4sTS5Yscdvm6308UFRCOO+gJCIiIiIiIr9htUMiIiIiIqIAYPBFREREREQUAAy+iIiIiIiIAoDBFxERERERUQAw+CIiIiIiIgoABl9EREREREQBwOCLiIiIiIgoABh8ERERERERBQCDLyIiIiIiogBg8EVERERERBQADL6IiIiIiIgCgMEXERERERFRAPx/AMO5VSjQcssAAAAASUVORK5CYII=\n", + "image/png": "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799fXL16VTE2MDBQdO7cucjj379/X7z55psiMDBQODg4CF9fXzF27Fhx+/ZtecysWbOESqUy69B2+PBhodFoxKRJkxTHKqrb4VdffaV47Zo1awQAcezYsSLf1/Xr1+Vt27dvF88995xwcnIS/v7+4o033hDfffedACD2798vj7t165bo1auXqFq1qpAkSZj+akKhbodCCPHrr7+Krl27Cg8PD6HVasVzzz0n1qxZoxhT3PyNP6vC44ty8OBB8a9//Uu4uLgIZ2dn0aJFC7F9+/Yi92dNt8MvvvhCTJw4UdSoUUM4OjqK1q1bi59//tls/LZt20Tz5s2Fk5OTcHFxEe3atRP/7//9P/n5Bw8eiDFjxojGjRsLd3d34ezsLOrXry9mz54t7t27J48r6fPNzc0VS5YskX9Orq6u4plnnhGvvfaauHDhgjyupHOx8LkjhBAXL14UAwYMENWrVxcODg6ifv36YvHixYrujdZ8dkaWnPemBgwYIACIVq1aFbvP1atXi+bNm8s/57p164rBgwcrfiaRkZHi2WeftWiOxv9HirsRkX2ThDCpaSAiIqv99ddfCA4OxuLFi80uaFzYnDlzMHfuXFy/fr1c1ifR4yMpKQlt27bFV199JTduISIi+8I1X0RERERERI8Agy8iIiIiIqJHgGWHREREREREjwAzX0RERERERI8Agy8iIiIiIqJHgMEXERERERHRI8CLLJeRwWDAlStX4Obm9lAX2yQiIiIiosebEAJ3796Fn58fVKri81sMvsroypUrCAgIsPU0iIiIiIiokrh06RJq1apV7PMMvsrIzc0NQN4H7O7ubuPZEBERERGRrWRmZiIgIECOEYrD4KuMjKWG7u7uDL6IiIiIiKjU5UhsuEFERERERPQIMPgiIiIiIiJ6BBh8ERERERERPQIMvoiIiIiIiB6BShF8LV++HMHBwXByckJYWBgOHjxY7NhPP/0UrVu3hqenJzw9PdG+fXv89NNPijFCCMyZMwd+fn5wdnZGmzZtcObMGcWY27dvIzo6Gh4eHvDw8EB0dDTu3LlTIe+PiIiIiIjI5sFXQkICJk+ejFmzZuHEiRNo3bo1OnbsiNTU1CLHJyUloX///ti/fz+OHDmC2rVrIyoqCpcvX5bHLFq0CEuXLsWyZctw7Ngx+Pj4oEOHDrh79648ZsCAATh58iR27dqF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\n", "text/plain": [ "
" ] @@ -268,7 +268,7 @@ "\n", "# this is for running the notebook in our testing framework\n", "smoke_test = ('CI' in os.environ)\n", - "n_steps = 2 if smoke_test else 10000\n", + "n_steps = 2 if smoke_test else 12000\n", "pyro.set_rng_seed(2)\n", "\n", "# enable validation (e.g. validate parameters of distributions)\n", @@ -277,23 +277,25 @@ "# clear the param store in case we're in a REPL\n", "pyro.clear_param_store()\n", "\n", - "data = torch.tensor([4.0, 4.2, 3.9, 4.1, 3.8, 3.5, 4.3]*10)\n", + "# Sample observations from a Normal distribution with loc 4 and scale 0.1\n", + "n = torch.distributions.Normal(torch.tensor([4.0]), torch.tensor([0.1]))\n", + "data = n.sample((100,))\n", + "\n", "\n", "def guide(data, index):\n", " scale_q = pyro.param('scale_{}'.format(index), torch.tensor([1.0]), constraints.positive)\n", " loc_q = pyro.param('loc_{}'.format(index), torch.tensor([0.0]))\n", - " pyro.sample(\"loc\", dist.Normal(loc_q, scale_q))\n", + " pyro.sample(\"z\", dist.Normal(loc_q, scale_q))\n", "\n", "\n", "def model(data):\n", " prior_loc = torch.tensor([0.])\n", " prior_scale = torch.tensor([5.])\n", - " loc = pyro.sample('loc', dist.Normal(prior_loc, prior_scale))\n", + " z = pyro.sample('z', dist.Normal(prior_loc, prior_scale))\n", " scale = torch.tensor([0.1])\n", "\n", " with pyro.plate('data', len(data)):\n", - "\n", - " pyro.sample('obs', dist.Normal(loc*loc, scale), obs=data)\n", + " pyro.sample('x', dist.Normal(z*z, scale), obs=data)\n", "\n", "\n", "def relbo(model, guide, *args, **kwargs):\n", @@ -304,8 +306,8 @@ " guide_trace = trace(guide).get_trace(*args, **kwargs)\n", "\n", " # We do not want to update parameters of previously fitted components and thus block all\n", - " # parameters in the approximation apart from loc.\n", - " replayed_approximation = trace(replay(block(approximation, expose=['loc']), guide_trace))\n", + " # parameters in the approximation apart from z.\n", + " replayed_approximation = trace(replay(block(approximation, expose=['z']), guide_trace))\n", " approximation_trace = replayed_approximation.get_trace(*args, **kwargs)\n", "\n", " loss_fn = pyro.infer.Trace_ELBO(max_plate_nesting=1).differentiable_loss(model,\n", @@ -316,7 +318,7 @@ " relbo = -loss_fn - approximation_trace.log_prob_sum()\n", " \n", " # By convention, the negative (R)ELBO is returned.\n", - " return - relbo\n", + " return -relbo\n", "\n", "\n", "def approximation(data, components, weights):\n", @@ -389,7 +391,7 @@ " total_approximation += Y\n", " pyplot.plot(X, total_approximation)\n", " pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*')\n", - " pyplot.title('Approximation of posterior over loc')\n", + " pyplot.title('Approximation of posterior over z')\n", " pyplot.ylabel('probability density')\n", " pyplot.show()\n", "\n", From a8883406a6af2b1b1d517adf153b276b06c11985 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 16 Dec 2019 11:58:14 +0100 Subject: [PATCH 26/29] Refoactor greedy algorithm section --- boosting_bbvi_tutorial.ipynb | 167 +++++++++++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 9 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index de0f3ab..a6fcaa5 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -76,6 +76,28 @@ "We will illustrate these points by looking at simple example: approximating a bimodal posterior.\n" ] }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from collections import defaultdict\n", + "from functools import partial\n", + "\n", + "import numpy as np\n", + "import pyro\n", + "import pyro.distributions as dist\n", + "import scipy.stats\n", + "import torch\n", + "import torch.distributions.constraints as constraints\n", + "from matplotlib import pyplot\n", + "from pyro.infer import SVI, Trace_ELBO\n", + "from pyro.optim import Adam\n", + "from pyro.poutine import block, replay, trace\n" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -219,12 +241,146 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Using all of the above components and using Pyro's SVI, we get the complete implementation of BBBVI:" + "We now have all the necessary parts to implement the greedy algorithm. First, we initialize the approximation:" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [], + "source": [ + "initial_approximation = partial(guide, index=0)\n", + "components = [initial_approximation]\n", + "weights = torch.tensor([1.])\n", + "wrapped_approximation = partial(approximation, components=components, weights=weights)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we iteratively find the $T$ components of the approximation by maximizing the RELBO at every step:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 1:\n", + "loc = -1.9934829473495483\n", + "scale = 0.020978907123208046\n", + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + ] + } + ], + "source": [ + "# clear the param store in case we're in a REPL\n", + "pyro.clear_param_store()\n", + "\n", + "# Sample observations from a Normal distribution with loc 4 and scale 0.1\n", + "n = torch.distributions.Normal(torch.tensor([4.0]), torch.tensor([0.1]))\n", + "data = n.sample((100,))\n", + "\n", + "#T=2\n", + "n_steps = 2 if smoke_test else 12000\n", + "pyro.set_rng_seed(2)\n", + "n_iterations = 2\n", + "locs = [0]\n", + "scales = [0]\n", + "for t in range(1, n_iterations + 1):\n", + "\n", + " # Create guide that only takes data as argument\n", + " wrapped_guide = partial(guide, index=t)\n", + " losses = []\n", + "\n", + " adam_params = {\"lr\": 0.01, \"betas\": (0.90, 0.999)}\n", + " optimizer = Adam(adam_params)\n", + "\n", + " # Pass our custom RELBO to SVI as the loss function.\n", + " svi = SVI(model, wrapped_guide, optimizer, loss=relbo)\n", + " for step in range(n_steps):\n", + " # Pass the existing approximation to SVI.\n", + " loss = svi.step(data, approximation=wrapped_approximation)\n", + " losses.append(loss)\n", + "\n", + " if step % 100 == 0:\n", + " print('.', end=' ')\n", + "\n", + " # Update the list of approximation components.\n", + " components.append(wrapped_guide)\n", + "\n", + " # Set new mixture weight.\n", + " new_weight = 2 / (t + 1)\n", + "\n", + " # In this specific case, we set the mixture weight of the second component to 0.5.\n", + " if t == 2:\n", + " new_weight = 0.5\n", + " weights = weights * (1-new_weight)\n", + " weights = torch.cat((weights, torch.tensor([new_weight])))\n", + "\n", + " # Update the approximation\n", + " wrapped_approximation = partial(approximation, components=components, weights=weights)\n", + "\n", + " print('Parameters of component {}:'.format(t))\n", + " scale = pyro.param(\"scale_{}\".format(t)).item()\n", + " scales.append(scale)\n", + " loc = pyro.param(\"loc_{}\".format(t)).item()\n", + " locs.append(loc)\n", + " print('loc = {}'.format(loc))\n", + " print('scale = {}'.format(scale))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Plot the resulting approximation\n", + "X = np.arange(-10, 10, 0.1)\n", + "pyplot.figure(figsize=(10, 4), dpi=100).set_facecolor('white')\n", + "total_approximation = np.zeros(X.shape)\n", + "for i in range(1, n_iterations + 1):\n", + " Y = weights[i].item() * scipy.stats.norm.pdf((X - locs[i]) / scales[i])\n", + " pyplot.plot(X, Y)\n", + " total_approximation += Y\n", + "pyplot.plot(X, total_approximation)\n", + "pyplot.plot(data.data.numpy(), np.zeros(len(data)), 'k*')\n", + "pyplot.title('Approximation of posterior over z')\n", + "pyplot.ylabel('probability density')\n", + "pyplot.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that boosting BBVI successfully approximates the bimodal posterior distributions with modes around -2 and +2." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Complete Implementation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Putting all the components together, we then get the complete implementation of boosting black box Variational Inference:" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 74, "metadata": {}, "outputs": [ { @@ -399,13 +555,6 @@ " boosting_bbvi()\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that boosting BBVI successfully approximates the bimodal posterior distributions with modes around -2 and +2." - ] - }, { "cell_type": "markdown", "metadata": {}, From 1b7d70b3cff7b2d954450f72ec01bd3d948ec597 Mon Sep 17 00:00:00 2001 From: Gideon Dresdner Date: Mon, 16 Dec 2019 13:47:25 +0100 Subject: [PATCH 27/29] small notation / latex changes --- boosting_bbvi_tutorial.ipynb | 46 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index a6fcaa5..6f2682a 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -31,26 +31,26 @@ "\n", "Briefly, Variational Inference allows us to find approximations of probability densities which are intractable to compute analytically. For instance, one might have observed variables $\\textbf{x}$, latent variables $\\textbf{z}$ and a joint distribution $p(\\textbf{x}, \\textbf{z})$. One can then use Variational Inference to approximate $p(\\textbf{z}|\\textbf{x})$. To do so, one first chooses a set of tractable densities, a variational family, and then tries to find the element of this set which most closely approximates the target distribution $p(\\textbf{z}|\\textbf{x})$.\n", "This approximating density is found by maximizing the Evidence Lower BOund (ELBO):\n", - "$$ \\mathbb{E}_q[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\mathbb{E}_q[\\text{log} q(\\mathbf{z})]$$\n", + "$$ \\mathbb{E}_q[\\log p(\\mathbf{x}, \\mathbf{z})] - \\mathbb{E}_q[\\log q(\\mathbf{z})]$$\n", "\n", "where $s(\\mathbf{z})$ is the approximating density.\n", "\n", "### Boosting Black Box Variational Inference \n", "\n", "In boosting black box Variational inference (BBBVI), we approximate the target density with a mixture of densities from the variational family:\n", - "$$q^T(\\mathbb{z}) = \\sum_{t=1}^T \\gamma_t s_t(\\mathbf{z})$$\n", + "$$q^t(\\mathbf{z}) = \\sum_{i=1}^t \\gamma_i s_i(\\mathbf{z})$$\n", "\n", - "$$\\text{where} \\sum_{t=1}^T \\gamma_t =1$$\n", + "$$\\text{where} \\sum_{i=1}^t \\gamma_i =1$$\n", "\n", "and $s_t(\\mathbf{z})$ are elements of the variational family.\n", "\n", "The components of the approximation are selected greedily by maximising the so-called Residual ELBO (RELBO) with respect to the next component $s_{t+1}(\\mathbf{z})$:\n", "\n", - "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", + "$$\\mathbb{E}_s[\\log p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\log s(\\mathbf{z})] - \\mathbb{E}_s[\\log q^t(\\mathbf{z})]$$\n", "\n", "Where the first two terms are the same as in the ELBO and the last term is the cross entropy between the next component $s_{t+1}(\\mathbf{z})$ and the current approximation $q^t(\\mathbf{z})$.\n", "\n", - "It's called *black box* Variational Inference because this optimization does not have to be tailored to the variational family which is being used. By setting $\\lambda$ (the regularization factor of the entropy term) to 1, standard SVI methods can be used to compute $\\mathbb{E}_s[\\text{log} p(\\mathbf{x}, \\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})]$. See the explanation of [the section on the implementation of the RELBO](#the-relbo) below for an explanation of how we compute the term $- \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", + "It's called *black box* Variational Inference because this optimization does not have to be tailored to the variational family which is being used. By setting $\\lambda$ (the regularization factor of the entropy term) to 1, standard SVI methods can be used to compute $\\mathbb{E}_s[\\log p(\\mathbf{x}, \\mathbf{z})] - \\lambda \\mathbb{E}_s[\\log s(\\mathbf{z})]$. See the explanation of [the section on the implementation of the RELBO](#the-relbo) below for an explanation of how we compute the term $- \\mathbb{E}_s[\\log q^t(\\mathbf{z})]$. Imporantly, we do not need to make any additional assumptions about the variational family that's being used to ensure that this algorithm converges. \n", "\n", "In [1], a number of different ways of finding the mixture weights $\\gamma_t$ are suggested, ranging from fixed step sizes based on the iteration to solving the optimisation problem of finding $\\gamma_t$ that will minimise the RELBO. Here, we used the fixed step size method.\n", "For more details on the theory behind boosting black box variational inference, please refer to [1]." @@ -79,7 +79,9 @@ { "cell_type": "code", "execution_count": 26, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "import os\n", @@ -117,7 +119,9 @@ { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def model(data):\n", @@ -148,7 +152,9 @@ { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def guide(data, index):\n", @@ -164,19 +170,21 @@ "### The RELBO \n", "\n", "We implement the RELBO as a function which can be passed to Pyro's SVI class in place of ELBO to find the approximation components $s_t(z)$. Recall that the RELBO has the following form:\n", - "$$\\mathbb{E}_s[\\text{log} p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\text{log}s(\\mathbf{z})] - \\mathbb{E}_s[\\text{log} q^t(\\mathbf{z})]$$\n", + "$$\\mathbb{E}_s[\\log p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\log s(\\mathbf{z})] - \\mathbb{E}_s[\\log q^t(\\mathbf{z})]$$\n", "\n", "Conveniently, this is very similar to the regular ELBO which allows us to reuse Pyro's existing ELBO. Specifically, we compute \n", - "$$E_s[\\text{log} p(x,z)] - \\lambda E_s[\\text{log}s]$$\n", + "$$E_s[\\log p(x,z)] - \\lambda E_s[\\log s]$$\n", "using Pyro's `Trace_ELBO` and then compute \n", - "$$ - E_s[\\text{log} q^t]$$\n", + "$$ - E_s[\\log q^t]$$\n", "using Poutine. For more information on how this works, we recommend going through the Pyro tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." ] }, { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def relbo(model, guide, *args, **kwargs):\n", @@ -221,7 +229,9 @@ { "cell_type": "code", "execution_count": 169, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def approximation(data, components, weights):\n", @@ -247,7 +257,9 @@ { "cell_type": "code", "execution_count": 88, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "initial_approximation = partial(guide, index=0)\n", @@ -339,7 +351,9 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# Plot the resulting approximation\n", @@ -586,7 +600,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.5" + "version": "3.6.7" }, "mimetype": "text/x-python", "name": "python", From bf257e9d880a7ca7b97a19dedf50cb4c5693bba1 Mon Sep 17 00:00:00 2001 From: Gideon Dresdner Date: Mon, 16 Dec 2019 13:51:20 +0100 Subject: [PATCH 28/29] more small latex changes --- boosting_bbvi_tutorial.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index 6f2682a..d3092a5 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -173,9 +173,9 @@ "$$\\mathbb{E}_s[\\log p(\\mathbf{x},\\mathbf{z})] - \\lambda \\mathbb{E}_s[\\log s(\\mathbf{z})] - \\mathbb{E}_s[\\log q^t(\\mathbf{z})]$$\n", "\n", "Conveniently, this is very similar to the regular ELBO which allows us to reuse Pyro's existing ELBO. Specifically, we compute \n", - "$$E_s[\\log p(x,z)] - \\lambda E_s[\\log s]$$\n", + "$$\\mathbb{E}_s[\\log p(x,z)] - \\lambda \\mathbb{E}_s[\\log s]$$\n", "using Pyro's `Trace_ELBO` and then compute \n", - "$$ - E_s[\\log q^t]$$\n", + "$$ - \\mathbb{E}_s[\\log q^t]$$\n", "using Poutine. For more information on how this works, we recommend going through the Pyro tutorials [on Poutine](https://pyro.ai/examples/effect_handlers.html) and [custom SVI objectives](https://pyro.ai/examples/custom_objectives.html)." ] }, @@ -221,7 +221,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Our implementation of the approximation $q^T(z) = \\sum_{t=1}^T \\gamma_t s_t(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample a component according to the mixture weights. In a second step, we draw a sample from the corresponding component.\n", + "Our implementation of the approximation $q^t(z) = \\sum_{i=1}^t \\gamma_i s_i(z)$ consists of a list of components, i.e. the guides from the greedy selection steps, and a list containing the mixture weights of the components. To sample from the approximation, we thus first sample a component according to the mixture weights. In a second step, we draw a sample from the corresponding component.\n", "\n", "Similarly as with the guide, we use `partial(approximation, components=components, weights=weights)` to get an approximation function which has the same signature as the model." ] From 1dcf43b870534b876ae51d7ba6748bcc6b76d682 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Tue, 17 Dec 2019 12:42:29 +0100 Subject: [PATCH 29/29] Back up before pulling --- boosting_bbvi_tutorial.ipynb | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/boosting_bbvi_tutorial.ipynb b/boosting_bbvi_tutorial.ipynb index a6fcaa5..3a9d402 100644 --- a/boosting_bbvi_tutorial.ipynb +++ b/boosting_bbvi_tutorial.ipynb @@ -265,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 89, "metadata": {}, "outputs": [ { @@ -275,7 +275,9 @@ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 1:\n", "loc = -1.9934829473495483\n", "scale = 0.020978907123208046\n", - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Parameters of component 2:\n", + "loc = 1.9889194965362549\n", + "scale = 0.012325801886618137\n" ] } ], @@ -338,9 +340,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 90, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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558X4eHhIjw8XDz//PPi+vXrPnxnLdtzzz0n0tPTVfeVlZUp/huUl5eLAQMGiI4dO4rQ0FDRvXt3MX36dHHt2jUf9jhwHDp0SKSmpgqj0SjCwsJEz549xcKFC8XNmzcV7QCInJwc+bHdbhcLFy4UJpNJGAwGMWDAAHHs2DEf977ly8nJUf3MaPz3No7hpnv33XdFbGysCA0NFcnJyYoy6AMHDhQvvPCCov3f//530bNnT6HX60V8fLzYunWrj3scONyN18b//zuf45kzZ4quXbuK0NBQ8ZOf/ERkZGSIwsJC33c+AGRmZoqoqCih1+tFdHS0eOaZZ0Rpaam8/4UXXhADBw5UHFNQUCAeffRRERoaKrp16ybWrVvn414Hnl27dgkA4uTJky77OH6bRrpudf6RzuHdXA/ExsaKhQsXKrZ5+hz3FY0QjhWURERERERE5DWsdkhEREREROQDDL6IiIiIiIh8gMEXERERERGRDzD4IiIiIiIi8gEGX0RERERERD7A4IuIiIiIiMgHGHwRERERERH5AIMvIiIiIiIiH2DwRURERERE5AMMvoiIiIiIiHyAwRcREREREZEPMPgiIiIiIiLygf8DUttc+hM14bIAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Plot the resulting approximation\n", "X = np.arange(-10, 10, 0.1)\n", @@ -380,7 +393,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 92, "metadata": {}, "outputs": [ {