一尘不染

性能:Matlab与Python

python

我最近从切换MatlabPython。在转换我冗长的代码之一时,我很惊讶地发现运行Python速度很慢。我用一个耗时的功能来分析和跟踪问题。我的代码中的各个位置都正在调用此函数(是其他递归调用的函数的一部分)。Profiler建议在和中都对该函数进行
300次 调用。Matlab``Python

简而言之,以下代码总结了当前的问题:

MATLAB

包含函数的类:

classdef ExampleKernel1 < handle  
methods (Static)
    function [kernel] = kernel_2D(M,x,N,y) 
        kernel  = zeros(M,N);
        for i= 1 : M
            for j= 1 : N
                % Define the custom kernel function here
                kernel(i , j) = sqrt((x(i , 1) - y(j , 1)) .^ 2 + ...
                                (x(i , 2) - y(j , 2)) .^2 );             
            end
        end
    end
end
end

和调用test.m的脚本:

xVec=[   
49.7030   78.9590
42.6730   11.1390
23.2790   89.6720
75.6050   25.5890
81.5820   53.2920
44.9680    2.7770
38.7890   78.9050
39.1570   33.6790
33.2640   54.7200
4.8060   44.3660
49.7030   78.9590
42.6730   11.1390
23.2790   89.6720
75.6050   25.5890
81.5820   53.2920
44.9680    2.7770
38.7890   78.9050
39.1570   33.6790
33.2640   54.7200
4.8060   44.3660
];
N=size(xVec,1);
kex1=ExampleKernel1;
tic
for i=1:300
    K=kex1.kernel_2D(N,xVec,N,xVec);
end
toc

给出输出

clear all
>> test
Elapsed time is 0.022426 seconds.
>> test
Elapsed time is 0.009852 seconds.

PYTHON 3.4

包含函数CustomKernels.py的类:

from numpy import zeros
from math import sqrt
class CustomKernels:
"""Class for defining the custom kernel functions"""
    @staticmethod
    def exampleKernelA(M, x, N, y):
        """Example kernel function A"""
        kernel = zeros([M, N])
        for i in range(0, M):
            for j in range(0, N):
                # Define the custom kernel function here
                kernel[i, j] = sqrt((x[i, 0] - y[j, 0]) ** 2 + (x[i, 1] - y[j, 1]) ** 2)
        return kernel

和调用test.py的脚本:

import numpy as np
from CustomKernels import CustomKernels
from time import perf_counter

xVec = np.array([
    [49.7030,  78.9590],
    [42.6730,  11.1390],
    [23.2790,  89.6720],
    [75.6050,  25.5890],
    [81.5820,  53.2920],
    [44.9680,   2.7770],
    [38.7890,  78.9050],
    [39.1570,  33.6790],
    [33.2640,  54.7200],
    [4.8060 ,  44.3660],
    [49.7030,  78.9590],
    [42.6730,  11.1390],
    [23.2790,  89.6720],
    [75.6050,  25.5890],
    [81.5820,  53.2920],
    [44.9680,   2.7770],
    [38.7890,  78.9050],
    [39.1570,  33.6790],
    [33.2640,  54.7200],
    [4.8060 ,  44.3660]
    ])
N = xVec.shape[0]
kex1 = CustomKernels.exampleKernelA
start=perf_counter()
for i in range(0,300):
    K = kex1(N, xVec, N, xVec)
print(' %f secs' %(perf_counter()-start))

给出输出

%run test.py
 0.940515 secs
%run test.py
 0.884418 secs
%run test.py
 0.940239 secs

结果

比较结果,似乎Matlabclear all调用“ ”之后要快大约42倍,如果脚本多次运行而不调用“ clear all”则要快100倍。如果不是两个数量级,则至少快一个数量级。这对我来说是非常令人惊讶的结果。我期望结果是相反的。

有人可以说明一下吗?

有人可以建议一种更快的方法来执行此操作吗?

边注

我也试图利用numpy.sqrt这使得性能更差,因此我使用math.sqrtPython

编辑

for调用函数的循环纯粹是虚构的。他们在那里只是为了“ 模拟 ”对该函数的 300个
调用。如前所述,内核函数(kernel_2DinMatlabkex1in
Python)是从程序中的不同位置调用的。为了简化问题,我使用循环“ 模拟 ”了 300个
调用for。该for内核函数内部循环,因为核矩阵的结构是必要的,不可避免的。

编辑2

这是更大的问题:https :
//github.com/drfahdsiddiqui/bbfmm2d-python


阅读 166

收藏
2020-12-20

共1个答案

一尘不染

您想摆脱那些for循环。尝试这个:

def exampleKernelA(M, x, N, y):
    """Example kernel function A"""
    i, j = np.indices((N, M))
    # Define the custom kernel function here
    kernel[i, j] = np.sqrt((x[i, 0] - y[j, 0]) ** 2 + (x[i, 1] - y[j, 1]) ** 2)
    return kernel

您也可以通过广播来做到这一点,它可能更快,但是来自的直观性却有所下降MATLAB

2020-12-20