Поскольку это похоже на код, написанный другими, и вы хотите понять, что делает этот случай (в частности, не в целом), для целей переноса я воспользуюсь простой демонстрацией:
In [46]: A = np.arange(24).reshape(2,3,4); B = np.array([10,20])
In [47]: A
Out[47]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
In [48]: A.T
Out[48]:
array([[[ 0, 12],
[ 4, 16],
[ 8, 20]],
[[ 1, 13],
[ 5, 17],
[ 9, 21]],
[[ 2, 14],
[ 6, 18],
[10, 22]],
[[ 3, 15],
[ 7, 19],
[11, 23]]])
dot
:
In [50]: C = np.dot(A.T, B)
In [51]: C
Out[51]:
array([[240, 360, 480],
[270, 390, 510],
[300, 420, 540],
[330, 450, 570]])
то же самое, но с использованием широковещательной рассылки, поэлементного умножения и суммы:
In [52]: (A.T * B[None,None,:]).sum(axis=2)
Out[52]:
array([[240, 360, 480],
[270, 390, 510],
[300, 420, 540],
[330, 450, 570]])
Или с обозначением индексации einsum
:
In [53]: np.einsum('ijk,i->kj',A,B)
Out[53]:
array([[240, 360, 480],
[270, 390, 510],
[300, 420, 540],
[330, 450, 570]])
Промежуточный шаг в поэлементном умножении:
In [54]: (A.T * B[None,None,:])
Out[54]:
array([[[ 0, 240],
[ 40, 320],
[ 80, 400]],
[[ 10, 260],
[ 50, 340],
[ 90, 420]],
[[ 20, 280],
[ 60, 360],
[100, 440]],
[[ 30, 300],
[ 70, 380],
[110, 460]]])
Итак, это скалярное произведение (скалярное произведение) каждой строки A.T
(последнее измерение) с B
. Итак, есть одно значение для первых двух измерений (здесь (4,3)).