@vectorize函数的输出作为元组:我应该使用什么签名?

huangapple go评论58阅读模式
英文:

tuple as output of @vectorize function (numba): what signature so I have to use?

问题

@vectorize((float64[:], float64[:])(float64[:]))
英文:

I am trying to create a vectorized function

@vectorize()
def rhou(f):
    rho = numpy.sum(f, axis=-1)
    u = 1.0
    v = 2.0
    w = 3.0
    velocity = numpy.array([u,v,w])
    return rho, velocity

rho, f, u, v, w, and velocity are all of the type float64. f is an numpy array of the form f[:,:,:,:]. So the input array (being f) can be an array of any size regarding the first three indexes. The sum is taken over the fourth in the function rhou.

My question is: what signature should I put in @vectorize()?

I have tried @vectorize((float 64, float64)(float64)) (and many other probably stupid attempts with Tuple for example), but that does not work. The help page of numba deals with s single output, but in this case the function returns two results.

Thanks!

Tried many things, but nothing helps. The numba help page is not clear about multiple outputs

答案1

得分: 2

The vectorized 装饰器不支持多个输出(afaik),但你可以使用 guvectorize 以实现这一点。 guvectorize 更加灵活,但这也意味着你将需要提供更多关于形状和类型的信息。

但你的代码目前也不太清晰,而且没有提供任何示例输入,这使得无法运行。对任何数组应用 vectorized 就像其名称所示,将操作向量化,这意味着它将对输入中的每个条目执行逐元素计算。因此,你的 sum(f) 语句毫无意义,因为它总是对单个值求和。所以我预期你要么不想向量化(逐元素),要么不想求和,但从你的帖子中无法确定这一点。

下面的示例使用 guvectorize 显示了与我认为你试图实现的类似的内容,但我不确定。使用 guvectorize,你将需要指定要保留的维度(在函数中“看到”),其他所有内容都将被向量化。默认假设是在“末尾”的剩余维度上向量化,但该函数将自动获得一个轴关键字(类似于Numpy的ufuncs),允许你更改它。

请注意,没有返回语句,输出数组是函数的参数,并且结果设置在这些数组上!这类似于大多数Numpy函数上的 out= 关键字。

我不知道有任何方法可以避免不传递一个虚拟输入来让Numba知道“m”的大小是多少(velocity的形状),即使你明确提供了返回数组如上所示,这是必要的。

另一种编写方式是让Numba创建/分配输出数组。它可以做到这一点,因为签名中知道形状(从签名中),并且知道数据类型。但我经常看到有人尝试这样做,而不了解必须通过索引数组来设置结果(即使输出标量!)。特别是一开始,自己创建输出并将其明确传递给函数可能更直观。

但那会看起来像:

英文:

The vectorized decorator does not support multiple outputs (afaik), but you can use guvectorize in order to achieve this. The guvectorize is more flexible, but that also means you'll have to specify a bit more information regarding shapes & types.

But your code is also unclear at the moment, and you don't provide any sample input making it impossible to run. Applying vectorized on any array, will as the name suggests, vectorize the operation, meaning it will perform an element-wise calculation on each entry in the input individually. So that makes your sum(f) statement meaningless, since it will always take the sum of a single value. So I expect you either don't want to vectorize (element-wise), or don't want to take the sum, but this is unclear from your post.

The example below using guvectorize shows something similar as what I think you're trying to achieve, but I'm not sure. With guvectorize you'll have to specify the dimensions you want to keep ("see" in the function), and everything else will be vectorized. The default assumption is to vecorize over remaining dimensions at the "end", but the function will automatically get an axis keyword (similar as Numpy ufuncs) that allows you to change that.

@guvectorize([
    "void(float64[:], float64[:], float64[:], float64[:])"
], "(n),(m)->(),(m)")
def rhou(f, dummy, rho, velocity):
    rho[0] = np.sum(f)
    velocity[0] = 1.0
    velocity[1] = 2.0
    velocity[2] = 3.0

f = np.random.randn(3)
velocity = np.empty(3, dtype=np.float64)
rho = np.empty(1, dtype=np.float64)

rhou(f, velocity, rho, velocity)

Note how there is no return statement, the output arrays are arguments to the function, and the results as set on those! This is a similar pattern as the out= keyword on most Numpy functions.

I don't know anyway to avoid having to pass a dummy input to let Numba know what the size of "m" is (shape of velocity), this is necessary even if you provide the return array explicitly as shown above.

An alternative way of writing this is having Numba create/allocate the output arrays. It can do this because both the shape (from the signature) and the datatype is known. But I often see people who try this not realizing you have to set the result by indexing the array (even if you output a scalar!). Especially at first it's probably more intuitive to create the outputs yourself, and pass the explicitly to the function.

But that would look something like:

import numba; import numpy as np

@numba.guvectorize([
    "void(float64[:], float64[:], float64[:], float64[:])",
], "(n),(m)->(),(m)")
def rhou(f, _, rho, velocity):
    rho[0] = np.sum(f)
    velocity[0] = 1.0
    velocity[1] = 2.0
    velocity[2] = 3.0

f = np.random.randn(3)
dummy = np.empty(3, dtype=np.float64)

rho, velocity = rhou(f, dummy)

huangapple
  • 本文由 发表于 2023年2月10日 02:41:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/75403075.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定