Numpy 使用lambdify和函数求值优化运行时
我目前正在优化代码的运行时,它仍然不在我希望的时间消耗范围内。我已经到了这样的地步,80%的时间都花在对我的辛矩阵表达式运行lambdify(),并在执行高斯求积时计算得到的lambda函数上。代码的所有其他方面都得到了充分的优化,因此我希望有人能帮助我优化代码中lambdizing和求值sympy表达式的实质性“瓶颈” 代码是在64位Windows 7机器上使用Python 3.5.2编写的(下面的示例演示了代码,在Jupyter QtConsole上执行)和以下模块版本:Numpy 使用lambdify和函数求值优化运行时,numpy,optimization,sympy,numba,lambdify,Numpy,Optimization,Sympy,Numba,Lambdify,我目前正在优化代码的运行时,它仍然不在我希望的时间消耗范围内。我已经到了这样的地步,80%的时间都花在对我的辛矩阵表达式运行lambdify(),并在执行高斯求积时计算得到的lambda函数上。代码的所有其他方面都得到了充分的优化,因此我希望有人能帮助我优化代码中lambdizing和求值sympy表达式的实质性“瓶颈” 代码是在64位Windows 7机器上使用Python 3.5.2编写的(下面的示例演示了代码,在Jupyter QtConsole上执行)和以下模块版本: Sympy:1.
- Sympy:1.0
- Numpy:1.11.1
- 努巴:0.27
from sympy import *
import numpy as np
import timeit
xi1 = symbols('xi1')
xi2 = symbols('xi2')
M = Matrix([[-0.0015625*(3.46410161513775*(0.00624999999999998*xi2 -
0.99375)*Piecewise((-1, 0.00624999999999998*xi2 - 0.99375 >= 0),
(1, 0.00624999999999998*xi2 - 0.99375 < 0)) +
1.73205080756888)*Piecewise((1, And(0.00624999999999998*xi2 -
0.99375 <= 1, 0.00624999999999998*xi2 -
0.99375 >= -1)), (0, True))],
[-0.00156249999999999*(0.0187499999999999*xi2 + 2.0*Piecewise((-1,
0.00624999999999998*xi2 - 0.99375 >= 0), (1,
0.00624999999999998*xi2 - 0.99375 < 0)) - 2.98125)*Piecewise((1,
And(0.00624999999999998*xi2 - 0.99375 <= 1,
0.00624999999999998*xi2 - 0.99375 >= -1)), (0, True))],
[-0.00270632938682636*xi1*(3.46410161513775*
(0.00624999999999998*xi2 - 0.99375)*Piecewise((-1,
0.00624999999999998*xi2 - 0.99375 >= 0), (1,
0.00624999999999998*xi2 - 0.99375 < 0)) +
1.73205080756888)*Piecewise((1, And(0.00624999999999998*xi2 -
0.99375 <= 1, 0.00624999999999998*xi2 - 0.99375 >= -1)), (0,
True))]])
M_simpl = Matrix([(xi2**2),(xi2**2)*xi1,(xi2**2)*(xi1**2)])
这表明,处理更复杂的表达式的速度比处理更简单的矩阵慢近10倍,当lambdify()应用于其中几种类型的矩阵时,这对运行时有很大的贡献。
研究了我在Struts.Uptual.AutoWrAP中使用的更快UfcIffy()函数的主题,它似乎使用FORTRAN或C++后端工作得最好。然而,这不是我的最佳选择,因为函数还没有扩展到Saly矩阵,我希望代码足够通用。S.T.其他Windows用户适应代码不需要安装C++编译器等。
那么,在不使用其他编译器的情况下,这些类型的symphy表达式是否可以加快lambdify()函数的速度?
Lambda函数求值
上述辛矩阵的lambdifyed函数在特定坐标下进行求值时也会执行不同的操作。这通过以下简单的5点正交示例进行说明:
# Quadrature coordinates
xi_v = np.array([[-1,-1], [-0.5,-0.5], [0,0], [0.5,0.5], [1,1]])
# Quadrature weights
w = np.array([3, 2, 1, 2, 3])
# Quadrature
def quad_func(func, xi_v, w):
G = np.zeros((3, 1))
for i in range(0, len(w), 1):
G += w[i]*func(*xi_v[i,:])
return G
# Testing time usage
f = lambdify([xi1,xi2], M, 'numpy')
%timeit quad_func(f, xi_v, w)
1000 loops, best of 3: 852 µs per loop
f_simpl = lambdify([xi1,xi2], M_simpl, 'numpy')
%timeit quad_func(f_simpl, xi_v, w)
10000 loops, best of 3: 33.9 µs per loop
我的第一反应是从numba模块引入jit,以加快评估速度。但是,这导致出现一个弹出窗口,指出python已停止工作,内核已重新启动(对于f和f_siml都发生):
那么,为了减少总的运行时间,有没有加快这些lambda函数的计算速度?或者可能是某种避免numba.jit崩溃的方法?您可以尝试更新
numba
,当前版本为0.33,可能只是他们修复了“内核死机”的原因。
# Quadrature coordinates
xi_v = np.array([[-1,-1], [-0.5,-0.5], [0,0], [0.5,0.5], [1,1]])
# Quadrature weights
w = np.array([3, 2, 1, 2, 3])
# Quadrature
def quad_func(func, xi_v, w):
G = np.zeros((3, 1))
for i in range(0, len(w), 1):
G += w[i]*func(*xi_v[i,:])
return G
# Testing time usage
f = lambdify([xi1,xi2], M, 'numpy')
%timeit quad_func(f, xi_v, w)
1000 loops, best of 3: 852 µs per loop
f_simpl = lambdify([xi1,xi2], M_simpl, 'numpy')
%timeit quad_func(f_simpl, xi_v, w)
10000 loops, best of 3: 33.9 µs per loop
import numba
quad_func_jit = numba.jit(quad_func)
quad_func_jit(f, xi_v, w)
Kernel died, restarting