Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有办法提高cython代码的速度_Python_Performance_Numpy_Optimization_Cython - Fatal编程技术网

Python 有没有办法提高cython代码的速度

Python 有没有办法提高cython代码的速度,python,performance,numpy,optimization,cython,Python,Performance,Numpy,Optimization,Cython,我希望加快以下python numpy代码的速度: def fun_np(m,data): a, b, c = data[:,0], data[:,1], data[:,2] M = len(data[:,0]) n = round((m+1)*(m+2)*(m+3)/6) u =np.zeros((M,n)) C = 0 for i in range(0,m+1): for j in range(0,i+1): for k in range(0,j+1):

我希望加快以下python numpy代码的速度:

def fun_np(m,data):
a, b, c = data[:,0], data[:,1], data[:,2] 

M = len(data[:,0]) 
n = round((m+1)*(m+2)*(m+3)/6) 
u =np.zeros((M,n))

C = 0
for i in range(0,m+1):
    for j in range(0,i+1):
        for k in range(0,j+1):
            if ((i-j)!=0):
                u[:,C] = (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

        C=C+1  
return u
相应的cython代码如下所示:

%%cython 
import numpy as np
cimport numpy as np
from cython import wraparound, boundscheck, nonecheck

@boundscheck(False)
@wraparound(False)
@nonecheck(False)

cpdef fun_cyt(int m,np.ndarray[np.float64_t, ndim=2] data):

cdef:
    np.ndarray[np.float64_t, ndim=1] a = data[:,0]
    np.ndarray[np.float64_t, ndim=1] b = data[:,1]
    np.ndarray[np.float64_t, ndim=1] c = data[:,2]
    int M, n
    Py_ssize_t i, j, k, s
M = len(data[:,0]) 
n = round((m+1)*(m+2)*(m+3)/6)   
cdef np.ndarray[np.float64_t, ndim=2]  u = np.zeros((M,n), dtype=np.float64)

cdef int C = 0
for i in range(m+1): #range(0,m+1):
    for j in range(i+1):
        for k in range(j+1):
            for s in range(M):
                if (i-j)!=0:
                    u[s,C] = (j-k)*(a[s])**(i-j)*(b[s])**(j-k-1)*(c[s])**k

            C=C+1
return u
这里是时间安排

z = np.random.randn(6000, 3); m=20;

%timeit fun_np(m,z);
结果:每个回路1.97 s±11.2 ms(7次运行的平均值±标准偏差,每个回路1次)

结果:每个循环1.91 s±12.7 ms(7次循环的平均值±标准偏差,每个循环1次)

正如您所看到的,numpy和cython代码之间没有显著的速度。如果您能尽可能帮助优化cython代码,我将不胜感激


cython代码的带注释的html

如注释中所述,您可以使用numba进行尝试。我建议进一步并行化循环:

from numba import prange, jit

@jit(nopython=True, parallel=True)
def fun_numba(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n))

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in prange(0,j+1):
                if ((i-j)!=0):
                    u[:,C] = (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u
在我的机器上给我:

In [11]: %timeit fun_np(m,z)                                                                         
642 ms ± 4.13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [12]: %timeit fun_numba(m,z)                                                                      
101 ms ± 7.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

正如评论中已经提到的,你可以用numba试试。我建议进一步并行化循环:

from numba import prange, jit

@jit(nopython=True, parallel=True)
def fun_numba(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n))

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in prange(0,j+1):
                if ((i-j)!=0):
                    u[:,C] = (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u
在我的机器上给我:

In [11]: %timeit fun_np(m,z)                                                                         
642 ms ± 4.13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [12]: %timeit fun_numba(m,z)                                                                      
101 ms ± 7.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
非常有趣的例子! 大多数操作是在6000个元素向量上进行的。 当涉及到大向量幂、乘法和加法时,Cython不可能真的比numpy快。 通过在Cython中实现这一点,您的速度可能与numpy一样快,甚至可以通过删除numpy的一些开销获得10%到20%的收益

但是,还有其他方法可以加快计算速度。 向量操作是对数据向量的三列的操作,您可以写入输出向量的列。 默认情况下,numpy数组具有行主顺序,即在内存中,行在内存中是连续的。 对于这里所做的操作来说,这是不好的。 进一步阅读:

这两个函数基本上是相同的,如果输出向量的创建发生在函数之外,它们将是相同的

注意:我替换了u[:,C]=。。。与u[:,C]+=,因为否则结果仅由k=j定义,因此始终为0。 我不知道这些计算的意义是什么,但可能不是这样

import numpy as np
def fun_np(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n))

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in range(0,j+1):
                if ((i-j)!=0):
                    u[:,C] += (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u

def fun_npF(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n),order='F')

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in range(0,j+1):
                if ((i-j)!=0):
                    u[:,C] += (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u

z = np.random.randn(6000, 3); m=20;
print("Numpy Row-major")
%timeit fun_np(m,z);

# Fortran order, because vector operations on columns
print("Numpy Column-major")
zF = np.asarray(z.copy(),order='F')
%timeit fun_npT(m,zF);

# Check if output the same
diff = (max(np.ravel(abs(fun_np(m,z)-fun_npF(m,zF)))))
max_rm = (max(np.ravel(abs(fun_np(m,z)))))
max_cm = (max(np.ravel(abs(fun_npF(m,zF)))))
print("Dffference: %f, Max value Row-major: %f, Max value Column-major: %f"%(diff, max_rm, max_cm))
这给了我

Numpy Row-major
1.64 s ± 12.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Numpy Column-major
16 ms ± 345 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Dffference: 0.000000, Max value Row-major: 196526643123.792450, Max value Column-major: 196526643123.792450
当你考虑把“如果”放在哪里,并把它与Cython结合起来时,你可以获得更多,但我猜也只有大约10%到20%。

非常有趣的例子! 大多数操作是在6000个元素向量上进行的。 当涉及到大向量幂、乘法和加法时,Cython不可能真的比numpy快。 通过在Cython中实现这一点,您的速度可能与numpy一样快,甚至可以通过删除numpy的一些开销获得10%到20%的收益

但是,还有其他方法可以加快计算速度。 向量操作是对数据向量的三列的操作,您可以写入输出向量的列。 默认情况下,numpy数组具有行主顺序,即在内存中,行在内存中是连续的。 对于这里所做的操作来说,这是不好的。 进一步阅读:

这两个函数基本上是相同的,如果输出向量的创建发生在函数之外,它们将是相同的

注意:我替换了u[:,C]=。。。与u[:,C]+=,因为否则结果仅由k=j定义,因此始终为0。 我不知道这些计算的意义是什么,但可能不是这样

import numpy as np
def fun_np(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n))

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in range(0,j+1):
                if ((i-j)!=0):
                    u[:,C] += (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u

def fun_npF(m,data):
    a, b, c = data[:,0], data[:,1], data[:,2] 

    M = len(data[:,0]) 
    n = round((m+1)*(m+2)*(m+3)/6) 
    u = np.zeros((M,n),order='F')

    C = 0
    for i in range(0,m+1):
        for j in range(0,i+1):
            for k in range(0,j+1):
                if ((i-j)!=0):
                    u[:,C] += (j-k)*(a)**(i-j)*(b)**(j-k-1)*(c)**k

            C=C+1  
    return u

z = np.random.randn(6000, 3); m=20;
print("Numpy Row-major")
%timeit fun_np(m,z);

# Fortran order, because vector operations on columns
print("Numpy Column-major")
zF = np.asarray(z.copy(),order='F')
%timeit fun_npT(m,zF);

# Check if output the same
diff = (max(np.ravel(abs(fun_np(m,z)-fun_npF(m,zF)))))
max_rm = (max(np.ravel(abs(fun_np(m,z)))))
max_cm = (max(np.ravel(abs(fun_npF(m,zF)))))
print("Dffference: %f, Max value Row-major: %f, Max value Column-major: %f"%(diff, max_rm, max_cm))
这给了我

Numpy Row-major
1.64 s ± 12.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Numpy Column-major
16 ms ± 345 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Dffference: 0.000000, Max value Row-major: 196526643123.792450, Max value Column-major: 196526643123.792450

在考虑将“如果”放在何处并与Cython结合使用时,您可以获得更多,但我猜只能获得大约10%到20%。

如果您要查看代码,请访问codereview.stackexchange.com试试运气,因为您的问题在StackOverflow上是离题的。@HIlle否-没有理由在这里离题。我认为它属于“特定编程问题”中列出的第一个要点。事实上,它也可能在代码评审时出现在主题上,但这并不意味着它在这里脱离主题。@ForBonder您看过带注释的html输出(从运行
cython-a yourfile.pyx
)了吗?如果你有什么发现,它通常会给你一个线索missed@DavidW谢谢,我看了带注释的html,但没有进步。我添加了带注释的html的链接。看起来很不错。这是Cython非常擅长的一类问题,看起来你做了正确的事情,所以你看不出有什么不同有点令人惊讶。如果你正在寻找代码审查,请在codereview.stackexchange.com试试你的运气,因为你的问题在StackOverflow上是离题的。@HIlle不-没有理由在这里离题。我认为它属于“特定编程问题”中列出的第一个要点。事实上,它也可能在代码评审时出现在主题上,但这并不意味着它在这里脱离主题。@ForBonder您看过带注释的html输出(从运行
cython-a yourfile.pyx
)了吗?如果你有什么发现,它通常会给你一个线索missed@DavidW谢谢,我看了带注释的html,但没有进步。我添加了带注释的html的链接。看起来很不错。这是Cython非常擅长的问题,看起来你做了正确的事情,所以有点奇怪你没有看到区别。