This notebook is available on GitHub. Interactive online version: Binder badge

Test computational scaling

Here we give an example of how to measure the training computation time as a function of training iteration and number of dimensions.

[1]:
import alabi
from alabi.core import SurrogateModel
from alabi import benchmarks as bm
import numpy as np
import matplotlib.pyplot as plt
from functools import partial
from scipy.stats import multivariate_normal

Define common settings for all tests

[2]:
ncore = 1                       # we'll run one active learning chain on one core
ntrain = 100                    # number of initial training samples
savedir = "results/scaling"     # directory to save results

gp_kwargs = {"kernel": "ExpSquaredKernel",
             "fit_amp": True,
             "fit_mean": True,
             "fit_white_noise": False,
             "white_noise": -12,
             "gp_opt_method": "l-bfgs-b",
             "gp_scale_rng": [-2,2],
             "optimizer_kwargs": {"max_iter": 50, "xatol": 1e-3, "fatol": 1e-2, "adaptive": True}}

al_kwargs = {"algorithm": "bape",
             "gp_opt_freq": 20,
             "obj_opt_method": "nelder-mead",
             "nopt": 1,
             "optimizer_kwargs": {"max_iter": 50, "xatol": 1e-3, "fatol": 1e-2, "adaptive": True}}

Define a general function that trains alabi on an N-dimensional Gaussian for max_iter iterations

[3]:
def run_alabi(ndim, max_iter=100, savedir="results/scaling"):

    path = f"{savedir}/multivariate_normal_{ndim}d/"

    # Define the multivariate normal likelihood function
    mean = np.zeros(ndim)
    cov = bm.random_gaussian_covariance(ndim)
    lnlike = partial(multivariate_normal.logpdf, mean=mean, cov=cov)

    # Train surrogate model
    sm = SurrogateModel(lnlike_fn=lnlike,
                        bounds=[(-3., 3.) for _ in range(ndim)],
                        savedir=path,
                        cache=True,
                        verbose=True,
                        ncore=ncore)

    # save the true mean and covariance to a file
    np.savez(f"{path}gaussian_mean_cov.npz", mean=mean, cov=cov)

    # Initialize surrogate model
    if ndim >= 40:
        sm.init_samples(ntrain=ntrain, sampler="uniform")
    else:
        sm.init_samples(ntrain=ntrain, sampler="sobol")

    sm.init_gp(**gp_kwargs)
    sm.active_train(niter=max_iter, **al_kwargs)
    sm.plot(plots=["gp_all"])

For a quick test, we’ll just run alabi for a 5-dimensional gaussian and measure the amount of computational overhead alabi takes to train the surrogate model. To test more dimensions add them to the dimensions array, or to test for more iterations increase max_iter.

[4]:
dimensions = [5]
# dimensions = [10, 20, 30]

# Test the scaling of ALABI with dimensionality
for ndim in dimensions:
    run_alabi(ndim, max_iter=200, savedir=savedir)
Initialized GP with squared exponential kernel.
Successfully initialized GP on attempt 1

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
Running 200 active learning iterations using bape...
  8%|▊         | 17/200 [00:00<00:02, 79.35it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 16%|█▋        | 33/200 [00:00<00:04, 35.49it/s]
Train MSE: 5.290769548379788e-16

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 24%|██▍       | 49/200 [00:01<00:05, 29.95it/s]
Train MSE: 2.8140615805435077e-16
 29%|██▉       | 58/200 [00:01<00:03, 38.40it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 36%|███▋      | 73/200 [00:02<00:04, 28.77it/s]
Train MSE: 4.740593184211731e-16

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 44%|████▎     | 87/200 [00:03<00:04, 24.17it/s]
Train MSE: 1.5158058487886292e-15
 47%|████▋     | 94/200 [00:03<00:03, 29.82it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 54%|█████▍    | 108/200 [00:04<00:03, 24.03it/s]
Train MSE: 5.561937160794517e-15
 57%|█████▊    | 115/200 [00:04<00:02, 29.48it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 64%|██████▍   | 128/200 [00:05<00:03, 21.95it/s]
Train MSE: 1.3563998408462552e-14
 68%|██████▊   | 135/200 [00:05<00:02, 27.36it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 74%|███████▎  | 147/200 [00:06<00:02, 18.96it/s]
Train MSE: 3.814731814602212e-12
 80%|███████▉  | 159/200 [00:06<00:01, 27.91it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 84%|████████▍ | 168/200 [00:07<00:02, 14.01it/s]
Train MSE: 2.661067977783123e-10
 90%|████████▉ | 179/200 [00:07<00:00, 22.16it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
 92%|█████████▏| 184/200 [00:09<00:01,  9.85it/s]
Train MSE: 2.6148026975461192e-09
 98%|█████████▊| 195/200 [00:09<00:00, 16.86it/s]

Optimizing GP hyperparameters using 5-fold cross-validation...
Evaluating 100 hyperparameter candidates using 5-fold CV...
100%|██████████| 200/200 [00:10<00:00, 18.99it/s]
Train MSE: 2.0152473853508697e-07
Caching model to results/scaling/multivariate_normal_5d/surrogate_model...
Plotting the gp mean squared error with 0 test samples...
Saving to results/scaling/multivariate_normal_5d//gp_mse_vs_iteration.png

Get the recorded train time for each step of alabi’s training process.

[5]:
train_time = []
opt_time = []
test_mse = []
hp_opt_time = []
hp_opt_iter = []

for ndim in dimensions[::-1]: # Reverse order for plotting
    path = f"{savedir}/multivariate_normal_{ndim}d/"
    sm = alabi.load_model_cache(path)
    train_time.append(sm.training_results['gp_train_time'])
    opt_time.append(sm.training_results['obj_fn_opt_time'])
    test_mse.append(sm.training_results['test_mse'])
    hp_opt_time.append(sm.training_results['gp_hyperparam_opt_time'])
    hp_opt_iter.append(sm.training_results['gp_hyperparameter_opt_iteration'])
iterations = sm.training_results['iteration']

train_time = np.array(train_time)
opt_time = np.array(opt_time)
test_mse = np.array(test_mse)
hp_opt_time = np.array(hp_opt_time)
hp_opt_iter = np.array(hp_opt_iter)

cum_time = np.sum(train_time, axis=1) + np.sum(opt_time, axis=1) + np.sum(hp_opt_time, axis=1)
[6]:
logy = False

fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 18), sharex=True)
plt.subplots_adjust(hspace=0.05)

# Top panel - Training time
for ii, ndim in enumerate(dimensions):
    ax1.plot(iterations, train_time[ii], label=f"{dimensions[ii]} dimensions", linewidth=1)
ax1.set_ylabel("GP training time (s)", fontsize=22)
ax1.legend(loc="upper left", fontsize=18)
ax1.minorticks_on()

# Middle panel - Optimization time
for ii, ndim in enumerate(dimensions):
    ax2.plot(iterations, opt_time[ii], linewidth=1)
ax2.set_ylabel("BAPE optimization time (s)", fontsize=22)
ax2.minorticks_on()

# # Bottom panel - Total time
for ii, ndim in enumerate(dimensions):
    ax3.plot(hp_opt_iter[ii], hp_opt_time[ii][1:], linewidth=1.5)
ax3.set_xlabel("Number of active learning iterations", fontsize=22)
ax3.set_ylabel("Hyperparameter optimization time (s)", fontsize=22)
ax3.minorticks_on()

if logy:
    ax1.set_yscale("log")
    ax2.set_yscale("log")
    # ax3.set_yscale("log")
ax1.set_xlim(0, iterations[-1])

plt.savefig(f"{savedir}/multivariate_normal_training_time.png", bbox_inches='tight', dpi=800)
plt.show()
_images/11_plot_gaussian_nd_10_0.png

Plot the cummulative training time as a bar chart for each dimension.

[7]:
plt.bar(dimensions, cum_time, width=1, color='blue', alpha=0.7)
plt.xlabel("Number of dimensions", fontsize=22)
plt.ylabel("Total training time (s)", fontsize=22)
plt.xticks(dimensions, fontsize=20)
plt.yticks(fontsize=20)
plt.savefig(f"{savedir}/multivariate_normal_total_training_time.png", bbox_inches='tight', dpi=600)
plt.show()
_images/11_plot_gaussian_nd_12_0.png