Exemple #1
0
def _compute_projections(tensor_slices, factors, svd_fun, out=None):
    A, B, C = factors

    if out is None:
        out = [
            T.zeros((tensor_slice.shape[0], C.shape[1]),
                    **T.context(tensor_slice))
            for tensor_slice in tensor_slices
        ]

    slice_idxes = range(T.shape(A)[0])
    for projection, i, tensor_slice in zip(out, slice_idxes, tensor_slices):
        a_i = A[i]
        lhs = T.dot(B, T.transpose(a_i * C))
        rhs = T.transpose(tensor_slice)
        U, S, Vh = svd_fun(T.dot(lhs, rhs), n_eigenvecs=A.shape[1])

        out[i] = tl.index_update(projection, tl.index[:],
                                 T.transpose(T.dot(U, Vh)))

    return out
Exemple #2
0
def initialize_decomposition(tensor_slices,
                             rank,
                             init='random',
                             svd='numpy_svd',
                             random_state=None):
    r"""Initiate a random PARAFAC2 decomposition given rank and tensor slices

    Parameters
    ----------
    tensor_slices : Iterable of ndarray
    rank : int
    init : {'random', 'svd', CPTensor, Parafac2Tensor}, optional
    random_state : `np.random.RandomState`

    Returns
    -------
    parafac2_tensor : Parafac2Tensor
        List of initialized factors of the CP decomposition where element `i`
        is of shape (tensor.shape[i], rank)

    """
    context = tl.context(tensor_slices[0])
    shapes = [m.shape for m in tensor_slices]

    if init == 'random':
        return random_parafac2(shapes,
                               rank,
                               full=False,
                               random_state=random_state,
                               **context)
    elif init == 'svd':
        try:
            svd_fun = tl.SVD_FUNS[svd]
        except KeyError:
            message = 'Got svd={}. However, for the current backend ({}), the possible choices are {}'.format(
                svd, tl.get_backend(), tl.SVD_FUNS)
            raise ValueError(message)
        padded_tensor = _pad_by_zeros(tensor_slices)
        A = T.ones((padded_tensor.shape[0], rank), **context)

        unfolded_mode_2 = unfold(padded_tensor, 2)
        if T.shape(unfolded_mode_2)[0] < rank:
            raise ValueError(
                "Cannot perform SVD init if rank ({}) is greater than the number of columns in each tensor slice ({})"
                .format(rank,
                        T.shape(unfolded_mode_2)[0]))
        C = svd_fun(unfold(padded_tensor, 2), n_eigenvecs=rank)[0]
        B = T.eye(rank, **context)
        projections = _compute_projections(tensor_slices, (A, B, C), svd_fun)
        return Parafac2Tensor((None, [A, B, C], projections))

    elif isinstance(init, (tuple, list, Parafac2Tensor, CPTensor)):
        try:
            decomposition = Parafac2Tensor.from_CPTensor(
                init, parafac2_tensor_ok=True)
        except ValueError:
            raise ValueError(
                'If initialization method is a mapping, then it must '
                'be possible to convert it to a Parafac2Tensor instance')
        if decomposition.rank != rank:
            raise ValueError(
                'Cannot init with a decomposition of different rank')
        return decomposition
    raise ValueError('Initialization method "{}" not recognized'.format(init))