python - python中的快速平方根反比来规范化向量

标签 python numpy performance vector

我想规范化一个向量。最简单的方法是

import numpy as np
v = np.random.rand(3)
v /= np.linalg.norm(v)

但我担心我的包的性能和对平方求和(不可避免),取平方根,然后除所有向量不是一个好主意。

然后我进入了this question哪个解决方案使用 sklearn.preprocessing.normalize 来做到这一点。不幸的是,它向我的包添加了另一个要求/依赖项。

这是问题。

  1. 不应该有一个 numpy 函数来做到这一点吗?其中使用 fast inverse square root algorithm .还是它超出了 numpy 的范围,不应该有这样的函数?
  2. 我应该在 cython/numba 中实现我自己的函数吗?
  3. 或者,如果我非常担心性能,我是否应该放弃 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/

相关文章:

Python矢量化嵌套for循环

ios - glCopyTexImage2D 作为 glReadPixels (OpenGL ES) 的替代品

python - 为什么 2 * x * x 在 Python 3.x 中比 2 * ( x * x ) 快,对于整数?

python - tensorflow 中边界框的坐标

python - numpy.random.seed(0) 做什么?

python - CPU 密集型的依赖属性

python - 在 numpy/matplotlib.plot 中设置轴值

keyboard - 在 Windows 中编程的最佳键盘宏是什么?

python - Pyspark 数据框使用默认值左连接

python - 在 ZeroMQ/Tornado ioloop 或 Twisted 中使用 BluetoothSocket?