首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >python中快速逆平方根对向量的规范化

python中快速逆平方根对向量的规范化
EN

Stack Overflow用户
提问于 2022-06-18 17:12:43
回答 3查看 312关注 0票数 3

我想把向量归一化。最简单的方法就是

代码语言:javascript
运行
复制
import numpy as np
v = np.random.rand(3)
v /= np.linalg.norm(v)

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

然后我进入了这个问题,哪个解决方案使用sklearn.preprocessing.normalize来完成它。不幸的是,它为我的包增加了另一个需求/依赖。

这就是问题所在。

  1. 难道不应该有一个numpy函数来这样做吗?它使用快速逆平方根算法。还是它超出了numpy的范围,不应该有这样的函数?
  2. 我应该在cython/numba中实现自己的函数吗?
  3. 或者,如果我如此担心性能,我应该放弃python,开始用C/C++编写代码吗?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-06-19 00:19:26

难道不应该有一个矮胖的函数来这样做吗?该算法采用快速逆平方根算法。或者是超出了numpy的范围,而不应该有这样的函数?

我不知道在Numpy中有什么功能能做到这一点。纯Numpy中需要多个函数调用。sklearn.preprocessing.normalize确实是一个很好的选择(而且AFAIK并不是唯一提供该功能的包)。

问题是,Numpy的设计并不是为了高效地计算小数组。对于小型数组(比如只有3个值),Numpy调用的开销很大。将多个函数调用组合在一起只会使情况更糟。造成这种开销的主要原因是类型/形状/值检查、内部函数调用、CPython解释器以及新数组的分配。因此,即使Numpy提供了您想要的函数,对于一个只有3项的数组来说,它也会很慢。

我应该在cython/numba中实现我的函数吗?

,这是一个很好的主意,,因为Numba可以用更小的开销来完成这个任务。注意,Numba函数调用的开销仍然很小,但是从Numba上下文调用它们非常便宜(本机调用)。

例如,您可以使用:

代码语言:javascript
运行
复制
# 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平台上的专用快速指令计算倒数平方根(请注意,如果您使用NaN之类的特殊值或关心FP的结合性,则fastmath是不安全的)。尽管如此,在主流机器上调用此函数的开销可能是100到300 ns,用于非常小的向量: CPython包装函数有很大的开销。删除它的唯一解决方案是在调用方函数中使用Numba/Cython。如果您需要在大多数项目中使用它们,那么直接编写C/C++代码当然更好。

或者,如果我如此担心性能,我应该放弃python,开始用C/C++编写代码吗?

--它取决于您的整个项目,但是您想要操作许多这样的小向量,直接使用C/C++要有效得多。另一种方法是将Numba或Cython用于当前速度较慢的内核。

优化良好的Numba代码或Cython代码的性能可以非常接近于本地编译的C/C++代码。例如,我成功地用Numba一次超过了经过高度优化的OpenBLAS代码(多亏了专门化)。Numba中开销的主要来源之一是数组绑定检查(通常可以针对循环进行优化)。C/C++是较低级别的,所以您不支付任何隐藏成本,但代码可能更难维护。此外,您还可以应用Numba/Cython中甚至不可能实现的低级优化(例如。直接使用SIMD内部指令或装配指令,生成带有模板的专用代码)。

票数 2
EN

Stack Overflow用户

发布于 2022-06-18 17:37:52

您可以获得的最佳解决方案是O(2n)的时间复杂度,它不是非常有效,而是线性的。下一步的办法如下:

1-首先计算向量的大小及其数值逆,这不可避免地会导致线性时间复杂度,而不管编程语言的性能如何。在此之前,我们有一个O(n)算法。

2-向量的所有分量与原向量的计算逆幅相乘,从而使其归一化。当我们再次遍历整个列表时,我们在算法的复杂性中添加了另一个O(n)项。最后,我们将这些时间复杂度项加起来,得到了O(n)+O(n)=O(2n)

代码语言:javascript
运行
复制
import numpy as np
v = np.random.rand(3)
mod = (sum([i**2 for i in v]))**-0.5
print(v, mod)
v *= mod
print(v)

然而,这似乎不需要高度的优化和效率。不过,我会再看一看,以找出一个更好的方法来处理这个问题。也许其他编程资源,如递归或高级数据结构,可以稍微减少其运行时间。

票数 1
EN

Stack Overflow用户

发布于 2022-06-18 17:37:36

正如@mkrieger1 1所写的,首先编写代码,然后测试性能是否适合您的工作。如果没有,请开始尝试上述解决方案,并比较设备上的差异。通常,在代码上运行的硬件可能会对性能差异产生影响。这意味着并非所有库最终都优于其他所有设备。

如果您真的想全部执行,我建议并行执行您的代码。最终甚至在GPU上。您可以为此使用pytorch,也可以用C和CUDA (或类似的)编写代码,以最大限度地利用系统。然而,重要的是,总结这些要素也必须并行进行。

最后,如果您坚持使用python,请看一下python 11,因为这个版本在某些方面提高了python的性能。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72671213

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档