Мой первый вопрос: почему вы ожидаете, что они будут такими же?
Давайте сделаем 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
является скаляром (это не тривиально)
Как работает функция numpy.tensordot шаг за шагом?
Указание 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]])
То есть я меняю средние 2 оси.
И, опуская форму, я получаю то же (2,2,2,2), что вы получаете от kron
:
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)
Или, используя трансляцию, 2 продукта:
X[:,:,None,None]*X[None,None,:,:] # tensordot 0
X[:,None,:,None]*X[None,:,None,:] # kron