Example #1
0
    def __init__(self,
                 X,
                 Y,
                 W,
                 kern,
                 feat=None,
                 mean_function=None,
                 Z=None,
                 **kwargs):
        """
        X is a data matrix, size N x D
        Y is a data matrix, size N x R
        Z is a matrix of pseudo inputs, size M x D
        kern, mean_function are appropriate GPflow objects
        This method only works with a Gaussian likelihood.
        """
        X = DataHolder(X)
        Y = DataHolder(Y)
        likelihood = likelihoods.Gaussian()
        GPModel.__init__(self, X, Y, kern, likelihood, mean_function, **kwargs)
        self.feature = features.inducingpoint_wrapper(feat, Z)
        self.num_data = X.shape[0]

        self.W_prior = tf.ones(W.shape, dtype=settings.float_type) / W.shape[1]
        self.W = Parameter(W)
        self.num_inducing = Z.shape[0] * W.shape[1]
Example #2
0
    def __init__(self,
                 X,
                 Y,
                 kern,
                 mu_old,
                 Su_old,
                 Kaa_old,
                 Z_old,
                 Z,
                 mean_function=Zero()):
        """
        X is a data matrix, size N x D
        Y is a data matrix, size N x R
        Z is a matrix of pseudo inputs, size M x D
        kern, mean_function are appropriate gpflow objects
        mu_old, Su_old are mean and covariance of old q(u)
        Z_old is the old inducing inputs
        This method only works with a Gaussian likelihood.
        """
        X = DataHolder(X, on_shape_change='pass')
        Y = DataHolder(Y, on_shape_change='pass')
        likelihood = likelihoods.Gaussian()
        GPModel.__init__(self, X, Y, kern, likelihood, mean_function)
        self.Z = Param(Z)
        self.num_data = X.shape[0]
        self.num_latent = Y.shape[1]

        self.mu_old = DataHolder(mu_old, on_shape_change='pass')
        self.M_old = Z_old.shape[0]
        self.Su_old = DataHolder(Su_old, on_shape_change='pass')
        self.Kaa_old = DataHolder(Kaa_old, on_shape_change='pass')
        self.Z_old = DataHolder(Z_old, on_shape_change='pass')
Example #3
0
 def __init__(self, X, Y, kern, mean_function=None, **kwargs):
     """
     X is a data matrix, size N x D
     Y is a data matrix, size N x R
     kern, mean_function are appropriate GPflow objects
     """
     likelihood = likelihoods.Gaussian()
     X = DataHolder(X)
     Y = DataHolder(Y)
     GPModel.__init__(self, X, Y, kern, likelihood, mean_function, **kwargs)
Example #4
0
 def __init__(self, x, y, kern, mean_function=None, **kwargs):
     """
     X is a data matrix, size N x D
     Y is a data matrix, size N x R
     kern, mean_function are appropriate GPflow objects
     """
     likelihood = likelihoods.Gaussian()
     x = [DataHolder(x_i) for x_i in x]
     y = DataHolder(y)
     print(x)
     print(y)
     print(kern)
     super().__init__(x, y, kern, likelihood, mean_function, **kwargs)
Example #5
0
    def __init__(
        self,
        encoder,
        kernel: Optional[Kernel] = None,
        inducing_variable=None,
        *,
        num_latent_gps: int = 1,  #Y.shape[-1]
        data_dim: tuple = None,
        mean_function=None,
        q_diag: bool = False,
        q_mu=None,
        q_sqrt=None,
        whiten: bool = False,
    ):
        """
        - kernel, likelihood, inducing_variables, mean_function are appropriate
          GPflow objects
        - num_latent_gps is the number of latent processes to use, defaults to 2, as
          the dimensionality reduction is at dimensions 2
        - q_diag is a boolean. If True, the covariance is approximated by a
          diagonal matrix.
        - whiten is a boolean. If True, we use the whitened representation of
          the inducing points.
        - num_data is the total number of observations, defaults to X.shape[0]
          (relevant when feeding in external minibatches)
        
        The prior is by default a Normal Gaussian

        """

        if kernel is None:
            kernel = gpflow.kernels.SquaredExponential()

        self.num_data = data_dim[0]
        self.num_latent_gps = data_dim[1]
        self.q_diag = q_diag
        self.whiten = whiten
        self.inducing_variable = inducingpoint_wrapper(inducing_variable)

        # init variational parameters
        num_inducing = self.inducing_variable.num_inducing
        self._init_variational_parameters(num_inducing, q_mu, q_sqrt, q_diag)
        self.loss_placeholder = defaultdict(
            list, {k: []
                   for k in ("KL_x", "ELBO", "KL_u")})

        self.encoder = encoder

        # init the super class, accept args
        super().__init__(kernel, likelihoods.Gaussian(variance=0.1),
                         mean_function, num_latent_gps)
Example #6
0
	def __init__(self, X, Y, kern, mean_function=None, minibatch_size=None, seed=0, **kwargs):
		likelihood = likelihoods.Gaussian()
		self._seed = seed
		self._minibatch_size = minibatch_size
		self._N = X.shape[0]
		if len(X.shape) >= 3: X = X.reshape((-1, np.prod(np.array(list(X.shape)[1:]))))
		if minibatch_size is None:
			X = DataHolder(X)
			Y = DataHolder(Y)
			self._iters_per_epoch = 1
		else:
			X = Minibatch(X, batch_size=self._N, shuffle=True, seed=seed)
			Y = Minibatch(Y, batch_size=self._N, shuffle=True, seed=seed)
			self._iters_per_epoch = self._N//minibatch_size + min(1, self._N%minibatch_size)
		GPModel.__init__(self, X, Y, kern, likelihood, mean_function, **kwargs)
Example #7
0
    def __init__(self,
                 X,
                 Y,
                 W1,
                 W1_index,
                 W2,
                 W2_index,
                 kern,
                 feat=None,
                 mean_function=None,
                 Z=None,
                 **kwargs):
        """
        X is a data matrix, size N x D
        Y is a data matrix, size N x R
        Z is a matrix of pseudo inputs, size M x D
        W1, size NxK
        W1_index PxL

        W2, size NxL
        W2_index PxL

        kern, mean_function are appropriate GPflow objects
        This method only works with a Gaussian likelihood.
        """
        X = DataHolder(X)
        Y = DataHolder(Y, fix_shape=True)
        likelihood = likelihoods.Gaussian()
        GPModel.__init__(self, X, Y, kern, likelihood, mean_function, **kwargs)
        self.feature = features.inducingpoint_wrapper(feat, Z)
        self.num_data = X.shape[0]

        self.W1_prior = Parameter(np.log(
            np.ones(W1.shape[1], dtype=settings.float_type) / W1.shape[1]),
                                  trainable=False)
        self.W1 = Parameter(W1)
        self.W1_index = DataHolder(W1_index, dtype=np.int32, fix_shape=True)
        self.K = W1.shape[1]

        self.W2_prior = Parameter(np.log(
            np.ones(W2.shape[1], dtype=settings.float_type) / W2.shape[1]),
                                  trainable=False)
        self.W2 = Parameter(W2)
        self.W2_index = DataHolder(W2_index, dtype=np.int32, fix_shape=True)
        self.L = W2.shape[1]

        self.num_inducing = Z.shape[0]
Example #8
0
    def __init__(self, X, Y, kern, Z, alpha, mean_function=Zero()):
        """
        X is a data matrix, size N x D
        Y is a data matrix, size N x R
        Z is a matrix of pseudo inputs, size M x D
        kern, mean_function are appropriate gpflow objects

        This method only works with a Gaussian likelihood.
        """
        X = DataHolder(X, on_shape_change='pass')
        Y = DataHolder(Y, on_shape_change='pass')
        likelihood = likelihoods.Gaussian()
        GPModel.__init__(self, X, Y, kern, likelihood, mean_function)
        self.Z = Param(Z)
        self.num_data = X.shape[0]
        self.num_latent = Y.shape[1]
        self.alpha = alpha
Example #9
0
    def __init__(self, X, Y, W, kern, idx=None, feat=None, Z=None,
                 mean_function=None, q_diag=False, whiten=False,
                 q_mu=None, q_sqrt=None,
                 minibatch_size=None, num_latent=None, **kwargs):
        """
        X is a data matrix, size N x D
        Y is a data matrix, size N x R
        Z is a matrix of pseudo inputs, size M x D
        kern, mean_function are appropriate GPflow objects
        This method only works with a Gaussian likelihood.
        """
        num_data = X.shape[0]

        if minibatch_size is None:
            X = DataHolder(X, fix_shape=True)
            Y = DataHolder(Y, fix_shape=True)

        else:
            X = Minibatch(X, batch_size=minibatch_size, seed=0)
            Y = Minibatch(Y, batch_size=minibatch_size, seed=0)

        # init the super class
        likelihood = likelihoods.Gaussian()
        num_latent = W.shape[1]
        GPModel.__init__(self, X, Y, kern, likelihood, mean_function,
                         num_latent=num_latent, **kwargs)

        if minibatch_size is not None:
            idx = Minibatch(np.arange(num_data), batch_size=minibatch_size, seed=0, dtype=np.int32)

        self.idx = idx
        self.W = Parameter(W, trainable=False)
        self.K = self.W.shape[1]
        self.W_prior = Parameter(np.ones(self.K) / self.K, trainable=False)
        self.num_data = num_data
        self.feature = features.inducingpoint_wrapper(feat, Z)

        self.minibatch_size = minibatch_size
        self.q_diag, self.whiten = q_diag, whiten

        # init variational parameters
        num_inducing = len(self.feature)
        self._init_variational_parameters(
            num_inducing, q_mu, q_sqrt, q_diag)
Example #10
0
    def __init__(self, embeds, m, name='Model'):
        Model.__init__(self, name)

        self.nkpts = len(m.Y.value[0])
        self.npts = len(embeds)
        embeds = np.array(m.X_mean.value)
        self.X_mean = Param(embeds)
        self.Z = Param(np.array(m.Z.value))
        self.kern = deepcopy(m.kern)
        self.X_var = Param(np.array(m.X_var.value))
        self.Y = m.Y
        self.likelihood = likelihoods.Gaussian()
        self.mean_function = Zero()

        self.likelihood._check_targets(self.Y.value)
        self._session = None

        self.X_mean.fixed = True
        self.Z.fixed = True
        self.kern.fixed = True
        self.X_var.fixed = True
        self.likelihood.fixed = True
Example #11
0
    def __init__(self, X_variational_mean, X_variational_var, Y, kern, t, kern_t, M , Z=None):
        """
        Initialization of Bayesian Gaussian Process Dynamics Model. This method only works with Gaussian likelihood.
        :param X_variational_mean: initial latent positions, size N (number of points) x Q (latent dimensions).
        :param X_variational_var: variance of latent positions (N x Q), for the initialisation of the latent space.
        :param Y: data matrix, size N (number of points) x D (dimensions).
        :param kern: kernel specification, by default RBF.
        :param t: time stamps.
        :param kern_t: dynamics kernel specification, by default RBF.
        :param M: number of inducing points.
        :param Z: matrix of inducing points, size M (inducing points) x Q (latent dimensions), By default
                  random permutation of X_mean.
        """
        super(BayesianDGPLVM, self).__init__(name='BayesianDGPLVM')
        self.kern = kern
        assert len(X_variational_mean) == len(X_variational_var), 'must be same amount of time series'
        self.likelihood = likelihoods.Gaussian()

        # multiple sequences
        series = []
        for i in range(len(X_variational_mean)):
            series.append(GPTimeSeries(X_variational_mean[i], X_variational_var[i], t[i]))
        self.series = ParamList(series)

        # inducing points
        if Z is None:
            # By default we initialize by permutation of initial
            Z = np.random.permutation(np.concatenate(X_variational_mean, axis=0).copy())[:M]
        else:
            assert Z.shape[0] == M
        self.Z = Param(Z)

        self.kern_t = kern_t
        self.Y = DataHolder(Y)
        self.M = M
        self.n_s = 0
Example #12
0
    def __init__(self, embeds, skeletons, dist, m, name='Model'):
        Model.__init__(self, name)
        self.skeletons = skeletons
        self.dist_embeds = dist
        self.nkpts = len(skeletons[0, :])
        self.npts = len(embeds)
        self.dist_skeletons = np.ones([self.npts, self.npts]) * -1
        embeds = np.array(m.X_mean.value)
        self.X_mean = Param(embeds)
        self.Z = Param(np.array(m.Z.value))
        self.kern = deepcopy(m.kern)
        self.X_var = Param(np.array(m.X_var.value))
        self.Y = m.Y
        self.likelihood = likelihoods.Gaussian()
        self.mean_function = Zero()

        self.likelihood._check_targets(self.Y.value)
        self._session = None

        self.X_mean.fixed = True
        self.Z.fixed = True
        self.kern.fixed = True
        self.X_var.fixed = True
        self.likelihood.fixed = True
Example #13
0
    def __init__(self,
                 Y,
                 T,
                 kern,
                 M=10,
                 num_latent=3,
                 dynamic_kern=None,
                 Z=None,
                 KL_weight=None):
        """
        Initialise VGPDS. This only works with Gaussian Likelihood for now

        :param Y: data matrix, size T (number of time points) x D (dimensions)
        :param T: time vector, positive real value, size 1 x T
        :param kern: Mapping kernel X -> Y specification, by default RBF
        :param M: Number of inducing points
        :param num_latent: Number of latent dimension. This is automatically found unless user force latent dimension
        :param force_latent_dim: Specify whether strict latent dimension is enforced
        :param dynamic_kern: temporal dynamics kernel specification, by default RBF
        :param Z: matrix of inducing points
        :param KL_weight: Weight of KL . weight of bound = 1 - w(KL)
        """
        X_mean = large_PCA(Y, num_latent)

        GPModel.__init__(self,
                         X_mean,
                         Y,
                         kern,
                         likelihood=likelihoods.Gaussian(),
                         mean_function=Zero())
        del self.X  # This is a params

        self.T = np.transpose(T[np.newaxis])
        self.num_latent = num_latent
        if KL_weight is None:
            self.KL_weight = 0.5
        else:
            assert KL_weight <= 1
            assert KL_weight >= 0
            self.KL_weight = KL_weight

        #This is only one way to initialize mu_bar_q
        mu_bar_q = X_mean
        lambda_q = np.ones((self.T.shape[0], self.num_latent))

        if dynamic_kern is None:
            self.dynamic_kern = kernels.RBF(1) + kernels.Bias(
                1) + kernels.White(1)
        else:
            self.dynamic_kern = dynamic_kern

        self.mu_bar_q = Parameter(mu_bar_q)
        self.lambda_q = Parameter(lambda_q)

        self.num_time, self.num_latent = X_mean.shape
        self.output_dim = Y.shape[1]

        # inducing points
        if Z is None:
            # By default we initialize by subset of initial latent points
            Z = np.random.permutation(X_mean.copy())[:M]

        self.feature = features.InducingPoints(Z)

        assert len(self.feature) == M
Example #14
0
 def __init__(self, X, Y, kern, mean_function=None, i=None, **kwargs):
     likelihood = likelihoods.Gaussian()
     X = DataHolder(X)
     Y = DataHolder(Y)
     GPModel.__init__(self, X, Y, kern, likelihood, mean_function, **kwargs)
     self.i = i
Example #15
0
    def __init__(
        self,
        data: OutputData,
        encoder,
        kernel: Optional[Kernel] = None,
        inducing_variable=None,
        X_prior_mean=None,
        X_prior_var=None,
    ):
        """
        Initialise Bayesian GPLVM object. This method only works with a Gaussian likelihood.

        :param data: data matrix, size N (number of points) x D (dimensions)
        :param X_data_mean: initial latent positions, size N (number of points) x Q (latent dimensions).
        :param X_data_var: variance of latent positions ([N, Q]), for the initialisation of the latent space.
        :param kernel: kernel specification, by default Squared Exponential
        :param num_inducing_variables: number of inducing points, M
        :param inducing_variable: matrix of inducing points, size M (inducing points) x Q (latent dimensions). By default
            random permutation of X_data_mean.
        :param X_prior_mean: prior mean used in KL term of bound. By default 0. Same size as X_data_mean.
        :param X_prior_var: prior variance used in KL term of bound. By default 1.
        """

        self.latent_dimensions = 2
        #grab data
        self.data = data_input_to_tensor(data)

        num_data, num_latent_gps = data.shape

        self.num_data = num_data

        #def kernel
        if kernel is None:
            kernel = gpflow.kernels.SquaredExponential()

        #init GPMODEL
        super().__init__(kernel,
                         likelihoods.Gaussian(variance=0.1),
                         num_latent_gps=num_latent_gps)

        #init parameter inducing point
        if (inducing_variable is None):
            raise ValueError(
                "BayesianGPLVM needs exactly one of `inducing_variable` and `num_inducing_variables`"
            )
        else:
            self.inducing_variable = inducingpoint_wrapper(inducing_variable)

        #loss placeholder for analysis purpuse
        self.loss_placeholder = defaultdict(list,
                                            {k: []
                                             for k in ("KL_x", "ELBO")})

        # deal with parameters for the prior mean variance of X
        if X_prior_mean is None:
            X_prior_mean = tf.zeros((self.num_data, self.latent_dimensions),
                                    dtype=default_float())
        if X_prior_var is None:
            X_prior_var = tf.ones((self.num_data, self.latent_dimensions),
                                  dtype=default_float())

        self.X_prior_mean = tf.convert_to_tensor(np.atleast_1d(X_prior_mean),
                                                 dtype=default_float())
        self.X_prior_var = tf.convert_to_tensor(np.atleast_1d(X_prior_var),
                                                dtype=default_float())

        # Encoder
        self.encoder = encoder

        #sanity check
        # assert np.all(X_data_mean.shape == X_data_var.shape)
        # assert X_data_mean.shape[0] == self.data.shape[0], "X mean and Y must be same size."
        # assert X_data_var.shape[0] == self.data.shape[0], "X var and Y must be same size."
        # assert X_data_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_mean.shape[0] == self.num_data
        assert self.X_prior_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_var.shape[0] == self.num_data
        assert self.X_prior_var.shape[1] == self.latent_dimensions
Example #16
0
    def __init__(
        self,
        data: OutputData,
        kernel: Optional[Kernel] = None,
        latent_dimensions: Optional[int] = 2,
        num_inducing_variables: Optional[int] = None,
        inducing_variable=None,
        *,
        mean_function=None,
        q_diag: bool = False,
        q_mu=None,
        q_sqrt=None,
        whiten: bool = False,
    ):
        """
        - kernel, likelihood, inducing_variables, mean_function are appropriate
          GPflow objects
        - num_latent_gps is the number of latent processes to use, defaults to 2, as
          the dimensionality reduction is at dimensions 2
        - q_diag is a boolean. If True, the covariance is approximated by a
          diagonal matrix.
        - whiten is a boolean. If True, we use the whitened representation of
          the inducing points.
        - num_data is the total number of observations, defaults to X.shape[0]
          (relevant when feeding in external minibatches)
        """

        self.latent_dimensions = latent_dimensions

        #grab data
        self.data = data_input_to_tensor(data)

        #define lat-space initialization
        X_data_mean = pca_reduce(data, self.latent_dimensions)

        num_data, num_latent_gps = data.shape

        self.num_data = num_data

        X_data_var = tf.ones((self.num_data, self.latent_dimensions),
                             dtype=default_float())

        assert X_data_var.ndim == 2

        #def kernel
        if kernel is None:
            kernel = gpflow.kernels.SquaredExponential()

        #init Parameters latent
        self.X_data_mean = Parameter(X_data_mean)
        self.X_data_var = Parameter(X_data_var, transform=positive())

        #init parameter inducing point
        if (inducing_variable is None) == (num_inducing_variables is None):
            raise ValueError(
                "BayesianGPLVM needs exactly one of `inducing_variable` and `num_inducing_variables`"
            )

        if inducing_variable is None:
            # By default we initialize by subset of initial latent points
            # Note that tf.random.shuffle returns a copy, it does not shuffle in-place
            #maybe use k-means clustering
            Z = tf.random.shuffle(X_data_mean)[:num_inducing_variables]
            inducing_variable = InducingPoints(Z)

        self.inducing_variable = inducingpoint_wrapper(inducing_variable)

        #loss placeholder for analysis purpuse
        self.loss_placeholder = defaultdict(
            list, {k: []
                   for k in ("KL_x", "ELBO", "KL_u")})

        # deal with parameters for the prior mean variance of X
        X_prior_mean = tf.zeros((self.num_data, self.latent_dimensions),
                                dtype=default_float())
        X_prior_var = tf.ones((self.num_data, self.latent_dimensions),
                              dtype=default_float())

        self.X_prior_mean = tf.convert_to_tensor(np.atleast_1d(X_prior_mean),
                                                 dtype=default_float())
        self.X_prior_var = tf.convert_to_tensor(np.atleast_1d(X_prior_var),
                                                dtype=default_float())

        #sanity check

        assert np.all(X_data_mean.shape == X_data_var.shape)
        assert X_data_mean.shape[0] == self.data.shape[
            0], "X mean and Y must be same size."
        assert X_data_var.shape[0] == self.data.shape[
            0], "X var and Y must be same size."
        assert X_data_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_mean.shape[0] == self.num_data
        assert self.X_prior_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_var.shape[0] == self.num_data
        assert self.X_prior_var.shape[1] == self.latent_dimensions

        # init the super class, accept args
        super().__init__(kernel, likelihoods.Gaussian(variance=0.1),
                         mean_function, num_latent_gps)
        self.q_diag = q_diag
        self.whiten = whiten
        #self.inducing_variable = inducingpoint_wrapper(inducing_variable)

        # init variational parameters
        num_inducing = self.inducing_variable.num_inducing
        self._init_variational_parameters(num_inducing, q_mu, q_sqrt, q_diag)
Example #17
0
    def __init__(self,
                 X_variational_mean,
                 X_variational_var,
                 Y,
                 Kern,
                 M,
                 Z=None,
                 X_prior_mean=None,
                 X_prior_var=None):
        """
        Initialise Bayesian GPLVM object. This method only works with a Gaussian likelihood.
        :param X_variational_mean: initial latent variational distribution mean, size N (number of points) x Q (latent dimensions)
        :param X_variational_var: initial latent variational distribution std (N X Q)
        :param Y: data matrix, size N (number of points) x D (dimensions)
        :param Kern: kernal specification, by default RBF-ARD
        :param M: number of inducing points 
        :param Z: matrix of inducing points, size M (inducing points) x Q (latent dimensions). By default
                  random permutation of X_mean.
        :param X_prior_mean: prior mean used in KL term of bound. By default 0. Same size as X_mean.
        :param X_prior_var: prior variance used in KL term of bound. By default 1.
        """
        GPModel.__init__(self,
                         X_variational_mean,
                         Y,
                         Kern,
                         likelihood=likelihoods.Gaussian(),
                         mean_function=Zero())
        del self.X  # in GPLVM this is a Param
        self.X_variational_mean = Param(X_variational_mean)

        assert X_variational_var.ndim == 2, 'Incorrect number of dimensions for X_std.'
        self.X_variational_var = Param(X_variational_var, transforms.positive)
        self.num_data = X_variational_mean.shape[0]
        self.output_dim = Y.shape[1]

        assert np.all((X_variational_mean.shape == X_variational_var.shape))
        assert X_variational_mean.shape[0] == Y.shape[
            0], 'X variational mean and Y must be the same size.'
        assert X_variational_var.shape[0] == Y.shape[
            0], 'X variational std and Y must be the same size.'

        # inducing points
        if Z is None:
            # By default it's initialized by random permutation of the latent inputs.
            Z = np.random.permutation(X_variational_mean.copy())[:M]
        else:
            assert Z.shape[
                0] == M, 'Only M inducing points are allowed, however {} are provided.'.format(
                    Z.shape[0])
        self.Z = Param(Z)
        self.num_latent = Z.shape[1]
        assert X_variational_mean.shape[1] == self.num_latent

        # Prior mean and variance for X TODO: the dynamic case is different
        if X_prior_mean is None:
            X_prior_mean = np.zeros((self.num_data, self.num_latent))
        self.X_prior_mean = X_prior_mean
        if X_prior_var is None:
            X_prior_var = np.ones((self.num_data, self.num_latent))
        self.X_prior_var = X_prior_var

        assert X_prior_var.shape[0] == self.num_data
        assert X_prior_var.shape[1] == self.num_latent
        assert X_prior_mean.shape[0] == self.num_data
        assert X_prior_mean.shape[1] == self.num_latent
Example #18
0
    def __init__(
        self,
        data: OutputData,
        split_space: bool, 
        Xp_mean: tf.Tensor,
        Xp_var: tf.Tensor,
        pi: tf.Tensor,
        kernel_K: List[Kernel],
        Zp: tf.Tensor,
        Xs_mean=None,
        Xs_var=None,
        kernel_s=None,
        Zs=None,
        Xs_prior_mean=None,
        Xs_prior_var=None,
        Xp_prior_mean=None,
        Xp_prior_var=None,
        pi_prior=None
    ):
        """
        Initialise Bayesian GPLVM object. This method only works with a Gaussian likelihood.

        :param data: data matrix, size N (number of points) x D (dimensions)
        :param: split_space, if true, have both shared and private space; 
            if false, only have private spaces (note: to recover GPLVM, set split_space=False and let K=1)
        :param Xp_mean: mean latent positions in the private space [N, Qp] (Qp is the dimension of the private space)
        :param Xp_var: variance of the latent positions in the private space [N, Qp]
        :param pi: mixture responsibility of each category to each point [N, K] (K is the number of categories), i.e. q(c)
        :param kernel_K: private space kernel, one for each category
        :param Zp: inducing inputs of the private space [M, Qp]
        :param num_inducing_variables: number of inducing points, M
        :param Xs_mean: mean latent positions in the shared space [N, Qs] (Qs is the dimension of the shared space). i.e. mus in q(Xs) ~ N(Xs | mus, Ss)
        :param Xs_var: variance of latent positions in shared space [N, Qs], i.e. Ss, assumed diagonal
        :param kernel_s: shared space kernel 
        :param Zs: inducing inputs of the shared space [M, Qs] (M is the number of inducing points)
        :param Xs_prior_mean: prior mean used in KL term of bound, [N, Qs]. By default 0. mean in p(Xs)
        :param Xs_prior_var: prior variance used in KL term of bound, [N, Qs]. By default 1. variance in p(Xs)
        :param Xp_prior_mean: prior mean used in KL term of bound, [N, Qp]. By default 0. mean in p(Xp)
        :param Xp_prior_var: prior variance used in KL term of bound, [N, Qp]. By default 1. variance in p(Xp)
        :param pi_prior: prior mixture weights used in KL term of the bound, [N, K]. By default uniform. p(c)        
        """

        # if don't want shared space, set shared space to none --> get a mixture of GPLVM
        # if don't want private space, set shared space to none, set K = 1 and only include 1 kernel in `kernel_K` --> recover the original GPLVM 

        # TODO: think about how to do this with minibatch
        # it's awkward since w/ minibatch the model usually doesn't store the data internally
        # but for gplvm, you need to keep the q(xn) for all the n's
        # so you need to know which ones to update for each minibatch, probably can be solved but not pretty
        # using inference network / back constraints will solve this, since we will be keeping a global set of parameters
        # rather than a set for each q(xn)
        self.N, self.D = data.shape
        self.Qp = Xp_mean.shape[1]
        self.K = pi.shape[1]
        self.split_space = split_space

        assert Xp_var.ndim == 2
        assert len(kernel_K) == self.K
        assert np.all(Xp_mean.shape == Xp_var.shape)
        assert Xp_mean.shape[0] == self.N, "Xp_mean and Y must be of same size"
        assert pi.shape[0] == self.N, "pi and Y must be of the same size"

        super().__init__()
        self.likelihood = likelihoods.Gaussian()
        self.kernel_K = kernel_K
        self.data = data_input_to_tensor(data)
        # the covariance of q(X) as a [N, Q] matrix, the assumption is that Sn's are diagonal
        # i.e. the latent dimensions are uncorrelated
        # otherwise would require a [N, Q, Q] matrix
        self.Xp_mean = Parameter(Xp_mean)
        self.Xp_var = Parameter(Xp_var, transform=positive())
        self.pi = Parameter(pi, transform=tfp.bijectors.SoftmaxCentered())
        self.Zp = inducingpoint_wrapper(Zp)
        self.M = len(self.Zp)

        # initialize the variational parameters for q(U), same way as in SVGP
        # q_mu: List[K], mean of the inducing variables U [M, D], i.e m in q(U) ~ N(U | m, S), 
        #   initialized as zeros
        # q_sqrt: List[K], cholesky of the covariance matrix of the inducing variables [D, M, M]
        #   q_diag is false because natural gradient only works for full covariance
        #   initialized as all identities
        # we need K sets of q(Uk), each approximating fs+fk
        self.q_mu = []
        self.q_sqrt = []
        for k in range(self.K):
            q_mu = np.zeros((self.M, self.D))
            q_mu = Parameter(q_mu, dtype=default_float())  # [M, D]
            self.q_mu.append(q_mu)

            q_sqrt = [
                np.eye(self.M, dtype=default_float()) for _ in range(self.D)
            ]
            q_sqrt = np.array(q_sqrt)
            q_sqrt = Parameter(q_sqrt, transform=triangular())  # [D, M, M]
            self.q_sqrt.append(q_sqrt)

        # deal with parameters for the prior 
        if Xp_prior_mean is None:
            Xp_prior_mean = tf.zeros((self.N, self.Qp), dtype=default_float())
        if Xp_prior_var is None:
            Xp_prior_var = tf.ones((self.N, self.Qp))
        if pi_prior is None:
            pi_prior = tf.ones((self.N, self.K), dtype=default_float()) * 1/self.K

        self.Xp_prior_mean = tf.convert_to_tensor(np.atleast_1d(Xp_prior_mean), dtype=default_float())
        self.Xp_prior_var = tf.convert_to_tensor(np.atleast_1d(Xp_prior_var), dtype=default_float()) 
        self.pi_prior = tf.convert_to_tensor(np.atleast_1d(pi_prior), dtype=default_float()) 


        # if we have both shared space and private space, need to initialize the parameters for the shared space
        if split_space:
            assert Xs_mean is not None and Xs_var is not None and kernel_s is not None and Zs is not None, 'Xs_mean, Xs_var, kernel_s, Zs need to be initialize if `split_space=True`'
            assert Xs_var.ndim == 2 
            assert np.all(Xs_mean.shape == Xs_var.shape)
            assert Xs_mean.shape[0] == self.N, "Xs_mean and Y must be of same size"
            self.Qs = Xs_mean.shape[1]
            self.kernel_s = kernel_s
            self.Xs_mean = Parameter(Xs_mean)
            self.Xs_var = Parameter(Xs_var, transform=positive())
            self.Zs = inducingpoint_wrapper(Zs)

            if len(Zs) != len(Zp):
                raise ValueError(
                    '`Zs` and `Zp` should have the same length'
                )

            if Xs_prior_mean is None:
                Xs_prior_mean = tf.zeros((self.N, self.Qs), dtype=default_float())
            if Xs_prior_var is None:
                Xs_prior_var = tf.ones((self.N, self.Qs))
            self.Xs_prior_mean = tf.convert_to_tensor(np.atleast_1d(Xs_prior_mean), dtype=default_float())
            self.Xs_prior_var = tf.convert_to_tensor(np.atleast_1d(Xs_prior_var), dtype=default_float())

        self.Fq = tf.zeros((self.N, self.K), dtype=default_float())
Example #19
0
    def __init__(
        self,
        data: OutputData,
        X_data_mean: Optional[tf.Tensor] = None,
        X_data_var: Optional[tf.Tensor] = None,
        kernel: Optional[Kernel] = None,
        num_inducing_variables: Optional[int] = None,
        inducing_variable=None,
        X_prior_mean=None,
        X_prior_var=None,
    ):
        """
        Initialise Bayesian GPLVM object. This method only works with a Gaussian likelihood.

        :param data: data matrix, size N (number of points) x D (dimensions)
        :param X_data_mean: initial latent positions, size N (number of points) x Q (latent dimensions).
        :param X_data_var: variance of latent positions ([N, Q]), for the initialisation of the latent space.
        :param kernel: kernel specification, by default Squared Exponential
        :param num_inducing_variables: number of inducing points, M
        :param inducing_variable: matrix of inducing points, size M (inducing points) x Q (latent dimensions). By default
            random permutation of X_data_mean.
        :param X_prior_mean: prior mean used in KL term of bound. By default 0. Same size as X_data_mean.
        :param X_prior_var: prior variance used in KL term of bound. By default 1.
        """

        self.latent_dimensions = 2
        #grab data
        self.data = data_input_to_tensor(data)

        #define lat-space initialization
        if X_data_mean is None:
            X_data_mean = pca_reduce(data, self.latent_dimensions)

        num_data, num_latent_gps = X_data_mean.shape

        self.num_data = num_data

        if X_data_var is None:
            X_data_var = tf.ones((self.num_data, self.latent_dimensions),
                                 dtype=default_float())

        assert X_data_var.ndim == 2

        self.output_dim = self.data.shape[-1]  #num_latent maybe

        #def kernel
        if kernel is None:
            kernel = gpflow.kernels.SquaredExponential()

        #init GPMODEL
        super().__init__(kernel,
                         likelihoods.Gaussian(variance=0.1),
                         num_latent_gps=num_latent_gps)

        #init Parameters latent
        self.X_data_mean = Parameter(X_data_mean)
        self.X_data_var = Parameter(X_data_var, transform=positive())

        #init parameter inducing point
        if (inducing_variable is None) == (num_inducing_variables is None):
            raise ValueError(
                "BayesianGPLVM needs exactly one of `inducing_variable` and `num_inducing_variables`"
            )

        if inducing_variable is None:
            # By default we initialize by subset of initial latent points
            # Note that tf.random.shuffle returns a copy, it does not shuffle in-place
            #maybe use k-means clustering
            Z = tf.random.shuffle(X_data_mean)[:num_inducing_variables]
            inducing_variable = InducingPoints(Z)

        self.inducing_variable = inducingpoint_wrapper(inducing_variable)

        #loss placeholder for analysis purpuse
        self.loss_placeholder = defaultdict(list,
                                            {k: []
                                             for k in ("KL_x", "ELBO")})

        # deal with parameters for the prior mean variance of X
        if X_prior_mean is None:
            X_prior_mean = tf.zeros((self.num_data, self.latent_dimensions),
                                    dtype=default_float())
        if X_prior_var is None:
            X_prior_var = tf.ones((self.num_data, self.latent_dimensions),
                                  dtype=default_float())

        self.X_prior_mean = tf.convert_to_tensor(np.atleast_1d(X_prior_mean),
                                                 dtype=default_float())
        self.X_prior_var = tf.convert_to_tensor(np.atleast_1d(X_prior_var),
                                                dtype=default_float())

        #sanity check

        assert np.all(X_data_mean.shape == X_data_var.shape)
        assert X_data_mean.shape[0] == self.data.shape[
            0], "X mean and Y must be same size."
        assert X_data_var.shape[0] == self.data.shape[
            0], "X var and Y must be same size."
        assert X_data_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_mean.shape[0] == self.num_data
        assert self.X_prior_mean.shape[1] == self.latent_dimensions
        assert self.X_prior_var.shape[0] == self.num_data
        assert self.X_prior_var.shape[1] == self.latent_dimensions