Tensor Decomposition in TensorLy

最近因论文需要而学习张量和张量分解。看了诸多论文之后,想使用一些开源工具来实际操作一下张量。就选择了TensorLy,选择它的原因主要因为它文档写得详细…

QuickSort

1.What is TensorLy

传送门在这里。TensorLy是一个简单快速的Python张量库,优点在于纯Python实现,依赖少,并且能够支持如Numpy、MXnet多种数据的底层。最重要的是文档详细。

2.Basic Operations

1.Import the library

首先要引入相应的库才能使用

1
2
import numpy as np
import tensorly as tl

2.Create a tensor

使用numpy生成一个三维数组,并构建成TensorLy中的张量

1
tensor = tl.tensor(np.arange(24).reshape((3, 4, 2)))

3.Unfolding tensor by mode

将张量按维度展开

1
2
import tensorly as unfold
unfold(tensor, 0) # mode-1 unfolding

4.Folding tensor

将展开的数组按维度还原成张量

1
2
3
4
from tensorly import fold
unfolding = unfold(tensor, 1)
original_shape = tensor.shape
fold(unfolding, 1, original_shape)

3.Tensor decomposition

张量分解有很多种分解方法,但主要的分解方法有两种:Tucker分解和CP分解,其中CP分解是Tucker分解的一个特例。TensorLy也提供了这两种方法的实现。
Tucker分解的公式为 X = S * A * B * C,X是原张量,S为分解之后产生的核心张量,A、B、C分别为分解之后关于3个维度的矩阵。图示如下:Image

1
2
3
4
from tensorly.decomposition import tucker
# tucker函数传入一个张量,并指定核心张量的各个维度的长度
# tucker函数的返回结果是分解完成之后的核心张量,和各个维度的矩阵
core, factors = tucker(tensor, ranks=[2, 3, 1])

CP分解是Tucker分解的特例。如果Tucker分解中的核心张量是一个超对角结构(对角,并且三个维度的长度相等),则Tucker分解退化为CP分解。公式为 X = λ * A * B * C(带权重),X是原张量,λ矩阵为分解之后超对角张量的对角值,A、B、C分别为分解之后关于3个维度的矩阵。图示如下:Image

1
2
3
4
from tensorly.decomposition import parafac
# parafac函数传入一个张量,并指定原张量的一个估计(近似)的秩
# 返回的就是分解之后
factors = parafac(tensor, rank=2)

4.Demo

使用张量分解的的一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import matplotlib.pyplot as plt
import tensorly as tl
import numpy as np
from tensorly.decomposition import parafac
from tensorly.decomposition import tucker
from PIL import Image


random_state = 12345
tl.set_backend('numpy')

# 打开图片
image_png = Image.open('/Users/orechou/Downloads/index_1.jpg')
# 打印图片的信息
print(image_png)
data = np.reshape(image_png, [1000, 1500, 3])

# 将值从int转变成float,因为在分解的过程中会产生浮点数
image = tl.tensor(data, dtype='float64')


def to_image(tensor):
"""A convenience function to convert from a float dtype back to uint8"""
im = tl.to_numpy(tensor)
im -= im.min()
im /= im.max()
im *= 255
return im.astype(np.uint8)


# Rank of the CP decomposition
cp_rank = 25
# Rank of the Tucker decomposition
tucker_rank = [100, 100, 2]

# Perform the CP decomposition
factors = parafac(image, rank=cp_rank, init='random', tol=10e-6)
# Reconstruct the image from the factors
cp_reconstruction = tl.kruskal_to_tensor(factors)

# Tucker decomposition
core, tucker_factors = tucker(image, ranks=tucker_rank, init='random', tol=10e-5, random_state=random_state)
tucker_reconstruction = tl.tucker_to_tensor(core, tucker_factors)

# Plotting the original and reconstruction from the decompositions
fig = plt.figure()
ax = fig.add_subplot(1, 3, 1)
ax.set_axis_off()
ax.imshow(to_image(image))
ax.set_title('Original')

ax = fig.add_subplot(1, 3, 2)
ax.set_axis_off()
ax.imshow(to_image(cp_reconstruction))
ax.set_title('CP')

ax = fig.add_subplot(1, 3, 3)
ax.set_axis_off()
ax.imshow(to_image(tucker_reconstruction))
ax.set_title('Tucker')

plt.tight_layout()
plt.show()

效果如下:Image