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