矩阵乘法的矢量化
我有许多3 * 2矩阵(A1,A2,A3 ..),每个3 * 2都是一个画图。在两次抽签的情况下,我们有一个3 * 4(我们水平叠加每个A1,A2的抽签)。显然,我更容易将3 * 4矩阵(A)绘制为更大的矩阵,而不是一遍又一遍地绘制3 * 2。矩阵乘法的矢量化
但我需要为每个抽奖(每个A1,A2 ......)的矩阵B.说A1 * B执行矩阵乘法,和A2 * B ... AN * B
#each draw of the 3*2 matrix
A1 = np.array([[ 0, 1],
[ 4, 5],
[ 8, 9]])
A2 = np.array([[ 2, 3],
[ 6, 7],
[ 10, 11]])
# A is [A1,A2]
# Easier to draw A once for all (the larger matrix)
A = np.array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b = np.array([[ 0, 1],
[ 4, 5]
])
desired output
array([[ 4, 5, 12, 17],
[20, 29, 28, 41],
[36, 53, 44, 65]])
可以重塑矩阵A为2列,使其适形于b
,做矩阵乘法,然后重塑回:
np.dot(A.reshape(-1, 2), b).reshape(3, -1)
#array([[ 4, 5, 12, 17],
# [20, 29, 28, 41],
# [36, 53, 44, 65]])
转变你的观点。你不必要地锁定自己到3 x 2
。
你能想到的A1
和A2
为2x3
代替,然后A
将
array([[ 0, 4, 8, 2, 6, 10],
[ 1, 5, 9, 3, 7, 11]])
然后取b = b.T
array([[0, 4],
[1, 5]])
转置这样你可以做你运行
b @ A
array([[ 4, 20, 36, 12, 28, 44],
[ 5, 29, 53, 17, 41, 65]])
让你的“画”这个样子
A = np.random.randint(10, size=(2, 9))
A
array([[7, 2, 1, 0, 9, 9, 1, 0, 2],
[8, 6, 1, 6, 6, 2, 4, 2, 9]])
b @ A
array([[32, 24, 4, 24, 24, 8, 16, 8, 36],
[47, 32, 6, 30, 39, 19, 21, 10, 47]])
如果您不确定如何存储/堆栈传入阵列,一种方式是堆叠那些为3D
阵列,使得那些进入阵列的每一个都其第一轴指数能够 -
a = np.array((A1,A2))
采样运行 -
In [143]: a = np.array((A1,A2))
In [144]: a.shape
Out[144]: (2, 3, 2)
|-----------------> axis of stacking
然后,拿到equivalen每个进入阵列的矩阵乘法的T个输出与b
,我们可以在3D
堆叠阵列a
上使用np.tensordot
与b
,从而从a
从b
丢失最后轴和第一总和中还原,像这样 -
out = np.tensordot(a,b,axes=((2),(0)))
让我们来看看输出值,并与A1
,A2
等的每个矩阵乘法进行比较。 -
In [138]: out[0]
Out[138]:
array([[ 4, 5],
[20, 29],
[36, 53]])
In [139]: out[1]
Out[139]:
array([[12, 17],
[28, 41],
[44, 65]])
In [140]: A1.dot(b)
Out[140]:
array([[ 4, 5],
[20, 29],
[36, 53]])
In [141]: A2.dot(b)
Out[141]:
array([[12, 17],
[28, 41],
[44, 65]])
因此,本质上与此层叠动作,后来tensordot
我们:
out[0], out[1], .... = A1.dot(b), A2.dot(b), ....
替代np.tensordot
-
我们可以用一个简单的版本np.matmul
,得到与tensordot
相同的输出 -
out = np.matmul(a,b)
关于Python 3.5,还有一个更简单的版本替换np.matmul
,将@ operator
-
out = a @ b
即使不计算所需einsum
可以帮助我们思考这个问题:
In [584]: np.einsum('ij,jk->ik', A1,b)
Out[584]:
array([[ 4, 5],
[20, 29],
[36, 53]])
In [585]: np.einsum('ij,jk->ik', A2,b)
Out[585]:
array([[12, 17],
[28, 41],
[44, 65]])
A
是(3,4),它不会与(2,2)b
一起使用。可以把它想象成尝试使用加倍的j
尺寸:'i(2j),jk->i?k'
。但是如果我们插入一个轴呢? 'IMK,JK-> IMK'?或者将额外的维度添加到i
?
In [587]: np.einsum('imj,jk->imk', A.reshape(3,2,2),b)
Out[587]:
array([[[ 4, 5],
[12, 17]],
[[20, 29],
[28, 41]],
[[36, 53],
[44, 65]]])
数字在那里,只是形状是(3,2,2)。
In [590]: np.einsum('imj,jk->imk', A.reshape(3,2,2),b).reshape(3,4)
Out[590]:
array([[ 4, 5, 12, 17],
[20, 29, 28, 41],
[36, 53, 44, 65]])
或者你也可以从一开始就建立A
使mij,jk->mik
作品(@Divaker
)
@Psidom
:
np.einsum('ij,jk->ik', A.reshape(3,2,2).reshape(-1,2) ,b).reshape(3,-1)
`@piRSquared':
'kj,jI->kI`
我会重新审视这一个。我想要和朋友一起做好事。 – piRSquared
你是什么意思通过“draw”? –
@ juanpa.arrivillaga,A1,A2 ..... a从一些分布重新绘制,它们是相似的。 – alphabetagamma
所以你想要'np.hstack([A1.dot(b),A2.dot(b)])',但是用'A'来代替? –