了解tensordot

新手上路,请多包涵

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

但是,我有点迷茫,尤其是关于参数 axes 的各种可能性。

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

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

在这种情况下,有哪些不同的可能性 np.tensordot 你将如何手动计算它?

原文由 floflo29 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 487
2 个回答

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)`.

二。和归约的两个轴

输入:

 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)`

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

原文由 Divakar 发布,翻译遵循 CC BY-SA 3.0 许可协议

tensordot 交换轴并重塑输入,以便它可以应用 np.dot 到 2 个二维数组。然后它交换并重塑回目标。实验可能比解释更容易。没有特殊的张量数学运算,只是扩展 dot 以在更高的维度上工作。 tensor 仅表示大于 2d 的数组。如果您已经对 einsum 感到满意,那么将结果与其进行比较将是最简单的。

样本测试,在一对轴上求和

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) 对做同样的事情。考虑到维度的混合,我认为没有另一种组合。

原文由 hpaulj 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题