用Cython优化NumPy [英] Optimizing NumPy with Cython

查看:202
本文介绍了用Cython优化NumPy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试优化我用纯Python编写的代码.当我使用NumPy数组时,此代码非常大量地使用 NumPy .在下面,您可以看到我转换为 Cython 的最简单的类.仅对两个Numpy数组进行乘法运算.在这里:

I am currently trying to optimize the code that I had written in pure Python. This code uses NumPy very heavily as I am working with NumPy arrays. Below you can see the simplest of my classes that I converted to Cython. Which only does a multiplication of two Numpy arrays. Here:

bendingForces = self.matrixPrefactor * membraneHeight

我的问题是,当我查看"cython -a"生成的C代码时,是否以及如何对其进行优化,因此有很多NumPy调用,看起来效率不高.

My question is, if and how I can optimize this as, when I look at the C-code that "cython -a" generates has a lot of NumPy-callings, which does not look very efficient.

import numpy as np
cimport numpy as np
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

    cdef class bendingForcesClass( object ):
        cdef dtype_t bendingRigidity
        cdef np.ndarray matrixPrefactor
        cdef np.ndarray bendingForces

        def __init__( self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm ):
            self.bendingRigidity = bendingRigidity
            self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm**2

        cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
            cdef np.ndarray bendingForces
            bendingForces = self.matrixPrefactor * membraneHeight
            return bendingForces

我的想法是使用两个for循环并遍历数组的条目.也许我可以使用编译器通过SIMD操作对其进行优化?我尝试了一下,可以编译,但是结果却很奇怪,而且花了很长时间.这是替代函数的代码:

The idea I had was to use two for loops and iterate over the entries of the arrays. Perhaps I could use the compiler to optimize this with SIMD-operations?! I tried, which I could compile, but it gave strange results and took forever. Here's the code of the substitute function:

cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :

    cdef index_t index1, index2 # corresponds to: cdef Py_ssize_t index1, index2
    for index1 in range( self.matrixSize ):
        for index2 in range( self.matrixSize ):
            self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]
    return self.bendingForces

但是,正如我所说,此代码确实很慢,并且无法按预期运行.那我在做什么错?对此进行优化并删除NumPy调用操作的最佳方法是什么?

This code however, as I said, is really slow and does not function as expected. So what am I doing wrong? What would be the best way to optimize this and remove the NumPy calling operations?

推荐答案

对于简单的矩阵乘法,NumPy代码已经只在本地进行循环和乘法运算,因此很难在Cython中做到这一点. Cython非常适合将Python中的循环替换为Cython中的循环的情况.您的代码比NumPy慢的原因之一是因为每次在数组中执行索引查找时,

For simple matrix multiplications, the NumPy code is already doing only the looping and multiplying natively, so it would be hard to beat that in Cython. Cython is great for situations where you are replacing loops in Python with those in Cython. One of the reasons your code is slower than NumPy is because every time you do an index lookup in your array,

self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]

它执行更多的计算,例如边界检查(索引有效).如果将索引转换为无符号整数,则可以在函数之前使用修饰符@cython.boundscheck(False).

it does more calculations like bounds checking (the index is valid). If you cast your indices to unsigned ints, you could use the decorator @cython.boundscheck(False) before the function.

有关加速Cython代码的更多详细信息,请参见教程.

See this tutorial for more details in speeding up Cython code.

这篇关于用Cython优化NumPy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆