繁体   English   中英

如何从3维中的sympy表达式获得快速lambda函数?

[英]How to get a fast lambda function from an sympy expression in 3 dimensions?

我正在使用sympy为cfd模拟生成不同的表达式。 这些表达式大多数是exp = f(x,y,z),例如f(x,y,z)= sin(x)* cos(y)* sin(z)。 要在网格上获取值,我使用simpy.lambdify。 例如:

import numpy as np
import sympy as sp
from sympy.abc import x,y,z

xg, yg, zg = np.mgrid[0:1:50*1j, 0:1:50*1j, 0:1:50*1j]
f  = sp.sin(x)*sp.cos(y)*sp.sin(z)

lambda_f = sp.lambdify([x,y,z], f, "numpy")
fn = lambda_f(xg, yg, zg)

print fn

这似乎工作得很好但不幸的是我的表达式越来越复杂,网格计算需要花费很多时间。 我的想法是,可能使用uFuncify方法(参见http://docs.sympy.org/latest/modules/numeric-computation.html )来加快计算速度,我不确定这是否是正确的方法? 我也不知道如何让3d功能为3d网格工作? 感谢您的任何建议

在以前的版本(0.7.5和之前版本)中, ufuncify仅针对第一个参数(单个维度数组)进行了第一个参数(不是非常令人兴奋)。 由于0.7.6(尚未公布,但应该是在一个星期!) ufuncify创建的实际情况numpy.ufunc默认(包在numpy的API C代码)。 上面的代码只需要很小的改动就可以了。

In [1]: import numpy as np

In [2]: from sympy import sin, cos, lambdify

In [3]: from sympy.abc import x,y,z

In [4]: from sympy.utilities.autowrap import ufuncify

In [5]: from sympy.printing.theanocode import theano_function

In [6]: xg, yg, zg = np.mgrid[0:1:50*1j, 0:1:50*1j, 0:1:50*1j]

In [7]: f  = sym.sin(x)*sym.cos(y)*sym.sin(z)

In [8]: ufunc_f = ufuncify([x,y,z], f)

In [9]: theano_f = theano_function([x, y, z], f, dims={x: 3, y: 3, z: 3})

In [10]: lambda_f = lambdify([x, y, z], f)

In [11]: type(ufunc_f)
Out[11]: numpy.ufunc

In [12]: type(theano_f)
Out[12]: theano.compile.function_module.Function

In [13]: type(lambda_f)
Out[13]: function

In [14]: %timeit ufunc_f(xg, yg, zg)
10 loops, best of 3: 21 ms per loop

In [15]: %timeit theano_f(xg, yg, zg)
10 loops, best of 3: 20.7 ms per loop

In [16]: %timeit lambda_f(xg, yg, zg)
10 loops, best of 3: 22.3 ms per loop

对于这个简单的表达式, ufuncifytheano_function是可比的,并且比lambdify稍快。 使用下面给出的更复杂的表达式,差异更大:

In [17]: f = sin(x)*cos(y)*sin(z) + sin(4*(x - y**2*sin(z)))

In [18]: ufunc_f = ufuncify([x,y,z], f)

In [19]: theano_f = theano_function([x, y, z], f, dims={x: 3, y: 3, z: 3})

In [20]: lambda_f = lambdify([x, y, z], f)

In [21]: %timeit ufunc_f(xg, yg, zg)
10 loops, best of 3: 29.2 ms per loop

In [22]: %timeit theano_f(xg, yg, zg)
10 loops, best of 3: 29.2 ms per loop

In [23]: %timeit lambda_f(xg, yg, zg)
10 loops, best of 3: 42.1 ms per loop

这比使用python版本快得多,因为没有创建中间数组,遍历循环并且计算在C中运行.Theano产生相同的速度,因为它们也编译为本机代码。 对于我在进行多体动力学时看到的大表达式, ufuncify (和相关的自动autowrap )的执行速度明显快于lambdify 我对theano没有多少经验,所以我不能说他们的方法有多好,但我认为它会是相似的。

正如我上面所说,这仅适用于0.7.6及更高版本。 应尽快发布,但在此之前你可以从github获取源代码。 关于ufuncify新行为的文档可以在这里找到

也许你可以使用sympy的theano_function 根据您提供的文档的链接 ,它具有与ufuncify类似的速度,并且可以与mgrid一起使用:

import numpy as np
import sympy as sp
from sympy.printing.theanocode import theano_function

x,y,z  = sp.symbols('x y z')
xg, yg, zg = np.mgrid[0:1:50*1j, 0:1:50*1j, 0:1:50*1j]
f  = sp.sin(x)*sp.cos(y)*sp.sin(z)

ft = theano_function([x,y,z], [f], dims={x: 3, y: 3, z: 3})
ft(xg,yg,zg)  # result is similar to your fn

但是,对于这个特定的函数f ,我的lambdified版本系统和theano-ized版本的执行速度是相似的:

In [24]: %timeit fn = lambda_f(xg, yg, zg)
10 loops, best of 3: 53.2 ms per loop

In [25]: %timeit fn = ft(xg,yg,zg)
10 loops, best of 3: 52.7 ms per loop

使功能稍微困难一点,

In [27]: f = sp.sin(x)*sp.cos(y)*sp.sin(z) + sp.sin(4*(x-y**2*sp.sin(z)))

In [30]: %timeit fl(xg,yg,zg)  # lambdified version
10 loops, best of 3: 89.4 ms per loop

In [31]: %timeit ft(xg,yg,zg)  # Theano version
10 loops, best of 3: 67.6 ms per loop

使得时间差异对我来说稍微大一些(并且支持theano),但也许在你的功能上你会遇到更大的时间差异?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM