广播用于逐元素乘法的 3d 数组
Broadcasting 3d arrays for elementwise multiplication
晚上好,
我需要一些帮助来理解复杂 numpy 数组的高级广播。
我有:
数组A:50000x2000
数组 B:2000x10x10
for 循环的实现:
for k in range(50000):
temp = A[k,:].reshape(2000,1,1)
finalarray[k,:,:]=np.sum ( B*temp , axis=0)
我想要一个具有 2000 个元素的轴的逐元素乘法和求和,最终产品:
finalarray: 50000x10x10
是否可以避免for循环?
谢谢!
这应该有效:
(A[:, :, None, None] * B[None, :, :]).sum(axis=1)
但它会耗尽您对产品创建的中间数组的记忆。
乘积的形状为 (50000, 2000, 10, 10)
,因此包含 100 亿个元素,对于 64 位浮点值,这是 80 GB。
对于这样的事情,我会使用 np.einsum
,这样可以很容易地根据您想要的索引操作写下您想要发生的事情:
fast = np.einsum('ij,jkl->ikl', A, B)
这给了我相同的结果(下降 50000->500 所以循环很快完成):
A = np.random.random((500, 2000))
B = np.random.random((2000, 10, 10))
finalarray = np.zeros((500, 10, 10))
for k in range(500):
temp = A[k,:].reshape(2000,1,1)
finalarray[k,:,:]=np.sum ( B*temp , axis=0)
fast = np.einsum('ij,jkl->ikl', A, B)
给我
In [81]: (finalarray == fast).all()
Out[81]: True
即使在 50000 的情况下也有合理的表现:
In [88]: %time fast = np.einsum('ij,jkl->ikl', A, B)
Wall time: 4.93 s
In [89]: fast.shape
Out[89]: (50000, 10, 10)
或者,在这种情况下,您可以使用 tensordot
:
faster = np.tensordot(A, B, axes=1)
这会快几倍(代价是不太通用):
In [29]: A = np.random.random((50000, 2000))
In [30]: B = np.random.random((2000, 10, 10))
In [31]: %time fast = np.einsum('ij,jkl->ikl', A, B)
Wall time: 5.08 s
In [32]: %time faster = np.tensordot(A, B, axes=1)
Wall time: 504 ms
In [33]: np.allclose(fast, faster)
Out[33]: True
我不得不在这里使用 allclose
,因为最终值略有不同:
In [34]: abs(fast - faster).max()
Out[34]: 2.7853275241795927e-12
晚上好,
我需要一些帮助来理解复杂 numpy 数组的高级广播。
我有:
数组A:50000x2000
数组 B:2000x10x10
for 循环的实现:
for k in range(50000):
temp = A[k,:].reshape(2000,1,1)
finalarray[k,:,:]=np.sum ( B*temp , axis=0)
我想要一个具有 2000 个元素的轴的逐元素乘法和求和,最终产品:
finalarray: 50000x10x10
是否可以避免for循环? 谢谢!
这应该有效:
(A[:, :, None, None] * B[None, :, :]).sum(axis=1)
但它会耗尽您对产品创建的中间数组的记忆。
乘积的形状为 (50000, 2000, 10, 10)
,因此包含 100 亿个元素,对于 64 位浮点值,这是 80 GB。
对于这样的事情,我会使用 np.einsum
,这样可以很容易地根据您想要的索引操作写下您想要发生的事情:
fast = np.einsum('ij,jkl->ikl', A, B)
这给了我相同的结果(下降 50000->500 所以循环很快完成):
A = np.random.random((500, 2000))
B = np.random.random((2000, 10, 10))
finalarray = np.zeros((500, 10, 10))
for k in range(500):
temp = A[k,:].reshape(2000,1,1)
finalarray[k,:,:]=np.sum ( B*temp , axis=0)
fast = np.einsum('ij,jkl->ikl', A, B)
给我
In [81]: (finalarray == fast).all()
Out[81]: True
即使在 50000 的情况下也有合理的表现:
In [88]: %time fast = np.einsum('ij,jkl->ikl', A, B)
Wall time: 4.93 s
In [89]: fast.shape
Out[89]: (50000, 10, 10)
或者,在这种情况下,您可以使用 tensordot
:
faster = np.tensordot(A, B, axes=1)
这会快几倍(代价是不太通用):
In [29]: A = np.random.random((50000, 2000))
In [30]: B = np.random.random((2000, 10, 10))
In [31]: %time fast = np.einsum('ij,jkl->ikl', A, B)
Wall time: 5.08 s
In [32]: %time faster = np.tensordot(A, B, axes=1)
Wall time: 504 ms
In [33]: np.allclose(fast, faster)
Out[33]: True
我不得不在这里使用 allclose
,因为最终值略有不同:
In [34]: abs(fast - faster).max()
Out[34]: 2.7853275241795927e-12