如何在 Numba Vectorize 签名中指定元组?

How do I specify a tuple in a Numba Vectorize signature?

我正在定义一个函数,并想使用 Numba Vectorize 和 cuda 来加速它。我在函数签名方面遇到了问题。该函数将 return 一个 float64 值。我想传递两个将被矢量化的 float64 值,以及一个 9 元组的 float64 值,这将是标量。

这是我的函数头:

from numba import vectorize

@vectorize(['float64(float64, float64, UniTuple(float64, 9))'], target='cuda')
def fn_vec(E, L, fparams):
    # calculations... 
    return result

但这给出了一个错误:

TypeError: data type "(float64 x 9)" not understood

我尝试了很多变体,包括 (float64, ..., float64) 代替 UniTuple(),但无法使任何东西起作用。我该怎么做?

How do I specify a tuple in a Numba Vectorize signature?

numba.vectorize 函数中不能使用元组。那是因为 vectorize 这些类型的数组 向量化了代码。

因此使用 float, float, tuple 签名创建了一个函数,该函数需要两个包含浮点数的数组和一个包含元组的数组。问题是包含元组的数组没有 dtype - 如果您使用结构化数组而不是包含元组的数组,它可以工作,但我没有尝试过。

How do I specify a tuple in a Numba jit signature?

在 numba 签名中指定 UniTuple 的正确方法是使用 numba.types.containers.UniTuple。你的情况:

nb.types.containers.UniTuple(nb.types.float64, 9)

所以正确的签名应该是这样的:

import numba as nb

@nb.njit(
    nb.types.float64(
        nb.types.float64, 
        nb.types.float64, 
        nb.types.containers.UniTuple(nb.types.float64, 9)))
def func(f1, f2, ftuple):
    # ...
    return f1

我经常避免显式输入我的 numba 函数 - 但当我这样做时,我发现使用 numba.typeof 非常有用,例如:

>>> nb.typeof((1.0, ) * 9)
tuple(float64 x 9)

>>> type(nb.typeof((1.0, ) * 9))
numba.types.containers.UniTuple

>>> help(type(nb.typeof((1.0, ) * 9)))  # I shortened the result:
Help on class UniTuple in module numba.types.containers:

class UniTuple(BaseAnonymousTuple, _HomogeneousTuple, numba.types.abstract.Sequence)
 |  UniTuple(*args, **kwargs)
 |  
 |  Type class for homogeneous tuples.
 |  
 |  Methods defined here:
 |  
 |  __init__(self, dtype, count)
 |      Initialize self.  See help(type(self)) for accurate signature.

所以信息就在那里:它是 numba.types.containes.UniTuple,你用两个参数实例化它,dtype(这里是 float64)和数字(在本例中是 9).

In case you wanted to vectorize over the float arrays only

如果您不想为元组参数向量化函数,您可以简单地在另一个函数中创建向量化函数并在那里调用它:

import numba as nb
import numpy as np

def func(E, L, fparams):
    @nb.vectorize(['float64(float64, float64)'])
    def fn_vec(e, l):
        return e + l + fparams[1]  # just to illustrate that the tuple is available
    return fn_vec(E, L)

这使得元组在 vectorized 函数中可用。但是它必须创建内部函数并在每次调用外部函数时编译它,所以这实际上可能更慢。我也不确定这是否适用于 target="cuda",您可能需要自己测试一下。