def test_cp_vonneumann_entropy_mixed_state(): """Test for cp_vonneumann_entropy on CP tensors. This test checks that the VNE of mixed states is calculated correctly. """ state1 = tl.tensor([[ 0.03004805, 0.42426117, 0.5483771, 0.4784077, 0.25792725, 0.34388784, 0.99927586, 0.96605812 ]]) state1 = state1 / tl.norm(state1) state2 = tl.tensor([[ 0.84250089, 0.43429687, 0.26551928, 0.18262211, 0.55584835, 0.2565509, 0.33197401, 0.97741178 ]]) state2 = state2 / tl.norm(state2) mat_mixed = tl.tensor((tl.dot(tl.transpose(state1), state1) + tl.dot(tl.transpose(state2), state2)) / 2.) actual_vne = 0.5546 mat = parafac(tl.tensor(mat_mixed), rank=2, normalize_factors=True) mat_unnorm = parafac(tl.tensor(mat_mixed), rank=2, normalize_factors=False) tl_vne = cp_vonneumann_entropy(mat) tl_vne_unnorm = cp_vonneumann_entropy(mat_unnorm) tl.testing.assert_array_almost_equal(tl_vne, actual_vne, decimal=3) tl.testing.assert_array_almost_equal(tl_vne_unnorm, actual_vne, decimal=3) assert_array_almost_equal(tl_vne, actual_vne, decimal=3) assert_array_almost_equal(tl_vne_unnorm, actual_vne, decimal=3)
def __factor_non_negative(self, tensor, factors, mode): """Compute a non-negative factor optimization for TCA Parameters ---------- tensor : torch.Tensor The tensor of activity of N neurons, T timepoints and K trials of shape N, T, K factors : list List of tensors, each one containing a factor mode : int Index of the factor to optimize Returns ------- float Number to which multiply the factor to for optimization """ sub_indices = [i for i in range(self.dimension) if i != mode] for i, e in enumerate(sub_indices): if i: accum = accum * tl.dot(tl.transpose(factors[e]), factors[e]) else: accum = tl.dot(tl.transpose(factors[e]), factors[e]) numerator = tl.dot(tl.base.unfold(tensor, mode), tl.tenalg.khatri_rao(factors, skip_matrix=mode)) numerator = tl.clip(numerator, a_min=self.epsilon, a_max=None) denominator = tl.dot(factors[mode], accum) denominator = tl.clip(denominator, a_min=self.epsilon, a_max=None) return (numerator / denominator)
def __factor(self, tensor, factors, mode, pseudo_inverse): """Compute a factor optimization for TCA Parameters ---------- tensor : torch.Tensor The tensor of activity of N neurons, T timepoints and K trials of shape N, T, K factors : list List of tensors, each one containing a factor mode : int Index of the factor to optimize pseudo_inverse : torch.Tensor Pseudo inverse matrix of the current factor Returns ------- torch.Tensor Optimized factor """ for i, factor in enumerate(factors): if i != mode: pseudo_inverse = pseudo_inverse * tl.dot( tl.transpose(factor), factor) factor = tl.dot(tl.base.unfold(tensor, mode), tl.tenalg.khatri_rao(factors, skip_matrix=mode)) factor = tl.transpose( tl.solve(tl.transpose(pseudo_inverse), tl.transpose(factor))) return factor
def als(tensor,rank,factors=None,it_max=100,tol=1e-7,list_factors=False,error_fast=True,time_rec=False): """ ALS methode of CP decomposition Parameters ---------- tensor : tensor rank : int factors : list of matrices, optional an initial factor matrices. The default is None. it_max : int, optional maximal number of iteration. The default is 100. tol : float, optional error tolerance. The default is 1e-7. list_factors : boolean, optional If true, then return factor matrices of each iteration. The default is False. error_fast : boolean, optional If true, use err_fast to compute data fitting error, otherwise, use err. The default is True. time_rec : boolean, optional If true, return computation time of each iteration. The default is False. Returns ------- the CP decomposition, number of iteration and termination criterion. list_fac and list_time are optional. """ N=tl.ndim(tensor) # order of tensor norm_tensor=tl.norm(tensor) # norm of tensor if time_rec == True : list_time=[] if list_factors==True : list_fac=[] # list of factor matrices if (factors==None): factors=svd_init_fac(tensor,rank) weights=None it=0 if list_factors==True : list_fac.append(copy.deepcopy(factors)) error=[err(tensor,weights,factors)/norm_tensor] while (error[len(error)-1]>tol and it<it_max): if time_rec == True : tic=time.time() for n in range(N): V=np.ones((rank,rank)) for i in range(len(factors)): if i != n : V=V*tl.dot(tl.transpose(factors[i]),factors[i]) W=tl.cp_tensor.unfolding_dot_khatri_rao(tensor, (None,factors), n) factors[n]= tl.transpose(tl.solve(tl.transpose(V),tl.transpose(W))) if list_factors==True : list_fac.append(copy.deepcopy(factors)) it=it+1 if (error_fast==False) : error.append(err(tensor,weights,factors)/norm_tensor) else : error.append(err_fast(norm_tensor,factors[N-1],V,W)/norm_tensor) if time_rec == True : toc=time.time() list_time.append(toc-tic) # weights,factors=tl.cp_tensor.cp_normalize((None,factors)) if list_factors==True and time_rec==True: return(weights,factors,it,error,list_fac,list_time) if time_rec==True : return(weights,factors,it,error,list_time) if list_factors==True : return(weights,factors,it,error,list_fac) return(weights,factors,it,error)
def tt_conv(x, tt_tensor, bias=None, stride=1, padding=0, dilation=1): """Perform a factorized tt convolution Parameters ---------- x : torch.tensor tensor of shape (batch_size, C, I_2, I_3, ..., I_N) Returns ------- NDConv(x) with an tt kernel """ shape = tt_tensor.shape rank = tt_tensor.rank batch_size = x.shape[0] order = len(shape) - 2 if isinstance(padding, int): padding = (padding, )*order if isinstance(stride, int): stride = (stride, )*order if isinstance(dilation, int): dilation = (dilation, )*order # Change the number of channels to the rank x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)).contiguous() # First conv == tensor contraction # from (1, in_channels, rank) to (rank == out_channels, in_channels, 1) x = F.conv1d(x, tl.transpose(tt_tensor.factors[0], [2, 1, 0])) x_shape[1] = x.shape[1]#rank[1] x = x.reshape(x_shape) # convolve over non-channels for i in range(order): # From (in_rank, kernel_size, out_rank) to (out_rank, in_rank, kernel_size) kernel = tl.transpose(tt_tensor.factors[i+1], [2, 0, 1]) x = general_conv1d(x.contiguous(), kernel, i+2, stride=stride[i], padding=padding[i]) # Revert back number of channels from rank to output_channels x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)) # Last conv == tensor contraction # From (rank, out_channels, 1) to (out_channels, in_channels == rank, 1) x = F.conv1d(x, tl.transpose(tt_tensor.factors[-1], [1, 0, 2]), bias=bias) x_shape[1] = x.shape[1] x = x.reshape(x_shape) return x
def test_vonneumann_entropy_mixed_state(): """Test for vonneumann_entropy on 2-dimensional tensors. This test checks that the VNE of mixed states is calculated correctly. """ state1 = tl.tensor([[0.03004805, 0.42426117, 0.5483771 , 0.4784077 , 0.25792725, 0.34388784, 0.99927586, 0.96605812]]) state1 = state1/tl.norm(state1) state2 = tl.tensor([[0.84250089, 0.43429687, 0.26551928, 0.18262211, 0.55584835, 0.2565509 , 0.33197401, 0.97741178]]) state2 = state2/tl.norm(state2) mat_mixed = tl.tensor((tl.dot(tl.transpose(state1), state1) + tl.dot(tl.transpose(state2), state2))/2.) actual_vne = 0.5546 tl_vne = vonneumann_entropy(mat_mixed) assert_array_almost_equal(tl_vne, actual_vne, decimal=3)
def contract(tensor1, modes1, tensor2, modes2): """Tensor contraction between two tensors on specified modes Parameters ---------- tensor1 : tl.tensor modes1 : int list or int modes on which to contract tensor1 tensor2 : tl.tensor modes2 : int list or int modes on which to contract tensor2 Returns ------- contraction : tensor1 contracted with tensor2 on the specified modes """ if isinstance(modes1, int): modes1 = [modes1] if isinstance(modes2, int): modes2 = [modes2] modes1 = list(modes1) modes2 = list(modes2) if len(modes1) != len(modes2): raise ValueError( 'Can only contract two tensors along the same number of modes' '(len(modes1) == len(modes2))' 'However, got {} modes for tensor 1 and {} mode for tensor 2' '(modes1={}, and modes2={})'.format(len(modes1), len(modes2), modes1, modes2)) contraction_dims = [tl.shape(tensor1)[i] for i in modes1] if contraction_dims != [tl.shape(tensor2)[i] for i in modes2]: raise ValueError( 'Trying to contract tensors over modes of different sizes' '(contracting modes of sizes {} and {}'.format( contraction_dims, [tl.shape(tensor2)[i] for i in modes2])) shared_dim = int(np.prod(contraction_dims)) modes1_free = [i for i in range(tl.ndim(tensor1)) if i not in modes1] free_shape1 = [tl.shape(tensor1)[i] for i in modes1_free] tensor1 = tl.reshape(tl.transpose(tensor1, modes1_free + modes1), (int(np.prod(free_shape1)), shared_dim)) modes2_free = [i for i in range(tl.ndim(tensor2)) if i not in modes2] free_shape2 = [tl.shape(tensor2)[i] for i in modes2_free] tensor2 = tl.reshape(tl.transpose(tensor2, modes2 + modes2_free), (shared_dim, int(np.prod(free_shape2)))) res = tl.dot(tensor1, tensor2) return tl.reshape(res, tuple(free_shape1 + free_shape2))
def cp_conv(x, cp_tensor, bias=None, stride=1, padding=0, dilation=1): """Perform a factorized CP convolution Parameters ---------- x : torch.tensor tensor of shape (batch_size, C, I_2, I_3, ..., I_N) Returns ------- NDConv(x) with an CP kernel """ shape = cp_tensor.shape rank = cp_tensor.rank batch_size = x.shape[0] order = len(shape) - 2 if isinstance(padding, int): padding = (padding, )*order if isinstance(stride, int): stride = (stride, )*order if isinstance(dilation, int): dilation = (dilation, )*order # Change the number of channels to the rank x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)).contiguous() # First conv == tensor contraction # from (in_channels, rank) to (rank == out_channels, in_channels, 1) x = F.conv1d(x, tl.transpose(cp_tensor.factors[1]).unsqueeze(2)) x_shape[1] = rank x = x.reshape(x_shape) # convolve over non-channels for i in range(order): # From (kernel_size, rank) to (rank, 1, kernel_size) kernel = tl.transpose(cp_tensor.factors[i+2]).unsqueeze(1) x = general_conv1d(x.contiguous(), kernel, i+2, stride=stride[i], padding=padding[i], groups=rank) # Revert back number of channels from rank to output_channels x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)) # Last conv == tensor contraction # From (out_channels, rank) to (out_channels, in_channels == rank, 1) x = F.conv1d(x*cp_tensor.weights.unsqueeze(1).unsqueeze(0), cp_tensor.factors[0].unsqueeze(2), bias=bias) x_shape[1] = x.shape[1] # = out_channels x = x.reshape(x_shape) return x
def vonneumann_entropy(tensor): """Returns the von Neumann entropy of a density matrix (2-mode, square) tensor (matrix). Parameters ---------- tensor : Non-decomposed tensor with indices whose shapes are all a factor of two (represent one or more qubits) Returns ------- von_neumann_entropy : order-0 tensor Notes ----- The von Neumann entropy is :math:`- \\sum_i p_i ln(p_i)`, where p_i are the probabilities that each state is occupied (the eigenvalues of the density matrix). """ square_dim = int(math.sqrt(prod(tensor.shape))) tensor = tl.reshape(tensor, (square_dim, square_dim)) try: eig_vals = T.eigh(tensor)[0] except: #All density matrices are Hermitian, here real. Hermitianize matrix if rounding/transformation #errors have occured. tensor = (tensor + tl.transpose(tensor)) / 2 eig_vals = T.eigh(tensor)[0] eps = tl.eps(eig_vals.dtype) eig_vals = eig_vals[eig_vals > eps] return -T.sum(T.log2(eig_vals) * eig_vals)
def vec2factors(vec, shape, rank, context=None): """Wrapper function detailed in Appendix C [1] Builds a set of N matrices, where the k-th matrix is shape(k) x rank in dimension Parameters ---------- vec : ndarray vector of values to proliferate matrices with shape: tensor shape shape of tensor dictates number of rows in each matrix rank: int number of columns in each matrix, *** rank cannot be > dimension of smallest mode *** Returns ------- M1 : CPTensor CPTensor with factor matrices formed by 'vec' """ numFacts = len(shape) factors = [] place = 0 for i in range(numFacts): factor = np.zeros((rank * shape[i]), **context) for j in range(shape[i] * rank): factor[j] = vec[j + place] factor = tl.tensor(factor.reshape((rank, shape[i])), **context) factors.append(tl.transpose(factor)) place += shape[i] * rank M1 = CPTensor((tl.ones(rank, ), factors)) return M1
def tucker_conv(x, tucker_tensor, bias=None, stride=1, padding=0, dilation=1): # Extract the rank from the actual decomposition in case it was changed by, e.g. dropout rank = tucker_tensor.rank batch_size = x.shape[0] n_dim = tl.ndim(x) # Change the number of channels to the rank x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)).contiguous() # This can be done with a tensor contraction # First conv == tensor contraction # from (in_channels, rank) to (rank == out_channels, in_channels, 1) x = F.conv1d(x, tl.transpose(tucker_tensor.factors[1]).unsqueeze(2)) x_shape[1] = rank[1] x = x.reshape(x_shape) modes = list(range(2, n_dim+1)) weight = tl.tenalg.multi_mode_dot(tucker_tensor.core, tucker_tensor.factors[2:], modes=modes) x = convolve(x, weight, bias=None, stride=stride, padding=padding) # Revert back number of channels from rank to output_channels x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)) # Last conv == tensor contraction # From (out_channels, rank) to (out_channels, in_channels == rank, 1) x = F.conv1d(x, tucker_tensor.factors[0].unsqueeze(2), bias=bias) x_shape[1] = x.shape[1] x = x.reshape(x_shape) return x
def tt_matrix_to_tensor(tt_matrix): """Returns the full tensor whose TT-Matrix decomposition is given by 'factors' Re-assembles 'factors', which represent a tensor in TT-Matrix format into the corresponding full tensor Parameters ---------- factors: list of 4D-arrays TT-Matrix factors (known as core) of shape (rank_k, left_dim_k, right_dim_k, rank_{k+1}) Returns ------- output_tensor: ndarray tensor whose TT-Matrix decomposition was given by 'factors' """ # Each core is of shape (rank_left, size_in, size_out, rank_right) rank, in_shape, out_shape, rank_right = zip(*(tl.shape(f) for f in tt_matrix)) rank += (rank_right[-1], ) ndim = len(in_shape) # Intertwine the dims # full_shape = in_shape[0], out_shape[0], in_shape[1], ... full_shape = sum(zip(*(in_shape, out_shape)), ()) order = list(range(0, ndim*2, 2)) + list(range(1, ndim*2, 2)) for i, factor in enumerate(tt_matrix): if not i: # factor = factor.squeeze(0) res = tl.reshape(factor, (factor.shape[1], -1)) else: res = tl.dot(tl.reshape(res, (-1, rank[i])), tl.reshape(factor, (rank[i], -1))) res = tl.reshape(res, full_shape) return tl.transpose(res, order)
def cp_conv_mobilenet(x, cp_tensor, bias=None, stride=1, padding=0, dilation=1): """Perform a factorized CP convolution Parameters ---------- x : torch.tensor tensor of shape (batch_size, C, I_2, I_3, ..., I_N) Returns ------- NDConv(x) with an CP kernel """ factors = cp_tensor.factors shape = cp_tensor.shape rank = cp_tensor.rank batch_size = x.shape[0] order = len(shape) - 2 # Change the number of channels to the rank x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)).contiguous() # First conv == tensor contraction # from (in_channels, rank) to (rank == out_channels, in_channels, 1) x = F.conv1d(x, tl.transpose(factors[1]).unsqueeze(2)) x_shape[1] = rank x = x.reshape(x_shape) # convolve over merged actual dimensions # Spatial convs # From (kernel_size, rank) to (out_rank, 1, kernel_size) if order == 1: weight = tl.transpose(factors[2]).unsqueeze(1) x = F.conv1d(x.contiguous(), weight, stride=stride, padding=padding, dilation=dilation, groups=rank) elif order == 2: weight = tenalg.tensordot(tl.transpose(factors[2]), tl.transpose(factors[3]), modes=(), batched_modes=0 ).unsqueeze(1) x = F.conv2d(x.contiguous(), weight, stride=stride, padding=padding, dilation=dilation, groups=rank) elif order == 3: weight = tenalg.tensordot(tl.transpose(factors[2]), tenalg.tensordot(tl.transpose(factors[3]), tl.transpose(factors[4]), modes=(), batched_modes=0), modes=(), batched_modes=0 ).unsqueeze(1) x = F.conv3d(x.contiguous(), weight, stride=stride, padding=padding, dilation=dilation, groups=rank) # Revert back number of channels from rank to output_channels x_shape = list(x.shape) x = x.reshape((batch_size, x_shape[1], -1)) # Last conv == tensor contraction # From (out_channels, rank) to (out_channels, in_channels == rank, 1) x = F.conv1d(x*cp_tensor.weights.unsqueeze(1).unsqueeze(0), factors[0].unsqueeze(2), bias=bias) x_shape[1] = x.shape[1] # = out_channels x = x.reshape(x_shape) return x
def show_proj(factors, matlab_data, ex1_em0): color = ["r", "g", "b"] for i in range(3): mat1 = np.array(factors[1][1]).transpose()[i] w = tl.norm(factors[1][0][i]) sq_mat = np.array(mat1).reshape(61, 201) m = np.max(sq_mat) ind = tl.where(sq_mat == m) if (ex1_em0 == 1): x = matlab_data["EmAx"][0] y = w * tl.transpose(sq_mat[ind[0]]) else: x = matlab_data["ExAx"][0] y = w * np.transpose(tl.transpose(sq_mat)[ind[1]]) plt.grid() plt.plot(x, y, color[i]) plt.show()
def test_cp_to_tensor(): """Test for cp_to_tensor.""" U1 = np.reshape(np.arange(1, 10), (3, 3)) U2 = np.reshape(np.arange(10, 22), (4, 3)) U3 = np.reshape(np.arange(22, 28), (2, 3)) U4 = np.reshape(np.arange(28, 34), (2, 3)) U = [tl.tensor(t) for t in [U1, U2, U3, U4]] true_res = tl.tensor([[[[ 46754., 51524.], [ 52748., 58130.]], [[ 59084., 65114.], [ 66662., 73466.]], [[ 71414., 78704.], [ 80576., 88802.]], [[ 83744., 92294.], [ 94490., 104138.]]], [[[ 113165., 124784.], [ 127790., 140912.]], [[ 143522., 158264.], [ 162080., 178730.]], [[ 173879., 191744.], [ 196370., 216548.]], [[ 204236., 225224.], [ 230660., 254366.]]], [[[ 179576., 198044.], [ 202832., 223694.]], [[ 227960., 251414.], [ 257498., 283994.]], [[ 276344., 304784.], [ 312164., 344294.]], [[ 324728., 358154.], [ 366830., 404594.]]]]) res = cp_to_tensor((tl.ones(3), U)) assert_array_equal(res, true_res, err_msg='Khatri-rao incorrectly transformed into full tensor.') columns = 4 rows = [3, 4, 2] matrices = [tl.tensor(np.arange(k * columns).reshape((k, columns))) for k in rows] tensor = cp_to_tensor((tl.ones(columns), matrices)) for i in range(len(rows)): unfolded = unfold(tensor, mode=i) U_i = matrices.pop(i) reconstructed = tl.dot(U_i, tl.transpose(khatri_rao(matrices))) assert_array_almost_equal(reconstructed, unfolded) matrices.insert(i, U_i)
def test_vonneumann_entropy_pure_state(): """Test for vonneumann_entropy on 2-dimensional tensors. This test checks that pure states have a VNE of zero. """ state = tl.randn((8, 1)) state = state / tl.norm(state) mat_pure = tl.dot(state, tl.transpose(state)) tl_vne = vonneumann_entropy(mat_pure) assert_array_almost_equal(tl_vne, 0, decimal=3)
def test_cp_vonneumann_entropy_pure_state(): """Test for cp_vonneumann_entropy on 2-dimensional CP tensors. This test checks that pure states have a VNE of zero. """ state = tl.randn((8, 1)) state = state / tl.norm(state) mat_pure = tl.dot(state, tl.transpose(state)) mat = parafac(mat_pure, rank=1, normalize_factors=True) tl_vne = cp_vonneumann_entropy(mat) assert_array_almost_equal(tl_vne, 0, decimal=3)
def test_factors2vec_1(): """ Test wrapper function from GCP paper""" X = tl.tensor(np.arange(24).reshape((3,4,2)), dtype=tl.float32) factors = [] for i in range(3): f = tl.transpose(X[:][:][i]) factors.append(f) vec = factors2vec(factors) for i in range(vec.size): assert(vec[i] == i), "Value at vec[i] = {} doesn't equal the index value i = {}".format(vec[i], i)
def test_tt_vonneumann_entropy_pure_state(): """Test for tt_vonneumann_entropy TT tensors. This test checks that pure states have a VNE of zero. """ state = tl.randn((8, 1)) state = state/tl.norm(state) mat_pure = tl.reshape(tl.dot(state, tl.transpose(state)), (2, 2, 2, 2, 2, 2)) mat_pure = matrix_product_state(mat_pure, rank=(1, 3, 2, 1, 2, 3, 1)) tl_vne = tt_vonneumann_entropy(mat_pure) assert_array_almost_equal(tl_vne, 0, decimal=3)
def uttkrp(tens, mode, mtxs, core=None, transpose=False): """ Alternative implementation of uttkrp in sktensor library. The description of that method is modified below: Unfolded tensor times Khatri-Rao product: :math:`Z = \\unfold{X}{3} (U_1 \kr \cdots \kr U_N)` Computes the _matrix_ product of the unfolding of a tensor and the Khatri-Rao product of multiple matrices. Efficient computations are perfomed by the respective tensor implementations. Parameters ---------- tens : input tensor mtxs : list of array-likes Matrices for which the Khatri-Rao product is computed and which are multiplied with the tensor in mode `mode`. mode : int Mode in which the Khatri-Rao product of `mtxs` is multiplied with the tensor. core: array-like Weights for each component (K-length) Returns ------- Z : np.ndarray Matrix which is the result of the matrix product of the unfolding of the tensor and the Khatri-Rao product of `mtxs`. See also -------- For efficient computations of unfolded tensor times Khatri-Rao products for specialiized tensors see also References ---------- [1] B.W. Bader, T.G. Kolda Efficient Matlab Computations With Sparse and Factored Tensors SIAM J. Sci. Comput, Vol 30, No. 1, pp. 205--231, 2007 """ if transpose: mtxs = [mtx.T for mtx in mtxs] K, D = mtxs[mode].shape order = sorted(range(tens.ndim), key=lambda m: mtxs[m].shape[0]) order.remove(mode) Z = tl.transpose(tens, [mode] + order) Z = tl.tenalg.mode_dot(Z, mtxs[order[-1]], -1) for m in reversed(order[:-1]): Z *= mtxs[m].T Z = Z.sum(axis=-2) if core is not None: Z *= core[:, np.newaxis] if not transpose else core return Z.T if not transpose else Z
def general_conv1d_(x, kernel, mode, bias=None, stride=1, padding=0, groups=1, dilation=1, verbose=False): """General 1D convolution along the mode-th dimension Parameters ---------- x : batch-dize, in_channels, K1, ..., KN kernel : out_channels, in_channels/groups, K{mode} mode : int weight along which to perform the decomposition stride : int padding : int groups : 1 typically would be equal to thhe number of input-channels at least for CP convolutions Returns ------- x convolved with the given kernel, along dimension `mode` """ if verbose: print(f'Convolving {x.shape} with {kernel.shape} along mode {mode}, ' f'stride={stride}, padding={padding}, groups={groups}') in_channels = tl.shape(x)[1] n_dim = tl.ndim(x) permutation = list(range(n_dim)) spatial_dim = permutation.pop(mode) channels_dim = permutation.pop(1) permutation += [channels_dim, spatial_dim] x = tl.transpose(x, permutation) x_shape = list(x.shape) x = tl.reshape(x, (-1, in_channels, x_shape[-1])) x = F.conv1d(x.contiguous(), kernel, bias=bias, stride=stride, dilation=dilation, padding=padding, groups=groups) x_shape[-2:] = x.shape[-2:] x = tl.reshape(x, x_shape) permutation = list(range(n_dim))[:-2] permutation.insert(1, n_dim - 2) permutation.insert(mode, n_dim - 1) x = tl.transpose(x, permutation) return x
def factors2vec(factors): """Wrapper function detailed in Appendix C [1] Stacks the column vectors of a set of matrices into a single vecto Parameters --------- factors : list of ndarrays Factor matrices or Gradient wrt factor gradient Returns ------- vec : ndarry column-wise vectorization of a list of matrices """ vec = None for factor in factors: if vec is None: vec = tl.tensor_to_vec(tl.transpose(factor)) else: vec = tl.concatenate([vec, tl.tensor_to_vec(tl.transpose(factor))]) return vec
def homo_decryption(encrypted_Tensor, key_Matrix, n): decrypted_tensor = [] for k in range(encrypted_Tensor.shape[0]): decrypted_columns = [] for i in range(encrypted_Tensor.shape[2]): # x, info = cg(key_Matrix, encrypted_Tensor[k, :, i].reshape(n, 1)) x = solve(key_Matrix, encrypted_Tensor[k, :, i]) decrypted_columns.append(x) decrypted_factors = tl.transpose( tl.fold(decrypted_columns, mode=0, shape=(n, n))) # print(decrypted_factors) decrypted_tensor.append(decrypted_factors) decrypted_tensor = tl.fold(decrypted_tensor, mode=0, shape=(n, n, n)) # print(decrypted_tensor) return decrypted_tensor
def test_cp_to_tensor_with_weights(): A = tl.reshape(tl.arange(1,5), (2,2)) B = tl.reshape(tl.arange(5,9), (2,2)) weigths = tl.tensor([2,-1], **tl.context(A)) out = cp_to_tensor((weigths, [A,B])) expected = tl.tensor([[-2,-2], [6, 10]]) # computed by hand assert_array_equal(out, expected) (weigths, factors) = random_cp((5, 5, 5), rank=5, normalise_factors=True, full=False) true_res = tl.dot(tl.dot(factors[0], tl.diag(weigths)), tl.transpose(tl.tenalg.khatri_rao(factors[1:]))) true_res = tl.fold(true_res, 0, (5, 5, 5)) res = cp_to_tensor((weigths, factors)) assert_array_almost_equal(true_res, res, err_msg='weights incorrectly incorporated in cp_to_tensor')
def test_vec2factors_1(): """ Test wrapper function from GCP paper""" rank = 2 X = tl.tensor(np.arange(24).reshape((3, 4, 2)), dtype=tl.float32) X_shp = tl.shape(X) X_cntx = tl.context(X) factors = [] for i in range(3): f = tl.transpose(X[:][:][i]) factors.append(f) vec1 = factors2vec(factors) M = vec2factors(vec1,X_shp, rank, X_cntx) vec2 = factors2vec(M[1]) for i in range(X_shp[0]): assert(vec1[i] == vec2[i])
def tensor_train_matrix(tensor, rank): """Decompose a tensor into a matrix in tt-format Parameters ---------- tensor : tensorized matrix if your input matrix is of size (4, 9) and your tensorized_shape (2, 2, 3, 3) then tensor should be tl.reshape(matrix, (2, 2, 3, 3)) rank : 'same', float or int tuple - if 'same' creates a decomposition with the same number of parameters as `tensor` - if float, creates a decomposition with `rank` x the number of parameters of `tensor` - otherwise, the actual rank to be used, e.g. (1, rank_2, ..., 1) of size tensor.ndim//2. Note that boundary conditions dictate that the first rank = last rank = 1. Returns ------- tt_matrix """ order = tl.ndim(tensor) n_input = order // 2 # (n_output = n_input) if tl.ndim(tensor) != n_input * 2: msg = 'The tensor should have as many dimensions for inputs and outputs, i.e. order should be even ' msg += f'but got a tensor of order tl.ndim(tensor)={order} which is odd.' raise ValueError(msg) in_shape = tl.shape(tensor)[:n_input] out_shape = tl.shape(tensor)[n_input:] if n_input == 1: # A TTM with a single factor is just a matrix... return TTMatrix([tensor.reshape(1, in_shape[0], out_shape[0], 1)]) new_idx = list([ idx for tuple_ in zip(range(n_input), range(n_input, 2 * n_input)) for idx in tuple_ ]) new_shape = list([a * b for (a, b) in zip(in_shape, out_shape)]) tensor = tl.reshape(tl.transpose(tensor, new_idx), new_shape) factors = tensor_train(tensor, rank).factors for i in range(len(factors)): factors[i] = tl.reshape( factors[i], (factors[i].shape[0], in_shape[i], out_shape[i], -1)) return TTMatrix(factors)
def vonneumann_entropy(tensor): """Returns the von Neumann entropy of a density matrix (2-mode, square) tensor (matrix). Parameters ---------- tensor : (matrix) Data structure Returns ------- von_neumann_entropy : order-0 tensor """ try: eig_vals = T.eigh(tensor)[0] except: #All density matrices are Hermitian, here real. Hermitianize matrix if rounding/transformation #errors have occured. tensor = (tensor + tl.transpose(tensor)) / 2 eig_vals = T.eigh(tensor)[0] eps = tl.eps(eig_vals.dtype) eig_vals = eig_vals[eig_vals > eps] return -T.sum(T.log2(eig_vals) * eig_vals)
def parafac(tensor, rank, n_iter_max=100, tol=1e-8, random_state=None, verbose=False, return_errors=False, mode_three_val=[[0.5, 0.5, 0.0], [0.0, 0.5, 0.5]]): """CANDECOMP/PARAFAC decomposition via alternating least squares (ALS) Computes a rank-`rank` decomposition of `tensor` [1]_ such that, ``tensor = [| factors[0], ..., factors[-1] |]``. Parameters ---------- tensor : ndarray rank : int Number of components. n_iter_max : int Maximum number of iteration tol : float, optional (Default: 1e-6) Relative reconstruction error tolerance. The algorithm is considered to have found the global minimum when the reconstruction error is less than `tol`. random_state : {None, int, np.random.RandomState} verbose : int, optional Level of verbosity return_errors : bool, optional Activate return of iteration errors Returns ------- factors : ndarray list List of factors of the CP decomposition element `i` is of shape (tensor.shape[i], rank) errors : list A list of reconstruction errors at each iteration of the algorithms. References ---------- .. [1] tl.G.Kolda and B.W.Bader, "Tensor Decompositions and Applications", SIAM REVIEW, vol. 51, n. 3, pp. 455-500, 2009. """ factors = initialize_factors(tensor, rank, random_state=random_state) rec_errors = [] norm_tensor = tl.norm(tensor, 2) # Mode-3 values that control the country factors are set using the # mode_three_val argument. fixed_ja = mode_three_val[0] fixed_ko = mode_three_val[1] for iteration in range(n_iter_max): for mode in range(tl.ndim(tensor)): pseudo_inverse = tl.tensor(np.ones((rank, rank)), **tl.context(tensor)) factors[2][0] = fixed_ja # set mode-3 values factors[2][1] = fixed_ko # set mode-3 values for i, factor in enumerate(factors): if i != mode: pseudo_inverse = pseudo_inverse * tl.dot( tl.transpose(factor), factor) factor = tl.dot(unfold(tensor, mode), khatri_rao(factors, skip_matrix=mode)) factor = tl.transpose( tl.solve(tl.transpose(pseudo_inverse), tl.transpose(factor))) factors[mode] = factor if tol: rec_error = tl.norm(tensor - kruskal_to_tensor(factors), 2) / norm_tensor rec_errors.append(rec_error) if iteration > 1: if verbose: print('reconstruction error={}, variation={}.'.format( rec_errors[-1], rec_errors[-2] - rec_errors[-1])) if tol and abs(rec_errors[-2] - rec_errors[-1]) < tol: if verbose: print('converged in {} iterations.'.format(iteration)) break if return_errors: return factors, rec_errors else: return factors
def non_negative_parafac(tensor, rank, n_iter_max=100, init='svd', svd='numpy_svd', tol=10e-7, random_state=None, verbose=0, normalize_factors=False, return_errors=False, mask=None, orthogonalise=False, cvg_criterion='abs_rec_error', fixed_modes=[]): """ Non-negative CP decomposition Uses multiplicative updates, see [2]_ This is the same as parafac(non_negative=True). Parameters ---------- tensor : ndarray rank : int number of components n_iter_max : int maximum number of iteration init : {'svd', 'random'}, optional svd : str, default is 'numpy_svd' function to use to compute the SVD, acceptable values in tensorly.SVD_FUNS tol : float, optional tolerance: the algorithm stops when the variation in the reconstruction error is less than the tolerance random_state : {None, int, np.random.RandomState} verbose : int, optional level of verbosity fixed_modes : list, default is [] A list of modes for which the initial value is not modified. The last mode cannot be fixed due to error computation. Returns ------- factors : ndarray list list of positive factors of the CP decomposition element `i` is of shape ``(tensor.shape[i], rank)`` References ---------- .. [2] Amnon Shashua and Tamir Hazan, "Non-negative tensor factorization with applications to statistics and computer vision", In Proceedings of the International Conference on Machine Learning (ICML), pp 792-799, ICML, 2005 """ epsilon = 10e-12 rank = validate_cp_rank(tl.shape(tensor), rank=rank) if mask is not None and init == "svd": message = "Masking occurs after initialization. Therefore, random initialization is recommended." warnings.warn(message, Warning) if orthogonalise and not isinstance(orthogonalise, int): orthogonalise = n_iter_max weights, factors = initialize_cp(tensor, rank, init=init, svd=svd, random_state=random_state, non_negative=True, normalize_factors=normalize_factors) rec_errors = [] norm_tensor = tl.norm(tensor, 2) if tl.ndim(tensor) - 1 in fixed_modes: warnings.warn( 'You asked for fixing the last mode, which is not supported while tol is fixed.\n The last mode will not be fixed. Consider using tl.moveaxis()' ) fixed_modes.remove(tl.ndim(tensor) - 1) modes_list = [ mode for mode in range(tl.ndim(tensor)) if mode not in fixed_modes ] for iteration in range(n_iter_max): if orthogonalise and iteration <= orthogonalise: for i, f in enumerate(factors): if min(tl.shape(f)) >= rank: factors[i] = tl.abs(tl.qr(f)[0]) if verbose > 1: print("Starting iteration", iteration + 1) for mode in modes_list: if verbose > 1: print("Mode", mode, "of", tl.ndim(tensor)) accum = 1 # khatri_rao(factors).tl.dot(khatri_rao(factors)) # simplifies to multiplications sub_indices = [i for i in range(len(factors)) if i != mode] for i, e in enumerate(sub_indices): if i: accum *= tl.dot(tl.transpose(factors[e]), factors[e]) else: accum = tl.dot(tl.transpose(factors[e]), factors[e]) if mask is not None: tensor = tensor * mask + tl.cp_to_tensor( (None, factors), mask=1 - mask) mttkrp = unfolding_dot_khatri_rao(tensor, (None, factors), mode) numerator = tl.clip(mttkrp, a_min=epsilon, a_max=None) denominator = tl.dot(factors[mode], accum) denominator = tl.clip(denominator, a_min=epsilon, a_max=None) factor = factors[mode] * numerator / denominator factors[mode] = factor if normalize_factors: weights, factors = cp_normalize((weights, factors)) if tol: # ||tensor - rec||^2 = ||tensor||^2 + ||rec||^2 - 2*<tensor, rec> factors_norm = cp_norm((weights, factors)) # mttkrp and factor for the last mode. This is equivalent to the # inner product <tensor, factorization> iprod = tl.sum(tl.sum(mttkrp * factor, axis=0) * weights) rec_error = tl.sqrt( tl.abs(norm_tensor**2 + factors_norm**2 - 2 * iprod)) / norm_tensor rec_errors.append(rec_error) if iteration >= 1: rec_error_decrease = rec_errors[-2] - rec_errors[-1] if verbose: print( "iteration {}, reconstraction error: {}, decrease = {}" .format(iteration, rec_error, rec_error_decrease)) if cvg_criterion == 'abs_rec_error': stop_flag = abs(rec_error_decrease) < tol elif cvg_criterion == 'rec_error': stop_flag = rec_error_decrease < tol else: raise TypeError("Unknown convergence criterion") if stop_flag: if verbose: print("PARAFAC converged after {} iterations".format( iteration)) break else: if verbose: print('reconstruction error={}'.format(rec_errors[-1])) cp_tensor = CPTensor((weights, factors)) if return_errors: return cp_tensor, rec_errors else: return cp_tensor
def coupled_matrix_tensor_3d_factorization(tensor_3d, matrix, rank, init='svd', n_iter_max=100, normalize_factors=False): """ Calculates a coupled matrix and tensor factorization of 3rd order tensor and matrix which are coupled in first mode. Assume you have tensor_3d = [[lambda; A, B, C]] and matrix = [[gamma; A, V]], which are coupled in 1st mode. With coupled matrix and tensor factorization (CTMF), the normalized factor matrices A, B, C for the CP decomposition of X, the normalized matrix V and the weights lambda_ and gamma are found. This implementation only works for a coupling in the first mode. Solution is found via alternating least squares (ALS) as described in Figure 5 of @article{acar2011all, title={All-at-once optimization for coupled matrix and tensor factorizations}, author={Acar, Evrim and Kolda, Tamara G and Dunlavy, Daniel M}, journal={arXiv preprint arXiv:1105.3422}, year={2011} } Notes ----- In the paper, the columns of the factor matrices are not normalized and therefore weights are not included in the algorithm. Parameters ---------- tensor_3d : tl.tensor or CP tensor 3rd order tensor X = [[A, B, C]] matrix : tl.tensor or CP tensor matrix that is coupled with tensor in first mode: Y = [[A, V]] rank : int rank for CP decomposition of X Returns ------- tensor_3d_pred : CPTensor tensor_3d_pred = [[lambda; A,B,C]] matrix_pred : CPTensor matrix_pred = [[gamma; A,V]] rec_errors : list contains the reconstruction error of each iteration: error = 1 / 2 * | X - [[ lambda_; A, B, C ]] | ^ 2 + 1 / 2 * | Y - [[ gamma; A, V ]] | ^ 2 Examples -------- A = tl.tensor([[1, 2], [3, 4]]) B = tl.tensor([[1, 0], [0, 2]]) C = tl.tensor([[2, 0], [0, 1]]) V = tl.tensor([[2, 0], [0, 1]]) R = 2 X = (None, [A, B, C]) Y = (None, [A, V]) tensor_3d_pred, matrix_pred = cmtf_als_for_third_order_tensor(X, Y, R) """ rank = validate_cp_rank(tl.shape(tensor_3d), rank=rank) # initialize values tensor_cp = initialize_cp(tensor_3d, rank, init=init) rec_errors = [] # alternating least squares # note that the order of the khatri rao product is reversed since tl.unfold has another order # than assumed in paper for iteration in range(n_iter_max): V = tl.transpose(tl.lstsq(tensor_cp.factors[0], matrix)[0]) # Loop over modes of the tensor for ii in range(tl.ndim(tensor_3d)): kr = khatri_rao(tensor_cp.factors, skip_matrix=ii) unfolded = tl.unfold(tensor_3d, ii) # If we are at the coupled mode, concat the matrix if ii == 0: kr = tl.concatenate((kr, V), axis=0) unfolded = tl.concatenate((unfolded, matrix), axis=1) tensor_cp.factors[ii] = tl.transpose( tl.lstsq(kr, tl.transpose(unfolded))[0]) error_new = tl.norm(tensor_3d - cp_to_tensor(tensor_cp))**2 + tl.norm( matrix - cp_to_tensor((None, [tensor_cp.factors[0], V])))**2 if iteration > 0 and (tl.abs(error_new - error_old) / error_old <= 1e-8 or error_new < 1e-5): break error_old = error_new rec_errors.append(error_new) matrix_pred = CPTensor((None, [tensor_cp.factors[0], V])) if normalize_factors: tensor_cp = cp_normalize(tensor_cp) matrix_pred = cp_normalize(matrix_pred) return tensor_cp, matrix_pred, rec_errors