def test_fourier_feature_layer_compute_covariance_of_inducing_variables(batch_size):
    """
    Ensure that the random fourier feature map can be used to approximate the covariance matrix
    between the inducing point vectors of a sparse GP, with the condition that the number of latent
    GP models is greater than one.
    """
    n_features = 10000

    kernel = gpflow.kernels.SquaredExponential()
    fourier_features = RandomFourierFeatures(kernel, n_features, dtype=tf.float64)

    x_new = tf.ones(shape=(2 * batch_size + 1, 1), dtype=tf.float64)

    u = fourier_features(x_new)
    approx_kernel_matrix = inner_product(u, u)

    actual_kernel_matrix = kernel.K(x_new, x_new)

    np.testing.assert_allclose(approx_kernel_matrix, actual_kernel_matrix, atol=0.05)
def test_fourier_features_can_approximate_kernel_multidim(kernel_class, lengthscale, n_dims):
    n_features = 10000
    x_rows = 20
    y_rows = 30
    # ARD
    lengthscales = np.random.rand((n_dims)) * lengthscale

    kernel = kernel_class(lengthscales=lengthscales)
    fourier_features = RandomFourierFeatures(kernel, n_features, dtype=tf.float64)

    x = tf.random.uniform((x_rows, n_dims), dtype=tf.float64)
    y = tf.random.uniform((y_rows, n_dims), dtype=tf.float64)

    u = fourier_features(x)
    v = fourier_features(y)
    approx_kernel_matrix = inner_product(u, v)

    actual_kernel_matrix = kernel.K(x, y)

    np.testing.assert_allclose(approx_kernel_matrix, actual_kernel_matrix, atol=0.05)
Exemplo n.º 3
0
The `KernelWithFeatureDecomposition` instance represents a kernel together with its finite feature decomposition,
$$
k(x, x') = \sum_{i=0}^L \lambda_i \phi_i(x) \phi_i(x'),
$$
where $\lambda_i$ and $\phi_i(\cdot)$ are the coefficients (eigenvalues) and features (eigenfunctions), respectively, and $L$ is the finite cutoff. See [the notebook on weight space approximation](weight_space_approximation.ipynb) for a detailed explanation of how to construct this decomposition using Random Fourier Features (RFF).
"""

# %%
kernel = gpflow.kernels.Matern52()
Z = np.linspace(X.min(), X.max(), 10).reshape(-1, 1).astype(np.float64)

inducing_variable = gpflow.inducing_variables.InducingPoints(Z)
gpflow.utilities.set_trainable(inducing_variable, False)

num_rff = 1000
eigenfunctions = RandomFourierFeatures(kernel, num_rff, dtype=default_float())
eigenvalues = np.ones((num_rff, 1), dtype=default_float())
kernel_with_features = KernelWithFeatureDecomposition(kernel, eigenfunctions,
                                                      eigenvalues)

# %% [markdown]
"""
# Building and training the single-layer GP

## Initialise the single-layer GP
Because `KernelWithFeatureDecomposition` is just a `gpflow.kernels.Kernel`, we can construct a GP layer with it.
"""
# %%
layer = gpflux.layers.GPLayer(
    kernel_with_features,
    inducing_variable,
def conduct_experiment(num_input_dimensions, num_train_samples, num_features):
    """
    Compute the log10 Wassertein distance between the weight space approximated GP and the exact GP,
    and between the hybrid-rule approximated GP and the exact GP.

    :param num_input_dimensions: The number of input dimensions.
    :param num_train_samples: The number of training samples.
    :param num_features: The number of feature functions.

    :return: The log10 Wasserstein distances for both approximations.
    """
    lengthscale = (
        num_input_dimensions /
        100.0)**0.5  # adjust kernel lengthscale to the number of input dims
    num_features = num_train_samples + num_features

    # exact kernel
    exact_kernel = kernel_class(lengthscales=lengthscale)

    # weight space approximated kernel
    feature_functions = RandomFourierFeatures(
        kernel=kernel_class(lengthscales=lengthscale),
        output_dim=num_features,
        dtype=default_float(),
    )
    feature_coefficients = np.ones((num_features, 1), dtype=default_float())
    approximate_kernel = KernelWithFeatureDecomposition(
        kernel=None,
        feature_functions=feature_functions,
        feature_coefficients=feature_coefficients)

    # create training data set and test points for evaluation
    X = []
    for i in range(num_input_dimensions):
        random_samples = np.random.uniform(low=0.15,
                                           high=0.85,
                                           size=(num_train_samples, ))
        X.append(random_samples)
    X = np.array(X).transpose()

    kXX = exact_kernel.K(X)
    kXX_plus_noise_var = tf.linalg.set_diag(
        kXX,
        tf.linalg.diag_part(kXX) + noise_variance)
    lXX = tf.linalg.cholesky(kXX_plus_noise_var)
    y = tf.matmul(lXX, tf.random.normal([num_train_samples, 1], dtype=X.dtype))

    X_star = (
        []
    )  # test data is created to lie within two intervals that partially overlap with the train data
    for i in range(num_input_dimensions):
        random_samples = np.random.uniform(low=0.0,
                                           high=0.3,
                                           size=(num_test_samples, ))
        indices = np.random.uniform(size=(num_test_samples, )) < 0.5
        random_samples[indices] = np.random.uniform(
            low=0.7, high=1.0, size=(num_test_samples, ))[indices]
        X_star.append(random_samples)
    X_star = np.array(X_star).transpose()

    # identify mean and covariance of the analytic GPR posterior
    f_mean_exact, f_var_exact = compute_analytic_GP_predictions(
        X=X,
        y=y,
        kernel=exact_kernel,
        noise_variance=noise_variance,
        X_star=X_star)

    # identify mean and covariance of the analytic GPR posterior when using the weight space approximated kernel
    f_mean_weight, f_var_weight = compute_analytic_GP_predictions(
        X=X,
        y=y,
        kernel=approximate_kernel,
        noise_variance=noise_variance,
        X_star=X_star)

    # identify mean and covariance using the hybrid approximation
    f_mean_hybrid, f_var_hybrid = compute_hybrid_rule_predictions(
        X=X,
        y=y,
        exact_kernel=exact_kernel,
        approximate_kernel=approximate_kernel,
        noise_variance=noise_variance,
        X_star=X_star,
    )

    # compute log10 Wasserstein distance between the exact solution and the weight space approximation
    log10_ws_dist_weight = log10_Wasserstein_distance(f_mean_exact,
                                                      f_var_exact,
                                                      f_mean_weight,
                                                      f_var_weight)

    # compute log10 Wassertein distance between the exact solution and the hybrid approximation
    log10_ws_dist_hybrid = log10_Wasserstein_distance(f_mean_exact,
                                                      f_var_exact,
                                                      f_mean_hybrid,
                                                      f_var_hybrid)

    # return the log Wasserstein distances for both approximations
    return log10_ws_dist_weight, log10_ws_dist_hybrid
def test_fourier_features_shapes(n_features, n_dims, batch_size):
    kernel = gpflow.kernels.SquaredExponential()
    fourier_features = RandomFourierFeatures(kernel, n_features, dtype=tf.float64)
    features = fourier_features(tf.ones(shape=(batch_size, n_dims)))

    np.testing.assert_equal(features.shape, [batch_size, n_features])
def test_throw_for_unsupported_kernel():
    kernel = gpflow.kernels.Constant()
    with pytest.raises(AssertionError) as excinfo:
        RandomFourierFeatures(kernel, 1)

    assert "Unsupported Kernel" in str(excinfo.value)