def state_tensor_decomposition(states, rank=3):
    import tensorly as tly
    from tensorly.decomposition import parafac

    s_tens = tly.tensor(states)
    f = parafac(s_tens, rank=rank)
    factors = []

    for ii in range(len(f)):
        factors.append(tly.to_numpy(f[ii]))

    return factors
示例#2
0
def MVLVM(X1, X2, X3, k=2, sigma=0.2, n_iter=100, reg=0):
    rank = k
    Xa = np.vstack((X1, X2))
    Xb = np.vstack((X2, X1))
    K = gauss_kernal_mat(Xa, Xa,
                         sigma)  # [1st elmts of pair, 2nd elmts of pair]
    K = 0.5 * (K + K.T) + reg * np.eye(Xa.shape[0])
    L = gauss_kernal_mat(Xb, Xb,
                         sigma)  # [2nd elmts of pair, 1st elmts of pair]
    L = 0.5 * (L + L.T) + reg * np.eye(Xa.shape[0])
    n = K.shape[0] // 2
    R = scipy.linalg.cholesky(K)  ### todo: why is K not full rank??
    R = R.T  #account for their convention
    s, beta_tilde = scipy.sparse.linalg.eigs((1 / (4 * n**2)) * R @ L @ R.T,
                                             k=rank)
    s = np.real(s)
    beta_tilde = np.real(beta_tilde)
    S12 = np.diag(s**0.5)
    Sn12 = np.diag(s**-0.5)
    beta = pinv(R) @ beta_tilde

    #form the tensor
    z1 = (Sn12 @ beta.T) @ K[:, :n]
    z2 = (Sn12 @ beta.T) @ K[:, n:]
    z3 = (Sn12 @ beta.T) @ gauss_kernal_mat(Xa, X3, sigma)
    weights = np.ones((n, ))
    factors = [z3, z1, z2]  #different order to make tensor power method
    T = tl.kruskal_to_tensor((weights, factors))
    T = (1 / (3 * n)) * tl.to_numpy(T)

    #tensor power method
    M = np.zeros((rank, rank))
    lams = np.zeros((rank, ))
    for j in range(rank):
        v = np.random.randn(rank, )
        v = v / np.inner(v, v)**0.5
        vold = v
        for i in range(n_iter):
            v = np.dot(T, v) @ v
            lam = np.inner(v, v)**0.5
            v = v / lam
            #             print(np.linalg.norm(v-vold))
            vold = v
        M[:, j] = v
        lams[j] = lam
        ws = np.ones((1, ))
        facs = [v, v, v]
        V = np.einsum("i,j,k ->ijk", v, v, v)
        T = T - lam * V
    A = beta @ S12 @ M @ np.diag(lams)
    pi = lams**-2

    return A, pi
def test_kruskal_norm():
    """Test for kruskal_norm
    """
    shape = (8, 5, 6, 4)
    rank = 25
    kruskal_tensor = random_kruskal(shape=shape,
                                    rank=rank,
                                    full=False,
                                    normalise_factors=True)
    tol = 10e-5
    rec = tl.kruskal_to_tensor(kruskal_tensor)
    true_res = tl.norm(rec, 2)
    res = kruskal_norm(kruskal_tensor)
    assert_(tl.to_numpy(tl.abs(true_res - res)) <= tol)
示例#4
0
def _congruence_coefficient_slow(A, B, absolute_value):
    _, r = tl.shape(A)
    corr_matrix = _tucker_congruence(A, B)
    if absolute_value:
        corr_matrix = tl.abs(corr_matrix)
    corr_matrix = tl.to_numpy(corr_matrix)

    best_corr = None
    best_permutation = None
    for permutation in itertools.permutations(range(r)):
        corr = 0
        for i, j in zip(range(r), permutation):
            corr += corr_matrix[i, j] / r
        
        if best_corr is None or corr > best_corr:
            best_corr = corr
            best_permutation = permutation
    
    return best_corr, best_permutation
示例#5
0
def to_image(tensor):
    """
	Convience function for analysis of images 
	where float has to converted back to uint8 
	for valid plots

	Params
	------
	tensor: np.ndarray or tl.tensor
	"""
    # if np.ndarray no transform
    if isinstance(tensor, np.ndarray):
        im = tensor
    # if tl.tensor transform to np.ndarray
    else:
        im = tl.to_numpy(tensor)
    im -= im.min()
    im /= im.max()
    im *= 255
    return im.astype(np.uint8)
示例#6
0
    def unfoldTemporal(self):
        # return object will be a 3d tensor
        # of dim: R^(Temp x (prod_spat) x Sub)
        # should have some rough input validation
        # TODO: create function that checks that all niftys
        #       in the niftyList are of equal dimensions
        if self.niftyList != None:
            shape_tensor = self.niftyList[0].shape
            # set up the dimensions of the return object
            spat_dim = shape_tensor[0] * shape_tensor[1] * shape_tensor[2]
            temp_dim = shape_tensor[3]
            # no of subjects
            subj_dim = len(self.niftyList)
            # create a (temp, spat, subj) tensor to hold the result
            X = tl.tensor(
                np.zeros(temp_dim * spat_dim * (subj_dim)).reshape(
                    temp_dim, spat_dim, subj_dim))
            # loop through the list of niftys, fold to temp_dim x spat_dim matricies
            # and add to the tensor. Folding is done on the temporal mode, leading
            # to the temporal fibers being the rows, with each column containing
            # the spatial information

            #temp_nifty = tl.tensor(np.zeros(temp_dim * spat_dim).reshape(temp_dim, spat_dim))

            # loop through the subjects
            # TODO: is this line causing problems?
            #       Should it be subj_dim or (subj_dim-1)
            for i in range(subj_dim):
                # temp_nifty = tl.unfold(self.niftyList[i], self.idx_temporal)
                # seems like you have to make it to a tl.tensor rather than ndarray
                # this code is extremely ineffecient, lots of casting
                X[:, :, i] = tl.unfold(tl.tensor(self.niftyList[i]),
                                       self.idx_temporal)
        else:
            raise TypeError("No niftys has been entered")
            # this is not very effective, but seems to be what is working
            # otherwise when slicing you get some really weird casting
            # <mxnet.ndarray.ndarray.NDarray>
        return tl.to_numpy(X)
示例#7
0
for i, pattern in enumerate(patterns):

    # Generate the original image
    weight_img = gen_image(region=pattern,
                           image_height=image_height,
                           image_width=image_width)
    weight_img = tl.tensor(weight_img)

    # Generate the labels
    y = tl.dot(partial_tensor_to_vec(X, skip_begin=1),
               tensor_to_vec(weight_img))

    # Plot the original weights
    ax = fig.add_subplot(n_rows, n_columns, i * n_columns + 1)
    ax.imshow(tl.to_numpy(weight_img),
              cmap=plt.cm.OrRd,
              interpolation='nearest')
    ax.set_axis_off()
    if i == 0:
        ax.set_title('Original\nweights')

    for j, rank in enumerate(ranks):

        # Create a tensor Regressor estimator
        estimator = CPRegressor(weight_rank=rank,
                                tol=10e-7,
                                n_iter_max=100,
                                reg_W=1,
                                verbose=0)
示例#8
0
tucker_rank = [
    round(compression * digit_tensor.shape[0]),
    round(compression * digit_tensor.shape[1]),
    round(compression * digit_tensor.shape[2])
]

core, tucker_factors = tucker(digit_tl,
                              ranks=tucker_rank,
                              init="random",
                              tol=10e-5,
                              random_state=1234,
                              n_iter_max=100,
                              verbose=False)

core_digit = tl.to_numpy(core)

print(core_digit.shape)

max_rank = 50

# estimate errors, take the time aswell
start_time = time.time()
X_error = error_parafac(tensor=digit_tensor,
                        max_rank=max_rank,
                        init="random",
                        verbose=False)
x_time = time.time() - start_time

start_time = time.time()
core_error = error_parafac(tensor=core_digit,
示例#9
0
tucker_rank = [
    round(compr * img.shape[0]),
    round(compr * img.shape[1]), img.shape[2]
]

img_tl = tl.tensor(img)

core, tucker_factors = tucker(img_tl,
                              ranks=tucker_rank,
                              init="random",
                              tol=10e-5,
                              random_state=1234,
                              n_iter_max=100,
                              verbose=False)

core_img = tl.to_numpy(core)

print(core_img.shape)

max_rank = 50

# estimate errors, take the time aswell
start_time = time.time()
X_error = error_parafac(tensor=img,
                        max_rank=max_rank,
                        init="random",
                        verbose=False)
x_time = time.time() - start_time
print("Time original data: " + str(x_time))

start_time = time.time()
示例#10
0
    def compute_tensor_factorization(self, rank, tf_type='non_negative_cp', init='svd', random_state=None, verbose=False,
                                     runs=1, normalize_loadings=True, var_ordered_factors=True, **kwargs):
        '''Performs a Tensor Factorization.
        There are no returns, instead the attributes factors and rank
         of the Tensor class are updated.

        Parameters
        ----------
        rank : int
            Rank of the Tensor Factorization (number of factors to deconvolve the original
            tensor).

        tf_type : str, default='non_negative_cp'
            Type of Tensor Factorization.

            - 'non_negative_cp' : Non-negative PARAFAC, as implemented in Tensorly

        init : str, default='svd'
            Initialization method for computing the Tensor Factorization.
            {‘svd’, ‘random’}

        random_state : int, default=None
            Seed for randomization.

        verbose : boolean, default=False
            Whether printing or not steps of the analysis.

        runs : int, default=1
            Number of models to choose among and find the lowest error.
            This helps to avoid local minima when using runs > 1.

        normalize_loadings : boolean, default=True
            Whether normalizing the loadings in each factor to unit
            Euclidean length.

        var_ordered_factors : boolean, default=True
            Whether ordering factors by the variance they explain. The order is from
            highest to lowest variance. `normalize_loadings` must be True. Otherwise,
            this parameter is ignored.

        **kwargs : dict
            Extra arguments for the tensor factorization according to inputs in tensorly.
        '''
        tensor_dim = len(self.tensor.shape)
        best_err = np.inf
        tf = None

        if kwargs is None:
            kwargs = {'return_errors' : True}
        else:
            kwargs['return_errors'] = True

        for run in tqdm(range(runs), disable=(runs==1)):
            if random_state is not None:
                random_state_ = random_state + run
            else:
                random_state_ = None
            local_tf, errors = _compute_tensor_factorization(tensor=self.tensor,
                                                             rank=rank,
                                                             tf_type=tf_type,
                                                             init=init,
                                                             random_state=random_state_,
                                                             mask=self.mask,
                                                             verbose=verbose,
                                                             **kwargs)
            # This helps to obtain proper error when the mask is not None.
            if self.mask is None:
                err = tl.to_numpy(errors[-1])
                if best_err > err:
                    best_err = err
                    tf = local_tf
            else:
                err = _compute_norm_error(self.tensor, local_tf, self.mask)
                if best_err > err:
                    best_err = err
                    tf = local_tf

        if runs > 1:
            print('Best model has a normalized error of: {0:.3f}'.format(best_err))

        self.tl_object = tf
        if normalize_loadings:
            self.norm_tl_object = tl.cp_tensor.cp_normalize(self.tl_object)

        factor_names = ['Factor {}'.format(i) for i in range(1, rank+1)]
        if self.order_labels is None:
            if tensor_dim == 4:
                order_labels = ['Contexts', 'Ligand-Receptor Pairs', 'Sender Cells', 'Receiver Cells']
            elif tensor_dim > 4:
                order_labels = ['Contexts-{}'.format(i+1) for i in range(tensor_dim-3)] + ['Ligand-Receptor Pairs', 'Sender Cells', 'Receiver Cells']
            elif tensor_dim == 3:
                order_labels = ['Ligand-Receptor Pairs', 'Sender Cells', 'Receiver Cells']
            else:
                raise ValueError('Too few dimensions in the tensor')
        else:
            assert len(self.order_labels) == tensor_dim, "The length of order_labels must match the number of orders/dimensions in the tensor"
            order_labels = self.order_labels

        if normalize_loadings:
            (weights, factors) = self.norm_tl_object
            weights = tl.to_numpy(weights)
            if var_ordered_factors:
                w_order = weights.argsort()[::-1]
                factors = [tl.to_numpy(f)[:, w_order] for f in factors]
                self.explained_variance_ratio_ = weights[w_order] / sum(weights)
            else:
                factors = [tl.to_numpy(f) for f in factors]
                self.explained_variance_ratio_ = weights / sum(weights)

        else:
            (weights, factors) = self.tl_object
            self.explained_variance_ratio_ = None

        self.explained_variance_ = self.explained_variance()

        self.factors = OrderedDict(zip(order_labels,
                                       [pd.DataFrame(tl.to_numpy(f), index=idx, columns=factor_names) for f, idx in zip(factors, self.order_names)]))
        self.rank = rank
示例#11
0
def to_trans(Fdtensor):
    """A convenience function to convert from L255  to TRANSPARENTS"""
    trans_tensor = tl.to_numpy(Fdtensor)
    trans_tensor /= trans_tensor.max()
    return trans_tensor.astype(np.float16)
示例#12
0
from decompositions.parafac_np import parafac
import numpy as np
import tensorly as tl
from tensorly.decomposition import tucker
import matplotlib.pyplot as plt
import math
from utils.utils_np import *

# X is 10x10x10 generated from N(2,8)
X = np.random.normal(2, 8, 10*10*10).reshape(10,10,10)
# X = np.random.exponential(5, 20*20*20).reshape(20,20,20)
# run tucker decomposition
Xt = tl.tensor(X)
core, factors = tucker(Xt , ranks = [8, 8, 8])
tucker_reconstruction = tl.tucker_to_tensor(core, factors)
core = tl.to_numpy(core)

# calculate product of 2norm of factor matricies
np_factors = []

for i in range(len(factors)):
	np_factors.append(tl.to_numpy(factors[i]))

print(two_norm(np_factors))
print(two_norm(np_factors[0]))
print(np.dot(np.transpose(np_factors[0]), np_factors[0]))
# product of spectral norm of independent tucker 
# factor matricies is 1 as the factor matricies
# are orthogonal
n_iter = 30
x_error_over_ranks = [None] * n_iter
def convert2uin8(tensor):
    im = tl.to_numpy(tensor)
    im -= im.min()
    im /= im.max()
    im *= 255
    return im.astype(np.uint8)
示例#14
0
 def shape(tensor):
     return tl.to_numpy(tensor).shape
示例#15
0
 def ndim(tensor):
     return len(tl.to_numpy(tensor).shape)
示例#16
0
def subset_tensor(interaction_tensor,
                  subset_dict,
                  remove_duplicates=True,
                  original_order=False):
    '''Subsets an InteractionTensor to contain only specific elements in
    respective dimensions.

    Parameters
    ----------
    interaction_tensor : cell2cell.tensor.BaseTensor
        A communication tensor generated with any of the tensor class in
        cell2cell.tensor

    subset_dict : dict
        Dictionary to subset the tensor. It must contain the axes or
        dimensions that will be subset as the keys of the dictionary
        and the values corresponds to lists of element names for the
        respective axes or dimensions. Those axes that are not present
        in this dictionary will not be subset.
        E.g. {0 : ['Context 1', 'Context2'], 1: ['LR 10', 'LR 100']}

    remove_duplicates : boolean, default=True
        Whether removing duplicated names in `elements`.

    original_order : boolean, default=False
        Wheter keeping the original order of the elements in
        interaction_tensor.order_names or keeping the
        new order as indicated in the lists in the `subset_dict`.

    Returns
    -------
    subset_tensor : cell2cell.tensor.BaseTensor
        A copy of interaction_tensor that was subset to contain
        only the elements specified for the respective axis in the
        `subset_dict`. Corresponds to a communication tensor
        generated with any of the tensor class in cell2cell.tensor
    '''
    # Perform a deep copy of the original tensor and reset previous factorization
    subset_tensor = copy.deepcopy(interaction_tensor)
    subset_tensor.rank = None
    subset_tensor.tl_object = None
    subset_tensor.factors = None

    # Initialize tensor into a numpy object for performing subset
    context = tl.context(subset_tensor.tensor)
    tensor = tl.to_numpy(subset_tensor.tensor)
    mask = None
    if subset_tensor.mask is not None:
        mask = tl.to_numpy(subset_tensor.mask)

    # Search for indexes
    axis_idxs = dict()
    for k, v in subset_dict.items():
        if k < len(tensor.shape):
            if len(v) != 0:
                idx = find_element_indexes(interaction_tensor=subset_tensor,
                                           elements=v,
                                           axis=k,
                                           remove_duplicates=remove_duplicates,
                                           original_order=original_order)
                if len(idx) == 0:
                    print(
                        "No elements found for axis {}. It will return an empty tensor."
                        .format(k))
                axis_idxs[k] = idx
        else:
            print(
                "Axis {} is out of index, not considering elements in this axis."
                .format(k))

    # Subset tensor
    for k, v in axis_idxs.items():
        if tensor.shape != (0, ):  # Avoids error when returned empty tensor
            tensor = tensor.take(indices=v, axis=k)

            subset_tensor.order_names[k] = [
                subset_tensor.order_names[k][i] for i in v
            ]
            if mask is not None:
                mask = mask.take(indices=v, axis=k)

    # Restore tensor and mask properties
    tensor = tl.tensor(tensor, **context)
    if mask is not None:
        mask = tl.tensor(mask, **context)

    subset_tensor.tensor = tensor
    subset_tensor.mask = mask
    return subset_tensor
示例#17
0
def test_tucker():
    """Test for the Tucker decomposition"""
    rng = check_random_state(1234)

    tol_norm_2 = 10e-3
    tol_max_abs = 10e-1
    tensor = tl.tensor(rng.random_sample((3, 4, 3)))
    for svd_func in tl.SVD_FUNS:
        core, factors = tucker(tensor,
                               rank=None,
                               n_iter_max=200,
                               svd=svd_func,
                               verbose=True)
        reconstructed_tensor = tucker_to_tensor((core, factors))
        norm_rec = tl.to_numpy(tl.norm(reconstructed_tensor, 2))
        norm_tensor = tl.to_numpy(tl.norm(tensor, 2))
        assert ((norm_rec - norm_tensor) / norm_rec < tol_norm_2)

        # Test the max abs difference between the reconstruction and the tensor
        assert (tl.to_numpy(tl.max(tl.abs(reconstructed_tensor - tensor))) <
                tol_max_abs)

        # Test the shape of the core and factors
        ranks = [2, 3, 1]
        core, factors = tucker(tensor,
                               rank=ranks,
                               n_iter_max=100,
                               svd=svd_func,
                               verbose=1)
        for i, rank in enumerate(ranks):
            assert_equal(
                factors[i].shape, (tensor.shape[i], ranks[i]),
                err_msg="factors[{}].shape={}, expected {} (svd=\"{}\")".
                format(i, factors[i].shape, (tensor.shape[i], ranks[i]),
                       svd_func))
            assert_equal(tl.shape(core)[i],
                         rank,
                         err_msg="Core.shape[{}]={}, "
                         "expected {} (svd=\"{}\")".format(
                             i, core.shape[i], rank, svd_func))

        # Random and SVD init should converge to a similar solution
        tol_norm_2 = 10e-1
        tol_max_abs = 10e-1

        core_svd, factors_svd = tucker(tensor,
                                       rank=[3, 4, 3],
                                       n_iter_max=200,
                                       init='svd',
                                       svd=svd_func,
                                       verbose=1)
        core_random, factors_random = tucker(tensor,
                                             rank=[3, 4, 3],
                                             n_iter_max=200,
                                             init='random',
                                             svd=svd_func,
                                             random_state=1234)
        rec_svd = tucker_to_tensor((core_svd, factors_svd))
        rec_random = tucker_to_tensor((core_random, factors_random))
        error = tl.norm(rec_svd - rec_random, 2)
        error /= tl.norm(rec_svd, 2)
        assert_(
            tl.to_numpy(error) < tol_norm_2,
            'norm 2 of difference between svd and random init too high '
            '(svd="{0}")'.format(svd_func))
        assert_(
            tl.to_numpy(tl.max(tl.abs(rec_svd - rec_random))) < tol_max_abs,
            'abs norm of difference between svd and random init too high '
            '(svd="{0}")'.format(svd_func))
示例#18
0
def maxvol(A):
    """ Find the rxr submatrix of maximal volume in A(nxr), n>=r

            We want to decompose matrix A as
                    A = A[:,J] * (A[I,J])^-1 * A[I,:]
            This algorithm helps us find this submatrix A[I,J] from A, which has the largest determinant.
            We greedily find vector of max norm, and subtract its projection from the rest of rows.

    Parameters
    ----------

    A: matrix
            The matrix to find maximal volume

    Returns
    -------
    row_idx: list of int
            is the list or rows of A forming the matrix with maximal volume,
    A_inv: matrix
            is the inverse of the matrix with maximal volume.

    References
    ----------
    S. A. Goreinov, I. V. Oseledets, D. V. Savostyanov, E. E. Tyrtyshnikov, N. L. Zamarashkin.
    How to find a good submatrix.Goreinov, S. A., et al.
    Matrix Methods: Theory, Algorithms and Applications: Dedicated to the Memory of Gene Golub. 2010. 247-256.

    Ali Çivril, Malik Magdon-Ismail
    On selecting a maximum volume sub-matrix of a matrix and related problems
    Theoretical Computer Science. Volume 410, Issues 47–49, 6 November 2009, Pages 4801-4811
    """

    (n, r) = tl.shape(A)

    # The index of row of the submatrix
    row_idx = tl.zeros(r)

    # Rest of rows / unselected rows
    rest_of_rows = tl.tensor(list(range(n)),dtype= tl.int64)

    # Find r rows iteratively
    i = 0
    A_new = A
    while i < r:
        mask = list(range(tl.shape(A_new)[0]))
        # Compute the square of norm of each row
        rows_norms = tl.sum(A_new ** 2, axis=1)

        # If there is only one row of A left, let's just return it. MxNet is not robust about this case.
        if tl.shape(rows_norms) == ():
            row_idx[i] = rest_of_rows
            break

        # If a row is 0, we delete it.
        if any(rows_norms == 0):
            zero_idx = tl.argmin(rows_norms,axis=0)
            mask.pop(zero_idx)
            rest_of_rows = rest_of_rows[mask]
            A_new = A_new[mask,:]
            continue

        # Find the row of max norm
        max_row_idx = tl.argmax(rows_norms, axis=0)
        max_row = A[rest_of_rows[max_row_idx], :]

        # Compute the projection of max_row to other rows
        # projection a to b is computed as: <a,b> / sqrt(|a|*|b|)
        projection = tl.dot(A_new, tl.transpose(max_row))
        normalization = tl.sqrt(rows_norms[max_row_idx] * rows_norms)
        # make sure normalization vector is of the same shape of projection (causing bugs for MxNet)
        normalization = tl.reshape(normalization, tl.shape(projection))
        projection = projection/normalization

        # Subtract the projection from A_new:  b <- b - a * projection
        A_new = A_new - A_new * tl.reshape(projection, (tl.shape(A_new)[0], 1))

        # Delete the selected row
        mask.pop(max_row_idx)
        A_new = A_new[mask,:]

        # update the row_idx and rest_of_rows
        row_idx[i] = rest_of_rows[max_row_idx]
        rest_of_rows = rest_of_rows[mask]
        i = i + 1

    row_idx = tl.tensor(row_idx, dtype=tl.int64)
    inverse = tl.solve(A[row_idx,:],
                 tl.eye(tl.shape(A[row_idx,:])[0], **tl.context(A)))
    row_idx = tl.to_numpy(row_idx)

    return row_idx, inverse
# plt.imshow(img)
# plt.show()
img = np.array(img, dtype=np.float64)

# Get tucker core
img_tl = tl.tensor(img)
tucker_rank = [30, 80, 3]
core, tucker_factors = tucker(img_tl,
                              ranks=tucker_rank,
                              init='random',
                              tol=10e-5,
                              random_state=1234,
                              n_iter_max=100,
                              verbose=True)

core_np = tl.to_numpy(core)

# train on original data and core
max_r = 40
t0 = time.time()
original_data_error = error_parafac(tensor=img,
                                    max_rank=max_r,
                                    init="random",
                                    verbose=True)
t1 = time.time()
print(t1 - t0)
t0 = time.time()
core_data_error = error_parafac(tensor=core_np,
                                max_rank=max_r,
                                init="random",
                                verbose=False)
示例#20
0
def _multiple_runs_elbow_analysis(tensor,
                                  upper_rank=50,
                                  runs=10,
                                  tf_type='non_negative_cp',
                                  init='svd',
                                  random_state=None,
                                  mask=None,
                                  verbose=False,
                                  **kwargs):
    '''Performs an elbow analysis with multiple runs of a tensor factorization for each
    rank

    Parameters
    ----------
    tensor : ndarray list
        A tensor that could be a list of lists, a multidimensional numpy array or a
        tensorly.tensor.

    upper_rank : int, default=50
        Upper bound of ranks to explore with the elbow analysis.

    runs : int, default=100
        Number of tensor factorization performed for a given rank. Each factorization
        varies in the seed of initialization.

    tf_type : str, default='non_negative_cp'
        Type of Tensor Factorization.
        - 'non_negative_cp' : Non-negative PARAFAC, as implemented in Tensorly

    init : str, default='svd'
        Initialization method for computing the Tensor Factorization.
        {‘svd’, ‘random’}

    random_state : int, default=None
        Seed for randomization.

    mask : ndarray list, default=None
        Helps avoiding missing values during a tensor factorization. A mask should be
        a boolean array of the same shape as the original tensor and should be 0
        where the values are missing and 1 everywhere else.

    verbose : boolean, default=False
        Whether printing or not steps of the analysis.

    **kwargs : dict
        Extra arguments for the tensor factorization according to inputs in tensorly.

    Returns
    -------
    all_loss : ndarray
        Array containing the errors associated with multiple runs for a given rank.
        This array is of shape (runs, upper_rank).
    '''
    assert isinstance(runs, int), "runs must be an integer"
    if kwargs is None:
        kwargs = {'return_errors': True}
    else:
        kwargs['return_errors'] = True

    all_loss = []
    for r in tqdm(range(1, upper_rank + 1)):
        run_errors = []
        for run in range(runs):
            if random_state is not None:
                rs = random_state + run
            else:
                rs = None
            tl_object, errors = _compute_tensor_factorization(tensor=tensor,
                                                              rank=r,
                                                              tf_type=tf_type,
                                                              init=init,
                                                              random_state=rs,
                                                              mask=mask,
                                                              verbose=verbose,
                                                              **kwargs)
            # This helps to obtain proper error when the mask is not None.
            if mask is None:
                run_errors.append(tl.to_numpy(errors[-1]))
            else:
                run_errors.append(_compute_norm_error(tensor, tl_object, mask))
        all_loss.append(run_errors)

    all_loss = np.array(all_loss).T
    return all_loss
示例#21
0
def unimodality_prox(tensor):
    """
    This function projects each column of the input array on the set of arrays so that
          x[1] <= x[2] <= x[j] >= x[j+1]... >= x[n]
    is satisfied columnwise.

    Parameters
    ----------
    tensor : ndarray

    Returns
    -------
    ndarray
         A tensor of which columns' distribution are unimodal.

    References
    ----------
    .. [1]: Bro, R., & Sidiropoulos, N. D. (1998). Least squares algorithms under
            unimodality and non‐negativity constraints. Journal of Chemometrics:
            A Journal of the Chemometrics Society, 12(4), 223-247.
    """
    if tl.ndim(tensor) == 1:
        tensor = tl.vec_to_tensor(tensor, [tl.shape(tensor)[0], 1])
    elif tl.ndim(tensor) > 2:
        raise ValueError(
            "Unimodality prox doesn't support an input which has more than 2 dimensions."
        )

    tensor_unimodal = tl.copy(tensor)
    monotone_increasing = tl.tensor(monotonicity_prox(tensor),
                                    **tl.context(tensor))
    monotone_decreasing = tl.tensor(monotonicity_prox(tensor, decreasing=True),
                                    **tl.context(tensor))
    # Next line finds mutual peak points
    values = tl.tensor(
        tl.to_numpy((tensor - monotone_decreasing >= 0)) * tl.to_numpy(
            (tensor - monotone_increasing >= 0)), **tl.context(tensor))

    sum_inc = tl.where(values == 1,
                       tl.cumsum(tl.abs(tensor - monotone_increasing), axis=0),
                       tl.tensor(0, **tl.context(tensor)))
    sum_inc = tl.where(values == 1,
                       sum_inc - tl.abs(tensor - monotone_increasing),
                       tl.tensor(0, **tl.context(tensor)))
    sum_dec = tl.where(
        tl.flip(values, axis=0) == 1,
        tl.cumsum(tl.abs(
            tl.flip(tensor, axis=0) - tl.flip(monotone_decreasing, axis=0)),
                  axis=0), tl.tensor(0, **tl.context(tensor)))
    sum_dec = tl.where(
        tl.flip(values, axis=0) == 1, sum_dec -
        tl.abs(tl.flip(tensor, axis=0) - tl.flip(monotone_decreasing, axis=0)),
        tl.tensor(0, **tl.context(tensor)))

    difference = tl.where(values == 1, sum_inc + tl.flip(sum_dec, axis=0),
                          tl.max(sum_inc + tl.flip(sum_dec, axis=0)))
    min_indice = tl.argmin(tl.tensor(difference), axis=0)

    for i in range(len(min_indice)):
        tensor_unimodal = tl.index_update(
            tensor_unimodal, tl.index[:int(min_indice[i]), i],
            monotone_increasing[:int(min_indice[i]), i])
        tensor_unimodal = tl.index_update(
            tensor_unimodal, tl.index[int(min_indice[i] + 1):, i],
            monotone_decreasing[int(min_indice[i] + 1):, i])
    return tensor_unimodal
示例#22
0
def _run_elbow_analysis(tensor,
                        upper_rank=50,
                        tf_type='non_negative_cp',
                        init='svd',
                        random_state=None,
                        mask=None,
                        verbose=False,
                        disable_pbar=False,
                        **kwargs):
    '''Performs an elbow analysis with just one run of a tensor factorization for each
    rank

    Parameters
    ----------
    tensor : ndarray list
        A tensor that could be a list of lists, a multidimensional numpy array or a
        tensorly.tensor.

    upper_rank : int, default=50
        Upper bound of ranks to explore with the elbow analysis.

    tf_type : str, default='non_negative_cp'
        Type of Tensor Factorization.
        - 'non_negative_cp' : Non-negative PARAFAC, as implemented in Tensorly

    init : str, default='svd'
        Initialization method for computing the Tensor Factorization.
        {‘svd’, ‘random’}

    random_state : int, default=None
        Seed for randomization.

    mask : ndarray list, default=None
        Helps avoiding missing values during a tensor factorization. A mask should be
        a boolean array of the same shape as the original tensor and should be 0
        where the values are missing and 1 everywhere else.

    verbose : boolean, default=False
        Whether printing or not steps of the analysis.

    disable_pbar : boolean, default=False
        Whether displaying a tqdm progress bar or not.

    **kwargs : dict
        Extra arguments for the tensor factorization according to inputs in tensorly.

    Returns
    -------
    loss : list
        List of  tuples with (x, y) coordinates for the elbow analysis. X values are
        the different ranks and Y values are the errors of each decomposition.
    '''
    if kwargs is None:
        kwargs = {'return_errors': True}
    else:
        kwargs['return_errors'] = True

    loss = []
    for r in tqdm(range(1, upper_rank + 1), disable=disable_pbar):
        tl_object, errors = _compute_tensor_factorization(
            tensor=tensor,
            rank=r,
            tf_type=tf_type,
            init=init,
            random_state=random_state,
            mask=mask,
            verbose=verbose,
            **kwargs)
        # This helps to obtain proper error when the mask is not None.
        if mask is None:
            loss.append((r, tl.to_numpy(errors[-1])))
        else:
            loss.append((r, _compute_norm_error(tensor, tl_object, mask)))

    return loss
fig = plt.figure()

for i, pattern in enumerate(patterns):

    print('fitting pattern n.{}'.format(i))

    # Generate the original image
    weight_img = gen_image(region=pattern, image_height=image_height, image_width=image_width)
    weight_img = tl.tensor(weight_img)

    # Generate the labels
    y = tl.dot(partial_tensor_to_vec(X, skip_begin=1), tensor_to_vec(weight_img))

    # Plot the original weights
    ax = fig.add_subplot(n_rows, n_columns, i*n_columns + 1)
    ax.imshow(tl.to_numpy(weight_img), cmap=plt.cm.OrRd, interpolation='nearest')
    ax.set_axis_off()
    if i == 0:
        ax.set_title('Original\nweights')

    for j, rank in enumerate(ranks):
        print('fitting for rank = {}'.format(rank))

        # Create a tensor Regressor estimator
        estimator = TuckerRegressor(weight_ranks=[rank, rank], tol=10e-7, n_iter_max=100, reg_W=1, verbose=0)

        # Fit the estimator to the data
        estimator.fit(X, y)

        ax = fig.add_subplot(n_rows, n_columns, i*n_columns + j + 2)
        ax.imshow(tl.to_numpy(estimator.weight_tensor_), cmap=plt.cm.OrRd, interpolation='nearest')
示例#24
0
print("Tucker rank: " + str(tucker_rank[0]) + ", " + str(tucker_rank[1]))

tl.set_backend('numpy')
#tensor_cube_tl = tl.tensor(tensor_cube)

# fit the tucker decomposition
core, tucker_factors = tucker(tensor_cube,
                              ranks=tucker_rank,
                              init="rand",
                              tol=10e-5,
                              random_state=123,
                              n_iter_max=40,
                              verbose=False)

core_cube = tl.to_numpy(core)
print("Core shape: " + str(core_cube.shape))

max_rank = 50

start_time = time.time()
X_error = error_parafac(tensor=tensor_cube,
                        max_rank=max_rank,
                        init="random",
                        verbose=False)
x_time = time.time() - start_time
print("X time: " + str(x_time))

start_time = time.time()
core_error_1 = error_parafac(tensor=core_cube,
                             max_rank=max_rank,