Python 使用3d阵列时,Numba矢量化比numpy慢?

Python 使用3d阵列时,Numba矢量化比numpy慢?,python,numpy,numba,Python,Numpy,Numba,在下面的代码中,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

在下面的代码中,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正在修改原有的数组

将适当的
.copy()
添加到numpy-one会使它稍微慢一点。你也可以让你的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)

正如@JoshAdel在评论中指出的,这里的关键区别在于
numba
版本正在分配和填充一个新数组,而numpy正在修改原有的数组

将适当的
.copy()
添加到numpy-one会使它稍微慢一点。你也可以让你的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\u func\u 2(虚拟,区域)
,我得到了大约80 u秒。这真的是你的瓶颈吗?还是你只是想学麻木?或者你真的在处理更大的数据吗?我发现
test\u func\u 1
大约慢2倍。当您计时时,是只计时一次(包括jit编译时间),还是计时后续调用(缓存了编译并且只是函数的运行时)?为了清晰起见,对其进行了简化。我打算使用一个类似的函数,它最终会在非常大的3d阵列上被调用数万次。运行它1k次,同时,如果你没有注意到的话,还有一个一般性的警告,但是numpy>1.10中的
np.swapaxes
返回一个视图,因此在示例中,每次调用函数时都要修改
time\u序列
。对于给定数据集的
test\u func\u 2(虚拟,区域)
,我得到大约80 u秒。这真的是你的瓶颈吗?还是你只是想学麻木?或者你真的在处理更大的数据吗?我发现
test\u func\u 1
大约慢2倍。当您计时时,是只计时一次(包括jit编译时间),还是计时后续调用(缓存了编译并且只是函数的运行时)?为了清晰起见,对其进行了简化。我打算使用一个类似的函数,它最终会在非常大的3d阵列上被调用数万次。运行它1k次,同时,如果你没有注意到的话,还有一个一般性的警告,但是numpy>1.10中的
np.swapaxes
返回一个视图,因此在示例中,每次调用函数时都要修改
时间序列。