在开始之前,我会说我之前已经问过这个问题,但是我一直在努力实现已建议的方法(例如通过PyPy运行它)。这是加速代码的最后尝试。
基本上我有一段大约600行的代码。大部分代码运行大约需要30秒,但是一个小部分(4行长)需要5到15分钟才能运行。原因很简单,它是for循环,for循环,for循环中的数学方程式。所以这个等式计算的次数为5000万次。我接受它需要一段时间,但是当在MATLAB中运行相同的东西时,它通常在一分钟内完成。我相信这是因为JIT加速;但我可能错了。无论哪种方式,这让我觉得必须有一种加快这一点的方法。代码部分如下(使用的矩阵非常大,所以我想我只是说它们的尺寸,因为它们中的数字可能会有所不同)。
for k in range(7500):
for jj in range(2):
for ii in range(k+1):
Y[k][jj,0] += S[ii][jj] * c[k-ii][jj,jj] * U[ii][jj,jj]
矩阵(/数组)的大小为:
numpy.shape(Y) = (7500, 2, 2)
numpy.shape(S) = (7500, 2, 1)
numpy.shape(c) = (7500, 2, 2)
numpy.shape(U) = (7500, 2, 2)
有人看到我能做些什么来加快这个速度吗?
编辑1:
根据要求,这是上面的MATLAB版本:
for k=1:7500
for j=1:2
for i=1:7500
Y(j,1,k)=Y(j,1,k)+S(j,1,i)*c(j,j,k+1-i)*U(j,j,i);
end
end
end
编辑2:
应该添加,我正在使用3.4.2
另外,遗憾的是我没有代码背后的源数学。我有大约2/3的代码,但不是后三分之一。我只是要转换MATLAB代码。 (至少现在)
答案 0 :(得分:2)
可以使用np.convolve
获得结果。
import numpy as np
S = np.random.rand(1000, 2, 1)
c = np.random.rand(1000, 2, 2)
U = np.random.rand(1000, 2, 2)
Y = np.zeros_like(U)
for k in range(1000):
for jj in range(2):
for ii in range(k+1):
Y[k,jj,0] += S[ii,jj,0] * c[k-ii,jj,jj] * U[ii,jj,jj]
Yx = np.zeros_like(Y)
for jj in range(2):
Yx[:,jj,0] += np.convolve(S[:,jj,0] * U[:,jj,jj], c[:,jj,jj], mode='full')[:Yx.shape[0]]
print(abs(Y - Yx).max())
# -> 3.12638803734e-13
如何找到这个?请注意,事物只是沿着jj轴相乘,并且ii求和实际上是一个卷积。然后,这只是在numpy函数中正确摆弄索引的问题。
如果你想要更快的速度,用convolve
代替scipy.signal.fftconvolve
可能会加快速度。一些时间:
for loops: 77 s
np.convolve: 33.6 ms
fftconvolve: 1.48 ms
这提供了一个很好的~50000x加速。
另请注意,您应始终编写Y[k,jj,0]
而不是Y[k][jj,0]
- 因为没有JIT,后者会创建一个临时数组视图,如果您评估表达式,将会花费您的成本很多次。将for循环表达式中的行重写为
Y[k,jj,0] += S[ii,jj,0] * c[k-ii,jj,jj] * U[ii,jj,jj]
将评估速度提高了4倍(!)。