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
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))