In [57]: W = np.array([1,2])
In [58]: X = np.ones((4,2))
In [59]: X[:,1] = [1,2,3,4]
In [60]: W
Out[60]: array([1, 2])
In [61]: X
Out[61]:
array([[1., 1.],
[1., 2.],
[1., 3.],
[1., 4.]])
In [62]: X.T
Out[62]:
array([[1., 1., 1., 1.],
[1., 2., 3., 4.]])
In [63]: W@X.T
Out[63]: array([3., 5., 7., 9.])
In [64]: X@W
Out[64]: array([3., 5., 7., 9.])
Первый @
использует форму (4,) и (2,4) для создания (4,).
Второй использует (4,2) и (4, ).
Посмотрите на matmul
правила обработки 1d-аргументов, таких как W
.
Я считаю, что нотация einsum
помогает прояснить, какие оси объединяются:
In [75]: np.einsum('i,ji->j', W,X)
Out[75]: array([3., 5., 7., 9.])
Эффект аргументов switch в @
мог бы быть более ясным, если бы W
был 2d.
In [76]: W1 # (2,1) shape
Out[76]:
array([[1],
[2]])
In [77]: W1.T@X.T # (1,2) with (2,4) produces (1,4)
Out[77]: array([[3., 5., 7., 9.]])
In [78]: _.shape
Out[78]: (1, 4)
(4,2) с (2,1) производит (4, 1)
In [79]: X@W1
Out[79]:
array([[3.],
[5.],
[7.],
[9.]])
In [80]: _.shape
Out[80]: (4, 1)
[77] и [80] могут быть транспонированы друг в друга, например, ((W1.T)@(X.T)).T
для получения (4,1).