使用cython加快numpy数组的速度

时间:2018-08-31 11:04:26

标签: python numpy vectorization cython

我有以下代码:

class _Particles:
    def __init__(self, num_particle, dim, fun, lower_bound, upper_bound):
        self.lower_bound = lower_bound   # np.array of shape (dim,)
        self.upper_bound = upper_bound   # np.array of shape (dim,)
        self.num_particle = num_particle   # a scalar
        self.dim = dim   # dimension, a scalar
        self.fun = fun   # a function

        self.pos = np.empty((num_particle,dim))
        self.val = np.empty(num_particle)
        self.randomize()


    def randomize(self):
        self.pos = np.random.rand(self.num_particle, self.dim)*(self.upper_bound\
                -self.lower_bound)+self.lower_bound
        self.val = self.fun(np.transpose(self.pos))
        self.best_idx = np.argmin(self.val)
        self.best_val = self.val[self.best_idx]
        self.best_pos = self.pos[self.best_idx]


    def move(self, displacement, idx='all', check_bound=True):
        if idx is 'all':
            self.pos += displacement
        elif isinstance(idx,(tuple,list,np.ndarray)):
            self.pos[idx] += displacement
        else:
            raise TypeError('Check the type of idx!',type(idx))

        self.pos = np.maximum(self.pos, self.lower_bound[np.newaxis,:])
        self.pos = np.minimum(self.pos, self.upper_bound[np.newaxis,:])
        self.val = self.fun(np.transpose(self.pos))
        self.best_idx = np.argmin(self.val)
        self.best_val = self.val[self.best_idx]
        self.best_pos = self.pos[self.best_idx]

我想看看是否可以加快上述代码的速度,我正在考虑使用cython,但是我不确定是否可行,因为它主要使用numpy数组,并且大多数执行都是通过向量化完成的。我尝试类似的东西:

# the .pyx file that will be compiled
cdef class _Particles(object):
    cdef int num_particle
    cdef int dim
    cdef fun
    cdef np.ndarray lower_bound
    cdef np.ndarray upper_bound
    cdef np.ndarray pos
    cdef np.ndarray val
    cdef int best_idx
    cdef double best_val
    cdef np.ndarray[np.float64_t, ndim=1] best_pos

    def __init__(self, int num_particle, int dim, fun,
                 np.ndarray lower_bound, np.ndarray upper_bound):
        self.num_particle = num_particle
        self.dim = dim
        self.fun = fun
        self.lower_bound = lower_bound
        self.upper_bound = upper_bound

        self.pos = np.empty((num_particle,dim))
        self.val = np.empty(num_particle)
        self.randomize()

    def randomize(self):
        self.pos = npr.rand(self.num_particle,self.dim)*(self.upper_bound\
                -self.lower_bound)+self.lower_bound

        self.val = self.fun(np.transpose(self.pos))
        self.best_idx = np.argmin(self.val)
        self.best_val = self.val[self.best_idx]
        self.best_pos = self.pos[self.best_idx]

它更快,但是只有一点点,这是可以预期的,因为它仍然主要是python代码。那么,有什么方法可以使用cython来加快上述代码的速度(或者让我指出一些其他完全方法)?特别是,如何加快诸如self.fun(self.pos)np.argmin(self.val)之类的代码?

谢谢。

1 个答案:

答案 0 :(得分:3)

实际上,恐怕上面的代码没有太多要优化的地方。 为了使using (WordprocessingDocument doc = WordprocessingDocument.Open(@"D:\DocFiles\Lscan.docx", true)) { Body body = doc.MainDocumentPart.Document.Body; var paras = body.Elements<DocumentFormat.OpenXml.Drawing.Paragraph>(); foreach (Paragraph para in doc.MainDocumentPart.Document.Body.Descendants<Paragraph>()) { string prg = para.InnerText.ToString(); } 更快,我建议您使用多线程支持(或者可以自己重新实现一些多线程argmin)来获取(或自行编译)NumPy。

就Cython而言,当您开始使用C类型时,您会获得真正的收获,但是对于您发布的代码,这是我不会看到的重大改进。 那主要是粘合代码,不涉及任何数字运算。

我希望在函数argmin中进行数字运算,并且这可能是唯一的实际手动优化可能有所作为的地方,只要它不那么容易矢量化(请参阅:那里是fun或其他手动循环)。然后,我将从for开始,如果可以的话,这对于您的代码来说是一个简单得多的插入加速。如果没有,开始研究numba可能是合适的。