了解Numpy内部结构以进行性能分析

时间:2012-09-14 16:34:18

标签: numpy profiling

分析一段numpy代码表明我大部分时间都花在这两个函数中

numpy/matrixlib/defmatrix.py.__getitem__:301
numpy/matrixlib/defmatrix.py.__array_finalize__:279

这是Numpy来源:

问题#1:

每当我使用类似__getitem__的内容时,似乎都会调用{p> my_array[arg],如果arg不是整数而是切片,则会变得更加昂贵。有没有办法加快对数组切片的调用?

E.g。在

for i in range(idx): res[i] = my_array[i:i+10].mean()

问题#2:

何时调用__array_finalize__,如何通过减少对此函数的调用次数来加快速度?

谢谢!

2 个答案:

答案 0 :(得分:11)

你不能使用矩阵,只使用2d numpy数组。我通常只使用矩阵短时间来利用乘法的语法(但是在数组上添加.dot方法,我发现我做的越来越少)。

但是,对于你的问题:

1)__getitem__确实没有捷径,除非defmatrix超越__getslice__它可以做但是还没有。有.item和.itemset方法,它们针对整数获取和设置进行了优化(并返回Python对象而不是NumPy的数组标量)

2)每当创建数组对象(或子类)时,都会调用__array_finalize__。它是从C函数调用的,每个数组创建都可以通过它进行管道传输。 https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/ctors.c#L1003

对于纯粹在Python中定义的子类,它从C调用回来的Python解释器,它有开销。如果矩阵类是内置类型(例如,基于Cython的cdef类),则调用可以避免Python解释器开销。

答案 1 :(得分:3)

问题1:

由于数组切片有时可能需要底层数据结构的副本(保存指向内存中数据的指针),因此它们可能非常昂贵。如果您在上面的示例中确实存在瓶颈,则可以通过实际迭代i到i + 10元素并手动创建均值来执行平均操作。对于某些操作,这不会提高性能,但是避免创建新的数据结构通常会加快这一过程。

另外请注意,如果你没有在numpy中使用本机类型,那么操作numpy数组会受到非常大的性能损失。假设您的数组有dtype = float64,并且您的本机浮动大小为float32 - 这将为numpy耗费大量额外的计算能力,整体性能将下降。有时这很好,你可以采取维护数据类型的命中。其他时候,float或int在内部存储的类型是任意的。在这些情况下,请尝试使用dtype = float而不是dtype = float64。 Numpy应该默认为您的本机类型。通过进行此更改,我在numpy密集算法上获得了3倍以上的加速。

问题2:

只要系统在内部从obj分配一个新数组,就会调用

__array_finalize__“,其中obj是(大)ndarray的子​​类(子类型),根据SciPy。因此,这是第一个问题中描述的结果。切片并创建新数组时,必须通过制作结构副本或包装原始结构来最终确定该数组。此操作需要时间。避免切片将节省此操作,但对于多维数据,可能无法完全避免对__array_finalize__的调用。