Numba 矢量化比 3d 数组的 numpy 慢?
Numba vectorization slower than numpy with 3d array?
在下面的代码中,test_func_1 大约比 test_func_2 慢一个数量级。是否无法改进甚至匹配此操作的 numpy 性能?
from numba import guvectorize
import numpy as np
@guvectorize(['void(float64[:,:,:], float64[:], float64[:,:,:])'], '(n,o,p),(n)->(n,o,p)', nopython=True)
def test_func_1(time_series, areas, res):
for i in range(areas.size):
area = areas[i]
adjusted_area = (area / 10000.) ** .12 # used to adjust erosion
for k in range(time_series.shape[0]):
res[i, 0, k] = time_series[i, 0, k] * area
res[i, 1, k] = time_series[i, 1, k] * adjusted_area
res[i, 2, k] = time_series[i, 2, k] * area
res[i, 3, k] = time_series[i, 3, k] * adjusted_area
def test_func_2(time_series, areas):
array = np.swapaxes(time_series, 0, 2)
array[:, :2] *= areas
array[:, 2:] *= (areas / 10000.) ** .12
return array
dummy = np.float32(np.random.randint(0, 10, (20, 5, 5000)))
areas = np.float32(np.random.randint(0, 10, 20))
test_func_1(dummy, areas)
test_func_2(dummy, areas)
正如@JoshAdel 在评论中指出的那样,这里的主要区别在于您的 numba
版本正在分配和填充新数组,而 numpy 正在就地修改原始数组。
向 numpy 添加适当的 .copy()
会使它对我来说稍微慢一些。您也可以让您的 numba 版本在适当的位置工作——据我所知,使用 gufunc 是不可能的,但是如果您不需要 gufunc 提供的广播,则可以使用常规的 jit 函数。
def test_func_2(time_series, areas):
array = np.swapaxes(time_series, 0, 2).copy()
array[:, :2] *= areas
array[:, 2:] *= (areas / 10000.) ** .12
return array
dummy = np.float32(np.random.randint(0, 10, (20, 5, 5000)))
areas = np.float32(np.random.randint(0, 10, 20))
%timeit test_func_1(dummy, areas)
1.21 ms ± 5.33 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test_func_2(dummy, areas)
1.77 ms ± 15.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
在下面的代码中,test_func_1 大约比 test_func_2 慢一个数量级。是否无法改进甚至匹配此操作的 numpy 性能?
from numba import guvectorize
import numpy as np
@guvectorize(['void(float64[:,:,:], float64[:], float64[:,:,:])'], '(n,o,p),(n)->(n,o,p)', nopython=True)
def test_func_1(time_series, areas, res):
for i in range(areas.size):
area = areas[i]
adjusted_area = (area / 10000.) ** .12 # used to adjust erosion
for k in range(time_series.shape[0]):
res[i, 0, k] = time_series[i, 0, k] * area
res[i, 1, k] = time_series[i, 1, k] * adjusted_area
res[i, 2, k] = time_series[i, 2, k] * area
res[i, 3, k] = time_series[i, 3, k] * adjusted_area
def test_func_2(time_series, areas):
array = np.swapaxes(time_series, 0, 2)
array[:, :2] *= areas
array[:, 2:] *= (areas / 10000.) ** .12
return array
dummy = np.float32(np.random.randint(0, 10, (20, 5, 5000)))
areas = np.float32(np.random.randint(0, 10, 20))
test_func_1(dummy, areas)
test_func_2(dummy, areas)
正如@JoshAdel 在评论中指出的那样,这里的主要区别在于您的 numba
版本正在分配和填充新数组,而 numpy 正在就地修改原始数组。
向 numpy 添加适当的 .copy()
会使它对我来说稍微慢一些。您也可以让您的 numba 版本在适当的位置工作——据我所知,使用 gufunc 是不可能的,但是如果您不需要 gufunc 提供的广播,则可以使用常规的 jit 函数。
def test_func_2(time_series, areas):
array = np.swapaxes(time_series, 0, 2).copy()
array[:, :2] *= areas
array[:, 2:] *= (areas / 10000.) ** .12
return array
dummy = np.float32(np.random.randint(0, 10, (20, 5, 5000)))
areas = np.float32(np.random.randint(0, 10, 20))
%timeit test_func_1(dummy, areas)
1.21 ms ± 5.33 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test_func_2(dummy, areas)
1.77 ms ± 15.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)