我想规范化一个向量。最简单的方法是
import numpy as np
v = np.random.rand(3)
v /= np.linalg.norm(v)
但我担心我的包的性能和对平方求和(不可避免),取平方根,然后除所有向量不是一个好主意。
然后我进入了this question哪个解决方案使用 sklearn.preprocessing.normalize
来做到这一点。不幸的是,它向我的包添加了另一个要求/依赖项。
这是问题。
- 不应该有一个
numpy
函数来做到这一点吗?其中使用 fast inverse square root algorithm .还是它超出了numpy
的范围,不应该有这样的函数? - 我应该在
cython
/numba
中实现我自己的函数吗? - 或者,如果我非常担心性能,我是否应该放弃
python
并开始使用C
/C++
编写代码?<
最佳答案
Shouldn’t there be a numpy function to do that? Which uses the fast inverse square root algorithm. Or is it outside the numpy's scope and there shouldn't be a function like that?
我不知道 Numpy 中有任何函数可以做到这一点。纯 Numpy 中需要多个函数调用。 sklearn.preprocessing.normalize
确实是一个不错的选择(而且 AFAIK 不是唯一提供该功能的包)。
问题是 Numpy 并不是为高效计算小型数组而设计的。 Numpy 调用的开销对于小数组来说是巨大的(比如只有 3 个值)。组合多个函数调用只会使情况变得更糟。开销主要是由于类型/形状/值检查、内部函数调用、CPython 解释器以及新数组的分配。因此,即使 Numpy 能够提供您想要的功能,对于只有 3 个项目的数组来说它也会很慢。
Should I implement my function own in cython/numba?
这是个好主意,因为 Numba 可以用更小的开销做到这一点。请注意,尽管 Numba 函数调用仍有少量开销,但从 Numba 上下文调用它们非常便宜( native 调用)。
例如,您可以使用:
# Note:
# - The signature cause an eager compilation
# - ::1 means the axis is contiguous (generate a faster code)
@nb.njit('(float64[::1],)')
def normalize(v):
s = 0.0
for i in range(v.size):
s += v[i] * v[i]
inv_norm = 1.0 / np.sqrt(s)
for i in range(v.size):
v[i] *= inv_norm
此函数不会分配任何新数组,因为它就地工作。此外,Numba 只能在包装函数中进行最少数量的检查。循环非常快,但如果您将 v.size
替换为实际大小(例如 3),它们可以变得更快,因为 JIT 然后可以展开循环并生成接近最佳的代码。 np.sqrt
将被内联,它应该生成一个快速平方根 FP 指令。如果您使用标志 fastmath=True
,JIT 甚至可以在 x86-64 平台上使用专用的更快指令计算倒数平方根(注意 fastmath
是如果您使用 NaN 等特殊值或关心 FP 关联性,则不安全)。尽管如此,对于非常小的向量,在主流机器上调用此函数的开销可能为 100-300 ns:CPython 包装函数的开销很大。删除它的唯一解决方案是在调用函数中使用 Numba/Cython。如果您需要在您的大部分项目中使用它们,那么直接编写 C/C++ 代码当然更好。
Or if I'm so worried about performance, should I give up python and start making code in C/C++?
这取决于您的整体项目,但如果您想像这样操作许多小向量,直接使用 C/C++ 效率更高。另一种方法是对当前速度较慢的内核使用 Numba 或 Cython。
经过良好优化的 Numba 代码或 Cython 代码的性能可以非常接近本地编译的 C/C++ 代码。例如,我使用 Numba 成功地超越了高度优化的 OpenBLAS 代码一次(由于特化)。 Numba 开销的主要来源之一是数组边界检查(通常可以针对循环进行优化)。 C/C++ 是较低级别的,因此您无需支付任何隐藏成本,但代码可能更难维护。此外,您可以应用在 Numba/Cython 中甚至不可能实现的低级优化(例如,直接使用 SIMD 内在函数或汇编指令,使用模板生成专用代码)。
关于python - python中的快速平方根反比来规范化向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72671213/