Coregionalization с пакетным обучением в gpflow - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь реализовать модель GP с coregionalization, которая может обучаться, используя партии.

Пример coregionalization в документах (https://gpflow.readthedocs.io/en/master/notebooks/advanced/coregionalisation.html) использует модель VGP (gpflow.models.VGP), и это просто в использовании. Тем не менее, я не могу обучить это с пакетами (это может быть возможно?)

В идеале я хотел бы использовать модель SVGP (gpflow.models.SVGP) - для которой есть хороший пример с пакетным обучением (https://gpflow.readthedocs.io/en/master/notebooks/advanced/gps_for_big_data.html). Модель тренируется (см. Ниже), но я не могу дать ей разумный прогноз. Я думаю, что это предсказание неправильно.

Я запрограммировал расчет «вручную», чтобы получить ожидаемое решение.

Любые идеи очень ценятся!

Большое спасибо,

Уилл.

import gpflow
import tensorflow as tf
import numpy as np
import matplotlib
from tqdm import trange
%matplotlib inline

from copy import copy, deepcopy
from gpflow.ci_utils import ci_niter

matplotlib.rcParams['figure.figsize'] = (12, 6)
plt = matplotlib.pyplot
np.random.seed(123)

Генерирование некоторых данных

# make a dataset with two outputs, correlated, heavy-tail noise. One has more noise than the other.
X1 = np.random.rand(100, 1)  # Observed locations for first output
X2 = np.random.rand(50, 1) * 0.5  # Observed locations for second output

Y1 = np.sin(6*X1) + np.random.randn(*X1.shape) * 0.03
Y2 = np.sin(6*X2 + 0.7) + np.random.randn(*X2.shape) * 0.1

plt.figure(figsize=(8, 4))
plt.plot(X1, Y1, 'x', mew=2)
plt.plot(X2, Y2, 'x', mew=2)

Увеличение данных с многозадачным индексом

# Augment the input with ones or zeros to indicate the required output dimension
X_augmented = np.vstack((np.hstack((X1, np.zeros_like(X1))), np.hstack((X2, np.ones_like(X2)))))

# Augment the Y data
Y_augmented = np.vstack((np.hstack((Y1, np.zeros_like(Y1))), np.hstack((Y2, np.ones_like(Y2)))))

Построение ядра

output_dim = 2  # Number of outputs
rank = 1  # Rank of W

# Base kernel
k = gpflow.kernels.Matern32(active_dims=[0])

# Coregion kernel
coreg = gpflow.kernels.Coregion(output_dim=output_dim, rank=rank, active_dims=[1])

kern = k * coreg

Set до модели

data = (X_augmented, Y_augmented)

M = 50  # Number of inducing locations
N = len(X_augmented)

Z = X_augmented[0::2, :].copy()  # Initialize inducing locations to the first M inputs in the dataset

m = gpflow.models.SVGP(kern, gpflow.likelihoods.Gaussian(), Z, num_data=N, num_latent_gps=1)

gpflow.utilities.set_trainable(m.inducing_variable, False)

настроить партии

minibatch_size = 100

train_dataset = tf.data.Dataset.from_tensor_slices(data) \
    .repeat() \
    .shuffle(N)

train_it = iter(train_dataset.batch(minibatch_size))

Функция обучения помощника

minibatch_size = 50

# We turn off training for inducing point locations
gpflow.utilities.set_trainable(m.inducing_variable, False)

@tf.function(autograph=False)
def optimization_step(optimizer, model: gpflow.models.SVGP, batch):
    with tf.GradientTape(watch_accessed_variables=False) as tape:
        tape.watch(model.trainable_variables)
        objective = - model.elbo(batch)
        grads = tape.gradient(objective, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))
    return objective

def run_adam(model, iterations):
    """
    Utility function running the Adam optimizer

    :param model: GPflow model
    :param interations: number of iterations
    """
    # Create an Adam Optimizer action
    logf = []
    train_it = iter(train_dataset.batch(minibatch_size))
    adam = tf.optimizers.Adam()
    for step in trange(iterations):
        elbo = - optimization_step(adam, model, next(train_it))
        if step % 10 == 0:
            logf.append(elbo.numpy())
    return logf

Модель поезда

maxiter = ci_niter(20000)

logf = run_adam(m, maxiter)
plt.plot(np.arange(maxiter)[::10], logf)
plt.xlabel('iteration')
plt.ylabel('ELBO');

Результат участка

def plot_gp(x, mu, var, color, label):
    plt.plot(x, mu, color=color, lw=2, label=label)
    plt.fill_between(x[:, 0],
                     (mu - 2*np.sqrt(var))[:, 0],
                     (mu + 2*np.sqrt(var))[:, 0],
                     color=color, alpha=0.4)

def plot(m):
    plt.figure(figsize=(8, 4))
    xtest = np.linspace(0, 1, 100)[:, None]
    line, = plt.plot(X1, Y1, 'x', mew=2)
    mu, var = m.predict_f(np.hstack((xtest, np.zeros_like(xtest))))
    plot_gp(xtest, mu, var, line.get_color(), 'Y1')

    line, = plt.plot(X2, Y2, 'x', mew=2)
    mu, var = m.predict_f(np.hstack((xtest, np.ones_like(xtest))))
    plot_gp(xtest, mu, var, line.get_color(), 'Y2')

    plt.legend()

plot(m)

Результат SVGP

Вычисления "вручную"

sig2n = m.likelihood.variance.numpy()

xtest = xtest = np.linspace(0, 1, 100)[:, None]
Xs1 = np.hstack((xtest, np.zeros_like(xtest)))
Xs2 = np.hstack((xtest, np.ones_like(xtest)))
Xs = np.vstack((Xs1,Xs2))

Kmm = kern(Z,Z).numpy()
Kmn = kern(Z,X_augmented).numpy()
Kxm = kern(Xs,Z).numpy()
Kxx = kern(Xs, Xs).numpy()

Sigma = np.linalg.inv(Kmm+1/sig2n*Kmn@Kmn.T)
mu = 1/sig2n * Kmm@Sigma@Kmn@Y_augmented[:,0]
A = Kmm@Sigma@Kmm

B = np.linalg.inv(Kmm)@A@np.linalg.inv(Kmm)

f = Kxm@np.linalg.inv(Kmm)@mu
var = np.diag(Kxx - Kxm@np.linalg.inv(Kmm)@Kxm.T + Kxm@B@Kxm.T)

plt.plot(Xs[:,0], f)

line, = plt.plot(X1, Y1, 'x', mew=2, c='k')
line, = plt.plot(X2, Y2, 'x', mew=2, c='k')
plt.fill_between(xtest[:,0],
                 f[0:100] - 2*np.sqrt(var[0:100]),
                 f[0:100] + 2*np.sqrt(var[0:100]),
                 color='r', alpha=0.4)
plt.fill_between(xtest[:,0],
                 f[100::] - 2*np.sqrt(var[100::]),
                 f[100::] + 2*np.sqrt(var[100::]),
                 color='r', alpha=0.4)

Мой результат

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...