Rendimiento: Matlab vs Python

Recientemente cambié deMatlab aPython. Mientras convertía uno de mis largos códigos, me sorprendió encontrarPython siendo muy lento Perfilé y rastreé el problema con una función que acaparaba el tiempo. Esta función se llama desde varios lugares en mi código (forma parte de otras funciones que se llaman recursivamente). Profiler sugiere que300 Se realizan llamadas a esta función tanto enMatlab yPython.

En resumen, los siguientes códigos resumen el problema en cuestión:

MATLAB

La clase que contiene la función:

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

y el script para llamar a 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

Da la salida

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

PYTHON 3.4

Clase que contiene la función 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

y el script para llamar a 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))

Da la salida

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

RESULTADOS

Comparando los resultados pareceMatlab es aproximadamente 42 veces más rápido después de un "clear all"se llama y luego 100 veces más rápido si el script se ejecuta varias veces sin llamar"clear all". Eso es al menos un orden de magnitud si no dos órdenes de magnitud más rápido. Este es un resultado muy sorprendente para mí. Esperaba que el resultado fuera al revés.

¿Alguien puede arrojar algo de luz sobre esto?

¿Alguien puede sugerir una forma más rápida de realizar esto?

NOTA LATERAL

También he tratado de usarnumpy.sqrt lo que empeora el rendimiento, por lo tanto, estoy usandomath.sqrt enPython.

EDITAR

losfor Los bucles para llamar a las funciones son puramente ficticios. Están ahí solo para "simular" 300 llamadas a la función. Como describí anteriormente, las funciones del núcleo (kernel_2D enMatlab ykex1 enPython) se llaman desde varios lugares diferentes del programa. Para acortar el problema, yo "simular" el300 llamadas usando elfor lazo. losfor los bucles dentro de las funciones del núcleo son esenciales e inevitables debido a la estructura de la matriz del núcleo.

EDITAR 2

Aquí está el problema más grande:https://github.com/drfahdsiddiqui/bbfmm2d-python

Respuestas a la pregunta(5)

Su respuesta a la pregunta