Esempio n. 1
0
 def post_transform(self, z_list, train=False):
     if train:
         self.cca = MCCA(latent_dims=self.latent_dims)
         z_list = self.cca.fit_transform(z_list)
     else:
         z_list = self.cca.transform(z_list)
     return z_list
Esempio n. 2
0
def test_unregularized_multi():
    # Tests unregularized CCA methods for more than 2 views. The idea is that all of these should give the same result.
    latent_dims = 2
    cca = rCCA(latent_dims=latent_dims).fit((X, Y, Z))
    iter = CCA_ALS(latent_dims=latent_dims,
                   stochastic=False,
                   tol=1e-12,
                   random_state=rng).fit((X, Y, Z))
    gcca = GCCA(latent_dims=latent_dims).fit((X, Y, Z))
    mcca = MCCA(latent_dims=latent_dims).fit((X, Y, Z))
    kcca = KCCA(latent_dims=latent_dims).fit((X, Y, Z))
    corr_cca = cca.score((X, Y, Z))
    corr_iter = iter.score((X, Y, Z))
    corr_gcca = gcca.score((X, Y, Z))
    corr_mcca = mcca.score((X, Y, Z))
    corr_kcca = kcca.score((X, Y, Z))
    # Check the correlations from each unregularized method are the same
    assert np.testing.assert_array_almost_equal(corr_cca, corr_iter,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_mcca,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_gcca,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_kcca,
                                                decimal=1) is None
Esempio n. 3
0
def test_sparse_input():
    # Tests unregularized CCA methods. The idea is that all of these should give the same result.
    latent_dims = 2
    cca = CCA(latent_dims=latent_dims, centre=False).fit((X_sp, Y_sp))
    iter = CCA_ALS(
        latent_dims=latent_dims,
        tol=1e-9,
        stochastic=False,
        centre=False,
        random_state=rng,
    ).fit((X_sp, Y_sp))
    iter_pls = PLS_ALS(latent_dims=latent_dims, tol=1e-9, centre=False).fit(
        (X_sp, Y_sp))
    gcca = GCCA(latent_dims=latent_dims, centre=False).fit((X_sp, Y_sp))
    mcca = MCCA(latent_dims=latent_dims, centre=False).fit((X_sp, Y_sp))
    kcca = KCCA(latent_dims=latent_dims, centre=False).fit((X_sp, Y_sp))
    scca = SCCA(latent_dims=latent_dims, centre=False, c=0.001).fit(
        (X_sp, Y_sp))
    corr_cca = cca.score((X, Y))
    corr_iter = iter.score((X, Y))
    corr_gcca = gcca.score((X, Y))
    corr_mcca = mcca.score((X, Y))
    corr_kcca = kcca.score((X, Y))
    # Check the correlations from each unregularized method are the same
    assert np.testing.assert_array_almost_equal(
        corr_iter, corr_mcca, decimal=1) is None
    assert np.testing.assert_array_almost_equal(
        corr_iter, corr_gcca, decimal=1) is None
    assert np.testing.assert_array_almost_equal(
        corr_iter, corr_kcca, decimal=1) is None
Esempio n. 4
0
def test_unregularized_methods():
    # Tests unregularized CCA methods. The idea is that all of these should give the same result.
    latent_dims = 2
    cca = CCA(latent_dims=latent_dims).fit([X, Y])
    iter = CCA_ALS(latent_dims=latent_dims,
                   tol=1e-9,
                   stochastic=False,
                   random_state=rng).fit([X, Y])
    gcca = GCCA(latent_dims=latent_dims).fit([X, Y])
    mcca = MCCA(latent_dims=latent_dims, eps=1e-9).fit([X, Y])
    kcca = KCCA(latent_dims=latent_dims).fit([X, Y])
    kgcca = KGCCA(latent_dims=latent_dims).fit([X, Y])
    tcca = TCCA(latent_dims=latent_dims).fit([X, Y])
    corr_cca = cca.score((X, Y))
    corr_iter = iter.score((X, Y))
    corr_gcca = gcca.score((X, Y))
    corr_mcca = mcca.score((X, Y))
    corr_kcca = kcca.score((X, Y))
    corr_kgcca = kgcca.score((X, Y))
    corr_tcca = tcca.score((X, Y))
    assert np.testing.assert_array_almost_equal(corr_cca, corr_iter,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_mcca,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_gcca,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_kcca,
                                                decimal=1) is None
    assert np.testing.assert_array_almost_equal(corr_cca, corr_tcca,
                                                decimal=1) is None
    assert (np.testing.assert_array_almost_equal(
        corr_kgcca, corr_gcca, decimal=1) is None)
    # Check standardized models have standard outputs
    assert (np.testing.assert_allclose(
        np.linalg.norm(iter.transform(
            (X, Y))[0], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(cca.transform(
            (X, Y))[0], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(mcca.transform(
            (X, Y))[0], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(kcca.transform(
            (X, Y))[0], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(iter.transform(
            (X, Y))[1], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(cca.transform(
            (X, Y))[1], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(mcca.transform(
            (X, Y))[1], axis=0)**2, n, rtol=0.2) is None)
    assert (np.testing.assert_allclose(
        np.linalg.norm(kcca.transform(
            (X, Y))[1], axis=0)**2, n, rtol=0.2) is None)
Esempio n. 5
0
class DCCA(_DCCA_base):
    """
    A class used to fit a DCCA model.

    :Citation:

    Andrew, Galen, et al. "Deep canonical correlation analysis." International conference on machine learning. PMLR, 2013.

    """

    def __init__(
        self,
        latent_dims: int,
        objective=objectives.MCCA,
        encoders=None,
        r: float = 0,
        eps: float = 1e-5,
    ):
        """
        Constructor class for DCCA

        :param latent_dims: # latent dimensions
        :param objective: # CCA objective: normal tracenorm CCA by default
        :param encoders: list of encoder networks
        :param r: regularisation parameter of tracenorm CCA like ridge CCA. Needs to be VERY SMALL. If you get errors make this smaller
        :param eps: epsilon used throughout. Needs to be VERY SMALL. If you get errors make this smaller
        """
        super().__init__(latent_dims=latent_dims)
        if encoders is None:
            encoders = [Encoder, Encoder]
        self.encoders = torch.nn.ModuleList(encoders)
        self.objective = objective(latent_dims, r=r, eps=eps)

    def forward(self, *args):
        z = []
        for i, encoder in enumerate(self.encoders):
            z.append(encoder(args[i]))
        return z

    def loss(self, *args):
        """
        Define the loss function for the model. This is used by the DeepWrapper class

        :param args:
        :return:
        """
        z = self(*args)
        return {"objective": self.objective.loss(*z)}

    def post_transform(self, z_list, train=False):
        if train:
            self.cca = MCCA(latent_dims=self.latent_dims)
            z_list = self.cca.fit_transform(z_list)
        else:
            z_list = self.cca.transform(z_list)
        return z_list
Esempio n. 6
0
 def test_cv_fit(self):
     latent_dims = 5
     c1 = [0.1, 0.2]
     c2 = [0.1, 0.2]
     param_candidates = {'c': list(itertools.product(c1, c2))}
     wrap_unweighted_gcca = GCCA(latent_dims=latent_dims).gridsearch_fit(self.X, self.Y, folds=2,
                                                                         param_candidates=param_candidates,
                                                                         plot=True)
     wrap_deweighted_gcca = GCCA(latent_dims=latent_dims, view_weights=[0.5, 0.5]).gridsearch_fit(
         self.X, self.Y, folds=2, param_candidates=param_candidates)
     wrap_mcca = MCCA(latent_dims=latent_dims).gridsearch_fit(
         self.X, self.Y, folds=2, param_candidates=param_candidates)
Esempio n. 7
0
def test_regularized_methods():
    # Test that linear regularized methods match PLS solution when using maximum regularisation.
    latent_dims = 2
    c = 1
    kernel = KCCA(latent_dims=latent_dims,
                  c=[c, c],
                  kernel=["linear", "linear"]).fit((X, Y))
    pls = PLS(latent_dims=latent_dims).fit([X, Y])
    gcca = GCCA(latent_dims=latent_dims, c=[c, c]).fit([X, Y])
    mcca = MCCA(latent_dims=latent_dims, c=[c, c]).fit([X, Y])
    rcca = rCCA(latent_dims=latent_dims, c=[c, c]).fit([X, Y])
    corr_gcca = gcca.score((X, Y))
    corr_mcca = mcca.score((X, Y))
    corr_kernel = kernel.score((X, Y))
    corr_pls = pls.score((X, Y))
    corr_rcca = rcca.score((X, Y))
    # Check the correlations from each unregularized method are the same
    assert np.testing.assert_array_almost_equal(corr_pls, corr_mcca,
                                                decimal=1) is None
    assert (np.testing.assert_array_almost_equal(
        corr_pls, corr_kernel, decimal=1) is None)
    assert np.testing.assert_array_almost_equal(corr_pls, corr_rcca,
                                                decimal=1) is None
Esempio n. 8
0
def _default_initializer(views, initialization, random_state, latent_dims):
    """
    This is a generator function which generates initializations for each dimension

    :param views:
    :param initialization:
    :param random_state:
    :param latent_dims:
    :return:
    """
    if initialization == "random":
        while True:
            yield np.array([
                random_state.normal(0, 1, size=(view.shape[0]))
                for view in views
            ])
    elif initialization == "uniform":
        while True:
            yield np.array([np.ones(view.shape[0]) for view in views])
    elif initialization == "pls":
        latent_dim = 0
        # use rCCA to use multiple views
        pls_scores = MCCA(latent_dims, c=1).fit_transform(views)
        while True:
            yield np.stack(pls_scores)[:, :, latent_dim]
            latent_dim += 1
    elif initialization == "cca":
        latent_dim = 0
        cca_scores = MCCA(latent_dims).fit_transform(views)
        while True:
            yield np.stack(cca_scores)[:, :, latent_dim]
            latent_dim += 1
    else:
        raise ValueError(
            "Initialization {type} not supported. Pass a generator implementing this method"
        )
Esempio n. 9
0
 def test_regularized_methods(self):
     # Test that linear regularized methods match PLS solution when using maximum regularisation
     latent_dims = 5
     c = 1
     wrap_kernel = KCCA(latent_dims=latent_dims, c=[c, c], kernel=['linear', 'linear']).fit(self.X,
                                                                                            self.Y)
     wrap_pls = PLS(latent_dims=latent_dims).fit(self.X, self.Y)
     wrap_gcca = GCCA(latent_dims=latent_dims, c=[c, c]).fit(self.X, self.Y)
     wrap_mcca = MCCA(latent_dims=latent_dims, c=[c, c]).fit(self.X, self.Y)
     wrap_rCCA = rCCA(latent_dims=latent_dims, c=[c, c]).fit(self.X, self.Y)
     corr_gcca = wrap_gcca.train_correlations[0, 1]
     corr_mcca = wrap_mcca.train_correlations[0, 1]
     corr_kernel = wrap_kernel.train_correlations[0, 1]
     corr_pls = wrap_pls.train_correlations[0, 1]
     corr_rcca = wrap_rCCA.train_correlations[0, 1]
     # Check the correlations from each unregularized method are the same
     # self.assertIsNone(np.testing.assert_array_almost_equal(corr_pls, corr_gcca, decimal=2))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_pls, corr_mcca, decimal=1))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_pls, corr_kernel, decimal=1))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_pls, corr_rcca, decimal=1))
Esempio n. 10
0
 def test_unregularized_methods(self):
     latent_dims = 1
     wrap_cca = CCA(latent_dims=latent_dims).fit(self.X, self.Y)
     wrap_iter = CCA_ALS(latent_dims=latent_dims, tol=1e-9).fit(self.X, self.Y)
     wrap_gcca = GCCA(latent_dims=latent_dims).fit(self.X, self.Y)
     wrap_mcca = MCCA(latent_dims=latent_dims).fit(self.X, self.Y)
     wrap_kcca = KCCA(latent_dims=latent_dims).fit(self.X, self.Y)
     corr_cca = wrap_cca.train_correlations[0, 1]
     corr_iter = wrap_iter.train_correlations[0, 1]
     corr_gcca = wrap_gcca.train_correlations[0, 1]
     corr_mcca = wrap_mcca.train_correlations[0, 1]
     corr_kcca = wrap_kcca.train_correlations[0, 1]
     # Check the score outputs are the right shape
     self.assertTrue(wrap_iter.score_list[0].shape == (self.X.shape[0], latent_dims))
     self.assertTrue(wrap_gcca.score_list[0].shape == (self.X.shape[0], latent_dims))
     self.assertTrue(wrap_mcca.score_list[0].shape == (self.X.shape[0], latent_dims))
     self.assertTrue(wrap_kcca.score_list[0].shape == (self.X.shape[0], latent_dims))
     # Check the correlations from each unregularized method are the same
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_cca, corr_iter, decimal=2))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_iter, corr_mcca, decimal=2))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_iter, corr_gcca, decimal=2))
     self.assertIsNone(np.testing.assert_array_almost_equal(corr_iter, corr_kcca, decimal=2))
Esempio n. 11
0
class DCCA(_DCCA_base, torch.nn.Module):
    """
    A class used to fit a DCCA model.

    Examples
    --------
    >>> from cca_zoo.deepmodels import DCCA
    >>> model = DCCA()
    """
    def __init__(self,
                 latent_dims: int,
                 objective=objectives.CCA,
                 encoders: List[BaseEncoder] = [Encoder, Encoder],
                 learning_rate=1e-3,
                 r: float = 1e-3,
                 eps: float = 1e-9,
                 schedulers: List = None,
                 optimizers: List[torch.optim.Optimizer] = None):
        """
        Constructor class for DCCA

        :param latent_dims: # latent dimensions
        :param objective: # CCA objective: normal tracenorm CCA by default
        :param encoders: list of encoder networks
        :param learning_rate: learning rate if no optimizers passed
        :param r: regularisation parameter of tracenorm CCA like ridge CCA
        :param eps: epsilon used throughout
        :param schedulers: list of schedulers for each optimizer
        :param optimizers: list of optimizers for each encoder
        """
        super().__init__(latent_dims)
        self.latent_dims = latent_dims
        self.encoders = torch.nn.ModuleList(encoders)
        self.objective = objective(latent_dims, r=r)
        if optimizers is None:
            self.optimizers = [
                torch.optim.Adam(list(encoder.parameters()), lr=learning_rate)
                for encoder in self.encoders
            ]
        else:
            self.optimizers = optimizers
        self.schedulers = []
        if schedulers:
            self.schedulers.extend(schedulers)
        self.covs = None
        self.eps = eps

    def update_weights(self, *args):
        [optimizer.zero_grad() for optimizer in self.optimizers]
        z = self(*args)
        loss = self.objective.loss(*z)
        loss.backward()
        [optimizer.step() for optimizer in self.optimizers]
        return loss

    def forward(self, *args):
        z = self.encode(*args)
        return z

    def encode(self, *args):
        z = []
        for i, encoder in enumerate(self.encoders):
            z.append(encoder(args[i]))
        return tuple(z)

    def loss(self, *args):
        z = self(*args)
        return self.objective.loss(*z)

    def post_transform(self, *z_list, train=False):
        if train:
            self.cca = MCCA(latent_dims=self.latent_dims)
            self.cca.fit(*z_list)
            z_list = self.cca.transform(*z_list)
        else:
            z_list = self.cca.transform(*z_list)
        return z_list
Esempio n. 12
0
p = 3
q = 3
r = 3
latent_dims = 1
cv = 3

(X, Y, Z), (tx, ty, tz) = generate_covariance_data(
    n, view_features=[p, q, r], latent_dims=latent_dims, correlation=[0.9]
)

# %%
# Eigendecomposition-Based Methods
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

# %%
mcca = MCCA(latent_dims=latent_dims).fit((X, Y, X)).score((X, Y, Z))

# %%
gcca = GCCA(latent_dims=latent_dims).fit((X, Y, X)).score((X, Y, Z))

# %%
# We can also use kernel versions of these methods
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

# %%
kcca = KCCA(latent_dims=latent_dims).fit((X, Y, X)).score((X, Y, Z))

# %%
kgcca = KGCCA(latent_dims=latent_dims).fit((X, Y, X)).score((X, Y, Z))

# %%
Esempio n. 13
0
 def test_data_gen(self):
     (x, y, z), true_feats = generate_covariance_data(1000, [10, 11, 12], 1, [0.5, 0.5, 0.5], correlation=0.5)
     cca = CCA().fit(x[:500], y[:500])
     cca_pred = cca.predict_corr(x[500:], y[500:])
     mcca = MCCA().fit(x[:500], y[:500], z[:500])
     mcca_pred = mcca.predict_corr(x[500:], y[500:], z[500:])
Esempio n. 14
0
class DCCA_NOI(DCCA, torch.nn.Module):
    """
    A class used to fit a DCCA model by non-linear orthogonal iterations

    Examples
    --------
    >>> from cca_zoo.deepmodels import DCCA_NOI
    >>> model = DCCA_NOI()
    """
    def __init__(self,
                 latent_dims: int,
                 objective=objectives.MCCA,
                 encoders: List[BaseEncoder] = [Encoder, Encoder],
                 learning_rate=1e-3,
                 r: float = 1e-3,
                 rho: float = 0.2,
                 eps: float = 1e-9,
                 shared_target: bool = False,
                 schedulers: List = None,
                 optimizers: List[torch.optim.Optimizer] = None):
        """
        Constructor class for DCCA

        :param latent_dims: # latent dimensions
        :param objective: # CCA objective: normal tracenorm CCA by default
        :param encoders: list of encoder networks
        :param learning_rate: learning rate if no optimizers passed
        :param r: regularisation parameter of tracenorm CCA like ridge CCA
        :param rho: covariance memory like DCCA non-linear orthogonal iterations paper
        :param eps: epsilon used throughout
        :param shared_target: not used
        :param schedulers: list of schedulers for each optimizer
        :param optimizers: list of optimizers for each encoder
        """
        super().__init__(latent_dims=latent_dims,
                         objective=objective,
                         encoders=encoders,
                         learning_rate=learning_rate,
                         r=r,
                         eps=eps,
                         schedulers=schedulers,
                         optimizers=optimizers)
        self.latent_dims = latent_dims
        self.encoders = torch.nn.ModuleList(encoders)
        self.objective = objective(latent_dims, r=r)
        if optimizers is None:
            self.optimizers = [
                torch.optim.Adam(list(encoder.parameters()), lr=learning_rate)
                for encoder in self.encoders
            ]
        else:
            self.optimizers = optimizers
        self.schedulers = []
        if schedulers:
            self.schedulers.extend(schedulers)
        self.covs = None
        self.eps = eps
        self.rho = rho
        self.shared_target = shared_target
        assert (0 <= self.rho <= 1), "rho should be between 0 and 1"

    def update_weights(self, *args):
        z = self(*args)
        self.update_covariances(*z)
        covariance_inv = [
            objectives._compute_matrix_power(cov, -0.5, self.eps)
            for cov in self.covs
        ]
        preds = [
            torch.matmul(z, covariance_inv[i]).detach()
            for i, z in enumerate(z)
        ]
        losses = [
            torch.mean(torch.norm(z_i - preds[-i], dim=0))
            for i, z_i in enumerate(z, start=1)
        ]
        obj = self.objective.loss(*z)
        self.optimizers[0].zero_grad()
        losses[0].backward()
        self.optimizers[0].step()
        self.optimizers[1].zero_grad()
        losses[1].backward()
        self.optimizers[1].step()
        return obj

    def forward(self, *args):
        z = self.encode(*args)
        return z

    def encode(self, *args):
        z = []
        for i, encoder in enumerate(self.encoders):
            z.append(encoder(args[i]))
        return tuple(z)

    def loss(self, *args):
        z = self(*args)
        return self.objective.loss(*z)

    def update_covariances(self, *args):
        b = args[0].shape[0]
        batch_covs = [z_i.T @ z_i for i, z_i in enumerate(args)]
        if self.covs is not None:
            self.covs = [
                (self.rho * self.covs[i]).detach() + (1 - self.rho) * batch_cov
                for i, batch_cov in enumerate(batch_covs)
            ]
        else:
            self.covs = batch_covs

    def post_transform(self, *z_list, train=False):
        if train:
            self.cca = MCCA(latent_dims=self.latent_dims)
            self.cca.fit(*z_list)
            z_list = self.cca.transform(*z_list)
        else:
            z_list = self.cca.transform(*z_list)
        return z_list
Esempio n. 15
0
"""
### (Regularized) Generalized CCA via alternating least squares (can pass more than 2 views)
"""

gcca = GCCA(latent_dims=latent_dims, c=[1, 1])

gcca.fit(train_view_1, train_view_2)

gcca_results = np.stack(
    (gcca.train_correlations[0, 1], gcca.predict_corr(test_view_1,
                                                      test_view_2)[0, 1]))
"""
### (Regularized) Multiset CCA via alternating least squares (can pass more than 2 views)
"""

mcca = MCCA(latent_dims=latent_dims, c=[0.5, 0.5])
# small ammount of regularisation added since data is not full rank

mcca.fit(train_view_1, train_view_2)

mcca_results = np.stack(
    (mcca.train_correlations[0, 1], mcca.predict_corr(test_view_1,
                                                      test_view_2)[0, 1]))
"""
### (Regularized) Tensor CCA via alternating least squares (can pass more than 2 views)
"""

tcca = TCCA(latent_dims=latent_dims, c=[0.99, 0.99])
# small ammount of regularisation added since data is not full rank

tcca.fit(train_view_1, train_view_2)