TensorLy 笔记系列
5. Tensor 分解
张量的最大特征之一是可以被紧密地表示为分解形式,并且我们有强大的保证方法来得到这些分解。在本教程中,我们将学习这些分解形式以及如何进行张量分解。关于张量分解的更多信息,请参考1。
5.1. Tensor 的 Kruskal 形式
其思想是将张量表示为一阶张量的和, 也就是向量的外积的和。这种表示可以通过应用典型的Canonical Polyadic 分解(也称为CANDECOMP-PARAFAC、CP或PARAFAC分解)得到。
5.1.1. CANDECOMP-PARAFAC分解
在这里演示如何执行 Canonical Polyadic 分解。一个 rank-r Parafac将一个tensor
分解成列-1张量的线性组合(详见1)。
首先,创建一个 swiss
形状是1其余是0的二阶 tensor
。
>>> import numpy as np
>>> import tensorly as tl
>>> tensor = tl.tensor([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
使用 rank-2 CANDECOMP-PARAFAC
(tensorly.decomposition.parafac)将tensor
分解成 kruskal tensor
。Parafac
分解将tensor
表示为kruskal tensor
,可以表示为一列因子(矩阵)。因此,parafac
函数返回一个因子列表。
>>> from tensorly.decomposition import parafac
>>> factors = parafac(tensor, rank=2)
>>> len(factors)
2
>>> [f.shape for f in factors]
[(12, 2), (12, 2)]
从kruskal tensor
(以矩阵列表的形式呈现),可以重构一个完整tensor
:
>>> print(tl.kruskal_to_tensor(factors))
[[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
[ 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
[ 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
[ 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
5.2. Tensor 的 Tucker 形式
Tucker
分解可以看作是CP分解的一般化:它将张量分解为一个小核心tensor
和因子矩阵。CP可以看作是一个具有超对角核心的tucker
分解。因此,一个分解后的Tucker
形式的张量只不过是一个与原始张量具有相同阶的核张量和一列投影矩阵,每个投影矩阵对应核张量的不同模式。
5.2.1. Tucker 分解
Tucker
(经典和非负)的形式在TensorLy
模块tensorly.decomposition.tucker
和tenorly.decomposition.non_negative_tucker
.
使用前文中的tensor
,演示tensor
的 rank [2, 3]
分解。
>>> from tensorly.decomposition import tucker
>>> core, factors = tucker(tensor, ranks=[2, 3])
# The core is a smaller tensor of size (2, 3):
>>> core.shape
(2, 3)
>>> len(factors)
2
>>> [f.shape for f in factors]
[(12, 2), (12, 3)]
和上述一样,也可以从Tucker
分解中重建完整的tensor
。
>>> from tensorly import tucker_to_tensor
>>> print(tucker_to_tensor(core, factors)
[[ 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ 7.746e-17 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 0.000e+00]
[ 7.746e-17 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 0.000e+00]
[ 7.746e-17 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 0.000e+00]
[ 7.746e-17 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 1.000e+00 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ -7.340e-17 2.617e-16 1.914e-16 2.475e-16 1.000e+00 1.000e+00 1.000e+00 1.000e+00 2.475e-16 2.475e-16 2.475e-16 0.000e+00]
[ 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00]]
注意,有些系数几乎为零(10e-16),但由于数值近似,并不完全是零。
5.3. Matrix-Product-State/Tensor-Train分解
Tensor-Train
分解,在物理学界又称矩阵积态,是一种将高阶tensor
分解为三阶tensor
的方法。对于一个d
阶张量A[i1,…,id]
,它将每个维度分成一个3阶子张量,称之为因子或核。子张量的一个维数是真实物理维数,而另外两个维数是连接其前后核心的边数。
A
[
i
1
,
…
,
i
d
]
≈
∑
α
1
⋯
∑
α
d
−
1
G
1
(
i
1
,
α
1
)
G
2
(
α
1
,
i
2
,
α
2
)
G
3
(
α
2
,
i
3
,
α
3
)
⋯
G
d
(
α
d
−
1
,
i
d
)
A[i_1, \ldots, i_d] \approx \sum_{\alpha_1}\cdots\sum_{\alpha_{d-1}}G_1(i_1, \alpha_1)G_2(\alpha_1, i_2, \alpha_2)G_3(\alpha_2, i_3, \alpha_3)\cdots G_d(\alpha_{d-1},i_d)
A[i1,…,id]≈∑α1⋯∑αd−1G1(i1,α1)G2(α1,i2,α2)G3(α2,i3,α3)⋯Gd(αd−1,id)
MPS/Tensor-Train
分解的优点是存储和计算时间和维度是线性的,使得高维度问题更容易解决。
5.3.1. 实现方式
TensorLy
中提供了两种tensor train
分解方式:基于SVD
的分解(tensorly.decomposition.mps_decomposition
) 和 基于交叉逼近的方法(tensorly.contrib.mps_decomposition_cross
)。使用上文中的tensor
,演示尺寸(12,12) tensor
的rank [1,2,1]
分解过程,第一个核的尺寸是(1,12,2)
和第二个核的尺寸是(2,12,1)
:
>>> from tensorly.decomposition import matrix_product_state
>>> factors = matrix_product_state(tensor, rank=[1,2,1])
>>> len(factors)
2
>>> [f.shape for f in factors]
[(1, 12, 2), (2, 12, 1)]
也可以从 Tensor-Train
分解的tensor
重建为整个tensor
。
>>> from tensorly import mps_to_tensor
>>> print(np.round(mps_to_tensor(factors), decimals=10))
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[-0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. -0.]
[-0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. -0.]
[-0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. -0.]
[-0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. -0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 1. 1. 1. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
对于矩阵情况,MPS/Tensor-Train
分解等价于奇异值分解。该矩阵的秩为2,因此可以通过rank-2
分解完全恢复。
5.4. 参考资料
- T.G.Kolda and B.W.Bader, “Tensor Decompositions and Applications”, SIAM REVIEW, vol. 51, n. 3, pp. 455-500, 2009.
- tensorly