Если я определяю массив X
с формой (2, 2)
:
X = np.array([[1, 2], [3, 4]])
и возьмите кронекер-продукт, затем измените результат, используя
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]]]])
который отличается от первого выхода. Почему это так? Я нашел это при поиске ответов, однако я не понимаю, почему это решение работает или как обобщать на более высокие размеры.
Мой первый вопрос: почему вы ожидаете, что они будут такими же?
Пусть делают 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