swh:1:snp:4e3e7077647a709f15b8c1b32ce7100175d0580b
Raw File
Tip revision: 6b5a5fe85b64da3ca5e4c383c8f7b7b475fdfb48 authored by Jean Kossaifi on 15 October 2020, 18:31:27 UTC
Update website + API fix
Tip revision: 6b5a5fe
_cp_power.py
import tensorly as tl
from ._base_decomposition import DecompositionMixin
from ..cp_tensor import _validate_cp_rank
from tensorly.tenalg import outer
from tensorly.metrics.regression import standard_deviation
import numpy as np

def power_iteration(tensor, n_repeat=10, n_iteration=10, verbose=False):
    """A single Robust Tensor Power Iteration

    Parameters
    ----------
    tensor : tl.tensor
        input tensor to decompose
    n_repeat : int, default is 10
        number of initializations to be tried
    n_iteration : int, default is 10
        number of power iterations
    verbose : bool
        level of verbosity

    Returns
    -------
    (eigenval, best_factor, deflated)

    eigenval : float
        the obtained eigenvalue
    best_factors: tl.tensor list
        the best estimated eigenvector, for each mode of the input tensor
    deflated : tl.tensor of same shape as `tensor`
        the deflated tensor (i.e. without the estimated component)
    """
    order = tl.ndim(tensor)
    
    # A list of candidates for each mode
    best_score = 0
    scores = []
    
    for _ in range(n_repeat):
        factors = [tl.tensor(np.random.random_sample(s), **tl.context(tensor)) for s in tl.shape(tensor)]

        for _ in range(n_iteration):
            for mode in range(order):
                factor = tl.tenalg.multi_mode_dot(tensor, factors, skip=mode)
                factor = factor / tl.norm(factor, 2)
                factors[mode] = factor
                
        score = tl.tenalg.multi_mode_dot(tensor, factors)
        scores.append(score) #round(score, 2))
        
        if score > best_score:
            best_score = score
            best_factors = factors
            
    if verbose:
        print(f'Best score of {n_repeat}: {best_score}')
    
    # Refine the init
    for _ in range(n_iteration):
        for mode in range(order):
            factor = tl.tenalg.multi_mode_dot(tensor, best_factors, skip=mode)
            factor = factor / tl.norm(factor, 2)
            best_factors[mode] = factor

    eigenval = tl.tenalg.multi_mode_dot(tensor, best_factors)
    deflated = tensor - outer(best_factors)*eigenval
    
    if verbose:
        explained = tl.norm(deflated)/tl.norm(tensor)
        print(f'Eingenvalue: {eigenval}, explained: {explained}')

    return eigenval, best_factors, deflated


def parafac_power_iteration(tensor, rank, n_repeat=10, n_iteration=10, verbose=0):
    """CP Decomposition via Robust Tensor Power Iteration

    Parameters
    ----------
    tensor : tl.tensor
        input tensor to decompose
    rank : int
        rank of the decomposition (number of rank-1 components)
    n_repeat : int, default is 10
        number of initializations to be tried
    n_iteration : int, default is 10
        number of power iterations
    verbose : bool
        level of verbosity

    Returns
    -------
    (weights, factors)

    weights : 1-D tl.tensor of length `rank`
        contains the eigenvalue of each eigenvector
    factors : list of 2-D tl.tensor of shape (size, rank)
        Each column of each factor corresponds to one eigenvector
    """
    rank = _validate_cp_rank(tl.shape(tensor), rank=rank)

    order = tl.ndim(tensor)
    factors = []
    weigths = []

    for _ in range(rank):
        eigenval, eigenvec, deflated = power_iteration(tensor, n_repeat=n_repeat, n_iteration=n_iteration, verbose=verbose)
        factors.append(eigenvec)
        weigths.append(eigenval)
        tensor = deflated

    factors = [tl.stack([f[i] for f in factors], axis=1) for i in range(order)]
    weigths = tl.stack(weigths)

    return weigths, factors




class CPPower(DecompositionMixin):
    def __init__(self, rank, n_repeat=10, n_iteration=10, verbose=0):
        """CP Decomposition via Robust Tensor Power Iteration

        Parameters
        ----------
        tensor : tl.tensor
            input tensor to decompose
        rank : int
            rank of the decomposition (number of rank-1 components)
        n_repeat : int, default is 10
            number of initializations to be tried
        n_iteration : int, default is 10
            number of power iterations
        verbose : bool
            level of verbosity

        Returns
        -------
        (weights, factors)

        weights : 1-D tl.tensor of length `rank`
            contains the eigenvalue of each eigenvector
        factors : list of 2-D tl.tensor of shape (size, rank)
            Each column of each factor corresponds to one eigenvector
        """
        self.rank = rank
        self.n_repeat = n_repeat
        self.n_iteration = n_iteration
        self.verbose = verbose

    
    def fit_transform(self, tensor):
        """Decompose an input tensor

        Parameters
        ----------
        tensor : tensorly tensor
            input tensor to decompose

        Returns
        -------
        CPTensor
            decomposed tensor
        """
        cp_tensor = parafac_power_iteration(tensor, rank=self.rank,
                                                 n_repeat=self.n_repeat,
                                                 n_iteration=self.n_iteration,
                                                 verbose=self.verbose)
        self.decomposition_ = cp_tensor 
        return cp_tensor

    def __repr__(self):
        return f'Rank-{self.rank} CP decomposition via Robust Tensor Power Iteration.'
back to top