用Cython科学优化代码:Ising模型

123 阅读3分钟

Python的编码快速而简单,但在进行密集的数字运算时可能会很慢。将代码翻译成Cython可能会有帮助,但在大多数情况下需要进行一些试验和错误,以达到最佳效果。Cython的教程包含了很多信息,但对于像用Cython进行优化这样的迭代工作流程,看到它 "现场 "完成往往很有用。

出于这个原因,我决定录制一些截屏,展示这个迭代优化过程,使用一个Ising模型,作为一个应用实例。

何时使用Cython¶

在播放视频之前,我想先说说什么时候以及为什么会选择Cython。

对于科学的Python代码,在转向Cython之前,我建议尽可能多地使用矢量化。矢量化包括明智地使用NumPy、SciPy、Pandas和其他库中的内置例程来减少代码中显式for-loops的数量。它在很多情况下都能很好地工作,而且在运行你的代码时不需要任何特殊的编译步骤。请看我在PyCon 2015的演讲《失去你的循环》,了解这种方法的介绍。

当一个问题不能用标准的矢量化方法轻易解决时,Cython是一个不错的选择。Cython提供了Python和C代码之间的桥梁,并且相当成熟和可靠:它构成了PyData/Scientific Python生态系统的大部分基础(例如,Cython在NumPy、SciPy、Pandas、Scikit-Learn和许多其他软件包中被大量使用)。

其他优化Python代码的方法也有,但我倾向于不像Cython那样经常使用它们。

PyPy项目是Python的另一种实现,它避免了默认CPython实现的慢速循环。虽然它很有前途,但目前它不支持许多核心科学软件包,所以不是科学代码的最佳选择(尽管这一点已经在改变)。

Numba是一个Python-to-LLVM转换器,通过给Python函数添加一个简单的编译装饰器,通常可以使你的Python速度提高100倍。关于Numba用于本笔记本中的代码的例子,见Matthew Rocklin的文章。虽然它很方便,但Numba还不支持所有的Python结构,而且当最直接的方法失败时,可能很难优化。

视频¶

最后,这里有使用Cython优化Ising模型的演示。

在[1]中。

from

第1部分¶

在第一部分中,我写了一个在Python中演化Ising模型的函数,以及一些可视化演化结果的工具。

在[2]中。

YouTubeVideo

Out[2]:

第2部分¶

在第二部分中,我通过Cython优化这个函数的过程。

在[3]中。

YouTubeVideo

Out[3]:

代码¶

下面你可以看到我在这两个视频中写的代码。

1.简单的Python Ising模型¶。

显示一个Ising字段¶。

In[4]:

import

Out[4]:

array([[ 1, -1, -1,  1, -1, -1,  1, -1,  1,  1],
       [ 1, -1,  1, -1, -1,  1, -1, -1, -1, -1],
       [-1,  1,  1,  1, -1, -1,  1,  1,  1, -1],
       [ 1, -1, -1,  1, -1,  1, -1,  1,  1, -1],
       [-1,  1, -1, -1, -1,  1, -1, -1, -1, -1],
       [-1,  1,  1, -1,  1, -1,  1,  1, -1, -1],
       [ 1, -1,  1, -1,  1, -1, -1,  1,  1, -1],
       [-1,  1, -1, -1,  1, -1, -1, -1, -1, -1],
       [ 1, -1, -1, -1,  1,  1, -1,  1, -1,  1],
       [ 1,  1,  1, -1,  1, -1,  1,  1, -1, -1]])

在[5]中。

# pip install pillow

Out[5]:

实现Ising模型¶。

在[6]中。

def

在[7]中。

display_spin_field

输出[7]:

为Ising序列制作动画¶。

注意,这需要一个活的内核,所以不会出现在博客或其他静态渲染上。

在[8]中。

from

在[9]中。

images

结果将看起来像这样。

[Ising-Slider-1.gif]

2.使用Cython来加快速度¶。

在[10]中。

%

在[11]中。

%%

对结果进行计时¶。

在[12]中。

field
317 ms ± 10.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
2.64 ms ± 132 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

实现结果的可视化¶。

(请注意,下面的代码需要一个实时的内核,而不会在静态的渲染中显示,如博客文章)。

在[13]中。

images

结果将看起来像这样。

[Ising-Slider-2.gif]