在 Numba 中设置结构化数组字段
Setting structured array field in Numba
我想在 Numba 编译的 nopython 函数中设置 NumPy 结构化标量的整个字段。下面代码中的 desired_fn 是我想做的一个简单示例,而 working_fn 是我目前如何完成此任务的示例。
import numpy as np
import numba as nb
test_numpy_dtype = np.dtype([("blah", np.int64)])
test_numba_dtype = nb.from_dtype(test_numpy_dtype)
@nb.njit
def working_fn(thing):
for j in range(len(thing)):
thing[j]['blah'] += j
@nb.njit
def desired_fn(thing):
thing['blah'] += np.arange(len(thing))
a = np.zeros(3,test_numpy_dtype)
print(a)
working_fn(a)
print(a)
desired_fn(a)
运行ning desired_fn(a) 产生的错误是:
numba.errors.InternalError: unsupported array index type const('blah') in [const('blah')]
[1] During: typing of staticsetitem at /home/sam/PycharmProjects/ChessAI/playground.py (938)
非常需要性能关键代码,并且将运行数十亿次,因此消除了需要因为这些类型的循环似乎是至关重要的。
以下作品(numba 0.37):
@nb.njit
def desired_fn(thing):
thing.blah[:] += np.arange(len(thing))
# or
# thing['blah'][:] += np.arange(len(thing))
如果您主要对数据的列而不是行进行操作,您可以考虑使用不同的数据容器。 numpy 结构化数组的布局类似于结构向量而不是数组结构。这意味着当你想更新 blah
时,你在遍历数组时正在移动非连续内存 space。
此外,对于任何代码优化,都值得使用 timeit
或其他一些计时工具(消除 jit 代码所需的时间)来查看实际性能。您可能会发现 numba 显式循环虽然更冗长,但实际上可能比矢量化代码更快。
没有numba
,访问字段值并不比访问二维数组的列慢:
In [1]: arr2 = np.zeros((10000), dtype='i,i')
In [2]: arr2.dtype
Out[2]: dtype([('f0', '<i4'), ('f1', '<i4')])
修改字段:
In [4]: %%timeit x = arr2.copy()
...: x['f0'] += 1
...:
16.2 µs ± 13.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
如果我将字段分配给新变量,则时间相同:
In [5]: %%timeit x = arr2.copy()['f0']
...: x += 1
...:
15.2 µs ± 14.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
如果我构造一个相同大小的一维数组会更快:
In [6]: %%timeit x = np.zeros(arr2.shape, int)
...: x += 1
...:
8.01 µs ± 15.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
但访问二维数组列的时间相似:
In [7]: %%timeit x = np.zeros((arr2.shape[0],2), int)
...: x[:,0] += 1
...:
17.3 µs ± 23.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
我想在 Numba 编译的 nopython 函数中设置 NumPy 结构化标量的整个字段。下面代码中的 desired_fn 是我想做的一个简单示例,而 working_fn 是我目前如何完成此任务的示例。
import numpy as np
import numba as nb
test_numpy_dtype = np.dtype([("blah", np.int64)])
test_numba_dtype = nb.from_dtype(test_numpy_dtype)
@nb.njit
def working_fn(thing):
for j in range(len(thing)):
thing[j]['blah'] += j
@nb.njit
def desired_fn(thing):
thing['blah'] += np.arange(len(thing))
a = np.zeros(3,test_numpy_dtype)
print(a)
working_fn(a)
print(a)
desired_fn(a)
运行ning desired_fn(a) 产生的错误是:
numba.errors.InternalError: unsupported array index type const('blah') in [const('blah')]
[1] During: typing of staticsetitem at /home/sam/PycharmProjects/ChessAI/playground.py (938)
非常需要性能关键代码,并且将运行数十亿次,因此消除了需要因为这些类型的循环似乎是至关重要的。
以下作品(numba 0.37):
@nb.njit
def desired_fn(thing):
thing.blah[:] += np.arange(len(thing))
# or
# thing['blah'][:] += np.arange(len(thing))
如果您主要对数据的列而不是行进行操作,您可以考虑使用不同的数据容器。 numpy 结构化数组的布局类似于结构向量而不是数组结构。这意味着当你想更新 blah
时,你在遍历数组时正在移动非连续内存 space。
此外,对于任何代码优化,都值得使用 timeit
或其他一些计时工具(消除 jit 代码所需的时间)来查看实际性能。您可能会发现 numba 显式循环虽然更冗长,但实际上可能比矢量化代码更快。
没有numba
,访问字段值并不比访问二维数组的列慢:
In [1]: arr2 = np.zeros((10000), dtype='i,i')
In [2]: arr2.dtype
Out[2]: dtype([('f0', '<i4'), ('f1', '<i4')])
修改字段:
In [4]: %%timeit x = arr2.copy()
...: x['f0'] += 1
...:
16.2 µs ± 13.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
如果我将字段分配给新变量,则时间相同:
In [5]: %%timeit x = arr2.copy()['f0']
...: x += 1
...:
15.2 µs ± 14.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
如果我构造一个相同大小的一维数组会更快:
In [6]: %%timeit x = np.zeros(arr2.shape, int)
...: x += 1
...:
8.01 µs ± 15.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
但访问二维数组列的时间相似:
In [7]: %%timeit x = np.zeros((arr2.shape[0],2), int)
...: x[:,0] += 1
...:
17.3 µs ± 23.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)