Python 如何在numba中的`@guvectorize`中调用`@guvectorize`?
我试图在Python 如何在numba中的`@guvectorize`中调用`@guvectorize`?,python,numba,Python,Numba,我试图在@guvectorize中调用@guvectorize,但我有一个错误: Untyped global name 'regNL_nb': cannot determine Numba type of <class 'numpy.ufunc'> File "di.py", line 12: def H2Delay_nb(S1, S2, R2): H1 = regNL_nb(S1, S2) ^ 我不知道如何告诉numba函数regNL_nb
@guvectorize
中调用@guvectorize
,但我有一个错误:
Untyped global name 'regNL_nb': cannot determine Numba type of <class 'numpy.ufunc'>
File "di.py", line 12:
def H2Delay_nb(S1, S2, R2):
H1 = regNL_nb(S1, S2)
^
我不知道如何告诉numba函数regNL_nb是一个guvectorize函数
@guvectorize(["float64[:], float64[:], float64[:]"], '(n),(n)->(n)',nopython=True)
def H2Delay_nb(S1, S2, R2):
H1 = regNL_nb(S1, S2)
H2 = regNL_nb(S1, S2,)
for i in range(len(S1)):
R2[i] = H1[i] + H2[i]
通过使用参数nopython=True
可以停用对象模式,因此Numba无法将所有值作为Python对象处理(请参阅:)
通常,如果使用nopython=True
,Panda、Numba或其他函数调用是不可能的。只有有限数量的库可用于Numba Jit(在nopython
中)。
可在此处找到完整列表:
因此,除了禁用nopython
,您尝试执行的操作是不可能的,即:
@guvectorize(["float64[:], float64[:], float64[:]"], '(n),(n)->(n)',nopython=False)
def H2Delay_nb(S1, S2, R2):
H1 = regNL_nb(S1, S2)
H2 = regNL_nb(S1, S2,)
for i in range(len(S1)):
R2[i] = H1[i] + H2[i]
按照这种方法,程序输出正确的值,即[4.8.12.16.20.24.28.32.36.]
用于H2
我还发现另一个StackOverflow问题涉及一个熟悉的问题:。积分到期时的积分:在提到的线程中建议您使用“更简单”的数据类型,这在CPython中最常见。除此之外,在这一点上我完全同意他的观点,我不知道在nopython
模式下有任何可能的解决方案
来源:
@guvectorize
-ed函数可能存在一些问题
但是Numba在其他njited中接受非常好的常规的@njit
-ed函数。因此,您可以重写您的函数以使用@njit,您的函数签名将与外部世界的@guvectorize ed保持相同@njit版本只需要额外使用np.empty_like(…)
+返回内部函数
@guvectorize(["float64[:], float64[:], float64[:]"], '(n),(n)->(n)',nopython=True)
def H2Delay_nb(S1, S2, R2):
H1 = regNL_nb(S1, S2)
H2 = regNL_nb(S1, S2,)
for i in range(len(S1)):
R2[i] = H1[i] + H2[i]
为了提醒您-所有@njit ed函数都始终启用了nopython模式,因此您的njite代码将与guvectorize+nopython一样快
我还提供CUDA解决方案作为第二个代码段
您也可以只使用@njited内部助手函数,但外部助手函数可能仍然可以使用@guvectorize-ed。此外,如果您想要通用函数(接受任何输入),只需从njited定义中删除签名“f8[:](f8[:],f8[:])”
,签名将在调用时自动解析
最终代码如下所示:
输出:
[ 4. 8. 12. 16. 20. 24. 28. 32. 36.]
CUDA是同一代码的变体,如果要自动创建并返回结果数组,则需要额外的函数包装器,因为CUDA代码函数不允许有返回值:
import numpy as np
from numba import guvectorize, float64, int64, njit, cuda, jit
@cuda.jit('void(f8[:], f8[:], f8[:])', cache = True)
def regNL_nb_cu(S1, S2, h2):
for i in range(len(S1)):
h2[i] = S1[i] + S2[i]
@njit('f8[:](f8[:], f8[:])', cache = True)
def regNL_nb(S1, S2):
h2 = np.empty_like(S1)
regNL_nb_cu(S1, S2, h2)
return h2
@cuda.jit('void(f8[:], f8[:], f8[:])', cache = True)
def H2Delay_nb_cu(S1, S2, R2):
H1 = regNL_nb(S1, S2)
H2 = regNL_nb(S1, S2)
for i in range(len(S1)):
R2[i] = H1[i] + H2[i]
@njit('f8[:](f8[:], f8[:])', cache = True)
def H2Delay_nb(S1, S2):
R2 = np.empty_like(S1)
H2Delay_nb_cu(S1, S2, R2)
return R2
S1 = np.array([1,2,3,4,5,6,7,8,9], dtype = np.float64)
S2 = np.array([1,2,3,4,5,6,7,8,9], dtype = np.float64)
H2 = H2Delay_nb(S1, S2)
print(H2)
预期的输出应该是
[4.8.12.16.20.24.28.32.36.]
,对吗?是的。每个数字执行上述脚本的方式只有四次,除了将参数nopython
设置为False
,因此代码可能会返回到对象模式——除了警告之外,它工作正常<代码>>>打印(H2)给出输出:[4.8.12.16.20.24.28.32.36.]
。是的,它是这样工作的,但速度较慢。关键是要保持nopython=True模式,这样代码运行得更快;尽管如果停用对象模式,并非所有值都将作为Python对象处理。(见附件)
import numpy as np
from numba import guvectorize, float64, int64, njit, cuda, jit
@cuda.jit('void(f8[:], f8[:], f8[:])', cache = True)
def regNL_nb_cu(S1, S2, h2):
for i in range(len(S1)):
h2[i] = S1[i] + S2[i]
@njit('f8[:](f8[:], f8[:])', cache = True)
def regNL_nb(S1, S2):
h2 = np.empty_like(S1)
regNL_nb_cu(S1, S2, h2)
return h2
@cuda.jit('void(f8[:], f8[:], f8[:])', cache = True)
def H2Delay_nb_cu(S1, S2, R2):
H1 = regNL_nb(S1, S2)
H2 = regNL_nb(S1, S2)
for i in range(len(S1)):
R2[i] = H1[i] + H2[i]
@njit('f8[:](f8[:], f8[:])', cache = True)
def H2Delay_nb(S1, S2):
R2 = np.empty_like(S1)
H2Delay_nb_cu(S1, S2, R2)
return R2
S1 = np.array([1,2,3,4,5,6,7,8,9], dtype = np.float64)
S2 = np.array([1,2,3,4,5,6,7,8,9], dtype = np.float64)
H2 = H2Delay_nb(S1, S2)
print(H2)