【发布时间】:2021-10-11 13:45:38
【问题描述】:
我遇到的基本问题如下:
In [39]: import numba as nb
In [40]: import numpy as np
In [41]: mat = np.array([[1.2, 1.6, 0.5, 0 ],
...: [1.2, 1.6, 0, 0.5]])
In [42]: @nb.vectorize
...: def f(a, b, c, d):
...: load = np.array([a, b, c, d])
...: return mat @ load
...:
In [43]: f(1.1, 2.1, 3, 4)
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<SNIP>
NotImplementedError: array(float64, 1d, C) cannot be represented as a Numpy dtype
旁注:在此示例中,mat 表示负载因子矩阵(要乘以一组负载)并且永远不会改变;在我的实际问题中,我动态生成了许多这样的mats 并动态生成了许多这些分解的负载组合函数(每个函数都有自己的常量mat 值)。
现在,显然这个函数更容易实现为基本的矩阵乘法运算,而无需使用 numba:
In [44]: def f(a, b, c, d):
...: load = np.array([a, b, c, d])
...: return mat @ load
...:
In [45]: f(1.1, 2.1, 3, 4)
Out[45]: array([6.18, 6.68])
但是,我使用 numba 的目标是允许一起广播各种形状的数组的参数,而不仅仅是原子值。示例:
>>> a = np.array([1, 2, 3])
>>> b = np.array([[1, 2, 3], [4, 5, 6]])
>>> c = 1
>>> d = 2
>>> f(a, b, c, d)
# expected output:
array([[[ 3.3, 3.8],
[ 6.1, 6.6],
[ 8.9, 9.4]],
[[ 8.1, 8.6],
[10.9, 11.4],
[13.7, 14.2]]])
如何对每个操作生成一个 numpy 数组的操作进行向量化,并返回与输入的广播形状匹配的结果嵌套矩阵?
编辑:
顺便说一句,我对输出形状不是很固执。输出这样的形状可能会更方便?
>>> f(a, b, c, d)
# expected output:
array([[[ 3.3, 6.1, 8.9],
[ 8.1, 10.9, 13.7]],
[[ 3.8, 6.6, 9.4],
[ 8.6, 11.4, 14.2]]])
编辑:
这是我使用nb.guvectorize 所能做出的最好尝试。它会给出性能警告和错误的结果。
In [97]: @nb.guvectorize(["f8, f8, f8, f8, f8[:,:], f8[::1]"], "(), (), (), (), (n,m)-> (n)")
...: def f(a, b, c, d, mat, res):
...: for i in range(mat.shape[0]):
...: res[i] = mat[i] @ np.array([a, b, c, d])
...:
<ipython-input-97-9dea8a9aed86>:4: NumbaPerformanceWarning: '@' is faster on contiguous arrays, called on (array(float64, 1d, A), array(float64, 1d, C))
res[i] = mat[i] @ np.array([a, b, c, d])
<SNIP>
In [98]: f(a, b, c, d, mat)
Out[98]:
array([[[ 3.3, 3.3],
[ 6.1, 6.1],
[ 8.9, 8.9]],
[[ 8.1, 8.1],
[10.9, 10.9],
[13.7, 13.7]]])
【问题讨论】:
-
添加为评论,因为我不想让问题脱轨:我认为正确的工具可能是
nb.guvectorize。但即使在阅读the documentation 之后,我仍然不知道如何正确使用它。如果有人同意这是正确的工具,我期待他们的解决方案。