#python #numpy #numpy-einsum
Вопрос:
Я хочу вычислить точечное произведение между двумя 3D-тензорами вдоль первого измерения. Я попробовал следующую нотацию einsum:
import numpy as np
a = np.random.randn(30).reshape(3, 5, 2)
b = np.random.randn(30).reshape(3, 2, 5)
# Expecting shape: (3, 5, 5)
np.einsum("ijk,ikj->ijj", a, b)
К сожалению, он возвращает эту ошибку:
ValueError: einstein sum subscripts string includes output subscript 'j' multiple times
Я пошел с суммой Эйнштейна после того, как потерпел неудачу в этом np.tensordot
. Идеи и последующие вопросы приветствуются!
Комментарии:
1. Умножение матрицы вдоль первой оси/измерения звучит так , как вы просто хотите
a @ b
, что позволит выполнить умножение матрицы(5, 2) x (2, 5)
для каждой из трех пар изa
иb
.
Ответ №1:
Ваши два измерения размера 5
и 5
не соответствуют одним и тем же осям. Таким образом, вам нужно использовать два разных индекса для их обозначения. Например, вы можете сделать:
>>> res = np.einsum('ijk,ilm->ijm', a, b)
>>> res.shape
(3, 5, 5)
Обратите внимание, что вам также необходимо изменить индекс для осей размера 2
и 2
. Это связано с тем, что вы вычисляете пакетированный внешний продукт (т. Е. Мы выполняем итерацию по двум осям одновременно), а не точечный продукт (т. Е. мы выполняем итерацию одновременно по двум осям).
- Наружный продукт:
>>> np.einsum('ijk,ilm->ijm', a, b)
- Точечный продукт над индексом
k
, который имеетaxis=2
a
иaxis=1
b
:>>> np.einsum('ijk,ikm->ijm', a, b)
что эквивалентно
a@b
.
Комментарии:
1. Что это нужно оператору? Я думала, он хочет
a@b
. Ваш первый пример приобретает правильную форму, но делает это, сначала уменьшаяa
иb
до (3,5,1) и (3,1,5), и делая транслируемую внешнюю.
Ответ №2:
dot product ... along the first dimension
это немного неясно. Является ли первое измерение «пакетным» измерением, с 3 точками на остальных? Или что-то еще?
In [103]: a = np.random.randn(30).reshape(3, 5, 2)
...: b = np.random.randn(30).reshape(3, 2, 5)
In [104]: (a@b).shape
Out[104]: (3, 5, 5)
In [105]: np.einsum('ijk,ikl->ijl',a,b).shape
Out[105]: (3, 5, 5)
@Ivan's
ответ другой:
In [106]: np.einsum('ijk,ilm->ijm', a, b).shape
Out[106]: (3, 5, 5)
In [107]: np.allclose(np.einsum('ijk,ilm->ijm', a, b), a@b)
Out[107]: False
In [108]: np.allclose(np.einsum('ijk,ikl->ijl', a, b), a@b)
Out[108]: True
Иван суммирует k
размерность одного и l
другого, а затем выполняет трансляцию по элементам. Это не умножение матриц:
In [109]: (a.sum(axis=-1,keepdims=True)* b.sum(axis=1,keepdims=True)).shape
Out[109]: (3, 5, 5)
In [110]: np.allclose((a.sum(axis=-1,keepdims=True)* b.sum(axis=1,keepdims=True)),np.einsum('ijk,ilm->ijm', a,
...: b))
Out[110]: True
Еще один тест пакетной обработки:
In [112]: res=np.zeros((3,5,5))
...: for i in range(3):
...: res[i] = a[i]@b[i]
...: np.allclose(res, a@b)
Out[112]: True