I have been trying to (crudely) train and save a gpflow
SVGP
model on a toy dataset largely following this notebook example
Upon saving the model using pickle
(I appreciate this is not recommended but I don't believe this is the main issue here), I discovered some unusual and what I presume is unintended behaviour:
If we do not call gpflow.utilities.freeze(model)
, before trying to pickle
model
, then we get an error.
If we do call gpflow.utilities.freeze(model)
(discarding the returned frozen model), then model
can be pickled without error.
To reproduce
Minimal, reproducible example
import numpy as np
import gpflow
import tensorflow as tf
import pickle
rng = np.random.RandomState(123)
N = 10000 # Number of training observations
X = rng.rand(N, 1)
Y = rng.randn(N, 1)
data = (X, Y)
n_inducing_vars = 100
Z = X[:n_inducing_vars]
minibatch_size = 100
n_iterations = 100
#Define model object
model = gpflow.models.SVGP(gpflow.kernels.Matern12(), gpflow.likelihoods.Bernoulli(), inducing_variable=Z, num_data=N)
#Create minibatch object
data_minibatch = (
tf.data.Dataset.from_tensor_slices(data).prefetch(
N).repeat().shuffle(N).batch(minibatch_size)
)
data_minibatch_it = iter(data_minibatch)
model_objective = model.training_loss_closure(data_minibatch_it)
#Define optimiser
optimizer = tf.keras.optimizers.Adam(0.001)
#Optimise both variational parameters and kernel hyperparameters.
for step in range(n_iterations):
optimizer.minimize(model_objective,
var_list=model.trainable_variables
)
freeze = False
if not freeze:
# pickle doesn't work
pickle.dump(model, open('test1', 'wb'))
else:
# if following code is executed, pickle works fine
_ = gpflow.utilities.freeze(model) # ignore return value
pickle.dump(model, open('test1', 'wb'))
Stack trace, or error message
TypeError Traceback (most recent call last)
<ipython-input-6-3d5f537ca994> in <module>
----> 1 pickle.dump(model, open('test1', 'wb'))
TypeError: can't pickle HashableWeakRef objects
Expected behaviour
Not saying that I expected the pickle to work in the first instance, as I know it isn't the recommended way of saving tensorflow
-related objects in general. However, I certainly wouldn't expect it to fail in the first instance but succeed in the second. From looking at the codebase, I don't believe gpflow.utilities.freeze(model)
should be mutating model
, which it seems to be doing.
System information
- Tested with GPflow versions 2.0.0 ... 2.0.4
- TensorFlow version: 2.1.0, tensorflow_probability 0.9.0
- Python version: Python 3.6.9
I would guess that in calling freeze
on model
it is inexplicably actually converting model
into a "frozen" model, which then has the "constant" properties (https://gpflow.readthedocs.io/en/master/notebooks/intro_to_gpflow2.html#TensorFlow-saved_model) that enable it to be pickled.
Any clarity on this matter would be very much appreciated.
Note I posted this as an issue
on the gpflow
github
(https://github.com/GPflow/GPflow/issues/1493), but it was decided that this issue should be broadcast here to the wider gpflow community.