如果我定义形状为X
的数组(2, 2)
:
X = np.array([[1, 2], [3, 4]])
并选择kronecker产品,然后使用
调整输出的形状np.kron(X, X).reshape((2, 2, 2, 2))
我得到一个结果矩阵:
array([[[[ 1, 2],
[ 2, 4]],
[[ 3, 4],
[ 6, 8]]],
[[[ 3, 6],
[ 4, 8]],
[[ 9, 12],
[12, 16]]]])
但是,当我使用np.tensordot(X, X, axes=0)
时,会输出以下矩阵
array([[[[ 1, 2],
[ 3, 4]],
[[ 2, 4],
[ 6, 8]]],
[[[ 3, 6],
[ 9, 12]],
[[ 4, 8],
[12, 16]]]])
与第一个输出不同。为什么会这样呢?我在寻找答案时发现了this,但是我不明白为什么该解决方案有效或如何将其推广到更高的维度。
答案 0 :(得分:1)
我的第一个问题是,为什么您期望它们相同?
让我们做kron
而无需重塑:
In [403]: X = np.array([[1, 2],
...: [3, 4]])
...:
In [404]: np.kron(X,X)
Out[404]:
array([[ 1, 2, 2, 4],
[ 3, 4, 6, 8],
[ 3, 6, 4, 8],
[ 9, 12, 12, 16]])
很容易看到动作。
[X*1, X*2
X*3, X*4]
tensordot
通常被认为是np.dot
的概括,它能够处理比普通矩阵乘积(即一个或多个轴上的乘积之和)更复杂的情况。但是这里没有总结。
In [405]: np.tensordot(X,X, axes=0)
Out[405]:
array([[[[ 1, 2],
[ 3, 4]],
[[ 2, 4],
[ 6, 8]]],
[[[ 3, 6],
[ 9, 12]],
[[ 4, 8],
[12, 16]]]])
当axes
是一个整数而不是一个元组时,该动作很难理解。文档说:
``axes = 0`` : tensor product :math:`a\otimes b`
我只是试图解释当axes
是标量时发生的情况(这并不重要)
How does numpy.tensordot function works step-by-step?
指定axes=0
等效于提供此元组:
np.tensordot(X,X, axes=([],[]))
无论如何,从输出中可以明显看出,该张量点产生的数字相同-但布局与kron
不同。
我可以复制kron
布局
In [424]: np.tensordot(X,X,axes=0).transpose(0,2,1,3).reshape(4,4)
Out[424]:
array([[ 1, 2, 2, 4],
[ 3, 4, 6, 8],
[ 3, 6, 4, 8],
[ 9, 12, 12, 16]])
也就是说,我交换了中间的两个轴。
省略重塑,我得到的是与kron
相同的(2,2,2,2):
np.tensordot(X,X,axes=0).transpose(0,2,1,3)
我喜欢np.einsum
的明确性:
np.einsum('ij,kl->ijkl',X,X) # = tensordot(X,X,0)
np.einsum('ij,kl->ikjl',X,X) # = kron(X,X).reshape(2,2,2,2)
或者使用广播,这两种产品是:
X[:,:,None,None]*X[None,None,:,:] # tensordot 0
X[:,None,:,None]*X[None,:,None,:] # kron