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
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)
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
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)
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)
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)
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,
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()
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
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)
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)
def shape(tensor): return tl.to_numpy(tensor).shape
def ndim(tensor): return len(tl.to_numpy(tensor).shape)
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
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))
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)
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
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
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')
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,