Basic use of Tensorlab¶
Tags: tensor construction
, tensor visualization
, cpd
, lmlra
, mlsvd
, initialization
, compression
Tensorlab is a Matlab package for complex optimization and tensor computations. This demo will discuss the basics of Tensorlab. It consists of three consecutive parts. A first section Tensor construction and visualization will explain how a tensor can be defined and visualized. The second section CPD for beginners handles the elementary use of the cpd
command for the computation of the canonical polyadic decomposition, while the third section CPD for pros discusses more advanced items such as customized initialization methods and algorithms.
A Matlab implementation of this demo is given in the demo_basic.m
file, which can be found in the demo folder of Tensorlab or downloaded
here.
Tensor construction and visualization¶
Construction of a tensor with random entries
A random tensor can be constructed by using the basic randn
and rand
commands in Matlab. For example, we can construct a tensor \(\ten{T}\in\R^{10\times 20\times 30}\) with entries randomly sampled from a Gaussian distribution as follows:
size_tens = [10 20 30];
T = randn(size_tens);
Construction of a tensor as a sum of R rank-1 terms
To construct a third-order tensor \(\ten{T}\in\R^{I\times J \times K}\) which can be written as a sum of \(R\) rank-1 terms, we start with the construction of the three factor matrices \(\mat{U}^{(1)}\in\R^{I\times R}\), \(\mat{U}^{(2)}\in\R^{J\times R}\) and \(\mat{U}^{(3)}\in\R^{K\times R}\), corresponding to the three different modes (see Canonical polyadic decomposition). This can be done with the command cpd_rnd
, returning a cell which collects these matrices:
size_tens = [10 20 30];
R = 4;
U = cpd_rnd(size_tens,R); % U is a cell containing the factor matrices
The tensor can then be obtained from the factor matrices using the command cpdgen
:
T = cpdgen(U);
For a graphical representation, we refer to Figure 53.
Note that it is possible to construct complex factor matrices and tensors too, through the options field of the cpd_rnd
command:
size_tens = [10 20 30];
R = 4;
options = struct;
options.Real = @randn;
options.Imag = @randn;
U = cpd_rnd(size_tens,R,options);
T = cpdgen(U);
Alternatively, instead of constructing a structure array, the options can be passed as follows:
U = cpd_rnd(size,tens,R,'Real',@randn,'Imag',@randn);
We will use this method in this demo when the number of options to be passed is small. Note that the option names are case insensitive.
Construction of a tensor obtained by a multilinear transformation of a core tensor
We start with the construction of the core tensor and the transformation matrices using the lmlra_rnd
command. The tensor can be obtained through the tensor-matrix product of the core tensor with the different matrices, for which one can use the lmlragen
command.
size_tens = [10 20 30];
size_core = [4 5 6];
[F,S] = lmlra_rnd(size_tens,size_core);
% F is a cell collecting the transformation matrices U, V and W
Tlmlra = lmlragen(F,S);
For a graphical representation of the multilinear product, we refer to Figure 54.
Perturbation of a tensor by noise
A tensor can be perturbed by Gaussian noise with a user-defined signal-to-noise-ratio using the command noisy
:
SNR = 20;
Tnoisy = noisy(T,SNR);
Visualization
Tensorlab offers four commands for tensor visualization: slice3
,
surf3
, voxel3
and visualize
. The plots of the first two commands
contain sliders to go through the different slices. The voxel3
command
plots the elements of a tensor as voxels whose color and opacity are
proportial to the value of the elements. The plot has two sliders for the
threshold parameter and the degree parameter. Figures 55,
56 and 57 visualize the tensor constructed in
the following block of code:
t = linspace(0,1,60).';
T = cpdgen({sin(2*pi*t+pi/4),sin(4*pi*t+pi/4),sin(6*pi*t+pi/4)});
figure(); slice3(T);
figure(); surf3(T);
figure(); voxel3(T);
Finally, the visualize method can be used to ‘walk through’ the data and to compare tensor a decomposed tensor with its decomposition. For example:
t = linspace(0,1,60).';
U = {sin(2*pi*t+pi/4),sin(4*pi*t+pi/4),sin(6*pi*t+pi/4)};
T = noisy(cpdgen(U), 30);
visualize(U, 'original', T);
The result can be seen in Figure 58. The check boxes can
be used to select the dimensions to plot. The sliders or the text fields allow
a user to select which slices are plotted. More examples involving the
visualize
method can be found in the user guide.
CPD for beginners¶
Let us consider a tensor \(\ten{T}\) that approximately has low rank, constructed for example using one of the techniques from the previous section. We discuss the estimation of the rank, the use of the basic cpd
command and the calculation of two different error measures.
Rank estimation
If the rank of a tensor is not known or cannot be obtained from prior knowledge, the command rankest
from Tensorlab may be useful. It estimates the corner of the L-curve obtained by sweeping over a number of rank-1 terms. This corner is taken as an estimate of the rank of the tensor. If there is no output argument, an L-curve as in Figure 59 is plotted.
figure();
U = cpd_rnd([10 20 30],4);
T = cpdgen(U);
rankest(T);
For noisy tensors, it can be worthwhile to edit the relative error tolerance MinRelErr
in the options
structure of the rankest
command.
The basic CPD command
The basic cpd
algorithm requires only a tensor and a value for the rank:
R = 4;
Uest = cpd(T,R)
An extra output
argument can be provided with [U,output] = cpd(T,R)
to obtain information about the convergence of the algorithm, among other things.
Error measures
The relative error on the estimates of the factor matrices can be calculated with the command cpderr
. It takes into account the permutation and scaling indeterminacies. The command returns the relative errors (for each factor matrix), the permutation matrix, the scaling matrices and the permuted and scaled factor matrices:
[relerrU,P,D,Uest] = cpderr(U,Uest)
% D is a cell collecting the different scaling matrices
The relative error on the estimate of the tensor can be determined using frob
and cpdres
, with the latter calculating the residuals:
relerrT = frob(cpdres(T,Uest))/frob(T)
CPD for pros¶
In general, a cpd
computation consists of a compression step, a step in which the CPD of the compressed tensor is computed, and a step in which the estimates are refined using the uncompressed tensor. The user has control over what happens in each step. In this section, we discuss the different steps in more detail.
Note that an overview of the output of each step can be obtained if the Display
option is set to true:
Uest = cpd(T,R,'Display',true);
Compression
In the compression step, the tensor is compressed to a smaller tensor using the mlsvd_rsi
command by default, which applies a randomized SVD algorithm in combination with randomized subspace iterations. Compression is only performed if it is expected to lead to a significant reduction in computational complexity. The user can alter the compression method with the Compression
option by providing a compression technique:
Uest = cpd(T,R,'Compression',@lmlra_aca);
In this example, a low multilinear rank approximation with adaptive cross-approximation is used. The user can also disable the compression step ( note that there will not be a refinement step then):
Uest = cpd(T,R,'Compression',false);
Initialization
To initialize the computation of the CPD of the compressed tensor, cpd
uses a method based on the generalized eigenvalue decomposition (implemented in cpd_gevd
) if the rank does not exceed the second largest dimension of the tensor. Otherwise, a random initialization is used. The initialization method can be altered with the Initialization
option:
Uest = cpd(T,R,'Initialization',@cpd_rnd);
In this example, a random initialization is chosen. The user can also provide particular factor matrices Uinit
for the initialization:
Uest = cpd(T,Uinit);
When specific factor matrices are provided, the compression step is skipped.
Core algorithms
Tensorlab provides several core algorithms for the computation of a CPD. First, there are optimization-based methods such as cpd_als
(alternating least squares), cpd_minf
(unconstrained nonlinear optimization) and cpd_nls
(nonlinear least squares). Second, there are (semi-)algebraic methods such as cpd3_sd
and cpd3_sgsd
. The former reduces the computation to the simultaneous diagonalization of symmetric matrices, also in cases where only one factor matrix has full column rank, while the latter reduces the computation to the estimation of orthogonal factors in a simultaneous generalized Schur decomposition.
By default, cpd_nls
is used for the CPD of the compressed tensor and for the refinement. The user can alter the choice of algorithm with the Algorithm
and Refinement
options. By default, Refinement
is equal to Algorithm
. The following example uses an alternating least squares approach for the CPD of the compressed tensor and for the refinement:
Uest = cpd(T,R,'Algorithm',@cpd_als);
Core algorithm parameters
Parameters can be passed to the core algorithm with the AlgorithmOptions
option for cpd
. Tensorlab provides default choices for all parameters.
A first parameter is Display
, which determines after how many iterations intermediate results are printed. The first column of the printed results shows the objective function values. The second and third column give the relative change in the objective function values and the step sizes, respectively.
There are three parameters that affect the stopping criterion. The parameter Maxiter
determines the maximum number of iterations. The parameters TolX
and TolFun
are tolerances for the step size and for the relative change in objective function value, respectively. For the NLS algorithm, the CGMaxIter
option determines the maximum number of conjugate gradient iterations in each NLS iteration. The following piece of code illustrates how these parameters can be changed for the cpd_nls
and cpd_als
algorithms:
R = 4;
T = cpdgen(cpd_rnd([10 20 30],R));
Uinit = cpd_rnd([10 20 30],R);
options = struct;
options.Compression = false;
options.Algorithm = @cpd_nls;
options.AlgorithmOptions.Display = 1;
options.AlgorithmOptions.MaxIter = 100; % Default 200
options.AlgorithmOptions.TolFun = eps^2; % Default 1e-12
options.AlgorithmOptions.TolX = eps; % Default 1e-6
options.AlgorithmOptions.CGMaxIter = 20; % Default 15
[Uest_nls,output_nls] = cpd(T,Uinit,options);
options = struct;
options.Compression = false;
options.Algorithm = @cpd_als;
options.AlgorithmOptions.Display = 1;
options.AlgorithmOptions.MaxIter = 100; % Default 200
options.AlgorithmOptions.TolFun = eps^2; % Default 1e-12
options.AlgorithmOptions.TolX = eps; % Default 1e-6
[Uest_als,output_als] = cpd(T,Uinit,options);
A convergence plot can be obtained from the link in the command terminal output, or by plotting the objective function values from output.Algorithm
(and output.Refinement
):
figure();
semilogy(output_nls.Algorithm.fval); hold all;
semilogy(output_als.Algorithm.fval);
ylabel('Objective function'); xlabel('Iteration');
title('Convergence plot'); legend('cpd\_nls','cpd\_als')
Figure 60 shows the output of the code block above and illustrates first-order convergence for the ALS algorithm and second-order convergence for the NLS algorithm.
Multilinear singular value decomposition and low multilinear rank approximation¶
Let us consider a tensor \(\ten{T}\in\R^{10\times 20 \times 30}\). The multilinear singular value decomposition (MLSVD) of \(\ten{T}\) is a decomposition of the form
with \(\ten{S}\in\R^{10\times 20 \times 30}\) an all-orthogonal and ordered tensor. The factor matrices \(\mat{U}^{(1)}\in\R^{10\times 10}\), \(\mat{U}^{(2)}\in\R^{20\times 20}\) and \(\mat{U}^{(3)}\in\R^{30\times 30}\) have orthonormal columns. This decomposition can be calculated using the mlsvd
command. In the following example, a tensor with random entries is decomposed:
size_tens = [10 20 30];
T = randn(size_tens);
[U,S,sv] = mlsvd(T);
The mode-\(n\) singular values are stored in sv{n}
. A truncated MLSVD can be obtained by providing the desired core size as second input argument:
size_core = [4 5 6];
[U,S,sv] = mlsvd(T,size_core);
Note that, due to the truncation, the core tensor may no longer be all-orthogonal and ordered. The truncated MLSVD is just one, not necessarily optimal, way of obtaining a low multilinear rank approximation (LMLRA). A better approximation with the same multilinear rank can be obtained with the lmlra
command:
[U,S] = lmlra(T,size_core);
Similar to the cpd
command as explained above, the initialization and core algorithm can be altered using the Initialization
and Algorithm
options. Various LMLRA core algorithms are available; we refer to the user guide and the documentation of the lmlra
command for more information. Factor matrices and a core tensor to initialize the algorithm can be provided with lmlra(T,U0,S0)
. By default, lmlra
provides orthogonal factor matrices and an all-orthogonal and ordered core tensor. This step can be skipped by setting the Normalize
option to false.
For a more in-depth discussion of MLSVD and LMLRA, we refer to the demo Multilinear singular value decomposition and low multilinear rank approximation.