【发布时间】:2020-01-14 23:08:16
【问题描述】:
所以我正在尝试在numba(我目前使用numba 0.45.1)中结合@njit 支持的矢量化和for循环来提高性能。令人失望的是,我发现它实际上比我的代码中的纯嵌套循环实现要慢。
这是我的代码:
import numpy as np
from numba import njit
@njit
def func3(arr_in, win_arr):
n = arr_in.shape[0]
win_len = len(win_arr)
result = np.full((n, win_len), np.nan)
alpha_arr = 2 / (win_arr + 1)
e = np.full(win_len, arr_in[0])
w = np.ones(win_len)
two_index = np.nonzero(win_arr <= 2)[0][-1]+1
result[0, :two_index] = arr_in[0]
for i in range(1, n):
w = w + (1-alpha_arr)**i
e = e*(1-alpha_arr) + arr_in[i]
result[i,:] = e /w
return result
@njit
def func4(arr_in, win_arr):
n = arr_in.shape[0]
win_len = len(win_arr)
result = np.full((n, win_len), np.nan)
alpha_arr = 2 / (win_arr + 1)
e = np.full(win_len, arr_in[0])
w = np.ones(win_len)
two_index = np.nonzero(win_arr <= 2)[0][-1]+1
result[0, :two_index] = arr_in[0]
for i in range(1, n):
for col in range(len(win_arr)):
w[col] = w[col] + (1-alpha_arr[col])**i
e[col] = e[col]*(1-alpha_arr[col]) + arr_in[i]
result[i,col] = e[col] /w[col]
return result
if __name__ == '__main__':
np.random.seed(0)
data_size = 200000
winarr_size = 1000
data = np.random.uniform(0,1000, size = data_size)+29000
win_array = np.arange(1, winarr_size+1)
abc_test3= func3(data, win_array)
abc_test4= func4(data, win_array)
print(np.allclose(abc_test3, abc_test4, equal_nan = True))
我使用以下配置对这两个函数进行了基准测试:
(data_size,winarr_size) = (200000,100), (200000,200),(200000,1000), (200000,2000), (20000,10000), (2000,100000).
并发现纯嵌套 for-loop 实现 (func4) 始终比 for-loop 与矢量化混合实现 (func3) 更快(大约快 2-5%)。
我的问题如下:
1) 进一步提高代码速度需要做哪些改动?
2)为什么函数的向量化版本的计算时间随着win_arr的大小线性增长?我认为矢量化应该使得无论矢量有多大/多小,运算速度都是恒定的,但显然这在这种情况下并不成立。
3) 是否存在一般情况下矢量化运算的计算时间仍会随输入大小线性增长?
【问题讨论】:
-
经典
numpy意义上的“向量化”是使用编译后的numpy全数组方法。它仍然使用循环,它们只是在编译代码中执行,而不是以 Python 速度执行。numba会为您进行编译,并且在使用循环时它实际上可能会创建更紧凑的 C 代码。速度差异约为 5%,您依赖于numba实现细节。 -
“矢量化”命令通常较慢,因为它们都必须被(多个)for 循环替换。但是func3还有很多需要改进的地方。例如。禁用检查除以零,不必要的幂运算,可以用乘法代替。 stackoverflow.com/a/57062221/4045774
-
是的,如果您愿意,我可以添加答案。但在您的情况下,这并不容易,因为下溢对性能有很大影响。
-
我不确定,但这似乎是对性能不佳的解释en.wikipedia.org/wiki/Denormal_number
标签: python performance numpy vectorization numba