Numpy 数组方法比 numpy 函数更快?

问题描述 投票:0回答:1

我必须处理 Keras 模型的学习历史。这是一项基本任务,但我测量了 Python 内置 min() 函数、numpy.min() 函数以及 list 和 ndarray 的 numpy ndarray.min() 函数的性能。与 ndarray 的 Numpy 相比,内置 Python min() 函数的性能毫无意义 - numpy 快了 10 倍(对于 list numpy 几乎慢了 6 倍,但这不是这个问题的情况)。 然而,ndarray.min()方法几乎是numpy.min()方法的两倍。 ndarray.min() 文档引用 numpy.amin() 文档,根据 numpy.amin 文档,它是 numpy.min() 的别名。因此,我假设 numpy.min() 和 ndarray.min() 具有相同的性能。但是,为什么这些功能的性能并不相等呢?

from timeit import default_timer
import random
a = random.sample(range(1,1000000), 10000)
b = np.array(random.sample(range(1,1000000), 10000))

def time_mgr(func):
    tms = []
    for i in range(3, 6):
        tm = default_timer()
        for j in range(10**i):
            func()
        tm = (default_timer()-tm) / 10**i * 10e6
        tms.append(tm)
    print(func.__name__, tms)

@time_mgr
def min_list():
    min(a)

@time_mgr
def np_min_list():
    np.min(a)

@time_mgr
def min_nd():
    min(b)

@time_mgr
def np_min_nd():
    np.min(b)

@time_mgr
def np_nd_min():
    b.min()

输出,时间(以 mks 为单位):

min_list [520.7690014503896, 515.3326001018286, 516.221239999868]
np_min_list [2977.614998817444, 3009.602500125766, 3014.1312699997798]
min_nd [2270.1649996452034, 2195.6873999442905, 2155.1631700014696]
np_min_nd [22.295000962913033, 21.675399970263243, 22.30485000181943]
np_nd_min [14.261999167501926, 12.929399963468313, 12.935079983435571]
python arrays numpy multidimensional-array min
1个回答
0
投票

列表和对象一样效率非常低:它们将 FP 数存储为对象,而列表包含指向这些对象的指针。它会阻止所有优化并导致非常糟糕的内存访问模式。更不用说对象是由全局解释器锁(GIL)进行引用计数和保护的。任何在热循环中涉及 CPython 对象的代码都注定会非常慢,尤其是在解释此循环时。这样的事情发生在

min_list
min_nd

Numpy 也无法直接对列表进行操作,因此它将它们转换为数组。这种转换通常比任何基本的 Numpy 数组计算慢得多(在

np.min(a)
中一次又一次地完成,因此性能较差)。

至于

np.min
b.min
,它们都是等效的,尽管第一个在小数组上可能会慢一些,因为 CPython 的函数获取开销和 Numpy 中采用的路径不同。 Numpy 针对大型数组进行了优化。在小型数组上,您会看到许多开销,如果不深入研究 Numpy 实现的代码,您将很难理解这些开销(因为此类开销显然依赖于实现)。

在我的机器(带有 Numpy 1.24.4 的 i5-9600KF CPU)上,前者需要 4.5 µs,后者需要 2.5 µs,所以时间非常短。这通常是 Numpy 的开销(即每次调用 1-10 µs)。对于 100 倍大的阵列,我得到 80 µs 与 83 µs (+/- 2 µs),因此两者在统计上没有差异。它还显示在小型阵列基准测试中花费的大部分时间只是纯粹的开销(~60% 到~80%)。

如果你想减少这些开销,那么你应该使用像 Cython/Numba 这样能够编译(专用)Python 代码的工具,或者首先不使用 Python,而使用 C/C++/Rust 等本地语言。

© www.soinside.com 2019 - 2024. All rights reserved.