Desempenho: Matlab vs Python
Eu mudei recentemente deMatlab
paraPython
. Ao converter um dos meus códigos longos, fiquei surpreso ao descobrirPython
sendo muito lento. Eu criei um perfil e traçou o problema com uma função que monitora o tempo. Essa função está sendo chamada de vários lugares no meu código (fazendo parte de outras funções que são chamadas recursivamente). O Profiler sugere que300 chamadas são feitas para essa função em ambosMatlab
ePython
.
Em resumo, os seguintes códigos resumem o problema em questão:
MATLAB
A classe que contém a função:
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
e o script para chamar 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
Dá a saída
clear all
>> test
Elapsed time is 0.022426 seconds.
>> test
Elapsed time is 0.009852 seconds.
PYTHON 3.4
Classe que contém a função 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
e o script para chamar 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))
Dá a saída
%run test.py
0.940515 secs
%run test.py
0.884418 secs
%run test.py
0.940239 secs
RESULTADOS
Comparando os resultados, pareceMatlab
é cerca de 42 vezes mais rápido depois de um "clear all
"é chamado e 100 vezes mais rápido se o script for executado várias vezes sem chamar"clear all
". Isso é pelo menos uma ordem de magnitude, senão duas ordens de magnitude mais rápidas. Esse é um resultado muito surpreendente para mim. Eu esperava que o resultado fosse o contrário.
Alguém por favor pode lançar alguma luz sobre isso?
Alguém pode sugerir uma maneira mais rápida de fazer isso?
NOTA
Eu também tentei usarnumpy.sqrt
o que piora o desempenho, por isso estou usandomath.sqrt
noPython
.
EDITAR
ofor
os loops para chamar as funções são puramente fictícios. Eles estão lá apenas para "simular" 300 chama para a função. Como descrevi anteriormente, o kernel funciona (kernel_2D
noMatlab
ekex1
noPython
) são chamados de vários lugares diferentes do programa. Para diminuir o problema, eu "simular" a300 chamadas usando ofor
ciclo. ofor
loops dentro das funções do kernel são essenciais e inevitáveis devido à estrutura da matriz do kernel.
EDIT 2
Aqui está o problema maior:https://github.com/drfahdsiddiqui/bbfmm2d-python