了解tensordot

时间:2017-01-26 09:22:18

标签: python numpy linear-algebra tensor dot-product

在我学会了如何使用einsum之后,我现在试图了解np.tensordot的工作原理。

但是,我有点迷失,特别是关于参数axes的各种可能性。

要理解它,因为我从未练习张量微积分,我使用以下示例:

A = np.random.randint(2, size=(2, 3, 5))
B = np.random.randint(2, size=(3, 2, 4))

在这种情况下,可能的np.tensordot有什么不同?您将如何手动计算它?

3 个答案:

答案 0 :(得分:24)

使用tensordot的想法非常简单 - 我们输入数组和各自的轴,沿着这些轴减少总和。参与减少的轴将在输出中被移除,并且输入数组中的所有剩余轴都展开,因为输出中的不同轴保持输入数组的顺序馈。

让我们看一下具有一个和两个减少轴的样本案例,并交换输入位置,看看订单在输出中是如何保留的。

予。减少一个轴

输入:

 In [7]: A = np.random.randint(2, size=(2, 6, 5))
   ...:  B = np.random.randint(2, size=(3, 2, 4))
   ...: 

案例#1:

In [9]: np.tensordot(A, B, axes=((0),(1))).shape
Out[9]: (6, 5, 3, 4)

A : (2, 6, 5) -> reduction of axis=0
B : (3, 2, 4) -> reduction of axis=1

Output : `(2, 6, 5)`, `(3, 2, 4)` ===(2 gone)==> `(6,5)` + `(3,4)` => `(6,5,3,4)`

案例#2(与案例#1相同,但输入被交换):

In [8]: np.tensordot(B, A, axes=((1),(0))).shape
Out[8]: (3, 4, 6, 5)

B : (3, 2, 4) -> reduction of axis=1
A : (2, 6, 5) -> reduction of axis=0

Output : `(3, 2, 4)`, `(2, 6, 5)` ===(2 gone)==> `(3,4)` + `(6,5)` => `(3,4,6,5)`.

II。两个减少轴

输入:

In [11]: A = np.random.randint(2, size=(2, 3, 5))
    ...: B = np.random.randint(2, size=(3, 2, 4))
    ...: 

案例#1:

In [12]: np.tensordot(A, B, axes=((0,1),(1,0))).shape
Out[12]: (5, 4)

A : (2, 3, 5) -> reduction of axis=(0,1)
B : (3, 2, 4) -> reduction of axis=(1,0)

Output : `(2, 3, 5)`, `(3, 2, 4)` ===(2,3 gone)==> `(5)` + `(4)` => `(5,4)`

案例#2:

In [14]: np.tensordot(B, A, axes=((1,0),(0,1))).shape
Out[14]: (4, 5)

B : (3, 2, 4) -> reduction of axis=(1,0)
A : (2, 3, 5) -> reduction of axis=(0,1)

Output : `(3, 2, 4)`, `(2, 3, 5)` ===(2,3 gone)==> `(4)` + `(5)` => `(4,5)`

我们可以将它扩展到尽可能多的轴。

答案 1 :(得分:4)

tensordot交换轴并重新整形输入,以便将np.dot应用于2个2d阵列。然后它交换并重新形状回到目标。实验可能比解释更容易。没有特殊的张量数学,只是将dot扩展到更高维度的工作。 tensor只表示超过2d的数组。如果您已经对einsum感到满意,那么将结果与之比较最简单。

样品测试,在1对轴上求和

In [823]: np.tensordot(A,B,[0,1]).shape
Out[823]: (3, 5, 3, 4)
In [824]: np.einsum('ijk,lim',A,B).shape
Out[824]: (3, 5, 3, 4)
In [825]: np.allclose(np.einsum('ijk,lim',A,B),np.tensordot(A,B,[0,1]))
Out[825]: True

另一个,总结两个。

In [826]: np.tensordot(A,B,[(0,1),(1,0)]).shape
Out[826]: (5, 4)
In [827]: np.einsum('ijk,jim',A,B).shape
Out[827]: (5, 4)
In [828]: np.allclose(np.einsum('ijk,jim',A,B),np.tensordot(A,B,[(0,1),(1,0)]))
Out[828]: True

我们可以对(1,0)对做同样的事情。考虑到维度的混合,我不认为还有另一种组合。

答案 2 :(得分:0)

上面的答案很棒,对我理解 imagesDF = ImageSchema.readImages("/path/to/imageFolder")``` However, I keep getting an AttributeError: '_ImageSchema' object has no attribute 'readImages' Can anybody help me with this? 很有帮助。但是它们并没有显示运算背后的实际数学原理。这就是为什么我自己在TF 2中进行了等效操作并决定在此处共享的原因:

tensordot

对于a = tf.constant([1,2.]) b = tf.constant([2,3.]) print(f"{tf.tensordot(a, b, 0)}\t tf.einsum('i,j', a, b)\t\t- ((the last 0 axes of a), (the first 0 axes of b))") print(f"{tf.tensordot(a, b, ((),()))}\t tf.einsum('i,j', a, b)\t\t- ((() axis of a), (() axis of b))") print(f"{tf.tensordot(b, a, 0)}\t tf.einsum('i,j->ji', a, b)\t- ((the last 0 axes of b), (the first 0 axes of a))") print(f"{tf.tensordot(a, b, 1)}\t\t tf.einsum('i,i', a, b)\t\t- ((the last 1 axes of a), (the first 1 axes of b))") print(f"{tf.tensordot(a, b, ((0,), (0,)))}\t\t tf.einsum('i,i', a, b)\t\t- ((0th axis of a), (0th axis of b))") print(f"{tf.tensordot(a, b, (0,0))}\t\t tf.einsum('i,i', a, b)\t\t- ((0th axis of a), (0th axis of b))") [[2. 3.] [4. 6.]] tf.einsum('i,j', a, b) - ((the last 0 axes of a), (the first 0 axes of b)) [[2. 3.] [4. 6.]] tf.einsum('i,j', a, b) - ((() axis of a), (() axis of b)) [[2. 4.] [3. 6.]] tf.einsum('i,j->ji', a, b) - ((the last 0 axes of b), (the first 0 axes of a)) 8.0 tf.einsum('i,i', a, b) - ((the last 1 axes of a), (the first 1 axes of b)) 8.0 tf.einsum('i,i', a, b) - ((0th axis of a), (0th axis of b)) 8.0 tf.einsum('i,i', a, b) - ((0th axis of a), (0th axis of b)) 形状:

(2,2)