python—在使用memmaps和CPU时快速执行矩阵乘法和减法的方法

python—在使用memmaps和CPU时快速执行矩阵乘法和减法的方法,python,numpy,numexpr,Python,Numpy,Numexpr,您好,我有问题做快速矩阵乘法,加法,函数覆盖和求和与轴减少和工作在numpy.memmaps在CPU上没有RAM(我想)。只有在使用numexpr时,我才有可能避免从点创建数组 For example: a=np.require(np.memmap('a.npy',mode='w+',order='C',dtype=np.float64,shape=(10,1)),requirements=['O']) b=np.memmap('b.npy',mode='w+',order='C',dtyp

您好,我有问题做快速矩阵乘法,加法,函数覆盖和求和与轴减少和工作在numpy.memmaps在CPU上没有RAM(我想)。只有在使用numexpr时,我才有可能避免从点创建数组

For example:

a=np.require(np.memmap('a.npy',mode='w+',order='C',dtype=np.float64,shape=(10,1)),requirements=['O']) 
b=np.memmap('b.npy',mode='w+',order='C',dtype=np.float64,shape=(1,5))
c=np.memmap('c.npy',mode='w+',order='C',dtype=np.float64,shape=(1,5))
#func -> some method, like i.e. sin()
#in numexpr it will be simple
ne.evaluate('sum(func(b*a+c),axis=1)')
#in numpy with einsum it will have to be with creating additional out-of-dot handling array
d=np.require(np.memmap('d.npy',mode='w+',order='C',dtype=np.float64,shape=(10,5)),requirements=['O']) 

np.einsum('ij,kj->ki',b,a,out=d)
d+=c
func(d,out=d)
np.einsum('ij->i',d,out=c)
在没有RAM的情况下使用CPU比使用numexpr更快吗?Cython+FORTRAN lapack或blass怎么样?欢迎提供任何提示或窍门!谢谢你的帮助

编辑信息: 顺便说一句,我在笔记本电脑上使用的是Intel Core2Duo t9300 CPU、2.7 GB RAM(由于一些bios问题,只有4GB内存)、SSD 250GB、旧Intel GPU。由于Firefox和一些插件所使用的内存水平较低,因此没有多少代码可供编写,因此我避免使用xD

我觉得我在编程方面处于高级水平(步骤1/1000),而现在我不知道代码在硬件上是如何工作的——我只是在猜测(所以我的一些想法可能会出现xD错误)

编辑: 我用cython编写了一些代码,用于使用numexpr和cython prange for loop计算正弦波

脉动数据(om、eps、频谱、振幅)存储在om numpy.memmap中,时间数据(t、z)存储在TI numpy.memmap中。OM的形状类似于(4,12500),TI的形状类似于(2,1,5e+5,1)-我只需要它的形状

cdef inline void sine_wave_numexpr(OM,TI,int num_of_threads):

    cdef long m,n=10
    cdef Py_ssize_t s=TI.shape[2]/n
    cdef str ex_sine_wave=r'sum(A*sin(om*ti+eps),axis=1)'
    cdef dict dct={'A':OM[3],'om':OM[0],'eps':OM[2]}
    for m in range(n):
        sl=slice(s*m,s*(m+1))
        dct['ti']=TI[0,0,sl]
        evaluate(ex_sine_wave,
                    global_dict=dct,
                    out=TI[1,0,sl,0])
cdef inline void sine_wave_cython(double[:,:,::1]OM,double[:,:,:,::1]TI,int num_of_threads):
    cdef int i,j
    cdef Py_ssize_t n,m
    cdef double t,A,om,eps
    n=OM.shape[2]
    m=TI.shape[2]
    for i in prange(m,nogil=True,num_threads=num_of_threads):
        t=TI[0,0,i,0]
        for j in prange(n,num_threads=num_of_threads):
            A=OM[3,0,j]
            om=OM[0,0,j]
            eps=OM[2,0,j]
            TI[1,0,i,0]+=A*sin(om*t+eps)

cpdef inline void wave_elevation(double dom,OM,TI,int num_of_threads, str method='cython'):
    cdef int ni
    cdef double i,j
    cdef Py_ssize_t shape=OM.shape[2]
    numexpr_threads(num_of_threads)
    OM[2,0]=2.*np.random.standard_normal(shape)
    evaluate('sqrt(dom*2*S)',out=OM[3],
            local_dict={'dom':dom,'S':OM[1]})
    if method=='cython':
        sine_wave_cython(OM,TI,num_of_threads)
    elif method=='numexpr':
        sine_wave_numexpr(OM,TI,num_of_threads)
    TI.shape=TI.shape[:3]

我只是从Cython开始,所以它可能没有得到很好的优化。就目前而言,使用prange编写的代码与使用numexpr编写的代码所用的时间相同(包括该部分在内的所有代码的RAM使用量为100 MB,CPU为50%,SSD为低端-计算时间为1-2分钟)。我尝试使用MemoryView,但随着时间的推移,它创建了一些本地副本并使用RAM。我需要学习高级步骤3/1000,以了解如何使用MemoryView。

您可能不应该在循环中计算
sqrt()
sin()
,这些都很昂贵。由于正弦是周期性的,一个相对较小的向量应该足以保持其值。因此
np.memmap
(即将数据存储在磁盘上)和“Fast”,听起来与我不兼容。“使用CPU而不使用RAM”与此相反,您希望在RAM中工作,尽管尽可能减少不必要的内存拷贝(numexpr就是这样做的),不是吗?注意:您也可以使用
np.dot(a,b,out)
代替
einsum
。您可以尝试使用Cython(另请参见scipy 0.16中的BLAS/LAPACK API),尽管性能einsum与BLAS内积将取决于您的阵列的大小,正如在关于SO的其他问题中所讨论的那样。