Gab*_*iel 6 python performance numpy scipy
我正在研究一个大型代码,我发现自己需要加速它的特定部分.我创建了MWE如下所示:
import numpy as np
import time
def random_data(N):
# Generate some random data.
return np.random.uniform(0., 10., N).tolist()
# Lists that contain all the data.
list1 = [random_data(10) for _ in range(1000)]
list2 = [random_data(1000), random_data(1000)]
# Start taking the time.
tik = time.time()
list4 = []
# Loop through all elements in list1.
for elem in list1:
list3 = []
# Loop through elements in list2.
for elem2 in zip(*list2):
A = np.exp(-0.5*((elem[0]-elem2[0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-elem2[1])/elem[3])**2)
list3.append(A*B)
# Sum elements in list3 and append result to list4.
sum_list3 = sum(list3) if sum(list3)>0. else 1e-06
list4.append(sum_list3)
# Print the elapsed time.
print time.time()-tik
Run Code Online (Sandbox Code Playgroud)
的怪异格式list1和list2是因为这是这个代码块如何接收他们.
大部分时间花费的明显部分是递归计算A和B术语.
有没有什么方法可以加快这段代码而不必并行化它(我之前尝试过,它给了我很多麻烦)?我愿意使用任何包装,numpy,scipy,等.
加
这是应用abarnert优化的结果,也是Jaime建议只进行一次取幂的结果.优化的功能在我的系统上平均快约60倍.
import numpy as np
import timeit
def random_data(N):
return np.random.uniform(0., 10., N).tolist()
# Lists that contain all the data.
list1 = [random_data(10) for _ in range(1000)]
list2 = [random_data(1000), random_data(1000)]
array1 = np.array(list1)
array2 = np.array(zip(*list2))
# Old non-optimezed function.
def func1():
list4 = []
# Process all elements in list1.
for elem in list1:
# Process all elements in list2.
list3 = []
for elem2 in zip(*list2):
A = np.exp(-0.5*((elem[0]-elem2[0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-elem2[1])/elem[3])**2)
list3.append(A*B)
# Sum elements in list3 and append result to list4.
sum_list3 = sum(list3) if sum(list3)>0. else 1e-06
list4.append(sum_list3)
# New optimized function.
def func2():
list4 = []
# Process all elements in list1.
for elem in array1:
# Broadcast over elements in array2.
A = -0.5*((elem[0]-array2[:,0])/elem[3])**2
B = -0.5*((elem[1]-array2[:,1])/elem[3])**2
array3 = np.exp(A+B)
# Sum elements in array3 and append result to list4.
sum_list3 = max(array3.sum(), 1e-10)
list4.append(sum_list3)
# Get time for both functions.
func1_time = timeit.timeit(func1, number=10)
func2_time = timeit.timeit(func2, number=10)
# Print hom many times faster func2 is versus func1.
print func1_time/func2_time
Run Code Online (Sandbox Code Playgroud)
您希望逐渐将其从使用列表和循环转换为使用数组和广播,首先抓取最简单和/或时间最关键的部分,直到它足够快.
第一步是不要zip(*list2)反复这样做(特别是如果这是Python 2.x).虽然我们正在使用它,但我们不妨将它存储在一个数组中,并执行相同的操作list1- 您现在仍然可以迭代它们.所以:
array1 = np.array(list1)
array2 = np.array(zip(*list2))
# …
for elem in array1:
# …
for elem2 in array2:
Run Code Online (Sandbox Code Playgroud)
这不会加速我的机器,它从14.1秒到12.9 - 但它给了我们一个开始工作的地方.
您还应该删除以下的双重计算sum(list3):
sum_list3 = sum(list3)
sum_list3 = sum_list3 if sum_list3>0. else 1e-06
Run Code Online (Sandbox Code Playgroud)
同时,这是一个有点奇怪,你想要value <= 0去1e-6的,但0 < value < 1e-6一个人呆着.这真的是故意的吗?如果没有,你可以解决这个问题,同时简化代码,只需这样做:
sum_list3 = max(array3.sum(), 1e-06)
Run Code Online (Sandbox Code Playgroud)
现在,让我们播放A和B计算:
# Broadcast over elements in list2.
A = np.exp(-0.5*((elem[0]-array2[:,0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-array2[:, 1])/elem[3])**2)
array3 = A*B
# Sum elements in list3 and append result to list4.
sum_list3 = max(array3.sum(), 1e-06)
list4.append(sum_list3)
Run Code Online (Sandbox Code Playgroud)
这让我们从12.9秒降到0.12秒.您可以更进一步,也可以通过广播来array1替换list4预先分配的数组,等等,但这可能已经足够快了.
| 归档时间: |
|
| 查看次数: |
210 次 |
| 最近记录: |