对于numba中出现这种问题numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend) Cannot,就拿下面这个代码来说:

x = np.arange(100).reshape(10, 10)

@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit

def go_fast(a):

trace = 1

for i in range(a.shape[0]):

trace += np.tanh(a[i, i])

return a + trace

print(go_fast(x))

这里是类型错误,就是trace(int)的类型和a(float)的类型不匹配,所以只需要把trace=1改成trace=1.0或者trace=float(1)或者trace=np.float32(1)等等:

x = np.arange(100).reshape(10, 10)

@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit

def go_fast(a):

trace = 1.0#trace=float(1)#改这里

for i in range(a.shape[0]):

trace += np.tanh(a[i, i])

return a + trace

print(go_fast(x))

还有这种问题TypeError: No matching definition for argument type(s) array(int32, 2d, C),原因是参数没用匹配到或者匹配不正确。如下面代码:

@jit("float32(float32)",nopython=True)

def go_sum(a):

result=a+1

return result

x = np.arange(100).reshape(10, 10)

print(go_sum(x))

这里x是一维数组(就是向量),而我们定义的参数是一个浮点型的参数,所以不能将数组带进去,这里这样改:

@jit("int32(int32)",nopython=True)

def go_fast(a):

result=a+1

return result

cc=1#cc=1或者1.0都行,因为我们已经在前面的jit里面定义好类型了,所以cc可以是浮点型或者整型

print(go_fast(cc))

接下来是关于numba中@cuda.jit的使用:从官网英文找了一个自定义的模块如下:中文文档、关于AP部分I

from numba import vectorize, cuda

# define a device function

@cuda.jit('float32(float32, float32, float32)', device=True, inline=True)

def cu_device_fn(x, y, z):

return x ** y / z

但是这个函数如何调用,官网并没用讲。根据官网对numba的定义,有如下方法可以调用。 第一种就是先定义一个装饰器为cuda.jit的主函数,并在内部定义输入和输出变量:

@cuda.jit()#jit这里有无括号都行

def main_func(ipx,ipy,ipz,out_xx):

#申请线程索引

tx = cuda.threadIdx.x

ty = cuda.threadIdx.y

#申请块索引

bx = cuda.blockIdx.x

by = cuda.blockIdx.y

#申请块内线程数

bw = cuda.blockDim.x

bh = cuda.blockDim.y

#计算数据下标

idx = tx + ty * bw + bx * bw * bh

XX = ipx[idx]

YY = ipy[idx]

ZZ = ipz[idx]

#调用设备函数

out_xx[idx]=cu_device_fn(XX,YY,ZZ)

if __name__=="__main__":

ipx = np.array([1, 2, 3],dtype=np.float32)

ipy = np.array([4, 5, 6],dtype=np.float32)

ipz = np.array([7, 8, 9],dtype=np.float32)

out_xx =cuda.device_array_like(ipy)

main_func[64,2](ipx,ipy,ipz,out_xx)#这里的[64,2]不是用的很严谨

第二种也是需要先编写一个在GPU上运行的函数,然后用该函数调用设备函数:

@cuda.jit('void(float32[:],float32[:],float32[:],float32[:])')#也可以写成@cuda.jit()或者@cuda.jit

def cu_host_fn(x,y,z,out):

i=cuda.grid

if i

out[i]=cu_device_fn(x[i],y[i],z[i])#调用设备函数

'''这里cuda.grid(1)语句用于获取线程在ID线程块中的位置,以便可以将其映射到输入数组的相应元素上。

如果线程索引i小于x的大小,则计算设备函数的结果,并将其存储在out[i]中。'''

if __name__=='__main__':

ipx = np.array([1, 2, 3],dtype=np.float32)

ipy = np.array([4, 5, 6],dtype=np.float32)

ipz = np.array([7, 8, 9],dtype=np.float32)

out_xx =cuda.device_array_like(ipy)

thread_per_block=64

block_per_grid=(x.size+(thread_per_block-1))//thread_per_block

#调用主机函数

cu_host_fn[thread_per_block,block_per_grid](ipx,ipy,ipz,out_xx)

#打印结果

print(out_xx.copy_to_host())#copy_to_host是复制设备->主机

第三中呢就是更改设备函数cu_device_fn:

from numba import vectorize, cuda

# define a device function

@cuda.jit('void(float32[:],float32[:],float32[:],float32[:])')#也可以写成@cuda,jit

def cu_device_fn(x, y, z,out_xx):

tid=cuda.grid(1)

if tid

for i in range(len(x)):

out_xx[i]=x[i] ** y[i] / z[i]

上面的这个for循环其实是多余的,应该去掉,然后写成如下:

from numba import vectorize, cuda

# define a device function

@cuda.jit('void(float32[:],float32[:],float32[:],float32[:])')

def cu_device_fn(x, y, z,out_xx):

tid=cuda.grid(1)

if tid

out_xx[idx]=x[idx] ** y[idx] / z[idx]

if __name__=='__main__':

ipx = cuda.to_device(np.array([1, 2, 3], dtype=np.float32))

ipy = cuda.to_device(np.array([4, 5, 6], dtype=np.float32))

ipz = cuda.to_device(np.array([7, 8, 9], dtype=np.float32))

out_xx = cuda.device_array_like(ipy)

'''

to_device()可用于创建阵列的设备端副本,即分配一个 numpy ndarray 或结构化标量并将其传输到设备。

array_like()是使用数组中的信息调用。而device_array_like()创建一个与现有数组具有相同形状和类型的未初始化数组

'''

cu_device_fn[64, 2](ipx, ipy, ipz, out_xx)

print(out_xx.copy_to_host())#打印结果

参考链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: