This notebook shows how to use GPFlow to approximate functions¶

In [1]:
import tensorflow as tf
import gpflow as gp
gp.config.set_default_summary_fmt("notebook")
import numpy as np
from matplotlib import pyplot as plt

1D example¶

In [2]:
def f(x):
    return x ** 2

# generate training data
Ntrain = 200
Ntest1 = 50
Ntest2 = 500
Ntest3 = 2000

X_train = np.random.rand(Ntrain, 1)
Y_train = f(X_train)

X_test1 = np.random.rand(Ntest1, 1)
Y_test1 = f(X_test1)

X_test2 = np.random.rand(Ntest2, 1)
Y_test2 = f(X_test2)

X_test3 = np.random.rand(Ntest3, 1)
Y_test3 = f(X_test3)

a) without @tf.function¶

In [3]:
approx = gp.models.GPR(data=(X_train, Y_train), kernel=gp.kernels.SquaredExponential(), mean_function=None)
gp.utilities.print_summary(approx)
# optimize hp
optimizer = gp.optimizers.Scipy()
optimizer.minimize(approx.training_loss, approx.trainable_variables, options=dict(maxiter=100))
gp.utilities.print_summary(approx)
name class transform prior trainable shape dtype value
GPR.kernel.variance ParameterSoftplus True () float64 1
GPR.kernel.lengthscalesParameterSoftplus True () float64 1
GPR.likelihood.varianceParameterSoftplus + Shift True () float64 1
name class transform prior trainable shape dtype value
GPR.kernel.variance ParameterSoftplus True () float64562.868
GPR.kernel.lengthscalesParameterSoftplus True () float64 5.72068
GPR.likelihood.varianceParameterSoftplus + Shift True () float64 1e-06
In [4]:
# make predictions
Y_train_approx, var_train_approx = approx.predict_f(X_train)
Y_test1_approx, var_test1_approx = approx.predict_f(X_test1)
Y_test2_approx, var_test2_approx = approx.predict_f(X_test2)
Y_test3_approx, var_test3_approx = approx.predict_f(X_test3)
In [5]:
plt.plot(X_train[:, 0], Y_train[:, 0], 'bo', label = 'training data')
plt.plot(X_train[:, 0], Y_train_approx[:, 0], 'rx', label = 'prediction')
plt.legend()
plt.show()
No description has been provided for this image
In [6]:
# measure timings
print('Create model:')
%timeit gp.models.GPR(data=(X_train, Y_train), kernel=gp.kernels.SquaredExponential(), mean_function=None)
print('Optimize hps:')
%timeit optimizer.minimize(approx.training_loss, approx.trainable_variables, options=dict(maxiter=100))
print('Predict test1:')
%timeit approx.predict_f(X_test1)
print('Predict test2:')
%timeit approx.predict_f(X_test2)
print('Predict test3:')
%timeit approx.predict_f(X_test3)
Create model:
100 loops, best of 3: 12.7 ms per loop
Optimize hps:
1 loop, best of 3: 294 ms per loop
Predict test1:
100 loops, best of 3: 14.4 ms per loop
Predict test2:
10 loops, best of 3: 19.5 ms per loop
Predict test3:
10 loops, best of 3: 31.7 ms per loop

b) now using @tf.function¶

For convenience I use the class implemented in new_approximators.py, it also normalizes and other things, but thats not the point. The point is that the _predict and _predict_with_var methods are decorated. Here the hp's are always optimized when the model is created. We can measure a significant speedup for prediction.

In [7]:
from new_approximators import GPflow_norm
In [8]:
# measure timings
approx_tf = GPflow_norm(X_train, Y_train, kernel_name = 'RBF')
print('Create model and optimize hps:')
%timeit GPflow_norm(X_train, Y_train, kernel_name = 'RBF')
print('Predict test1:')
%timeit approx_tf.predict_with_var(X_test1)
print('Predict test2:')
%timeit approx_tf.predict_with_var(X_test2)
print('Predict test3:')
%timeit approx_tf.predict_with_var(X_test3)
Create model and optimize hps:
1 loop, best of 3: 361 ms per loop
Predict test1:
The slowest run took 550.78 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 1.77 ms per loop
Predict test2:
The slowest run took 41.44 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 4.9 ms per loop
Predict test3:
The slowest run took 18.20 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 16 ms per loop

2D Example¶

In [9]:
def f(x):
    return x[:, 0:1] ** 2 + 0.4 * (x[:, 1:2] - 0.5) ** 3.

# generate training data
Ntrain = 200
Ntest1 = 50
Ntest2 = 500
Ntest3 = 2000

X_train = np.random.rand(Ntrain, 2)
Y_train = f(X_train)

X_test1 = np.random.rand(Ntest1, 2)
Y_test1 = f(X_test1)

X_test2 = np.random.rand(Ntest2, 2)
Y_test2 = f(X_test2)

X_test3 = np.random.rand(Ntest3, 2)
Y_test3 = f(X_test3)

a) without @tf.function¶

In [10]:
# note that we have to pass the array as lengthscales argument if we want non-isotropic lengthscales
approx = gp.models.GPR(data=(X_train, Y_train), kernel=gp.kernels.SquaredExponential(lengthscales = np.array([1., 1.])), mean_function=None)
gp.utilities.print_summary(approx)
# optimize hp
optimizer = gp.optimizers.Scipy()
optimizer.minimize(approx.training_loss, approx.trainable_variables, options=dict(maxiter=100))
gp.utilities.print_summary(approx)
name class transform prior trainable shape dtype value
GPR.kernel.variance ParameterSoftplus True () float641.0
GPR.kernel.lengthscalesParameterSoftplus True (2,) float64[1. 1.]
GPR.likelihood.varianceParameterSoftplus + Shift True () float641.0
name class transform prior trainable shape dtype value
GPR.kernel.variance ParameterSoftplus True () float642696.007281572945
GPR.kernel.lengthscalesParameterSoftplus True (2,) float64[9.2547561 4.99937864]
GPR.likelihood.varianceParameterSoftplus + Shift True () float641e-06
In [11]:
# make predictions
Y_train_approx, var_train_approx = approx.predict_f(X_train)
Y_test1_approx, var_test1_approx = approx.predict_f(X_test1)
Y_test2_approx, var_test2_approx = approx.predict_f(X_test2)
Y_test3_approx, var_test3_approx = approx.predict_f(X_test3)
In [12]:
plt.plot(X_train[:, 0], Y_train[:, 0], 'bo', label = 'training data')
plt.plot(X_train[:, 0], Y_train_approx[:, 0], 'rx', label = 'prediction')
plt.xlabel('Dimension 0')
plt.legend()
plt.show()

plt.plot(X_train[:, 1], Y_train[:, 0], 'bo', label = 'training data')
plt.plot(X_train[:, 1], Y_train_approx[:, 0], 'rx', label = 'prediction')
plt.xlabel('Dimension 1')
plt.legend()
plt.show()
No description has been provided for this image
No description has been provided for this image
In [13]:
# measure timings
print('Create model:')
%timeit gp.models.GPR(data=(X_train, Y_train), kernel=gp.kernels.SquaredExponential(), mean_function=None)
print('Optimize hps:')
%timeit optimizer.minimize(approx.training_loss, approx.trainable_variables, options=dict(maxiter=100))
print('Predict test1:')
%timeit approx.predict_f(X_test1)
print('Predict test2:')
%timeit approx.predict_f(X_test2)
print('Predict test3:')
%timeit approx.predict_f(X_test3)
Create model:
100 loops, best of 3: 12.9 ms per loop
Optimize hps:
1 loop, best of 3: 237 ms per loop
Predict test1:
100 loops, best of 3: 15.6 ms per loop
Predict test2:
10 loops, best of 3: 20.6 ms per loop
Predict test3:
10 loops, best of 3: 32.7 ms per loop

b) now using @tf.function¶

In [14]:
# measure timings
approx_tf = GPflow_norm(X_train, Y_train, kernel_name = 'RBF')
print('Create model and optimize hps:')
%timeit GPflow_norm(X_train, Y_train, kernel_name = 'RBF')
print('Predict test1:')
%timeit approx_tf.predict_with_var(X_test1)
print('Predict test2:')
%timeit approx_tf.predict_with_var(X_test2)
print('Predict test3:')
%timeit approx_tf.predict_with_var(X_test3)
WARNING:tensorflow:5 out of the last 66 calls to <function Scipy.eval_func.<locals>._tf_eval at 0x7f1eb4e41ea0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
Create model and optimize hps:
1 loop, best of 3: 563 ms per loop
Predict test1:
The slowest run took 100.53 times longer than the fastest. This could mean that an intermediate result is being cached.
100 loops, best of 3: 1.99 ms per loop
Predict test2:
The slowest run took 51.87 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 4.58 ms per loop
Predict test3:
The slowest run took 19.87 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 3: 17.8 ms per loop
In [ ]:
 
In [ ]: