我最近从Matlab切换到了 Python.在转换我的一个冗长代码时,我惊讶地发现Python非常慢.我用一个功能占用时间来描述和追踪问题.这个函数是从我的代码中的各个地方调用的(是递归调用的其
简而言之,以下代码总结了手头的问题:
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的不那么直观.