我recently asked about trying to optimise a Python loop for a scientific application,为我收到了{a2}!在
但是,B
值的计算实际上嵌套在其他几个循环中,因为它是在规则的位置网格上计算的。是否有一个类似的聪明的NumPy重写来缩短这个过程的时间?在
我怀疑此部件的性能增益不会太明显,缺点可能是无法向用户报告计算进度,计算结果在计算结束前无法写入输出文件,可能一个巨大的步骤做这个会对记忆产生影响吗?有没有可能绕过其中任何一个?在
import numpy as np
import time
def reshape_vector(v):
b = np.empty((3,1))
for i in range(3):
b[i][0] = v[i]
return b
def unit_vectors(r):
return r / np.sqrt((r*r).sum(0))
def calculate_dipole(mu, r_i, mom_i):
relative = mu - r_i
r_unit = unit_vectors(relative)
A = 1e-7
num = A*(3*np.sum(mom_i*r_unit, 0)*r_unit - mom_i)
den = np.sqrt(np.sum(relative*relative, 0))**3
B = np.sum(num/den, 1)
return B
N = 20000 # number of dipoles
r_i = np.random.random((3,N)) # positions of dipoles
mom_i = np.random.random((3,N)) # moments of dipoles
a = np.random.random((3,3)) # three basis vectors for this crystal
n = [10,10,10] # points at which to evaluate sum
gamma_mu = 135.5 # a constant
t_start = time.clock()
for i in range(n[0]):
r_frac_x = np.float(i)/np.float(n[0])
r_test_x = r_frac_x * a[0]
for j in range(n[1]):
r_frac_y = np.float(j)/np.float(n[1])
r_test_y = r_frac_y * a[1]
for k in range(n[2]):
r_frac_z = np.float(k)/np.float(n[2])
r_test = r_test_x +r_test_y + r_frac_z * a[2]
r_test_fast = reshape_vector(r_test)
B = calculate_dipole(r_test_fast, r_i, mom_i)
omega = gamma_mu*np.sqrt(np.dot(B,B))
# write r_test, B and omega to a file
frac_done = np.float(i+1)/(n[0]+1)
t_elapsed = (time.clock()-t_start)
t_remain = (1-frac_done)*t_elapsed/frac_done
print frac_done*100,'% done in',t_elapsed/60.,'minutes...approximately',t_remain/60.,'minutes remaining'
如果您profile您的代码,您将看到99%的运行时间在
calculate_dipole
中,因此减少此循环的时间并不会显著减少执行时间。如果你想让它更快的话,你还需要集中精力计算_偶极子。我为此尝试了我的Cython代码calculate_dipole
,在整个时间内减少了大约2倍。也许还有其他方法可以改进Cython代码。在你可以做的一件很明显的事情就是更换线路
与
^{pr2}$也许在性能上不会有什么大的不同,但无论如何,使用纽普的内置而不是重新设计轮子是有意义的。在
一般来说,正如您现在可能已经注意到的,优化numpy的诀窍是借助numpy整个数组操作来表达算法,或者至少用切片来表示,而不是迭代python代码中的每个元素。阻止这种“矢量化”的是所谓的循环携带依赖关系,即每次迭代都依赖于前一次迭代的结果的循环。简单地看一下你的代码,你没有这样的东西,应该可以很好地将你的代码矢量化。在
编辑:一个解决方案
我还没有证实这是正确的,但应该告诉你如何处理它。在
首先,取cartesian() function, which we'll use。那么
好吧,在我的测试中,这实际上比我开始的基于循环的方法稍微慢一些。问题是,在这个问题的原始版本中,它已经通过对shape(20000,3)数组的整个数组操作进行矢量化,所以任何进一步的矢量化都不会带来更多的好处。事实上,如上所述,它可能会使性能恶化,可能是因为大型临时阵列。在
相关问题 更多 >
编程相关推荐