2

嗨,我在使用轴缩减进行快速矩阵乘法、加法、function_overwrite 和求和以及在没有 RAM 的 CPU 上使用 numpy.memmaps 时遇到问题(我认为)。只有在使用 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 主要使用带有一些插件的低级别 RAM,编码所剩无几,所以这就是我避免使用它的原因 xD。

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

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

脉动数据(对于 om、eps、Spectra、Amplitude)存储在 OM numpy.memmap 中,时间数据(t、z)存储在 TI numpy.memmap 中。OM 的形状类似于 (4,1,2500),而 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 分钟)。我尝试使用 memoryviews,但这会创建一些本地副本并使用 RAM,时间会下降。我需要达到高级级别步骤 3/1000 才能了解如何使用内存视图。

4

0 回答 0