性能:Matlab vs Python

2024-10-01 15:45:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近从Matlab切换到Python。在转换我的一个冗长的代码时,我惊讶地发现Python非常慢。我用一个占用时间的函数描述并跟踪了这个问题。这个函数在我的代码中从不同的地方被调用(是递归调用的其他函数的一部分)。Profiler建议在MatlabPython中对该函数进行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的脚本:

^{pr2}$

给出输出

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

PYTHON 3.4

包含函数的类自定义内核.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

以及要调用的脚本测试.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

结果

比较结果,在调用“clear all”之后,Matlab大约快42倍,如果脚本多次运行而不调用“clear all”,则速度要快100倍。这至少是一个数量级,如果不是两个数量级的话。这对我来说是一个非常令人惊讶的结果。我原以为结果会是相反的。在

有人能解释一下吗?在

有人能建议一个更快的方法来完成这个吗?在

旁注

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

编辑

用于调用函数的for循环纯粹是虚构的。它们只是为了“模拟300调用函数。如前所述,内核函数(Matlab中的kernel_2D和{}中的kex1)是从程序的不同位置调用的。为了缩短问题,我使用for循环“模拟”调用300。由于核矩阵的结构,核函数内部的for循环是必不可少的,也是不可避免的。在

编辑2

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


Tags: 函数代码frompytestimportforfunction
3条回答

Matlab使用商业MKL库。如果您使用免费的python发行版,请检查您是否在python中使用了MKL或其他高性能blas库,或者它是默认库,这可能会慢得多。在

你想去掉那些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的直观性稍差。在

在进一步的调查中,我发现使用indices的方法仍然比较慢。在

解决方案:使用meshgrid

def exampleKernelA(M, x, N, y):
    """Example kernel function A"""
    # Euclidean norm function implemented using meshgrid idea.
    # Fastest
    x0, y0 = meshgrid(y[:, 0], x[:, 0])
    x1, y1 = meshgrid(y[:, 1], x[:, 1])
    # Define custom kernel here
    kernel = sqrt((x0 - y0) ** 2 + (x1 - y1) ** 2)
    return kernel

结果:非常快,比indices方法快10倍。我得到了更接近C的时间

然而:使用meshgridMatlab一起使用比这两个都快10倍的C和{}。在

还在想为什么!在

相关问题 更多 >

    热门问题