张量表示
1. 张量的另一种表示方法
前面我们学习了张量的基本概念,我们知道,一个标量我们定义为零阶张量,一个矢量我们称为一阶张量,矩阵称为二阶张量。。。
为了更加便捷的表示张量,我们用一个新的方式表示张量:用一个有
N
N
N 个腿的圆形形表示
N
N
N 阶张量,如下所示:
上图的第一行我们用一个圆形直接表示一个标量,因为标量是零阶张量,所以我们不在旁边加边。上图的第二行我们为圆形加了一个边,我们称为一阶张量,同时我们可以在边上写一个数表示该维度的大小,因此第二行表示一个
i
i
i 维的一阶张量(向量)。同理我们通过在这个圆上不断的增加边的个数来表示更高阶的张量,边上的数字可以用来表示每个维度有多少元素。
每个张量结点我们可以用不同的图形来表示,上面我们都是用圆形表示的结点,同样我们也可以用方形,三角形等来表示一个结点,我们可以自己选择。
2. 张量的缩并
下图我们用蓝色的图形表示一个二阶张量
M
i
j
M_{ij}
Mij ,用绿色图形表示一个二阶张量
N
j
k
N_{jk}
Njk ,二阶张量是一个矩阵,因此我们可以表示一个矩阵的乘积如下所示,上面两个矩阵的乘积得到的结果是一个
i
×
k
i×k
i×k 的矩阵,我们将值相同的两个边合并,将合并后的整体视为一个张量,它表示一个
i
×
k
i×k
i×k 的张量,我们将相乘的过程用求和公式表示为
(
M
N
)
i
k
=
∑
j
M
i
j
N
j
k
(MN)_{ik}=\sum_jM_{ij}N_{jk}
(MN)ik=∑jMijNjk。
为了更加简洁的表示张量相乘,我们将两个相乘的结点合并,将他们看成一个结点,忽略他们之间相乘的细节,如下图所示,直接一个结点表示相乘的结果。将具有相同大小边的张量合并为一个的过程称为张量的缩并。
下面我们用几个例子来更加深入的了解一下张量的缩并。
一个矩阵和向量的乘积为一个向量。矩阵和向量我们可以表示为二阶张量和一阶张量,我们可以用图表示他们的乘积如下,讲得到的结果视为一个整体,表示一个一阶张量,下面的结果我们可以记为 c i = A j i b j \pmb{c}_i=A_{ji}\pmb{b}_j ccci=Ajibbbj 。从表达式我们可以看出,张量的缩并可以表示为相同角标的合并,因为两个张量都包含角标 j j j 我们可以通过缩并消去 j j j 得到一个新的张量。
两个或更多的张量通过缩并组合在一起就形成了张量网络,如下
上面我们说了,节点的形状并不是只能是圆形,我们可以选择任意的形状,如下所示,我们可以选择方形或半圆形。
当我们选择半圆形做为节点时,我们可以通过他的对称图形来表示这个矩阵的转置,如下所示。
矩阵的迹我们可以表示为只有一条指向自己的边的结点,如下所示,因为他没有自由边,所以他表示一个数,这和矩阵的迹是吻合的。
前面我们说过,对于任意的矩阵,我们都可以通过奇异值分解,变为三个矩阵相乘,我们也可以用这种图示的方法表示如下。
我们同样可以用张量网络来表示 CP 分解,如下所示, CP 分解是将张量分解为几个秩一张量的和,每个秩一张量可以表示为几个向量的外积,我们用一个圆圈圈住表示里面若干个向量的外积,所以 CP 分解就可以表示如下
3. 张量缩并的 python 实现
张量的缩并有两种实现方式,分别是通过 numpy 的 tensordot 函数和 einsum 函数,下面是两种方法的具体代码:
import numpy as np
A = np.random.randn(5, 3, 2) #随机生成 5×3×2 的张量
B = np.random.randn(3, 6, 4)
C1 = np.tensordot(A, B, [[1], [0]]) #后面两个表示将 a 的第一个指标和 b 的第 0 个指标收缩
print('The shape of C = ')
print(C1.shape)
A = np.random.randn(5, 3, 3)
B = np.random.randn(6, 3, 3)
C = np.random.randn(4, 3, 3)
T = np.einsum('iab,jbc,kca->ijk', A, B, C) #前面参数 iab 表示 A 每个指标的维数,jbc 表示 B 每个指标的维数,kca 表示 C 每个指标的维数,缩并为 ijk 的张量
print('The shape of the resulting tensor = ')
print(T.shape)
运行结果如下: