Fixed broadcasting rules for gpflow.models.model.predict_y, partially resolves #1461. by mohit-rajpal · Pull Request #1597 · GPflow/GPflow
PR type: new feature
**Related issue(s)/PRs:#1461
Summary
Proposed changes
This proposed change fixes the broadcasting rules for predict_y to correctly handle full_cov/full_output_cov = True. The changes made rely on slightly abusing tf broadcasting rules in a compatible manner to the covariance matrix/tensor when full_cov/full_output_cov = True.
What alternatives have you considered?
I think at this time we should keep predict_log_densities for full_cov/full_output_cov = True as is. The reasoning behind this is that with large covariance matrix/tensors, there is no efficient way to compute these exactly without hitting OOM issues. I strongly prefer keeping the predict_log_densities 'as-is' to avoid a situation where predict_log_densities takes far too long to run, or approximates a solution.
Minimal working example
import gpflow import numpy as np import gpflow as gpf for foc in [False, True]: for oc in [False, True]: print(foc) print(oc) rng = np.random.RandomState(123) N = 100 # Number of training observations X = rng.rand(N, 1) * 2 - 1 # X values M = 50 # Number of inducing locations kernel = gpflow.kernels.SquaredExponential() Z = X[:M, :].copy() # Initialize inducing locations to the first M inputs in the dataset m = gpflow.models.SVGP(kernel, gpflow.likelihoods.Gaussian(), Z, num_data=N) pX = np.linspace(10, 20, 4)[:, None] # Test locations _, pYv = m.predict_y(pX, full_output_cov = foc, full_cov = oc) # Predict Y values at test locations _, pFv = m.predict_f(pX, full_output_cov = foc, full_cov = oc) print(pYv.shape) print(pYv - pFv) num_elements = 7 L = 2 Zinit = [gpf.inducing_variables.InducingPoints(np.linspace(0, 100, 60)[:, None]) for _ in range(L)] kern_list = [gpflow.kernels.SquaredExponential() for _ in range(L)] #linear model of coregionalization kernel = gpf.kernels.LinearCoregionalization( kern_list, W=np.random.randn(num_elements, L)) # create multi-output inducing variables from Z iv = gpf.inducing_variables.SeparateIndependentInducingVariables( Zinit ) # initialize mean of variational posterior to be of shape MxL q_mu = np.zeros((60, L)) # initialize \sqrt(Σ) of variational posterior to be of shape LxMxM q_sqrt = np.repeat(np.eye(60)[None, ...], L, axis=0) * 1.0 # create SVGP model as usual and optimize m = gpf.models.SVGP( kernel, gpf.likelihoods.Gaussian(), inducing_variable=iv, q_mu=q_mu, q_sqrt=q_sqrt ) _, pYv = m.predict_y(pX, full_output_cov = foc, full_cov = oc) # Predict Y values at test locations _, pFv = m.predict_f(pX, full_output_cov = foc, full_cov = oc) print(pYv.shape) print(pYv - pFv)
PR checklist
- New features: code is well-documented
- detailed docstrings (API documentation)
- notebook examples (usage demonstration)
- The bug case / new feature is covered by unit tests
- Code has type annotations
- I ran the black+isort formatter (
make format) - I locally tested that the tests pass (
make check-all)
Release notes
Fully backwards compatible: yes
If not, why is it worth breaking backwards compatibility:
Commit message (for release notes): Fixed broadcasting rules for gpflow.models.model.predict_y, partially resolves #1461.