当前位置 : 主页 > 网络安全 > 测试自动化 >

性能:Matlab与Python

来源:互联网 收集:自由互联 发布时间:2021-06-22
我最近从Matlab切换到了 Python.在转换我的一个冗长代码时,我惊讶地发现Python非常慢.我用一个功能占用时间来描述和追踪问题.这个函数是从我的代码中的各个地方调用的(是递归调用的其
我最近从Matlab切换到了 Python.在转换我的一个冗长代码时,我惊讶地发现Python非常慢.我用一个功能占用时间来描述和追踪问题.这个函数是从我的代码中的各个地方调用的(是递归调用的其他函数的一部分). Profiler建议在Matlab和Python中对此函数进行300次调用.

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

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

结果

比较结果似乎在调用“全部清除”后,Matlab的速度提高了约42倍,如果脚本多次运行而没有调用“全部清除”,则速度提高100倍.如果不是两个数量级更快,那至少是数量级.这对我来说是一个非常令人惊讶的结果.我期待结果是另一种方式.

有人可以对此有所了解吗?

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

边注

我也尝试使用numpy.sqrt,这会使性能变差,因此我在Python中使用math.sqrt.

编辑

调用函数的for循环纯粹是虚构的.他们只是为了“模拟”对函数的300次调用.正如我之前所描述的,内核函数(Matlab中的kernel_2D和Python中的kex1)是从程序中的各个不同位置调用的.为了缩短问题,我使用for循环“模拟”300个调用.由于内核矩阵的结构,内核函数内的for循环是必不可少的并且是不可避免的.

编辑2

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

你想摆脱那些循环.试试这个:

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的不那么直观.

网友评论