我试图加速我的代码,但这部分代码给我带来了问题
我尝试使用Cython,然后遵循给定的建议here,但是我的纯python函数比Cython和Cython优化的函数性能都要好
cython代码如下:
import numpy as np
cimport numpy as np
DTYPE = np.float
ctypedef np.float_t DTYPE_t
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def compute_cython(u, PorosityProfile, DensityIceProfile, DensityDustProfile, DensityProfile):
DustJ, DustF, DustG, DustH, DustI = 250.0, 633.0, 2.513, -2.2e-3, -2.8e-6
IceI, IceC, IceD, IceE, IceF, IceG, IceH = 273.16, 1.843e5, 1.6357e8, 3.5519e9, 1.6670e2, 6.4650e4, 1.6935e6
delta = u-DustJ
result_dust = DustF+DustG*delta+DustH*delta**2+DustI*(delta**3);
x= u/IceI;
result_ice = (x**3)*(IceC+IceD*(x**2)+IceE*(x**6))/(1+IceF*(x**2)+IceG*(x**4)+IceH*(x**8))
return (DensityIceProfile*result_ice+DensityDustProfile*result_dust)/DensityProfile
def compute_cythonOptimized(np.ndarray[DTYPE_t, ndim=1] u, np.ndarray[DTYPE_t, ndim=1] PorosityProfile, np.ndarray[DTYPE_t, ndim=1] DensityIceProfile, np.ndarray[DTYPE_t, ndim=1] DensityDustProfile, np.ndarray DensityProfile):
assert u.dtype == DTYPE
assert PorosityProfile.dtype == DTYPE
assert DensityIceProfile.dtype == DTYPE
assert DensityDustProfile.dtype == DTYPE
assert DensityProfile.dtype == DTYPE
cdef float DustJ = 250.0
cdef float DustF = 633.0
cdef float DustG = 2.513
cdef float DustH = -2.2e-3
cdef float DustI = -2.8e-6
cdef float IceI = 273.16
cdef float IceC = 1.843e5
cdef float IceD = 1.6357e8
cdef float IceE = 3.5519e9
cdef float IceF = 1.6670e2
cdef float IceG = 6.4650e4
cdef float IceH = 1.6935e6
cdef np.ndarray[DTYPE_t, ndim=1] delta = u-DustJ
cdef np.ndarray[DTYPE_t, ndim=1] result_dust = DustF+DustG*delta+DustH*delta**2+DustI*(delta**3);
cdef np.ndarray[DTYPE_t, ndim=1] x= u/IceI;
cdef np.ndarray[DTYPE_t, ndim=1] result_ice = (x**3)*(IceC+IceD*(x**2)+IceE*(x**6))/(1+IceF*(x**2)+IceG*(x**4)+IceH*(x**8))
return (DensityIceProfile*result_ice+DensityDustProfile*result_dust)/DensityProfile
然后运行以下命令:
^{pr2}$结果如下:
对于纯python:68.9 µs ± 851 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
对于非优化cython:68.2 µs ± 685 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
对于优化的一个:72.7 µs ± 416 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
我做错什么了?在
谢谢你的帮助
使用Numba的解决方案
代码外科医生已经用Cython给出了一个很好的答案。在这个答案中,我不想展示另一种使用Numba的方法。在
我创造了三个版本。在
naive_numba
中,我只添加了一个函数修饰符。在improved_Numba
中,我手动组合了这些循环(每个矢量化的命令实际上都是一个循环)。在improved_Numba_p
中,我已经并行化了函数。请注意,在使用平行加速器时,显然存在一个不允许定义常量值的错误。还需要注意的是,并行化版本只对较大的输入数组有利。但您也可以添加一个小包装器,根据输入数组的大小调用单线程或并行化版本。在代码dtype=float64
性能
^{pr2}$代码类型=np.浮动32
如果np.浮动32只需将函数中的所有常量值显式声明为float32就足够了。否则Numba将使用float64。在
性能
与@coderegram提供的Cython版本相比并不公平,因为他没有使用启用的AVX2和FMA3指令编译函数。Numba在默认情况下使用-march=native编译,它在我的核心i7-4xxx上启用AVX2和FMA3指令。在
但是如果你不想发布一个编译过的Cython版本的代码,这就很有意义了,因为如果启用了这些优化,它将不会在pre-Haswell处理器(或所有的奔腾和赛扬)上运行。编译多个代码路径应该是可能的,但这取决于编译器,而且需要更多的工作。在
我基本上同意@chepner和@胡安帕.阿里维拉加在评论中。此外,在mpy函数库中,所有的标量运算都是正确的。在
但是,实际上有一种方法可以显著提高cython代码的性能,这要归功于您的特定算法的构造方式,如果我们使用以下假设(并且可以容忍难看的代码):
numpy.dot
,因为代码中的所有操作都只将标量与矩阵结合起来。在for
循环是不可想象的,但在cython中迭代每个索引是非常可行的。此外,最终输出中的每个项只依赖于对应于该项索引的输入(即第0项使用u[0]
、PorosityProfile[0]
等)。在compute_python
函数中返回的最终结果感兴趣。因此,为什么要浪费时间为所有这些中间numpy数组分配内存呢?在x**y
语法的速度非常慢。我使用gcc
编译器选项ffast-math
来显著改善这一点。我还使用了几个cython编译器指令来避免python检查和开销。在考虑到所有这些因素,下面是修改后的代码。它的性能比我笔记本电脑上天真的python版本快了近一个数量级。在
升华.pyx
设置.py
^{pr2}$主.py
让我知道,如果在我的解释中,这个答案是如何工作的,我希望它有帮助!在
更新1:
不幸的是,我无法让MSYS2和numba(这取决于LLVM)彼此友好相处,因此我无法进行任何直接比较。然而,按照@max9111的建议,我将
-march=native
添加到我的setup.py
文件中的args
列表中;但是,时间安排与之前没有明显不同。在从this great answer来看,在numpy数组和类型化memoryviews之间的自动转换中,在初始函数调用中(以及在返回语句中,如果您将结果转换回原处)都会发生一些开销。恢复为使用如下函数签名:
每次调用节省1us,将其减少到3.6us,而不是4.6us,这有点重要,特别是如果函数要多次调用。当然,如果您计划多次调用该函数,那么只传入二维numpy数组可能更有效,这样可以节省大量的python函数调用开销,并分摊
numpy array -> typed memoryview
转换的成本。此外,使用numpy结构的数组可能会很有趣,它可以在cython中转换为一个类型化的memoryview结构,因为这样可以使缓存中的所有数据更接近,并加快内存访问时间。在最后,正如前面的评论中所承诺的,这里有一个使用
prange
的版本,它利用了并行处理。注意,这只能与类型化的memoryviews一起使用,因为python的GIL必须在prange循环中发布(并使用-fopenmp
fla进行编译)g代表args
和link_args
:更新2:
根据@max9111在注释中提供的非常有用的附加建议,我将代码中的所有
float[:]
声明切换到float[::1]
。这一点的意义在于,它允许数据连续存储,而cython不需要担心元素之间是否存在跨距。这允许SIMD矢量化,从而显著地进一步优化代码。以下是使用以下命令生成的更新的计时:相关问题 更多 >
编程相关推荐