【问题标题】:Speed up double for loop in numpy在numpy中加速双倍for循环
【发布时间】:2016-10-25 07:19:00
【问题描述】:

我的 Python 代码中目前有以下双循环:

for i in range(a):
    for j in range(b):
        A[:,i]*=B[j][:,C[i,j]]   

(A 是浮点矩阵。B 是浮点矩阵列表。C 是整数矩阵。矩阵是指 m x n np.arrays。

确切地说,大小是: A: mxa B: b 大小为 mxl 的矩阵(每个矩阵的 l 不同) C: axb。这里m很大,a很大,b很小,l比b还要小 )

我试图通过这样做来加快速度

for j in range(b):
    A[:,:]*=B[j][:,C[:,j]]

但令我惊讶的是,这表现得更糟。

更准确地说,这确实提高了 m 和 a 的小值(“大”数)的性能,但从 m=7000,a=700 开始,第一个方法的速度大约是原来的两倍。

还有什么我可以做的吗?

也许我可以并行化?但我真的不知道怎么做。

(我不致力于 Python 2 或 3)

【问题讨论】:

  • B 列表中的所有浮点矩阵是否都具有相同的形状?
  • 另外,* 是在谈论矩阵乘法还是元素乘法?你在处理 NumPy 数组或矩阵吗?
  • 否(#rows 相同,#cols 不同)。但它们差别不大,所以填充不会太昂贵,如果有帮助的话
  • 我正在处理元素乘法,正如问题中提到的,我正在处理 np.arrays
  • 通常B 中有多少个数组,即b 的典型值?

标签: python performance numpy parallel-processing vectorization


【解决方案1】:

这是一种矢量化方法,假设 B 是具有相同形状的数组列表 -

# Convert B to a 3D array
B_arr = np.asarray(B)

# Use advanced indexing to index into the last axis of B array with C
# and then do product-reduction along the second axis. 
# Finally, we perform elementwise multiplication with A
A *= B_arr[np.arange(B_arr.shape[0]),:,C].prod(1).T

对于较小的a,我们可以运行一个循环来迭代a 的长度。此外,为了获得更高的性能,最好将这些元素存储到一个单独的二维数组中,并在我们退出循环后只执行一次元素乘法。

因此,我们会有这样的替代实现 -

range_arr = np.arange(B_arr.shape[0])
out = np.empty_like(A)
for i in range(a):
    out[:,i] = B_arr[range_arr,:,C[i,:]].prod(0)
A *= out

【讨论】:

  • 感谢您的回答。你的建议和我的选择一样好。也就是说,对于不是那么大的矩阵,它更好,但对于大矩阵,它比双循环更糟糕
  • 您的第二种方法更接近原始双循环的性能。但与其他方法不同,它总是不如双循环。您对如何并行化双循环的第一个循环有什么建议吗?
  • @Bananach "How to parallelize the first loop of the double loop?" - 我以为你已经在第二种方法中做到了。作为一个小的改进,您可以简单地执行以下操作:A* = 而不是 A[:,:]*。所以,我们现在有四种方法——第一种方法是双循环,第二种方法是去掉第一个循环,第三种方法是去掉第二个循环,最后是第四种方法,所有东西都矢量化了。似乎我们已经探索了所有可能性:)
  • 我猜你是对的,这就是我的第二种方法。我仍然对它没有击败第一个感到困惑,但我也很高兴知道我的幼稚代码实际上并没有那么幼稚
猜你喜欢
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多