numpy数组乘法比向量乘法的for循环慢吗?

4
我在对numpy数组进行乘法时遇到了以下问题。在下面的示例中(稍微简化了一下我正在处理的真实版本),我从一个几乎为空的数组A和一个完整的数组C开始。然后我使用递归算法填充A。
下面,我用两种不同的方法执行此算法。第一种方法涉及以下操作:
n_array = np.arange(0,c-1)
temp_vec= C[c-n_array] * A[n_array]
A[c] += temp_vec.sum(axis=0) 

第二种方法涉及使用for循环。
for m in range(0, c - 1):
    B[c] +=  C[c-m] * B[m]  

请注意,数组A和B是相同的,但是它们是使用两种不同的方法填充的。 在下面的示例中,我计算了使用每种方法执行计算所需的时间。 我发现,例如,当n_pix=2和max_counts=400时,第一种方法比第二种方法快得多(也就是说,time_np比time_for小得多)。 然而,当我切换到例如n_pix=1000和max_counts=400时,我发现方法2要快得多(time_for比time_np小得多)。 我原以为方法1总是会更快,因为方法2明确地运行循环,而方法1使用np.multiply。
因此,我有两个问题:
1. 对于固定的max_counts,为什么时间随着n_pix的变化而表现出这种方式? 2. 写这段代码的最佳方法是什么,以便它在所有n_pix上都快速运行?
也就是说,有人能否建议第3种方法? 在我的项目中,这段代码对于大型和小型的n_pix范围内的快速运行非常重要。
import numpy as np
import time

def return_timing(n_pix,max_counts):
    A=np.zeros((max_counts+1,n_pix))
    A[0]=np.random.random(n_pix)*1.8
    A[1]=np.random.random(n_pix)*2.3

    B=np.zeros((max_counts+1,n_pix))
    B[0]=A[0]
    B[1]=A[1]

    C=np.outer(np.random.random(max_counts+1),np.random.random(n_pix))*3.24

    time_np=0
    time_for=0
    for c in range(2, max_counts + 1):

        t0 = time.time()
        n_array = np.arange(0,c-1)
        temp_vec= C[c-n_array] * A[n_array]
        A[c] += temp_vec.sum(axis=0) 
        time_np += time.time()-t0

        t0 = time.time()
        for m in range(0, c - 1):
            B[c] +=  C[c-m] * B[m]  
        time_for += time.time()-t0
    return time_np, time_for
2个回答

7

首先,您可以轻松更换:

n_array = np.arange(0,c-1)
temp_vec= C[c-n_array] * A[n_array]
A[c] += temp_vec.sum(axis=0) 

使用:

A[c] += (C[c:1:-1] * A[:c-1]).sum(0)

使用数组进行索引比使用切片要慢得多,因此这种方法更快。但是,temp_vec 仍然存在其中,在求和之前创建。这就引出了使用 einsum 的想法,它是最快的,因为它不会创建临时数组。

A[c] = np.einsum('ij,ij->j', C[c:1:-1], A[:c-1])

时序。对于小数组:

>>> return_timing(10,10)
numpy OP    0.000525951385498
loop OP     0.000250101089478
numpy slice 0.000246047973633
einsum      0.000170946121216

针对大规模应用:

>>> return_timing(1000,100)
numpy OP    0.185983896255
loop OP     0.0458009243011
numpy slice 0.038364648819
einsum      0.0167834758759

4
很可能是因为您仅使用 NumPy 的版本需要创建/分配新的 ndarrays(temp_vec 和 n_array),而另一种方法则不需要。
创建新的 ndarrays 很慢,如果您可以修改代码,使其不再不断地创建它们,那么我认为您可以从该方法中获得更好的性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接