通过MATLAB改善Numpy中复杂矩阵求和元素的更好方法

时间:2018-09-26 15:23:32

标签: python matlab

我试图将下面的MATLAB代码重写为Python,发现我的Python代码(2.7秒)比MATLAB(1.2秒)慢。 我尝试了许多不同的方法,包括numba模块,但还没有走运。 如何使Python代码更快?

MATLAB代码:

szA=[1024,1280]; HfszA=[512,640];
[aPx,aPy]=meshgrid(-HfszA(2):HfszA(2)-1,-HfszA(1):HfszA(1)-1);
img=randi(255,1024,1280);
fx=rand(); fy=rand();
tic
for i=1:20
    F=abs(sum(sum(img.*exp(-1i*2*pi*(fx*aPx+fy*aPy)))));
end
toc

Python代码:

import numpy as np
import time

szA=[1024,1280]; HfszA=[512,640]
aPx,aPy=np.meshgrid(np.arange(-HfszA[1],HfszA[1]),np.arange(-HfszA[0],HfszA[0]))
img=np.array(np.random.randint(256,size=(1024,1280)))

fx=np.random.rand()
fy=np.random.rand()

start = time.time()
for i in range(20):
    F=abs(np.sum(img*np.exp(-1j*2*np.pi*(fx*aPx+fy*aPy))))
end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))
print(F)

2 个答案:

答案 0 :(得分:0)

我相信您甚至可以尝试一个更简单的问题

MATLAB

function test
    szA=[1024,1280]; HfszA=[512,640];
    [aPx,aPy]=meshgrid(-HfszA(2):HfszA(2)-1,-HfszA(1):HfszA(1)-1);
    fx=1.0; fy=2.0;
    tic
    for i=1:2000
        F=sum(sum(fx*aPx+fy*aPy));
    end
    toc
    disp(F)

输出

  

经过的时间是9.566274秒。

     

-1966080

Python

import numpy as np
import time

szA=[1024,1280]; HfszA=[512,640]
aPx,aPy=np.meshgrid(np.arange(-HfszA[1],HfszA[1]),np.arange(-HfszA[0],HfszA[0]))

fx=1.0
fy=2.0

start = time.time()
for i in range(2000):
    F = np.sum(np.sum(fx*aPx+fy*aPy, axis=0))
end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))
print(F)

输出

  

经过(编译后)= 33.3840000629

     

-1966080.0

我相信两者之间的区别是双重的:

  • Matlab在执行许多阵列操作时使用OpenMP
  • 利用了AVX指令集。

我得出这个结论的原因是查看具有四个内核的Core i3上的CPU使用情况(您可以检查CPU上的内核数量),而使用python脚本,则为30%,而使用matlab,则为100%。

对于AVX指令集,只是我曾经将MATLAB matmul操作与Eigen的操作(http://eigen.tuxfamily.org/index.php?title=Main_Page)进行了比较,并且为了匹配性能,我必须使用-openmp和-axAVX编译Eigen。

最后要回答您的问题,除非您可以使用openmp,AVX指令编译numpy底层lib,否则我认为您无法使Python代码更快。

这是教程https://docs.scipy.org/doc/scipy/reference/building/linux.html

祝你好运,让我们知道如何进行。

答案 1 :(得分:0)

请始终发布您到目前为止尝试过的内容。关于您的Numba版本,我认为您做的事情会导致性能下降。

示例

import numpy as np
import numba as nb
import time

@nb.njit(fastmath=True)
def your_function(fx,fy,aPx,aPy,img):
  pi=np.pi
  sum=0.
  for i in range(aPx.shape[0]):
    for j in range(aPx.shape[1]):
      sum+=img[i,j]*np.exp(-1j*2*pi*(fx*aPx[i,j]+fy*aPy[i,j]))
  return np.abs(sum)

@nb.njit(fastmath=True,parallel=True)
def your_function_p(fx,fy,aPx,aPy,img):
  pi=np.pi
  sum=0.
  for i in nb.prange(aPx.shape[0]):
    for j in range(aPx.shape[1]):
      sum+=img[i,j]*np.exp(-1j*2*pi*(fx*aPx[i,j]+fy*aPy[i,j]))
  return np.abs(sum)

#The function gets compiled at the first call
#you may also use cache=True, which only works in single threaded code
F=your_function(fx,fy,aPx,aPy,img)
start = time.time()
for i in range(20):
    F=your_function(fx,fy,aPx,aPy,img)

end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))
print(F)

F=your_function_p(fx,fy,aPx,aPy,img)
start = time.time()
for i in range(20):
    F=your_function_p(fx,fy,aPx,aPy,img)

end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))
print(F)

定时(4C / 8T)

your_version: 2.45s
Numba single threaded: 0.17s
Numba parallel: 0.07s