Python:用于更快动态编程的 Numba njit 模式

Python: Numba njit mode for faster dynamic programming

我是 Python 的新手。我想使用 Python 进行我的数值实验,其中我需要精确地解决许多动态规划问题。因此,优化我的代码以提高效率很重要。我的代码实际上与带有 Numba 的 @jit 一起使用,但我想使用 @njit 进一步提高性能。您可以从下面的代码中看到,为了提高效率,我尝试在 for 循环内矢量化我的操作。正如我之前提到的,@jit 工作正常,但是对于 @njit,它一直给我错误消息。众所周知,准确地解决动态程序是计算密集型的,因此我真的很想使用@njit 来进一步提高性能。我真的可以使用一些帮助来更改代码以允许@njit。提前致谢!

我的代码:

import numba as nb
import numpy as np

#DP computation
@nb.njit
def dp(beta,cost,wcost,decisions,number_of_stages,states):
    tbeta=1-beta
    odcost=min((cost[-max(decisions):]+wcost)/beta[-max(decisions):])
    terminal=(max(states)-states)*odcost
    L=max(states)
    D=number_of_stages
    value=np.zeros((D+1,L+1))
    choice=np.zeros((D+1,L)).astype(np.int64)
    value[-1]=terminal
    for s in range(D-1,L-2,-1):
        intmatrix=cost[:, None]+np.outer(beta,value[s+1][1:L+1])+np.outer(tbeta,value[s+1][0:L])
        choice[s]=intmatrix.T.argmin(axis=1)
        value[s][0:L]=intmatrix[choice[s],np.arange(intmatrix.shape[1])]
    
    for s in range(L-2,-1,-1):
        intmatrix=cost[:, None]+np.outer(beta,value[s+1][1:s+2])+np.outer(tbeta,value[s+1][0:s+1])
        choice[s][0:s+1]=intmatrix.T.argmin(axis=1)
        value[s][0:s+1]=intmatrix[choice[s][0:s+1],np.arange(intmatrix.shape[1])]
        
    return value, choice


#initialization
decisions=np.arange(100)
number_of_stages=200
states=np.arange(101)

np.random.seed(2021)
beta=np.append(0,np.random.uniform(0,1,max(decisions)))
wcost=np.random.uniform(0,1)
cost=np.square(beta)



value, choice=dp(beta,cost,wcost,decisions,number_of_stages,states)

错误信息:

TypingError: No implementation of function Function(<built-in function getitem>) found for signature:
 
getitem(array(float64, 1d, C), Tuple(slice<a:b>, none))
 
There are 22 candidate implementations:
      - Of which 20 did not match due to:
      Overload of function 'getitem': File: <numerous>: Line N/A.
        With argument(s): '(array(float64, 1d, C), Tuple(slice<a:b>, none))':
       No match.
      - Of which 2 did not match due to:
      Overload in function 'GetItemBuffer.generic': File: numba\core\typing\arraydecl.py: Line 162.
        With argument(s): '(array(float64, 1d, C), Tuple(slice<a:b>, none))':
       Rejected as the implementation raised a specific error:
         TypeError: unsupported array index type none in Tuple(slice<a:b>, none)
  raised from C:\ProgramData\Anaconda3\lib\site-packages\numba\core\typing\arraydecl.py:68

似乎 numba 不支持所有类型的 numpy 奇特索引。你必须回到循环。这在 numba 中很常见,您需要忘记 numpy、向量化的编码方式才能回到显式循环。

这应该可以完成工作,我只是明确了循环。

@nb.njit
def dp(beta, cost, wcost, decisions, number_of_stages, states):
    tbeta = 1 - beta
    odcost = min((cost[-max(decisions) :] + wcost) / beta[-max(decisions) :])
    terminal = (max(states) - states) * odcost
    L = max(states)
    D = number_of_stages
    value = np.zeros((D + 1, L + 1))
    choice = np.zeros((D + 1, L)).astype(np.int64)
    value[-1] = terminal
    for s in range(D - 1, L - 2, -1):
        intmatrix = (
            cost.reshape(-1, 1)
            + np.outer(beta, value[s + 1][1 : L + 1])
            + np.outer(tbeta, value[s + 1][0:L])
        )
        choice[s] = intmatrix.T.argmin(axis=1)
        for i in range(intmatrix.shape[1]):
            value[s][i] = intmatrix[choice[s][i], i]

    for s in range(L - 2, -1, -1):
        intmatrix = (
            cost.reshape(-1, 1)
            + np.outer(beta, value[s + 1][1 : s + 2])
            + np.outer(tbeta, value[s + 1][0 : s + 1])
        )
        choice[s][0 : s + 1] = intmatrix.T.argmin(axis=1)
        for i in range(intmatrix.shape[1]):
            value[s][0 : s + 1][i] = intmatrix[choice[s][0 : s + 1][i], i]

    return value, choice