矩阵乘法比在numpy中循环点积慢吗?

时间:2019-05-03 16:37:43

标签: arrays performance numpy matrix-multiplication dot-product

我正在编写numpy代码以计算自相关。我正在尝试提高实施性能。

我尝试了两种方法:在数组视图中进行矩阵乘法,在for循环中对数组切片进行点积运算。令我惊讶的是,第一种方法似乎要慢得多。

该函数采用向量x和最大移位k,并针对每个移位i返回具有移位向量的向量的点积。

def acorr_aview(x, k):
    return np.dot([x[i:-k+i] for i in range(k)], x[:-k])

def acorr_loop(x, k):
    return np.array([np.dot(x[i:-k+i],x[:-k]) for i in range(k)])

我期望acorr_aview由于利用矩阵乘法而具有更好的性能,但情况恰恰相反。

x = np.random.randn(10000)
k = 100

%timeit acorr_aview(x,k)
%timeit acorr_loop(x,k)
3.32 ms ± 243 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
753 µs ± 33.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

为什么acorr_loop快得多?谢谢。

编辑:进行比较:

A = np.random.randn(9900,100)
v = np.random.randn(100)

%timeit np.dot(A,v)
%timeit np.array([np.dot(a,v) for a in A])
1.08 ms ± 10.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
12.4 ms ± 243 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

1 个答案:

答案 0 :(得分:1)

在第一种情况下,您用(100, 9900)点缀了(9900,)。在第二个步骤中,您将(9900,)(9900,)一起点了100次。

在第一种情况下的内存管理成本与第二种情况下的迭代成本之间需要权衡。其他SO问题也观察到,对大问题进行适度的迭代可能比对大问题进行一次计算要快。

Why is B = numpy.dot(A,x) so much slower looping through doing B[i,:,:] = numpy.dot(A[i,:,:],x) )?

您的情况还有另一件事-制作更大数组所需的时间:

In [366]: timeit np.array([x[i:-k+i] for i in range(k)])                             
2.62 ms ± 22.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [367]: timeit np.dot(np.array([x[i:-k+i] for i in range(k)]),x[:-k])              
3.6 ms ± 147 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [368]: %%timeit xx = np.array([x[i:-k+i] for i in range(k)]) 
     ...: np.dot(xx, x[:-k])                                                                  
1.05 ms ± 9.27 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

较大的dot仍比100个较小的xx花费更多的时间,但构造{{1}}是一项更大的工作。