代码之家  ›  专栏  ›  技术社区  ›  Physicist

使用cython使用numpy数组加速类

  •  1
  • Physicist  · 技术社区  · 8 年前

    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]
    

    # 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 回复  |  直到 8 年前
        1
  •  3
  •   norok2    8 年前

    实际上,恐怕上面的代码没有太多需要优化的地方。 使 argmin 我建议您更快地获得(或者自己编译)带有多线程支持的NumPy(或者您可以自己重新实现一些多线程argmin)。

    就Cython而言,当您开始使用C类型时,您得到了真正的好处,但是我不会看到您发布的代码有很大的改进。 这主要是胶水代码,不涉及数字运算。

    fun for 或其他手动循环)。然后,我会从 numba ,这对于代码来说是一种更简单的加速方法,如果它可以工作的话。如果不是这样的话,就应该开始研究 Cython .