Numpy 数组形状未被 numba 识别为 int

Numpy array shape not recognized as int by numba

我想基于一些数组生成一个 numpy 矩阵,并使用 jit 或理想情况下 njit 来加速这一生成。如果 nopython=False(启用 nopython 失败),它会继续发送我无法理解的 2 个以下警告:

:14: NumbaWarning: Compilation is falling back to object mode WITH looplifting enabled because Function "process_stuffs" failed type inference due to: No conversion from array(int32, 2d, C) to array(int64, 2d, A) for 'inp', defined at None

File "", line 23: def process_stuffs(output,inp,route1, route2, zoneidx):

input_pallets, _ = inp.shape
^

During: typing of argument at (23)

File "", line 23: def process_stuffs(output,inp,route1, route2, zoneidx):

input_pallets, _ = inp.shape
^

@jit(nopython=False, :14: NumbaWarning: Compilation is falling back to object mode WITHOUT looplifting enabled because Function "process_stuffs" failed type inference due to: Cannot determine Numba type of <class 'numba.core.dispatcher.LiftedLoop'>

File "", line 25: def process_stuffs(output,inp,route1, route2, zoneidx):

for minute in range(input_pallets):
^

@jit(nopython=False, C:\Anaconda3\envs\dev38\lib\site-packages\numba\core\object_mode_passes.py:151: NumbaWarning: Function "process_stuffs" was compiled in object mode without forceobj=True, but has lifted loops.

尽管该函数确实使用了复杂类型,但在确定 inp 数组的长度时,它在 非常 开始时失败,然后它不会想生成一个循环,虽然我已经看到了很多例子。

我试图通过使用 locals 指定类型来更正错误,但如您所见,它没有帮助。

这是一个最小的工作代码:

zoneidx=Dict.empty(key_type=types.unicode_type,value_type=types.int8)
zoneidx["A"]=np.int8(0)
zoneidx["B"]=np.int8(1)
zoneidx["C"]=np.int8(2)
zoneidx["D"]=np.int8(3)
zoneidx["E"]=np.int8(4)


output = np.zeros(shape=(110,5),dtype=np.int64)
inp = np.random.randint(0,2,size=(100,2))
route1 = np.random.choice(list('ABCDE'),size=10)
route2 = np.random.choice(list('ABCDE'),size=10)

@jit(nopython=False,
     locals={'input_pallets':numba.int64,
             'step':numba.int64,
             'inp':numba.types.int64[:,:],
             'route1':numba.types.unicode_type[:],
             'route2':numba.types.unicode_type[:],
             'output':numba.types.int64[:,:]})
def process_stuffs(output,inp,route1, route2, zoneidx):

    input_pallets, _ = inp.shape

    for minute in range(input_pallets):
        prod1, prod2 = inp[minute]
        if prod1+prod2 <1:
            continue

        if prod1:
            routing = route1
            number_of_pallets = prod1
            number_of_steps = route1.shape[0]
        else:
            routing = route2
            number_of_pallets = prod2
            number_of_steps = route2.shape[0]
        for step in range(number_of_steps):
            zone = routing[step]
            output[minute+step,zoneidx[zone]]+=number_of_pallets

    return output




numba.__version__ == 0.53.1
numpy.__version__ == 1.19.2

我的代码有什么问题?

注意:我对代码输出的正确性不感兴趣,我知道一旦“inp”激活“route1”,“route2”就会被忽略。我只想编译它。

警告信息具有误导性。事实上输入的类型确实没有正确给出,它与.shape方法无关。

我的解决方案是使用 numba.typeof 函数来告诉它期望的类型。例如。预期是 int32,而不是“inp”的 64。并且“unichr”是预期的,而不是 unicode。

这是我的最小示例的工作版本:

zoneidx=Dict.empty(key_type=numba.typeof(route1).dtype,value_type=types.int8)
zoneidx["A"]=np.int8(0)
zoneidx["B"]=np.int8(1)
zoneidx["C"]=np.int8(2)
zoneidx["D"]=np.int8(3)
zoneidx["E"]=np.int8(4)


output = np.zeros(shape=(110,5),dtype=np.int64)
inp = np.random.randint(0,2,size=(100,2))
route1 = np.random.choice(list('ABCDE'),size=10)
route2 = np.random.choice(list('ABCDE'),size=10)

@jit(nopython=False,
     locals={'input_pallets':numba.int64,
             'step':numba.int64,
             'inp':numba.types.int32[:,:],
             'route1':numba.typeof(route1),
             'route2':numba.typeof(route1),
             'output':numba.types.int64[:,:]})
def process_stuffs(output,inp,route1, route2, zoneidx):

    input_pallets, _ = inp.shape

    for minute in range(input_pallets):
        prod1, prod2 = inp[minute]
        if prod1+prod2 <1:
            continue

        if prod1:
            routing = route1
            number_of_pallets = prod1
            number_of_steps = route1.shape[0]
        else:
            routing = route2
            number_of_pallets = prod2
            number_of_steps = route2.shape[0]
        for step in range(number_of_steps):
            zone = routing[step]
            output[minute+step,zoneidx[zone]]+=number_of_pallets

    return output